mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-08-11 09:13:57 -04:00
corrected merge conflicts
This commit is contained in:
commit
fb6eedc644
@ -548,7 +548,7 @@ Calibre has several keyboard shortcuts to save you time and mouse movement. Thes
|
|||||||
- Toggle jobs list
|
- Toggle jobs list
|
||||||
* - :kbd:`Alt+Shift+B`
|
* - :kbd:`Alt+Shift+B`
|
||||||
- Toggle Cover Browser
|
- Toggle Cover Browser
|
||||||
* - :kbd:`Alt+Shift+B`
|
* - :kbd:`Alt+Shift+D`
|
||||||
- Toggle Book Details panel
|
- Toggle Book Details panel
|
||||||
* - :kbd:`Alt+Shift+T`
|
* - :kbd:`Alt+Shift+T`
|
||||||
- Toggle Tag Browser
|
- Toggle Tag Browser
|
||||||
|
@ -19,23 +19,12 @@ class Slashdot(BasicNewsRecipe):
|
|||||||
|
|
||||||
__author__ = 'floweros edited by Huan T'
|
__author__ = 'floweros edited by Huan T'
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
|
use_embedded_content = False
|
||||||
keep_only_tags = [
|
keep_only_tags = [
|
||||||
dict(name='div',attrs={'id':'article'}),
|
dict(name='div',attrs={'class':'story'}),
|
||||||
dict(name='div',attrs={'class':['postBody' 'details']}),
|
dict(name='div',attrs={'class':'body'}),
|
||||||
dict(name='footer',attrs={'class':['clearfix meta article-foot']}),
|
dict(name='ul',attrs={'id':'commentlisting'}),
|
||||||
dict(name='article',attrs={'class':['fhitem fhitem-story article usermode thumbs grid_24']}),
|
]
|
||||||
dict(name='dl',attrs={'class':'relatedPosts'}),
|
|
||||||
dict(name='h2',attrs={'class':'story'}),
|
|
||||||
dict(name='span',attrs={'class':'comments'}),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
remove_tags = [
|
|
||||||
dict(name='aside',attrs={'id':'slashboxes'}),
|
|
||||||
dict(name='div',attrs={'class':'paginate'}),
|
|
||||||
dict(name='section',attrs={'id':'comments'}),
|
|
||||||
dict(name='span',attrs={'class':'topic'}),
|
|
||||||
]
|
|
||||||
|
|
||||||
feeds = [
|
feeds = [
|
||||||
(u'Slashdot',
|
(u'Slashdot',
|
||||||
|
Binary file not shown.
@ -822,7 +822,6 @@ application/x-lzh lzh
|
|||||||
application/x-lzx lzx
|
application/x-lzx lzx
|
||||||
application/x-maker book fb fbdoc fm frame frm maker
|
application/x-maker book fb fbdoc fm frame frm maker
|
||||||
application/x-mif mif
|
application/x-mif mif
|
||||||
application/x-mobipocket-ebook mobi prc
|
|
||||||
application/x-ms-application application
|
application/x-ms-application application
|
||||||
application/x-ms-wmd wmd
|
application/x-ms-wmd wmd
|
||||||
application/x-ms-wmz wmz
|
application/x-ms-wmz wmz
|
||||||
@ -1371,11 +1370,11 @@ application/x-sony-bbeb lrf lrx
|
|||||||
application/adobe-page-template+xml xpgt
|
application/adobe-page-template+xml xpgt
|
||||||
application/x-font-opentype otf
|
application/x-font-opentype otf
|
||||||
application/x-font-truetype ttf
|
application/x-font-truetype ttf
|
||||||
application/x-mobipocket-ebook mobi prc azw
|
application/x-mobipocket-ebook mobi prc
|
||||||
|
application/vnd.amazon.ebook azw3 azw azw2 azw4
|
||||||
application/x-cbz cbz
|
application/x-cbz cbz
|
||||||
application/x-cbr cbr
|
application/x-cbr cbr
|
||||||
application/x-cb7 cb7
|
application/x-cb7 cb7
|
||||||
application/x-koboreader-ebook kobo
|
application/x-koboreader-ebook kobo
|
||||||
image/wmf wmf
|
image/wmf wmf
|
||||||
application/ereader pdb
|
application/ereader pdb
|
||||||
|
|
||||||
|
@ -172,13 +172,14 @@ if iswindows:
|
|||||||
[
|
[
|
||||||
'calibre/devices/mtp/windows/utils.cpp',
|
'calibre/devices/mtp/windows/utils.cpp',
|
||||||
'calibre/devices/mtp/windows/device_enumeration.cpp',
|
'calibre/devices/mtp/windows/device_enumeration.cpp',
|
||||||
|
'calibre/devices/mtp/windows/content_enumeration.cpp',
|
||||||
'calibre/devices/mtp/windows/device.cpp',
|
'calibre/devices/mtp/windows/device.cpp',
|
||||||
'calibre/devices/mtp/windows/wpd.cpp',
|
'calibre/devices/mtp/windows/wpd.cpp',
|
||||||
],
|
],
|
||||||
headers=[
|
headers=[
|
||||||
'calibre/devices/mtp/windows/global.h',
|
'calibre/devices/mtp/windows/global.h',
|
||||||
],
|
],
|
||||||
libraries=['ole32', 'portabledeviceguids'],
|
libraries=['ole32', 'portabledeviceguids', 'user32'],
|
||||||
# needs_ddk=True,
|
# needs_ddk=True,
|
||||||
cflags=['/X']
|
cflags=['/X']
|
||||||
),
|
),
|
||||||
|
@ -9,14 +9,14 @@ msgstr ""
|
|||||||
"Project-Id-Version: calibre\n"
|
"Project-Id-Version: calibre\n"
|
||||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"POT-Creation-Date: 2011-11-25 14:01+0000\n"
|
"POT-Creation-Date: 2011-11-25 14:01+0000\n"
|
||||||
"PO-Revision-Date: 2012-06-22 17:32+0000\n"
|
"PO-Revision-Date: 2012-08-15 10:30+0000\n"
|
||||||
"Last-Translator: Jellby <Unknown>\n"
|
"Last-Translator: Jellby <Unknown>\n"
|
||||||
"Language-Team: Español; Castellano <>\n"
|
"Language-Team: Español; Castellano <>\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-06-23 05:01+0000\n"
|
"X-Launchpad-Export-Date: 2012-08-16 04:40+0000\n"
|
||||||
"X-Generator: Launchpad (build 15461)\n"
|
"X-Generator: Launchpad (build 15810)\n"
|
||||||
|
|
||||||
#. name for aaa
|
#. name for aaa
|
||||||
msgid "Ghotuo"
|
msgid "Ghotuo"
|
||||||
@ -5540,7 +5540,7 @@ msgstr "Forro"
|
|||||||
|
|
||||||
#. name for crj
|
#. name for crj
|
||||||
msgid "Cree; Southern East"
|
msgid "Cree; Southern East"
|
||||||
msgstr "Cree sudoriental"
|
msgstr "Cree suroriental"
|
||||||
|
|
||||||
#. name for crk
|
#. name for crk
|
||||||
msgid "Cree; Plains"
|
msgid "Cree; Plains"
|
||||||
@ -8336,15 +8336,15 @@ msgstr "Gimi (provincia West New Britain)"
|
|||||||
|
|
||||||
#. name for giq
|
#. name for giq
|
||||||
msgid "Gelao; Green"
|
msgid "Gelao; Green"
|
||||||
msgstr ""
|
msgstr "Gelao verde"
|
||||||
|
|
||||||
#. name for gir
|
#. name for gir
|
||||||
msgid "Gelao; Red"
|
msgid "Gelao; Red"
|
||||||
msgstr ""
|
msgstr "Gelao rojo"
|
||||||
|
|
||||||
#. name for gis
|
#. name for gis
|
||||||
msgid "Giziga; North"
|
msgid "Giziga; North"
|
||||||
msgstr ""
|
msgstr "Giziga septentrional"
|
||||||
|
|
||||||
#. name for git
|
#. name for git
|
||||||
msgid "Gitxsan"
|
msgid "Gitxsan"
|
||||||
@ -8352,7 +8352,7 @@ msgstr "Gitxsan"
|
|||||||
|
|
||||||
#. name for giw
|
#. name for giw
|
||||||
msgid "Gelao; White"
|
msgid "Gelao; White"
|
||||||
msgstr ""
|
msgstr "Gelao blanco"
|
||||||
|
|
||||||
#. name for gix
|
#. name for gix
|
||||||
msgid "Gilima"
|
msgid "Gilima"
|
||||||
@ -8364,7 +8364,7 @@ msgstr "Giyug"
|
|||||||
|
|
||||||
#. name for giz
|
#. name for giz
|
||||||
msgid "Giziga; South"
|
msgid "Giziga; South"
|
||||||
msgstr ""
|
msgstr "Giziga meridional"
|
||||||
|
|
||||||
#. name for gji
|
#. name for gji
|
||||||
msgid "Geji"
|
msgid "Geji"
|
||||||
@ -9236,7 +9236,7 @@ msgstr "Habu"
|
|||||||
|
|
||||||
#. name for hca
|
#. name for hca
|
||||||
msgid "Creole Hindi; Andaman"
|
msgid "Creole Hindi; Andaman"
|
||||||
msgstr ""
|
msgstr "Hindi criollo de Andamán"
|
||||||
|
|
||||||
#. name for hch
|
#. name for hch
|
||||||
msgid "Huichol"
|
msgid "Huichol"
|
||||||
@ -9256,7 +9256,7 @@ msgstr "Hadiyya"
|
|||||||
|
|
||||||
#. name for hea
|
#. name for hea
|
||||||
msgid "Miao; Northern Qiandong"
|
msgid "Miao; Northern Qiandong"
|
||||||
msgstr ""
|
msgstr "Miao de Qiandong septentrional"
|
||||||
|
|
||||||
#. name for heb
|
#. name for heb
|
||||||
msgid "Hebrew"
|
msgid "Hebrew"
|
||||||
@ -9412,15 +9412,15 @@ msgstr "Nga la"
|
|||||||
|
|
||||||
#. name for hlu
|
#. name for hlu
|
||||||
msgid "Luwian; Hieroglyphic"
|
msgid "Luwian; Hieroglyphic"
|
||||||
msgstr ""
|
msgstr "Luvita jeroglífico"
|
||||||
|
|
||||||
#. name for hma
|
#. name for hma
|
||||||
msgid "Miao; Southern Mashan"
|
msgid "Miao; Southern Mashan"
|
||||||
msgstr ""
|
msgstr "Miao de Mashan meridional"
|
||||||
|
|
||||||
#. name for hmb
|
#. name for hmb
|
||||||
msgid "Songhay; Humburi Senni"
|
msgid "Songhay; Humburi Senni"
|
||||||
msgstr ""
|
msgstr "Songhay humburi senni"
|
||||||
|
|
||||||
#. name for hmc
|
#. name for hmc
|
||||||
msgid "Miao; Central Huishui"
|
msgid "Miao; Central Huishui"
|
||||||
@ -9428,27 +9428,27 @@ msgstr "Miao de Huishui central"
|
|||||||
|
|
||||||
#. name for hmd
|
#. name for hmd
|
||||||
msgid "Miao; Large Flowery"
|
msgid "Miao; Large Flowery"
|
||||||
msgstr ""
|
msgstr "Gran miao florido"
|
||||||
|
|
||||||
#. name for hme
|
#. name for hme
|
||||||
msgid "Miao; Eastern Huishui"
|
msgid "Miao; Eastern Huishui"
|
||||||
msgstr ""
|
msgstr "Miao de Huishui oriental"
|
||||||
|
|
||||||
#. name for hmf
|
#. name for hmf
|
||||||
msgid "Hmong Don"
|
msgid "Hmong Don"
|
||||||
msgstr ""
|
msgstr "Hmong don"
|
||||||
|
|
||||||
#. name for hmg
|
#. name for hmg
|
||||||
msgid "Hmong; Southwestern Guiyang"
|
msgid "Hmong; Southwestern Guiyang"
|
||||||
msgstr ""
|
msgstr "Hmong de Guiyang suroccidental"
|
||||||
|
|
||||||
#. name for hmh
|
#. name for hmh
|
||||||
msgid "Miao; Southwestern Huishui"
|
msgid "Miao; Southwestern Huishui"
|
||||||
msgstr ""
|
msgstr "Miao de Huishui suroccidental"
|
||||||
|
|
||||||
#. name for hmi
|
#. name for hmi
|
||||||
msgid "Miao; Northern Huishui"
|
msgid "Miao; Northern Huishui"
|
||||||
msgstr ""
|
msgstr "Miao de Huishui septentrional"
|
||||||
|
|
||||||
#. name for hmj
|
#. name for hmj
|
||||||
msgid "Ge"
|
msgid "Ge"
|
||||||
@ -9464,7 +9464,7 @@ msgstr "Miao del río Luobo"
|
|||||||
|
|
||||||
#. name for hmm
|
#. name for hmm
|
||||||
msgid "Miao; Central Mashan"
|
msgid "Miao; Central Mashan"
|
||||||
msgstr ""
|
msgstr "Miao de Mashan central"
|
||||||
|
|
||||||
#. name for hmn
|
#. name for hmn
|
||||||
msgid "Hmong"
|
msgid "Hmong"
|
||||||
@ -9476,11 +9476,11 @@ msgstr "Hiri motu"
|
|||||||
|
|
||||||
#. name for hmp
|
#. name for hmp
|
||||||
msgid "Miao; Northern Mashan"
|
msgid "Miao; Northern Mashan"
|
||||||
msgstr ""
|
msgstr "Miao de Mashan septentrional"
|
||||||
|
|
||||||
#. name for hmq
|
#. name for hmq
|
||||||
msgid "Miao; Eastern Qiandong"
|
msgid "Miao; Eastern Qiandong"
|
||||||
msgstr ""
|
msgstr "Miao de Qiandong oriental"
|
||||||
|
|
||||||
#. name for hmr
|
#. name for hmr
|
||||||
msgid "Hmar"
|
msgid "Hmar"
|
||||||
@ -9488,7 +9488,7 @@ msgstr "Hmar"
|
|||||||
|
|
||||||
#. name for hms
|
#. name for hms
|
||||||
msgid "Miao; Southern Qiandong"
|
msgid "Miao; Southern Qiandong"
|
||||||
msgstr ""
|
msgstr "Miao de Qiandong meridional"
|
||||||
|
|
||||||
#. name for hmt
|
#. name for hmt
|
||||||
msgid "Hamtai"
|
msgid "Hamtai"
|
||||||
@ -9504,15 +9504,15 @@ msgstr "Hmong dô"
|
|||||||
|
|
||||||
#. name for hmw
|
#. name for hmw
|
||||||
msgid "Miao; Western Mashan"
|
msgid "Miao; Western Mashan"
|
||||||
msgstr ""
|
msgstr "Miao de Mashan occidental"
|
||||||
|
|
||||||
#. name for hmy
|
#. name for hmy
|
||||||
msgid "Miao; Southern Guiyang"
|
msgid "Miao; Southern Guiyang"
|
||||||
msgstr ""
|
msgstr "Miao de Guiyang meridional"
|
||||||
|
|
||||||
#. name for hmz
|
#. name for hmz
|
||||||
msgid "Miao; Sinicized"
|
msgid "Miao; Sinicized"
|
||||||
msgstr ""
|
msgstr "Miao sinizado"
|
||||||
|
|
||||||
#. name for hna
|
#. name for hna
|
||||||
msgid "Mina (Cameroon)"
|
msgid "Mina (Cameroon)"
|
||||||
@ -21288,11 +21288,11 @@ msgstr "Lengua de signos de Penang"
|
|||||||
|
|
||||||
#. name for psh
|
#. name for psh
|
||||||
msgid "Pashayi; Southwest"
|
msgid "Pashayi; Southwest"
|
||||||
msgstr "Pashai sudoccidental"
|
msgstr "Pashai suroccidental"
|
||||||
|
|
||||||
#. name for psi
|
#. name for psi
|
||||||
msgid "Pashayi; Southeast"
|
msgid "Pashayi; Southeast"
|
||||||
msgstr "Pasai sudoriental"
|
msgstr "Pasai suroriental"
|
||||||
|
|
||||||
#. name for psl
|
#. name for psl
|
||||||
msgid "Puerto Rican Sign Language"
|
msgid "Puerto Rican Sign Language"
|
||||||
@ -28676,7 +28676,7 @@ msgstr "Lusitano"
|
|||||||
|
|
||||||
#. name for xlu
|
#. name for xlu
|
||||||
msgid "Luwian; Cuneiform"
|
msgid "Luwian; Cuneiform"
|
||||||
msgstr ""
|
msgstr "Luvita cuneiforme"
|
||||||
|
|
||||||
#. name for xly
|
#. name for xly
|
||||||
msgid "Elymian"
|
msgid "Elymian"
|
||||||
|
@ -10,14 +10,14 @@ msgstr ""
|
|||||||
"Report-Msgid-Bugs-To: Debian iso-codes team <pkg-isocodes-"
|
"Report-Msgid-Bugs-To: Debian iso-codes team <pkg-isocodes-"
|
||||||
"devel@lists.alioth.debian.org>\n"
|
"devel@lists.alioth.debian.org>\n"
|
||||||
"POT-Creation-Date: 2011-11-25 14:01+0000\n"
|
"POT-Creation-Date: 2011-11-25 14:01+0000\n"
|
||||||
"PO-Revision-Date: 2012-05-12 10:25+0000\n"
|
"PO-Revision-Date: 2012-08-09 04:41+0000\n"
|
||||||
"Last-Translator: kulkke <Unknown>\n"
|
"Last-Translator: kulkke <Unknown>\n"
|
||||||
"Language-Team: Turkish <gnome-turk@gnome.org>\n"
|
"Language-Team: Turkish <gnome-turk@gnome.org>\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-05-13 04:43+0000\n"
|
"X-Launchpad-Export-Date: 2012-08-10 04:58+0000\n"
|
||||||
"X-Generator: Launchpad (build 15225)\n"
|
"X-Generator: Launchpad (build 15761)\n"
|
||||||
"Language: tr\n"
|
"Language: tr\n"
|
||||||
|
|
||||||
#. name for aaa
|
#. name for aaa
|
||||||
@ -8874,7 +8874,7 @@ msgstr ""
|
|||||||
|
|
||||||
#. name for guj
|
#. name for guj
|
||||||
msgid "Gujarati"
|
msgid "Gujarati"
|
||||||
msgstr "Gujarati (Hindistan)"
|
msgstr "Gucaratça"
|
||||||
|
|
||||||
#. name for guk
|
#. name for guk
|
||||||
msgid "Gumuz"
|
msgid "Gumuz"
|
||||||
|
@ -40,9 +40,6 @@ def _init_mimetypes():
|
|||||||
global _mt_inited
|
global _mt_inited
|
||||||
import mimetypes
|
import mimetypes
|
||||||
mimetypes.init([P('mime.types')])
|
mimetypes.init([P('mime.types')])
|
||||||
mimetypes.add_type('application/epub+zip', '.epub')
|
|
||||||
mimetypes.add_type('application/x-mobipocket-ebook', '.mobi')
|
|
||||||
mimetypes.add_type('application/x-palmreader', '.pdb')
|
|
||||||
_mt_inited = True
|
_mt_inited = True
|
||||||
|
|
||||||
def guess_type(*args, **kwargs):
|
def guess_type(*args, **kwargs):
|
||||||
@ -62,7 +59,10 @@ def guess_extension(*args, **kwargs):
|
|||||||
import mimetypes
|
import mimetypes
|
||||||
if not _mt_inited:
|
if not _mt_inited:
|
||||||
_init_mimetypes()
|
_init_mimetypes()
|
||||||
return mimetypes.guess_extension(*args, **kwargs)
|
ext = mimetypes.guess_extension(*args, **kwargs)
|
||||||
|
if not ext and args and args[0] == 'application/x-palmreader':
|
||||||
|
ext = '.pdb'
|
||||||
|
return ext
|
||||||
|
|
||||||
def get_types_map():
|
def get_types_map():
|
||||||
import mimetypes
|
import mimetypes
|
||||||
|
@ -1461,7 +1461,8 @@ class StoreLegimiStore(StoreBase):
|
|||||||
actual_plugin = 'calibre.gui2.store.stores.legimi_plugin:LegimiStore'
|
actual_plugin = 'calibre.gui2.store.stores.legimi_plugin:LegimiStore'
|
||||||
|
|
||||||
headquarters = 'PL'
|
headquarters = 'PL'
|
||||||
formats = ['EPUB']
|
formats = ['EPUB', 'PDF', 'MOBI']
|
||||||
|
affiliate = True
|
||||||
|
|
||||||
class StoreLibreDEStore(StoreBase):
|
class StoreLibreDEStore(StoreBase):
|
||||||
name = 'Libri DE'
|
name = 'Libri DE'
|
||||||
|
329
src/calibre/devices/mtp/windows/content_enumeration.cpp
Normal file
329
src/calibre/devices/mtp/windows/content_enumeration.cpp
Normal file
@ -0,0 +1,329 @@
|
|||||||
|
/*
|
||||||
|
* content_enumeration.cpp
|
||||||
|
* Copyright (C) 2012 Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
*
|
||||||
|
* Distributed under terms of the GPL3 license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#define ADDPROP(x) hr = properties->Add(x); if (FAILED(hr)) { hresult_set_exc("Failed to add property to filesystem properties collection", hr); properties->Release(); return NULL; }
|
||||||
|
|
||||||
|
namespace wpd {
|
||||||
|
|
||||||
|
static IPortableDeviceKeyCollection* create_filesystem_properties_collection() { // {{{
|
||||||
|
IPortableDeviceKeyCollection *properties;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
hr = CoCreateInstance(CLSID_PortableDeviceKeyCollection, NULL,
|
||||||
|
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&properties));
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
|
||||||
|
if (FAILED(hr)) { hresult_set_exc("Failed to create filesystem properties collection", hr); return NULL; }
|
||||||
|
|
||||||
|
ADDPROP(WPD_OBJECT_CONTENT_TYPE);
|
||||||
|
ADDPROP(WPD_OBJECT_PARENT_ID);
|
||||||
|
ADDPROP(WPD_OBJECT_PERSISTENT_UNIQUE_ID);
|
||||||
|
ADDPROP(WPD_OBJECT_NAME);
|
||||||
|
ADDPROP(WPD_OBJECT_SYNC_ID);
|
||||||
|
ADDPROP(WPD_OBJECT_ISSYSTEM);
|
||||||
|
ADDPROP(WPD_OBJECT_ISHIDDEN);
|
||||||
|
ADDPROP(WPD_OBJECT_CAN_DELETE);
|
||||||
|
ADDPROP(WPD_OBJECT_SIZE);
|
||||||
|
|
||||||
|
return properties;
|
||||||
|
|
||||||
|
} // }}}
|
||||||
|
|
||||||
|
// Convert properties from COM to python {{{
|
||||||
|
static void set_string_property(PyObject *dict, REFPROPERTYKEY key, const char *pykey, IPortableDeviceValues *properties) {
|
||||||
|
HRESULT hr;
|
||||||
|
wchar_t *property = NULL;
|
||||||
|
PyObject *val;
|
||||||
|
|
||||||
|
hr = properties->GetStringValue(key, &property);
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
val = wchar_to_unicode(property);
|
||||||
|
if (val != NULL) {
|
||||||
|
PyDict_SetItemString(dict, pykey, val);
|
||||||
|
Py_DECREF(val);
|
||||||
|
}
|
||||||
|
CoTaskMemFree(property);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_bool_property(PyObject *dict, REFPROPERTYKEY key, const char *pykey, IPortableDeviceValues *properties) {
|
||||||
|
BOOL ok = 0;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
hr = properties->GetBoolValue(key, &ok);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
PyDict_SetItemString(dict, pykey, (ok)?Py_True:Py_False);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_size_property(PyObject *dict, REFPROPERTYKEY key, const char *pykey, IPortableDeviceValues *properties) {
|
||||||
|
ULONGLONG val = 0;
|
||||||
|
HRESULT hr;
|
||||||
|
PyObject *pval;
|
||||||
|
|
||||||
|
hr = properties->GetUnsignedLargeIntegerValue(key, &val);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
pval = PyInt_FromSsize_t((Py_ssize_t)val);
|
||||||
|
if (pval != NULL) {
|
||||||
|
PyDict_SetItemString(dict, pykey, pval);
|
||||||
|
Py_DECREF(pval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_content_type_property(PyObject *dict, IPortableDeviceValues *properties) {
|
||||||
|
GUID guid = GUID_NULL;
|
||||||
|
BOOL is_folder = 0;
|
||||||
|
|
||||||
|
if (SUCCEEDED(properties->GetGuidValue(WPD_OBJECT_CONTENT_TYPE, &guid)) && IsEqualGUID(guid, WPD_CONTENT_TYPE_FOLDER)) is_folder = 1;
|
||||||
|
PyDict_SetItemString(dict, "is_folder", (is_folder) ? Py_True : Py_False);
|
||||||
|
}
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
class GetBulkCallback : public IPortableDevicePropertiesBulkCallback {
|
||||||
|
|
||||||
|
public:
|
||||||
|
PyObject *items;
|
||||||
|
HANDLE complete;
|
||||||
|
ULONG self_ref;
|
||||||
|
PyThreadState *thread_state;
|
||||||
|
|
||||||
|
GetBulkCallback(PyObject *items_dict, HANDLE ev) : items(items_dict), complete(ev), self_ref(1), thread_state(NULL) {}
|
||||||
|
~GetBulkCallback() {}
|
||||||
|
|
||||||
|
HRESULT __stdcall OnStart(REFGUID Context) { return S_OK; }
|
||||||
|
|
||||||
|
HRESULT __stdcall OnEnd(REFGUID Context, HRESULT hrStatus) { SetEvent(this->complete); return S_OK; }
|
||||||
|
|
||||||
|
ULONG __stdcall AddRef() { InterlockedIncrement((long*) &self_ref); return self_ref; }
|
||||||
|
|
||||||
|
ULONG __stdcall Release() {
|
||||||
|
ULONG refcnt = self_ref - 1;
|
||||||
|
if (InterlockedDecrement((long*) &self_ref) == 0) { delete this; return 0; }
|
||||||
|
return refcnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT __stdcall QueryInterface(REFIID riid, LPVOID* obj) {
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
if (obj == NULL) { hr = E_INVALIDARG; return hr; }
|
||||||
|
|
||||||
|
if ((riid == IID_IUnknown) || (riid == IID_IPortableDevicePropertiesBulkCallback)) {
|
||||||
|
AddRef();
|
||||||
|
*obj = this;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*obj = NULL;
|
||||||
|
hr = E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT __stdcall OnProgress(REFGUID Context, IPortableDeviceValuesCollection* values) {
|
||||||
|
DWORD num = 0, i;
|
||||||
|
wchar_t *property = NULL;
|
||||||
|
IPortableDeviceValues *properties = NULL;
|
||||||
|
PyObject *temp, *obj;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
if (SUCCEEDED(values->GetCount(&num))) {
|
||||||
|
PyEval_RestoreThread(this->thread_state);
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
hr = values->GetAt(i, &properties);
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
|
||||||
|
hr = properties->GetStringValue(WPD_OBJECT_ID, &property);
|
||||||
|
if (!SUCCEEDED(hr)) continue;
|
||||||
|
temp = wchar_to_unicode(property);
|
||||||
|
CoTaskMemFree(property); property = NULL;
|
||||||
|
if (temp == NULL) continue;
|
||||||
|
obj = PyDict_GetItem(this->items, temp);
|
||||||
|
if (obj == NULL) {
|
||||||
|
obj = Py_BuildValue("{s:O}", "id", temp);
|
||||||
|
if (obj == NULL) continue;
|
||||||
|
PyDict_SetItem(this->items, temp, obj);
|
||||||
|
Py_DECREF(obj); // We want a borrowed reference to obj
|
||||||
|
}
|
||||||
|
Py_DECREF(temp);
|
||||||
|
|
||||||
|
set_content_type_property(obj, properties);
|
||||||
|
|
||||||
|
set_string_property(obj, WPD_OBJECT_PARENT_ID, "parent_id", properties);
|
||||||
|
set_string_property(obj, WPD_OBJECT_NAME, "name", properties);
|
||||||
|
set_string_property(obj, WPD_OBJECT_SYNC_ID, "sync_id", properties);
|
||||||
|
set_string_property(obj, WPD_OBJECT_PERSISTENT_UNIQUE_ID, "persistent_id", properties);
|
||||||
|
|
||||||
|
set_bool_property(obj, WPD_OBJECT_ISHIDDEN, "is_hidden", properties);
|
||||||
|
set_bool_property(obj, WPD_OBJECT_CAN_DELETE, "can_delete", properties);
|
||||||
|
set_bool_property(obj, WPD_OBJECT_ISSYSTEM, "is_system", properties);
|
||||||
|
|
||||||
|
set_size_property(obj, WPD_OBJECT_SIZE, "size", properties);
|
||||||
|
|
||||||
|
properties->Release(); properties = NULL;
|
||||||
|
}
|
||||||
|
} // end for loop
|
||||||
|
this->thread_state = PyEval_SaveThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
static PyObject* bulk_get_filesystem(IPortableDevice *device, IPortableDevicePropertiesBulk *bulk_properties, const wchar_t *storage_id, IPortableDevicePropVariantCollection *object_ids) {
|
||||||
|
PyObject *folders = NULL, *ret = NULL;
|
||||||
|
GUID guid_context = GUID_NULL;
|
||||||
|
HANDLE ev = NULL;
|
||||||
|
IPortableDeviceKeyCollection *properties;
|
||||||
|
GetBulkCallback *callback = NULL;
|
||||||
|
HRESULT hr;
|
||||||
|
DWORD wait_result;
|
||||||
|
int pump_result;
|
||||||
|
BOOL ok = TRUE;
|
||||||
|
|
||||||
|
ev = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||||
|
if (ev == NULL) return PyErr_NoMemory();
|
||||||
|
|
||||||
|
folders = PyDict_New();
|
||||||
|
if (folders == NULL) {PyErr_NoMemory(); goto end;}
|
||||||
|
|
||||||
|
properties = create_filesystem_properties_collection();
|
||||||
|
if (properties == NULL) goto end;
|
||||||
|
|
||||||
|
callback = new (std::nothrow) GetBulkCallback(folders, ev);
|
||||||
|
if (callback == NULL) { PyErr_NoMemory(); goto end; }
|
||||||
|
|
||||||
|
hr = bulk_properties->QueueGetValuesByObjectList(object_ids, properties, callback, &guid_context);
|
||||||
|
if (FAILED(hr)) { hresult_set_exc("Failed to queue bulk property retrieval", hr); goto end; }
|
||||||
|
|
||||||
|
hr = bulk_properties->Start(guid_context);
|
||||||
|
if (FAILED(hr)) { hresult_set_exc("Failed to start bulk operation", hr); goto end; }
|
||||||
|
|
||||||
|
callback->thread_state = PyEval_SaveThread();
|
||||||
|
while (TRUE) {
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
wait_result = MsgWaitForMultipleObjects(1, &(callback->complete), FALSE, 60000, QS_ALLEVENTS);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
if (wait_result == WAIT_OBJECT_0) {
|
||||||
|
break; // Event was signalled, bulk operation complete
|
||||||
|
} else if (wait_result == WAIT_OBJECT_0 + 1) { // Messages need to be dispatched
|
||||||
|
pump_result = pump_waiting_messages();
|
||||||
|
if (pump_result == 1) { PyErr_SetString(PyExc_RuntimeError, "Application has been asked to quit."); ok = FALSE; break;}
|
||||||
|
} else if (wait_result == WAIT_TIMEOUT) {
|
||||||
|
// 60 seconds with no updates, looks bad
|
||||||
|
PyErr_SetString(WPDError, "The device seems to have hung."); ok = FALSE; break;
|
||||||
|
} else if (wait_result == WAIT_ABANDONED_0) {
|
||||||
|
// This should never happen
|
||||||
|
PyErr_SetString(WPDError, "An unknown error occurred (mutex abandoned)"); ok = FALSE; break;
|
||||||
|
} else {
|
||||||
|
// The wait failed for some reason
|
||||||
|
PyErr_SetFromWindowsErr(0); ok = FALSE; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PyEval_RestoreThread(callback->thread_state);
|
||||||
|
if (!ok) {
|
||||||
|
// We deliberately leak the callback object to prevent any crashes in case COM tries to call methods on it during a future pump_waiting_messages()
|
||||||
|
PyDict_Clear(folders);
|
||||||
|
folders = NULL;
|
||||||
|
callback = NULL;
|
||||||
|
ev = NULL;
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
if (folders != NULL) {
|
||||||
|
ret = PyDict_Values(folders);
|
||||||
|
Py_DECREF(folders);
|
||||||
|
}
|
||||||
|
if (ev != NULL) CloseHandle(ev);
|
||||||
|
if (properties != NULL) properties->Release();
|
||||||
|
if (callback != NULL) callback->Release();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL find_all_objects_in(IPortableDeviceContent *content, IPortableDevicePropVariantCollection *object_ids, const wchar_t *parent_id) {
|
||||||
|
/*
|
||||||
|
* Find all children of the object identified by parent_id, recursively.
|
||||||
|
* The child ids are put into object_ids. Returns False if any errors
|
||||||
|
* occurred (also sets the python exception).
|
||||||
|
*/
|
||||||
|
IEnumPortableDeviceObjectIDs *children;
|
||||||
|
HRESULT hr = S_OK, hr2 = S_OK;
|
||||||
|
PWSTR child_ids[10];
|
||||||
|
DWORD fetched, i;
|
||||||
|
PROPVARIANT pv;
|
||||||
|
BOOL ok = 1;
|
||||||
|
|
||||||
|
PropVariantInit(&pv);
|
||||||
|
pv.vt = VT_LPWSTR;
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
hr = content->EnumObjects(0, parent_id, NULL, &children);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
|
||||||
|
if (FAILED(hr)) {hresult_set_exc("Failed to get children from device", hr); ok = 0; goto end;}
|
||||||
|
|
||||||
|
hr = S_OK;
|
||||||
|
|
||||||
|
while (hr == S_OK) {
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
hr = children->Next(10, child_ids, &fetched);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
for(i = 0; i < fetched; i++) {
|
||||||
|
pv.pwszVal = child_ids[i];
|
||||||
|
hr2 = object_ids->Add(&pv);
|
||||||
|
pv.pwszVal = NULL;
|
||||||
|
if (FAILED(hr2)) { hresult_set_exc("Failed to add child ids to propvariantcollection", hr2); break; }
|
||||||
|
ok = find_all_objects_in(content, object_ids, child_ids[i]);
|
||||||
|
if (!ok) break;
|
||||||
|
}
|
||||||
|
for (i = 0; i < fetched; i++) { CoTaskMemFree(child_ids[i]); child_ids[i] = NULL; }
|
||||||
|
if (FAILED(hr2) || !ok) { ok = 0; goto end; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (children != NULL) children->Release();
|
||||||
|
PropVariantClear(&pv);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject* wpd::get_filesystem(IPortableDevice *device, const wchar_t *storage_id, IPortableDevicePropertiesBulk *bulk_properties) {
|
||||||
|
PyObject *folders = NULL;
|
||||||
|
IPortableDevicePropVariantCollection *object_ids = NULL;
|
||||||
|
IPortableDeviceContent *content = NULL;
|
||||||
|
HRESULT hr;
|
||||||
|
BOOL ok;
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
hr = device->Content(&content);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
if (FAILED(hr)) { hresult_set_exc("Failed to create content interface", hr); goto end; }
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
hr = CoCreateInstance(CLSID_PortableDevicePropVariantCollection, NULL,
|
||||||
|
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&object_ids));
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
if (FAILED(hr)) { hresult_set_exc("Failed to create propvariantcollection", hr); goto end; }
|
||||||
|
|
||||||
|
ok = find_all_objects_in(content, object_ids, storage_id);
|
||||||
|
if (!ok) goto end;
|
||||||
|
|
||||||
|
if (bulk_properties != NULL) folders = bulk_get_filesystem(device, bulk_properties, storage_id, object_ids);
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (content != NULL) content->Release();
|
||||||
|
if (object_ids != NULL) object_ids->Release();
|
||||||
|
|
||||||
|
return folders;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace wpd
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
extern IPortableDevice* wpd::open_device(const wchar_t *pnp_id, IPortableDeviceValues *client_information);
|
extern IPortableDevice* wpd::open_device(const wchar_t *pnp_id, IPortableDeviceValues *client_information);
|
||||||
extern IPortableDeviceValues* wpd::get_client_information();
|
extern IPortableDeviceValues* wpd::get_client_information();
|
||||||
extern PyObject* wpd::get_device_information(IPortableDevice *device);
|
extern PyObject* wpd::get_device_information(IPortableDevice *device, IPortableDevicePropertiesBulk **pb);
|
||||||
|
|
||||||
using namespace wpd;
|
using namespace wpd;
|
||||||
// Device.__init__() {{{
|
// Device.__init__() {{{
|
||||||
@ -19,6 +19,8 @@ dealloc(Device* self)
|
|||||||
if (self->pnp_id != NULL) free(self->pnp_id);
|
if (self->pnp_id != NULL) free(self->pnp_id);
|
||||||
self->pnp_id = NULL;
|
self->pnp_id = NULL;
|
||||||
|
|
||||||
|
if (self->bulk_properties != NULL) { self->bulk_properties->Release(); self->bulk_properties = NULL; }
|
||||||
|
|
||||||
if (self->device != NULL) {
|
if (self->device != NULL) {
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
self->device->Close(); self->device->Release();
|
self->device->Close(); self->device->Release();
|
||||||
@ -44,12 +46,17 @@ init(Device *self, PyObject *args, PyObject *kwds)
|
|||||||
self->pnp_id = unicode_to_wchar(pnp_id);
|
self->pnp_id = unicode_to_wchar(pnp_id);
|
||||||
if (self->pnp_id == NULL) return -1;
|
if (self->pnp_id == NULL) return -1;
|
||||||
|
|
||||||
|
self->bulk_properties = NULL;
|
||||||
|
|
||||||
self->client_information = get_client_information();
|
self->client_information = get_client_information();
|
||||||
if (self->client_information != NULL) {
|
if (self->client_information != NULL) {
|
||||||
self->device = open_device(self->pnp_id, self->client_information);
|
self->device = open_device(self->pnp_id, self->client_information);
|
||||||
if (self->device != NULL) {
|
if (self->device != NULL) {
|
||||||
self->device_information = get_device_information(self->device);
|
self->device_information = get_device_information(self->device, &(self->bulk_properties));
|
||||||
if (self->device_information != NULL) ret = 0;
|
if (self->device_information != NULL) {
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,17 +69,34 @@ init(Device *self, PyObject *args, PyObject *kwds)
|
|||||||
static PyObject*
|
static PyObject*
|
||||||
update_data(Device *self, PyObject *args, PyObject *kwargs) {
|
update_data(Device *self, PyObject *args, PyObject *kwargs) {
|
||||||
PyObject *di = NULL;
|
PyObject *di = NULL;
|
||||||
di = get_device_information(self->device);
|
di = get_device_information(self->device, NULL);
|
||||||
if (di == NULL) return NULL;
|
if (di == NULL) return NULL;
|
||||||
Py_XDECREF(self->device_information); self->device_information = di;
|
Py_XDECREF(self->device_information); self->device_information = di;
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
} // }}}
|
} // }}}
|
||||||
|
|
||||||
|
// get_filesystem() {{{
|
||||||
|
static PyObject*
|
||||||
|
py_get_filesystem(Device *self, PyObject *args, PyObject *kwargs) {
|
||||||
|
PyObject *storage_id, *ans = NULL;
|
||||||
|
wchar_t *storage;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "O", &storage_id)) return NULL;
|
||||||
|
storage = unicode_to_wchar(storage_id);
|
||||||
|
if (storage == NULL) return NULL;
|
||||||
|
|
||||||
|
return wpd::get_filesystem(self->device, storage, self->bulk_properties);
|
||||||
|
} // }}}
|
||||||
|
|
||||||
static PyMethodDef Device_methods[] = {
|
static PyMethodDef Device_methods[] = {
|
||||||
{"update_data", (PyCFunction)update_data, METH_VARARGS,
|
{"update_data", (PyCFunction)update_data, METH_VARARGS,
|
||||||
"update_data() -> Reread the basic device data from the device (total, space, free space, storage locations, etc.)"
|
"update_data() -> Reread the basic device data from the device (total, space, free space, storage locations, etc.)"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{"get_filesystem", (PyCFunction)py_get_filesystem, METH_VARARGS,
|
||||||
|
"get_filesystem(storage_id) -> Get all files/folders on the storage identified by storage_id. Tries to use bulk operations when possible."
|
||||||
|
},
|
||||||
|
|
||||||
{NULL}
|
{NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -172,7 +172,8 @@ PyObject* get_storage_info(IPortableDevice *device) { // {{{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
for (i = 0; i < fetched; i ++) { CoTaskMemFree(object_ids[i]); object_ids[i] = NULL;}
|
||||||
|
}// if(SUCCEEDED(hr))
|
||||||
}
|
}
|
||||||
ans = storage;
|
ans = storage;
|
||||||
|
|
||||||
@ -185,9 +186,10 @@ end:
|
|||||||
return ans;
|
return ans;
|
||||||
} // }}}
|
} // }}}
|
||||||
|
|
||||||
PyObject* get_device_information(IPortableDevice *device) { // {{{
|
PyObject* get_device_information(IPortableDevice *device, IPortableDevicePropertiesBulk **pb) { // {{{
|
||||||
IPortableDeviceContent *content = NULL;
|
IPortableDeviceContent *content = NULL;
|
||||||
IPortableDeviceProperties *properties = NULL;
|
IPortableDeviceProperties *properties = NULL;
|
||||||
|
IPortableDevicePropertiesBulk *properties_bulk = NULL;
|
||||||
IPortableDeviceKeyCollection *keys = NULL;
|
IPortableDeviceKeyCollection *keys = NULL;
|
||||||
IPortableDeviceValues *values = NULL;
|
IPortableDeviceValues *values = NULL;
|
||||||
IPortableDeviceCapabilities *capabilities = NULL;
|
IPortableDeviceCapabilities *capabilities = NULL;
|
||||||
@ -336,10 +338,17 @@ PyObject* get_device_information(IPortableDevice *device) { // {{{
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
hr = properties->QueryInterface(IID_PPV_ARGS(&properties_bulk));
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
PyDict_SetItemString(ans, "has_bulk_properties", (FAILED(hr)) ? Py_False: Py_True);
|
||||||
|
if (pb != NULL) *pb = (SUCCEEDED(hr)) ? properties_bulk : NULL;
|
||||||
|
|
||||||
end:
|
end:
|
||||||
if (keys != NULL) keys->Release();
|
if (keys != NULL) keys->Release();
|
||||||
if (values != NULL) values->Release();
|
if (values != NULL) values->Release();
|
||||||
if (properties != NULL) properties->Release();
|
if (properties != NULL) properties->Release();
|
||||||
|
if (properties_bulk != NULL && pb == NULL) properties_bulk->Release();
|
||||||
if (content != NULL) content->Release();
|
if (content != NULL) content->Release();
|
||||||
if (capabilities != NULL) capabilities->Release();
|
if (capabilities != NULL) capabilities->Release();
|
||||||
if (categories != NULL) categories->Release();
|
if (categories != NULL) categories->Release();
|
||||||
|
@ -42,6 +42,7 @@ typedef struct {
|
|||||||
IPortableDeviceValues *client_information;
|
IPortableDeviceValues *client_information;
|
||||||
IPortableDevice *device;
|
IPortableDevice *device;
|
||||||
PyObject *device_information;
|
PyObject *device_information;
|
||||||
|
IPortableDevicePropertiesBulk *bulk_properties;
|
||||||
|
|
||||||
} Device;
|
} Device;
|
||||||
extern PyTypeObject DeviceType;
|
extern PyTypeObject DeviceType;
|
||||||
@ -49,10 +50,13 @@ extern PyTypeObject DeviceType;
|
|||||||
// Utility functions
|
// Utility functions
|
||||||
PyObject *hresult_set_exc(const char *msg, HRESULT hr);
|
PyObject *hresult_set_exc(const char *msg, HRESULT hr);
|
||||||
wchar_t *unicode_to_wchar(PyObject *o);
|
wchar_t *unicode_to_wchar(PyObject *o);
|
||||||
|
PyObject *wchar_to_unicode(wchar_t *o);
|
||||||
|
int pump_waiting_messages();
|
||||||
|
|
||||||
extern IPortableDeviceValues* get_client_information();
|
extern IPortableDeviceValues* get_client_information();
|
||||||
extern IPortableDevice* open_device(const wchar_t *pnp_id, IPortableDeviceValues *client_information);
|
extern IPortableDevice* open_device(const wchar_t *pnp_id, IPortableDeviceValues *client_information);
|
||||||
extern PyObject* get_device_information(IPortableDevice *device);
|
extern PyObject* get_device_information(IPortableDevice *device, IPortableDevicePropertiesBulk **bulk_properties);
|
||||||
|
extern PyObject* get_filesystem(IPortableDevice *device, const wchar_t *storage_id, IPortableDevicePropertiesBulk *bulk_properties);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,6 +66,7 @@ def main():
|
|||||||
# pprint.pprint(dev.detected_devices)
|
# pprint.pprint(dev.detected_devices)
|
||||||
print ('Trying to connect to:', pnp_id)
|
print ('Trying to connect to:', pnp_id)
|
||||||
dev.open(pnp_id, '')
|
dev.open(pnp_id, '')
|
||||||
|
pprint.pprint(dev.dev.data)
|
||||||
print ('Connected to:', dev.get_gui_name())
|
print ('Connected to:', dev.get_gui_name())
|
||||||
print ('Total space', dev.total_space())
|
print ('Total space', dev.total_space())
|
||||||
print ('Free space', dev.free_space())
|
print ('Free space', dev.free_space())
|
||||||
|
@ -33,6 +33,7 @@ PyObject *wpd::hresult_set_exc(const char *msg, HRESULT hr) {
|
|||||||
wchar_t *wpd::unicode_to_wchar(PyObject *o) {
|
wchar_t *wpd::unicode_to_wchar(PyObject *o) {
|
||||||
wchar_t *buf;
|
wchar_t *buf;
|
||||||
Py_ssize_t len;
|
Py_ssize_t len;
|
||||||
|
if (o == NULL) return NULL;
|
||||||
if (!PyUnicode_Check(o)) {PyErr_Format(PyExc_TypeError, "The python object must be a unicode object"); return NULL;}
|
if (!PyUnicode_Check(o)) {PyErr_Format(PyExc_TypeError, "The python object must be a unicode object"); return NULL;}
|
||||||
len = PyUnicode_GET_SIZE(o);
|
len = PyUnicode_GET_SIZE(o);
|
||||||
buf = (wchar_t *)calloc(len+2, sizeof(wchar_t));
|
buf = (wchar_t *)calloc(len+2, sizeof(wchar_t));
|
||||||
@ -42,3 +43,30 @@ wchar_t *wpd::unicode_to_wchar(PyObject *o) {
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyObject *wpd::wchar_to_unicode(wchar_t *o) {
|
||||||
|
PyObject *ans;
|
||||||
|
if (o == NULL) return NULL;
|
||||||
|
ans = PyUnicode_FromWideChar(o, wcslen(o));
|
||||||
|
if (ans == NULL) PyErr_NoMemory();
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
|
int wpd::pump_waiting_messages() {
|
||||||
|
UINT firstMsg = 0, lastMsg = 0;
|
||||||
|
MSG msg;
|
||||||
|
int result = 0;
|
||||||
|
// Read all of the messages in this next loop,
|
||||||
|
// removing each message as we read it.
|
||||||
|
while (PeekMessage(&msg, NULL, firstMsg, lastMsg, PM_REMOVE)) {
|
||||||
|
// If it's a quit message, we're out of here.
|
||||||
|
if (msg.message == WM_QUIT) {
|
||||||
|
result = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Otherwise, dispatch the message.
|
||||||
|
DispatchMessage(&msg);
|
||||||
|
} // End of PeekMessage while loop
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ wpd::ClientInfo wpd::client_info = {NULL, 0, 0, 0};
|
|||||||
|
|
||||||
extern IPortableDeviceValues* wpd::get_client_information();
|
extern IPortableDeviceValues* wpd::get_client_information();
|
||||||
extern IPortableDevice* wpd::open_device(const wchar_t *pnp_id, IPortableDeviceValues *client_information);
|
extern IPortableDevice* wpd::open_device(const wchar_t *pnp_id, IPortableDeviceValues *client_information);
|
||||||
extern PyObject* wpd::get_device_information(IPortableDevice *device);
|
extern PyObject* wpd::get_device_information(IPortableDevice *device, IPortableDevicePropertiesBulk **bulk_properties);
|
||||||
|
|
||||||
// Module startup/shutdown {{{
|
// Module startup/shutdown {{{
|
||||||
static PyObject *
|
static PyObject *
|
||||||
@ -151,7 +151,7 @@ wpd_device_info(PyObject *self, PyObject *args) {
|
|||||||
if (client_information != NULL) {
|
if (client_information != NULL) {
|
||||||
device = open_device(pnp_id, client_information);
|
device = open_device(pnp_id, client_information);
|
||||||
if (device != NULL) {
|
if (device != NULL) {
|
||||||
ans = get_device_information(device);
|
ans = get_device_information(device, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,7 +173,7 @@ def check_ebook_format(stream, current_guess):
|
|||||||
def normalize(x):
|
def normalize(x):
|
||||||
if isinstance(x, unicode):
|
if isinstance(x, unicode):
|
||||||
import unicodedata
|
import unicodedata
|
||||||
x = unicodedata.normalize('NFKC', x)
|
x = unicodedata.normalize('NFC', x)
|
||||||
return x
|
return x
|
||||||
|
|
||||||
def calibre_cover(title, author_string, series_string=None,
|
def calibre_cover(title, author_string, series_string=None,
|
||||||
|
@ -25,11 +25,12 @@ class LegimiStore(BasicStoreConfig, StorePlugin):
|
|||||||
|
|
||||||
def open(self, parent=None, detail_item=None, external=False):
|
def open(self, parent=None, detail_item=None, external=False):
|
||||||
|
|
||||||
url = 'http://www.legimi.com/pl/ebooks/?price=any'
|
plain_url = 'http://www.legimi.com/pl/ebooks/?price=any'
|
||||||
|
url = 'https://ssl.afiliant.com/affskrypt,,2f9de2,,11483,,,?u=(' + plain_url + ')'
|
||||||
detail_url = None
|
detail_url = None
|
||||||
|
|
||||||
if detail_item:
|
if detail_item:
|
||||||
detail_url = detail_item
|
detail_url = 'https://ssl.afiliant.com/affskrypt,,2f9de2,,11483,,,?u=(' + detail_item + ')'
|
||||||
|
|
||||||
if external or self.config.get('open_external', False):
|
if external or self.config.get('open_external', False):
|
||||||
open_url(QUrl(url_slash_cleaner(detail_url if detail_url else url)))
|
open_url(QUrl(url_slash_cleaner(detail_url if detail_url else url)))
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user