mirror of
https://github.com/kovidgoyal/calibre.git
synced 2026-05-31 02:55:19 -04:00
corrected merge conflicts
This commit is contained in:
+1
-1
@@ -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
|
||||
|
||||
+5
-16
@@ -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
|
||||
|
||||
|
||||
+2
-1
@@ -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']
|
||||
),
|
||||
|
||||
+30
-30
@@ -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"
|
||||
|
||||
+4
-4
@@ -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'
|
||||
|
||||
@@ -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}
|
||||
};
|
||||
|
||||
|
||||
@@ -171,8 +171,9 @@ PyObject* get_storage_info(IPortableDevice *device) { // {{{
|
||||
Py_DECREF(so);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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,
|
||||
|
||||
@@ -29,7 +29,7 @@ class OpenSearchOPDSStore(StorePlugin):
|
||||
def open(self, parent=None, detail_item=None, external=False):
|
||||
if not hasattr(self, 'web_url'):
|
||||
return
|
||||
|
||||
|
||||
if external or self.config.get('open_external', False):
|
||||
open_url(QUrl(detail_item if detail_item else self.web_url))
|
||||
else:
|
||||
@@ -52,7 +52,7 @@ class OpenSearchOPDSStore(StorePlugin):
|
||||
oquery.searchTerms = query
|
||||
oquery.count = max_results
|
||||
url = oquery.url()
|
||||
|
||||
|
||||
counter = max_results
|
||||
br = browser()
|
||||
with closing(br.open(url, timeout=timeout)) as f:
|
||||
@@ -60,18 +60,18 @@ class OpenSearchOPDSStore(StorePlugin):
|
||||
for data in doc.xpath('//*[local-name() = "entry"]'):
|
||||
if counter <= 0:
|
||||
break
|
||||
|
||||
|
||||
counter -= 1
|
||||
|
||||
|
||||
s = SearchResult()
|
||||
|
||||
|
||||
s.detail_item = ''.join(data.xpath('./*[local-name() = "id"]/text()')).strip()
|
||||
|
||||
for link in data.xpath('./*[local-name() = "link"]'):
|
||||
rel = link.get('rel')
|
||||
href = link.get('href')
|
||||
type = link.get('type')
|
||||
|
||||
|
||||
if rel and href and type:
|
||||
if 'http://opds-spec.org/thumbnail' in rel:
|
||||
s.cover_url = href
|
||||
@@ -86,10 +86,10 @@ class OpenSearchOPDSStore(StorePlugin):
|
||||
ext = ext[1:].upper().strip()
|
||||
s.downloads[ext] = href
|
||||
s.formats = ', '.join(s.downloads.keys()).strip()
|
||||
|
||||
|
||||
s.title = ' '.join(data.xpath('./*[local-name() = "title"]//text()')).strip()
|
||||
s.author = ', '.join(data.xpath('./*[local-name() = "author"]//*[local-name() = "name"]//text()')).strip()
|
||||
|
||||
|
||||
price_e = data.xpath('.//*[local-name() = "price"][1]')
|
||||
if price_e:
|
||||
price_e = price_e[0]
|
||||
@@ -97,6 +97,6 @@ class OpenSearchOPDSStore(StorePlugin):
|
||||
price = ''.join(price_e.xpath('.//text()')).strip()
|
||||
s.price = currency_code + ' ' + price
|
||||
s.price = s.price.strip()
|
||||
|
||||
|
||||
|
||||
yield s
|
||||
|
||||
@@ -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)))
|
||||
|
||||
+502
-495
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+499
-571
File diff suppressed because it is too large
Load Diff
+503
-511
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+501
-521
File diff suppressed because it is too large
Load Diff
+725
-618
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+502
-564
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+582
-554
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+507
-551
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+498
-574
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+510
-574
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+562
-621
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+502
-541
File diff suppressed because it is too large
Load Diff
+503
-558
File diff suppressed because it is too large
Load Diff
+516
-503
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+501
-500
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+490
-483
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+511
-540
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+581
-634
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+501
-571
File diff suppressed because it is too large
Load Diff
+505
-499
File diff suppressed because it is too large
Load Diff
+500
-512
File diff suppressed because it is too large
Load Diff
+501
-562
File diff suppressed because it is too large
Load Diff
+514
-572
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+498
-531
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+500
-543
File diff suppressed because it is too large
Load Diff
+501
-562
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+501
-494
File diff suppressed because it is too large
Load Diff
+563
-539
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+501
-494
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+503
-535
File diff suppressed because it is too large
Load Diff
+499
-492
File diff suppressed because it is too large
Load Diff
+503
-508
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user