corrected merge conflicts

This commit is contained in:
Florent FAYOLLE 2012-08-17 19:07:40 +02:00
commit fb6eedc644
97 changed files with 40007 additions and 40041 deletions

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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']
), ),

View File

@ -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"

View File

@ -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"

View File

@ -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

View File

@ -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'

View 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

View File

@ -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}
}; };

View File

@ -171,8 +171,9 @@ PyObject* get_storage_info(IPortableDevice *device) { // {{{
Py_DECREF(so); Py_DECREF(so);
} }
} }
} }
} 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();

View File

@ -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);
} }

View File

@ -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())

View File

@ -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;
}

View File

@ -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);
} }
} }

View File

@ -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,

View File

@ -29,7 +29,7 @@ class OpenSearchOPDSStore(StorePlugin):
def open(self, parent=None, detail_item=None, external=False): def open(self, parent=None, detail_item=None, external=False):
if not hasattr(self, 'web_url'): if not hasattr(self, 'web_url'):
return return
if external or self.config.get('open_external', False): if external or self.config.get('open_external', False):
open_url(QUrl(detail_item if detail_item else self.web_url)) open_url(QUrl(detail_item if detail_item else self.web_url))
else: else:
@ -52,7 +52,7 @@ class OpenSearchOPDSStore(StorePlugin):
oquery.searchTerms = query oquery.searchTerms = query
oquery.count = max_results oquery.count = max_results
url = oquery.url() url = oquery.url()
counter = max_results counter = max_results
br = browser() br = browser()
with closing(br.open(url, timeout=timeout)) as f: with closing(br.open(url, timeout=timeout)) as f:
@ -60,18 +60,18 @@ class OpenSearchOPDSStore(StorePlugin):
for data in doc.xpath('//*[local-name() = "entry"]'): for data in doc.xpath('//*[local-name() = "entry"]'):
if counter <= 0: if counter <= 0:
break break
counter -= 1 counter -= 1
s = SearchResult() s = SearchResult()
s.detail_item = ''.join(data.xpath('./*[local-name() = "id"]/text()')).strip() s.detail_item = ''.join(data.xpath('./*[local-name() = "id"]/text()')).strip()
for link in data.xpath('./*[local-name() = "link"]'): for link in data.xpath('./*[local-name() = "link"]'):
rel = link.get('rel') rel = link.get('rel')
href = link.get('href') href = link.get('href')
type = link.get('type') type = link.get('type')
if rel and href and type: if rel and href and type:
if 'http://opds-spec.org/thumbnail' in rel: if 'http://opds-spec.org/thumbnail' in rel:
s.cover_url = href s.cover_url = href
@ -86,10 +86,10 @@ class OpenSearchOPDSStore(StorePlugin):
ext = ext[1:].upper().strip() ext = ext[1:].upper().strip()
s.downloads[ext] = href s.downloads[ext] = href
s.formats = ', '.join(s.downloads.keys()).strip() s.formats = ', '.join(s.downloads.keys()).strip()
s.title = ' '.join(data.xpath('./*[local-name() = "title"]//text()')).strip() s.title = ' '.join(data.xpath('./*[local-name() = "title"]//text()')).strip()
s.author = ', '.join(data.xpath('./*[local-name() = "author"]//*[local-name() = "name"]//text()')).strip() s.author = ', '.join(data.xpath('./*[local-name() = "author"]//*[local-name() = "name"]//text()')).strip()
price_e = data.xpath('.//*[local-name() = "price"][1]') price_e = data.xpath('.//*[local-name() = "price"][1]')
if price_e: if price_e:
price_e = price_e[0] price_e = price_e[0]
@ -97,6 +97,6 @@ class OpenSearchOPDSStore(StorePlugin):
price = ''.join(price_e.xpath('.//text()')).strip() price = ''.join(price_e.xpath('.//text()')).strip()
s.price = currency_code + ' ' + price s.price = currency_code + ' ' + price
s.price = s.price.strip() s.price = s.price.strip()
yield s yield s

View File

@ -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