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
|
||||
* - :kbd:`Alt+Shift+B`
|
||||
- Toggle Cover Browser
|
||||
* - :kbd:`Alt+Shift+B`
|
||||
* - :kbd:`Alt+Shift+D`
|
||||
- Toggle Book Details panel
|
||||
* - :kbd:`Alt+Shift+T`
|
||||
- Toggle Tag Browser
|
||||
|
@ -19,23 +19,12 @@ class Slashdot(BasicNewsRecipe):
|
||||
|
||||
__author__ = 'floweros edited by Huan T'
|
||||
no_stylesheets = True
|
||||
use_embedded_content = False
|
||||
keep_only_tags = [
|
||||
dict(name='div',attrs={'id':'article'}),
|
||||
dict(name='div',attrs={'class':['postBody' 'details']}),
|
||||
dict(name='footer',attrs={'class':['clearfix meta article-foot']}),
|
||||
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'}),
|
||||
]
|
||||
dict(name='div',attrs={'class':'story'}),
|
||||
dict(name='div',attrs={'class':'body'}),
|
||||
dict(name='ul',attrs={'id':'commentlisting'}),
|
||||
]
|
||||
|
||||
feeds = [
|
||||
(u'Slashdot',
|
||||
|
Binary file not shown.
@ -822,7 +822,6 @@ application/x-lzh lzh
|
||||
application/x-lzx lzx
|
||||
application/x-maker book fb fbdoc fm frame frm maker
|
||||
application/x-mif mif
|
||||
application/x-mobipocket-ebook mobi prc
|
||||
application/x-ms-application application
|
||||
application/x-ms-wmd wmd
|
||||
application/x-ms-wmz wmz
|
||||
@ -1371,11 +1370,11 @@ application/x-sony-bbeb lrf lrx
|
||||
application/adobe-page-template+xml xpgt
|
||||
application/x-font-opentype otf
|
||||
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-cbr cbr
|
||||
application/x-cb7 cb7
|
||||
application/x-koboreader-ebook kobo
|
||||
image/wmf wmf
|
||||
application/ereader pdb
|
||||
|
||||
|
@ -172,13 +172,14 @@ if iswindows:
|
||||
[
|
||||
'calibre/devices/mtp/windows/utils.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/wpd.cpp',
|
||||
],
|
||||
headers=[
|
||||
'calibre/devices/mtp/windows/global.h',
|
||||
],
|
||||
libraries=['ole32', 'portabledeviceguids'],
|
||||
libraries=['ole32', 'portabledeviceguids', 'user32'],
|
||||
# needs_ddk=True,
|
||||
cflags=['/X']
|
||||
),
|
||||
|
@ -9,14 +9,14 @@ msgstr ""
|
||||
"Project-Id-Version: calibre\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\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"
|
||||
"Language-Team: Español; Castellano <>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2012-06-23 05:01+0000\n"
|
||||
"X-Generator: Launchpad (build 15461)\n"
|
||||
"X-Launchpad-Export-Date: 2012-08-16 04:40+0000\n"
|
||||
"X-Generator: Launchpad (build 15810)\n"
|
||||
|
||||
#. name for aaa
|
||||
msgid "Ghotuo"
|
||||
@ -5540,7 +5540,7 @@ msgstr "Forro"
|
||||
|
||||
#. name for crj
|
||||
msgid "Cree; Southern East"
|
||||
msgstr "Cree sudoriental"
|
||||
msgstr "Cree suroriental"
|
||||
|
||||
#. name for crk
|
||||
msgid "Cree; Plains"
|
||||
@ -8336,15 +8336,15 @@ msgstr "Gimi (provincia West New Britain)"
|
||||
|
||||
#. name for giq
|
||||
msgid "Gelao; Green"
|
||||
msgstr ""
|
||||
msgstr "Gelao verde"
|
||||
|
||||
#. name for gir
|
||||
msgid "Gelao; Red"
|
||||
msgstr ""
|
||||
msgstr "Gelao rojo"
|
||||
|
||||
#. name for gis
|
||||
msgid "Giziga; North"
|
||||
msgstr ""
|
||||
msgstr "Giziga septentrional"
|
||||
|
||||
#. name for git
|
||||
msgid "Gitxsan"
|
||||
@ -8352,7 +8352,7 @@ msgstr "Gitxsan"
|
||||
|
||||
#. name for giw
|
||||
msgid "Gelao; White"
|
||||
msgstr ""
|
||||
msgstr "Gelao blanco"
|
||||
|
||||
#. name for gix
|
||||
msgid "Gilima"
|
||||
@ -8364,7 +8364,7 @@ msgstr "Giyug"
|
||||
|
||||
#. name for giz
|
||||
msgid "Giziga; South"
|
||||
msgstr ""
|
||||
msgstr "Giziga meridional"
|
||||
|
||||
#. name for gji
|
||||
msgid "Geji"
|
||||
@ -9236,7 +9236,7 @@ msgstr "Habu"
|
||||
|
||||
#. name for hca
|
||||
msgid "Creole Hindi; Andaman"
|
||||
msgstr ""
|
||||
msgstr "Hindi criollo de Andamán"
|
||||
|
||||
#. name for hch
|
||||
msgid "Huichol"
|
||||
@ -9256,7 +9256,7 @@ msgstr "Hadiyya"
|
||||
|
||||
#. name for hea
|
||||
msgid "Miao; Northern Qiandong"
|
||||
msgstr ""
|
||||
msgstr "Miao de Qiandong septentrional"
|
||||
|
||||
#. name for heb
|
||||
msgid "Hebrew"
|
||||
@ -9412,15 +9412,15 @@ msgstr "Nga la"
|
||||
|
||||
#. name for hlu
|
||||
msgid "Luwian; Hieroglyphic"
|
||||
msgstr ""
|
||||
msgstr "Luvita jeroglífico"
|
||||
|
||||
#. name for hma
|
||||
msgid "Miao; Southern Mashan"
|
||||
msgstr ""
|
||||
msgstr "Miao de Mashan meridional"
|
||||
|
||||
#. name for hmb
|
||||
msgid "Songhay; Humburi Senni"
|
||||
msgstr ""
|
||||
msgstr "Songhay humburi senni"
|
||||
|
||||
#. name for hmc
|
||||
msgid "Miao; Central Huishui"
|
||||
@ -9428,27 +9428,27 @@ msgstr "Miao de Huishui central"
|
||||
|
||||
#. name for hmd
|
||||
msgid "Miao; Large Flowery"
|
||||
msgstr ""
|
||||
msgstr "Gran miao florido"
|
||||
|
||||
#. name for hme
|
||||
msgid "Miao; Eastern Huishui"
|
||||
msgstr ""
|
||||
msgstr "Miao de Huishui oriental"
|
||||
|
||||
#. name for hmf
|
||||
msgid "Hmong Don"
|
||||
msgstr ""
|
||||
msgstr "Hmong don"
|
||||
|
||||
#. name for hmg
|
||||
msgid "Hmong; Southwestern Guiyang"
|
||||
msgstr ""
|
||||
msgstr "Hmong de Guiyang suroccidental"
|
||||
|
||||
#. name for hmh
|
||||
msgid "Miao; Southwestern Huishui"
|
||||
msgstr ""
|
||||
msgstr "Miao de Huishui suroccidental"
|
||||
|
||||
#. name for hmi
|
||||
msgid "Miao; Northern Huishui"
|
||||
msgstr ""
|
||||
msgstr "Miao de Huishui septentrional"
|
||||
|
||||
#. name for hmj
|
||||
msgid "Ge"
|
||||
@ -9464,7 +9464,7 @@ msgstr "Miao del río Luobo"
|
||||
|
||||
#. name for hmm
|
||||
msgid "Miao; Central Mashan"
|
||||
msgstr ""
|
||||
msgstr "Miao de Mashan central"
|
||||
|
||||
#. name for hmn
|
||||
msgid "Hmong"
|
||||
@ -9476,11 +9476,11 @@ msgstr "Hiri motu"
|
||||
|
||||
#. name for hmp
|
||||
msgid "Miao; Northern Mashan"
|
||||
msgstr ""
|
||||
msgstr "Miao de Mashan septentrional"
|
||||
|
||||
#. name for hmq
|
||||
msgid "Miao; Eastern Qiandong"
|
||||
msgstr ""
|
||||
msgstr "Miao de Qiandong oriental"
|
||||
|
||||
#. name for hmr
|
||||
msgid "Hmar"
|
||||
@ -9488,7 +9488,7 @@ msgstr "Hmar"
|
||||
|
||||
#. name for hms
|
||||
msgid "Miao; Southern Qiandong"
|
||||
msgstr ""
|
||||
msgstr "Miao de Qiandong meridional"
|
||||
|
||||
#. name for hmt
|
||||
msgid "Hamtai"
|
||||
@ -9504,15 +9504,15 @@ msgstr "Hmong dô"
|
||||
|
||||
#. name for hmw
|
||||
msgid "Miao; Western Mashan"
|
||||
msgstr ""
|
||||
msgstr "Miao de Mashan occidental"
|
||||
|
||||
#. name for hmy
|
||||
msgid "Miao; Southern Guiyang"
|
||||
msgstr ""
|
||||
msgstr "Miao de Guiyang meridional"
|
||||
|
||||
#. name for hmz
|
||||
msgid "Miao; Sinicized"
|
||||
msgstr ""
|
||||
msgstr "Miao sinizado"
|
||||
|
||||
#. name for hna
|
||||
msgid "Mina (Cameroon)"
|
||||
@ -21288,11 +21288,11 @@ msgstr "Lengua de signos de Penang"
|
||||
|
||||
#. name for psh
|
||||
msgid "Pashayi; Southwest"
|
||||
msgstr "Pashai sudoccidental"
|
||||
msgstr "Pashai suroccidental"
|
||||
|
||||
#. name for psi
|
||||
msgid "Pashayi; Southeast"
|
||||
msgstr "Pasai sudoriental"
|
||||
msgstr "Pasai suroriental"
|
||||
|
||||
#. name for psl
|
||||
msgid "Puerto Rican Sign Language"
|
||||
@ -28676,7 +28676,7 @@ msgstr "Lusitano"
|
||||
|
||||
#. name for xlu
|
||||
msgid "Luwian; Cuneiform"
|
||||
msgstr ""
|
||||
msgstr "Luvita cuneiforme"
|
||||
|
||||
#. name for xly
|
||||
msgid "Elymian"
|
||||
|
@ -10,14 +10,14 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: Debian iso-codes team <pkg-isocodes-"
|
||||
"devel@lists.alioth.debian.org>\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"
|
||||
"Language-Team: Turkish <gnome-turk@gnome.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2012-05-13 04:43+0000\n"
|
||||
"X-Generator: Launchpad (build 15225)\n"
|
||||
"X-Launchpad-Export-Date: 2012-08-10 04:58+0000\n"
|
||||
"X-Generator: Launchpad (build 15761)\n"
|
||||
"Language: tr\n"
|
||||
|
||||
#. name for aaa
|
||||
@ -8874,7 +8874,7 @@ msgstr ""
|
||||
|
||||
#. name for guj
|
||||
msgid "Gujarati"
|
||||
msgstr "Gujarati (Hindistan)"
|
||||
msgstr "Gucaratça"
|
||||
|
||||
#. name for guk
|
||||
msgid "Gumuz"
|
||||
|
@ -40,9 +40,6 @@ def _init_mimetypes():
|
||||
global _mt_inited
|
||||
import mimetypes
|
||||
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
|
||||
|
||||
def guess_type(*args, **kwargs):
|
||||
@ -62,7 +59,10 @@ def guess_extension(*args, **kwargs):
|
||||
import mimetypes
|
||||
if not _mt_inited:
|
||||
_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():
|
||||
import mimetypes
|
||||
|
@ -1461,7 +1461,8 @@ class StoreLegimiStore(StoreBase):
|
||||
actual_plugin = 'calibre.gui2.store.stores.legimi_plugin:LegimiStore'
|
||||
|
||||
headquarters = 'PL'
|
||||
formats = ['EPUB']
|
||||
formats = ['EPUB', 'PDF', 'MOBI']
|
||||
affiliate = True
|
||||
|
||||
class StoreLibreDEStore(StoreBase):
|
||||
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 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;
|
||||
// Device.__init__() {{{
|
||||
@ -19,6 +19,8 @@ dealloc(Device* self)
|
||||
if (self->pnp_id != NULL) free(self->pnp_id);
|
||||
self->pnp_id = NULL;
|
||||
|
||||
if (self->bulk_properties != NULL) { self->bulk_properties->Release(); self->bulk_properties = NULL; }
|
||||
|
||||
if (self->device != NULL) {
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
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);
|
||||
if (self->pnp_id == NULL) return -1;
|
||||
|
||||
self->bulk_properties = NULL;
|
||||
|
||||
self->client_information = get_client_information();
|
||||
if (self->client_information != NULL) {
|
||||
self->device = open_device(self->pnp_id, self->client_information);
|
||||
if (self->device != NULL) {
|
||||
self->device_information = get_device_information(self->device);
|
||||
if (self->device_information != NULL) ret = 0;
|
||||
self->device_information = get_device_information(self->device, &(self->bulk_properties));
|
||||
if (self->device_information != NULL) {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,17 +69,34 @@ init(Device *self, PyObject *args, PyObject *kwds)
|
||||
static PyObject*
|
||||
update_data(Device *self, PyObject *args, PyObject *kwargs) {
|
||||
PyObject *di = NULL;
|
||||
di = get_device_information(self->device);
|
||||
di = get_device_information(self->device, NULL);
|
||||
if (di == NULL) return NULL;
|
||||
Py_XDECREF(self->device_information); self->device_information = di;
|
||||
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[] = {
|
||||
{"update_data", (PyCFunction)update_data, METH_VARARGS,
|
||||
"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}
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
||||
@ -185,9 +186,10 @@ end:
|
||||
return ans;
|
||||
} // }}}
|
||||
|
||||
PyObject* get_device_information(IPortableDevice *device) { // {{{
|
||||
PyObject* get_device_information(IPortableDevice *device, IPortableDevicePropertiesBulk **pb) { // {{{
|
||||
IPortableDeviceContent *content = NULL;
|
||||
IPortableDeviceProperties *properties = NULL;
|
||||
IPortableDevicePropertiesBulk *properties_bulk = NULL;
|
||||
IPortableDeviceKeyCollection *keys = NULL;
|
||||
IPortableDeviceValues *values = 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:
|
||||
if (keys != NULL) keys->Release();
|
||||
if (values != NULL) values->Release();
|
||||
if (properties != NULL) properties->Release();
|
||||
if (properties_bulk != NULL && pb == NULL) properties_bulk->Release();
|
||||
if (content != NULL) content->Release();
|
||||
if (capabilities != NULL) capabilities->Release();
|
||||
if (categories != NULL) categories->Release();
|
||||
|
@ -42,6 +42,7 @@ typedef struct {
|
||||
IPortableDeviceValues *client_information;
|
||||
IPortableDevice *device;
|
||||
PyObject *device_information;
|
||||
IPortableDevicePropertiesBulk *bulk_properties;
|
||||
|
||||
} Device;
|
||||
extern PyTypeObject DeviceType;
|
||||
@ -49,10 +50,13 @@ extern PyTypeObject DeviceType;
|
||||
// Utility functions
|
||||
PyObject *hresult_set_exc(const char *msg, HRESULT hr);
|
||||
wchar_t *unicode_to_wchar(PyObject *o);
|
||||
PyObject *wchar_to_unicode(wchar_t *o);
|
||||
int pump_waiting_messages();
|
||||
|
||||
extern IPortableDeviceValues* get_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)
|
||||
print ('Trying to connect to:', pnp_id)
|
||||
dev.open(pnp_id, '')
|
||||
pprint.pprint(dev.dev.data)
|
||||
print ('Connected to:', dev.get_gui_name())
|
||||
print ('Total space', dev.total_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 *buf;
|
||||
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;}
|
||||
len = PyUnicode_GET_SIZE(o);
|
||||
buf = (wchar_t *)calloc(len+2, sizeof(wchar_t));
|
||||
@ -42,3 +43,30 @@ wchar_t *wpd::unicode_to_wchar(PyObject *o) {
|
||||
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 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 {{{
|
||||
static PyObject *
|
||||
@ -151,7 +151,7 @@ wpd_device_info(PyObject *self, PyObject *args) {
|
||||
if (client_information != NULL) {
|
||||
device = open_device(pnp_id, client_information);
|
||||
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):
|
||||
if isinstance(x, unicode):
|
||||
import unicodedata
|
||||
x = unicodedata.normalize('NFKC', x)
|
||||
x = unicodedata.normalize('NFC', x)
|
||||
return x
|
||||
|
||||
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):
|
||||
|
||||
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
|
||||
|
||||
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):
|
||||
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