mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Add top level folder filtering to the windows mtp driver as well
This commit is contained in:
parent
e17fce9cc8
commit
5d9e9e4abf
@ -75,7 +75,8 @@ class MTP_DEVICE(BASE):
|
|||||||
|
|
||||||
return name in {
|
return name in {
|
||||||
'alarms', 'android', 'dcim', 'movies', 'music', 'notifications',
|
'alarms', 'android', 'dcim', 'movies', 'music', 'notifications',
|
||||||
'pictures', 'ringtones', 'samsung', 'sony', 'htc'}
|
'pictures', 'ringtones', 'samsung', 'sony', 'htc', 'bluetooth',
|
||||||
|
'games', 'lost.dir', 'video', 'whatsapp', 'image'}
|
||||||
|
|
||||||
def configure_for_kindle_app(self):
|
def configure_for_kindle_app(self):
|
||||||
proxy = self.prefs
|
proxy = self.prefs
|
||||||
|
@ -239,12 +239,12 @@ class TestDeviceInteraction(unittest.TestCase):
|
|||||||
|
|
||||||
# Test get_filesystem
|
# Test get_filesystem
|
||||||
used_by_one = self.measure_memory_usage(1,
|
used_by_one = self.measure_memory_usage(1,
|
||||||
self.dev.dev.get_filesystem, self.storage.object_id, lambda x:
|
self.dev.dev.get_filesystem, self.storage.object_id,
|
||||||
x)
|
lambda x, l:True)
|
||||||
|
|
||||||
used_by_many = self.measure_memory_usage(5,
|
used_by_many = self.measure_memory_usage(5,
|
||||||
self.dev.dev.get_filesystem, self.storage.object_id, lambda x:
|
self.dev.dev.get_filesystem, self.storage.object_id,
|
||||||
x)
|
lambda x, l: True)
|
||||||
|
|
||||||
self.check_memory(used_by_one, used_by_many,
|
self.check_memory(used_by_one, used_by_many,
|
||||||
'Memory consumption during get_filesystem')
|
'Memory consumption during get_filesystem')
|
||||||
|
@ -133,12 +133,14 @@ class GetBulkCallback : public IPortableDevicePropertiesBulkCallback {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
PyObject *items;
|
PyObject *items;
|
||||||
|
PyObject *subfolders;
|
||||||
|
unsigned int level;
|
||||||
HANDLE complete;
|
HANDLE complete;
|
||||||
ULONG self_ref;
|
ULONG self_ref;
|
||||||
PyThreadState *thread_state;
|
PyThreadState *thread_state;
|
||||||
PyObject *callback;
|
PyObject *callback;
|
||||||
|
|
||||||
GetBulkCallback(PyObject *items_dict, HANDLE ev, PyObject* pycallback) : items(items_dict), complete(ev), self_ref(1), thread_state(NULL), callback(pycallback) {}
|
GetBulkCallback(PyObject *items_dict, PyObject *subfolders, unsigned int level, HANDLE ev, PyObject* pycallback) : items(items_dict), subfolders(subfolders), level(level), complete(ev), self_ref(1), thread_state(NULL), callback(pycallback) {}
|
||||||
~GetBulkCallback() {}
|
~GetBulkCallback() {}
|
||||||
|
|
||||||
HRESULT __stdcall OnStart(REFGUID Context) { return S_OK; }
|
HRESULT __stdcall OnStart(REFGUID Context) { return S_OK; }
|
||||||
@ -172,7 +174,7 @@ public:
|
|||||||
DWORD num = 0, i;
|
DWORD num = 0, i;
|
||||||
wchar_t *property = NULL;
|
wchar_t *property = NULL;
|
||||||
IPortableDeviceValues *properties = NULL;
|
IPortableDeviceValues *properties = NULL;
|
||||||
PyObject *temp, *obj;
|
PyObject *temp, *obj, *r;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
if (SUCCEEDED(values->GetCount(&num))) {
|
if (SUCCEEDED(values->GetCount(&num))) {
|
||||||
@ -196,7 +198,11 @@ public:
|
|||||||
Py_DECREF(temp);
|
Py_DECREF(temp);
|
||||||
|
|
||||||
set_properties(obj, properties);
|
set_properties(obj, properties);
|
||||||
Py_XDECREF(PyObject_CallFunctionObjArgs(callback, obj, NULL));
|
r = PyObject_CallFunction(callback, "OI", obj, this->level);
|
||||||
|
if (r != NULL && PyObject_IsTrue(r)) {
|
||||||
|
PyList_Append(this->subfolders, PyDict_GetItemString(obj, "id"));
|
||||||
|
}
|
||||||
|
Py_XDECREF(r);
|
||||||
|
|
||||||
properties->Release(); properties = NULL;
|
properties->Release(); properties = NULL;
|
||||||
}
|
}
|
||||||
@ -209,8 +215,7 @@ public:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyObject* bulk_get_filesystem(IPortableDevice *device, IPortableDevicePropertiesBulk *bulk_properties, const wchar_t *storage_id, IPortableDevicePropVariantCollection *object_ids, PyObject *pycallback) {
|
static bool bulk_get_filesystem(unsigned int level, IPortableDevice *device, IPortableDevicePropertiesBulk *bulk_properties, IPortableDevicePropVariantCollection *object_ids, PyObject *pycallback, PyObject *ans, PyObject *subfolders) {
|
||||||
PyObject *folders = NULL;
|
|
||||||
GUID guid_context = GUID_NULL;
|
GUID guid_context = GUID_NULL;
|
||||||
HANDLE ev = NULL;
|
HANDLE ev = NULL;
|
||||||
IPortableDeviceKeyCollection *properties;
|
IPortableDeviceKeyCollection *properties;
|
||||||
@ -218,18 +223,15 @@ static PyObject* bulk_get_filesystem(IPortableDevice *device, IPortableDevicePro
|
|||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
DWORD wait_result;
|
DWORD wait_result;
|
||||||
int pump_result;
|
int pump_result;
|
||||||
BOOL ok = TRUE;
|
bool ok = true;
|
||||||
|
|
||||||
ev = CreateEvent(NULL, FALSE, FALSE, NULL);
|
ev = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||||
if (ev == NULL) return PyErr_NoMemory();
|
if (ev == NULL) {PyErr_NoMemory(); return false; }
|
||||||
|
|
||||||
folders = PyDict_New();
|
|
||||||
if (folders == NULL) {PyErr_NoMemory(); goto end;}
|
|
||||||
|
|
||||||
properties = create_filesystem_properties_collection();
|
properties = create_filesystem_properties_collection();
|
||||||
if (properties == NULL) goto end;
|
if (properties == NULL) goto end;
|
||||||
|
|
||||||
callback = new (std::nothrow) GetBulkCallback(folders, ev, pycallback);
|
callback = new (std::nothrow) GetBulkCallback(ans, subfolders, level, ev, pycallback);
|
||||||
if (callback == NULL) { PyErr_NoMemory(); goto end; }
|
if (callback == NULL) { PyErr_NoMemory(); goto end; }
|
||||||
|
|
||||||
hr = bulk_properties->QueueGetValuesByObjectList(object_ids, properties, callback, &guid_context);
|
hr = bulk_properties->QueueGetValuesByObjectList(object_ids, properties, callback, &guid_context);
|
||||||
@ -245,13 +247,13 @@ static PyObject* bulk_get_filesystem(IPortableDevice *device, IPortableDevicePro
|
|||||||
break; // Event was signalled, bulk operation complete
|
break; // Event was signalled, bulk operation complete
|
||||||
} else if (wait_result == WAIT_OBJECT_0 + 1) { // Messages need to be dispatched
|
} else if (wait_result == WAIT_OBJECT_0 + 1) { // Messages need to be dispatched
|
||||||
pump_result = pump_waiting_messages();
|
pump_result = pump_waiting_messages();
|
||||||
if (pump_result == 1) { PyErr_SetString(PyExc_RuntimeError, "Application has been asked to quit."); ok = FALSE; break;}
|
if (pump_result == 1) { PyErr_SetString(PyExc_RuntimeError, "Application has been asked to quit."); ok = false; break;}
|
||||||
} else if (wait_result == WAIT_TIMEOUT) {
|
} else if (wait_result == WAIT_TIMEOUT) {
|
||||||
// 60 seconds with no updates, looks bad
|
// 60 seconds with no updates, looks bad
|
||||||
PyErr_SetString(WPDError, "The device seems to have hung."); ok = FALSE; break;
|
PyErr_SetString(WPDError, "The device seems to have hung."); ok = false; break;
|
||||||
} else if (wait_result == WAIT_ABANDONED_0) {
|
} else if (wait_result == WAIT_ABANDONED_0) {
|
||||||
// This should never happen
|
// This should never happen
|
||||||
PyErr_SetString(WPDError, "An unknown error occurred (mutex abandoned)"); ok = FALSE; break;
|
PyErr_SetString(WPDError, "An unknown error occurred (mutex abandoned)"); ok = false; break;
|
||||||
} else {
|
} else {
|
||||||
// The wait failed for some reason
|
// The wait failed for some reason
|
||||||
PyErr_SetFromWindowsErr(0); ok = FALSE; break;
|
PyErr_SetFromWindowsErr(0); ok = FALSE; break;
|
||||||
@ -261,22 +263,21 @@ static PyObject* bulk_get_filesystem(IPortableDevice *device, IPortableDevicePro
|
|||||||
if (!ok) {
|
if (!ok) {
|
||||||
bulk_properties->Cancel(guid_context);
|
bulk_properties->Cancel(guid_context);
|
||||||
pump_waiting_messages();
|
pump_waiting_messages();
|
||||||
Py_DECREF(folders); folders = NULL;
|
|
||||||
}
|
}
|
||||||
end:
|
end:
|
||||||
if (ev != NULL) CloseHandle(ev);
|
if (ev != NULL) CloseHandle(ev);
|
||||||
if (properties != NULL) properties->Release();
|
if (properties != NULL) properties->Release();
|
||||||
if (callback != NULL) callback->Release();
|
if (callback != NULL) callback->Release();
|
||||||
|
|
||||||
return folders;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
// find_all_objects_in() {{{
|
// find_objects_in() {{{
|
||||||
static BOOL find_all_objects_in(IPortableDeviceContent *content, IPortableDevicePropVariantCollection *object_ids, const wchar_t *parent_id, PyObject *callback) {
|
static bool find_objects_in(IPortableDeviceContent *content, IPortableDevicePropVariantCollection *object_ids, const wchar_t *parent_id) {
|
||||||
/*
|
/*
|
||||||
* Find all children of the object identified by parent_id, recursively.
|
* Find all children of the object identified by parent_id.
|
||||||
* The child ids are put into object_ids. Returns False if any errors
|
* The child ids are put into object_ids. Returns False if any errors
|
||||||
* occurred (also sets the python exception).
|
* occurred (also sets the python exception).
|
||||||
*/
|
*/
|
||||||
@ -285,8 +286,7 @@ static BOOL find_all_objects_in(IPortableDeviceContent *content, IPortableDevice
|
|||||||
PWSTR child_ids[10];
|
PWSTR child_ids[10];
|
||||||
DWORD fetched, i;
|
DWORD fetched, i;
|
||||||
PROPVARIANT pv;
|
PROPVARIANT pv;
|
||||||
BOOL ok = 1;
|
bool ok = true;
|
||||||
PyObject *id;
|
|
||||||
|
|
||||||
PropVariantInit(&pv);
|
PropVariantInit(&pv);
|
||||||
pv.vt = VT_LPWSTR;
|
pv.vt = VT_LPWSTR;
|
||||||
@ -295,7 +295,7 @@ static BOOL find_all_objects_in(IPortableDeviceContent *content, IPortableDevice
|
|||||||
hr = content->EnumObjects(0, parent_id, NULL, &children);
|
hr = content->EnumObjects(0, parent_id, NULL, &children);
|
||||||
Py_END_ALLOW_THREADS;
|
Py_END_ALLOW_THREADS;
|
||||||
|
|
||||||
if (FAILED(hr)) {hresult_set_exc("Failed to get children from device", hr); ok = 0; goto end;}
|
if (FAILED(hr)) {hresult_set_exc("Failed to get children from device", hr); ok = false; goto end;}
|
||||||
|
|
||||||
hr = S_OK;
|
hr = S_OK;
|
||||||
|
|
||||||
@ -306,19 +306,12 @@ static BOOL find_all_objects_in(IPortableDeviceContent *content, IPortableDevice
|
|||||||
if (SUCCEEDED(hr)) {
|
if (SUCCEEDED(hr)) {
|
||||||
for(i = 0; i < fetched; i++) {
|
for(i = 0; i < fetched; i++) {
|
||||||
pv.pwszVal = child_ids[i];
|
pv.pwszVal = child_ids[i];
|
||||||
id = wchar_to_unicode(pv.pwszVal);
|
|
||||||
if (id != NULL) {
|
|
||||||
Py_XDECREF(PyObject_CallFunctionObjArgs(callback, id, NULL));
|
|
||||||
Py_DECREF(id);
|
|
||||||
}
|
|
||||||
hr2 = object_ids->Add(&pv);
|
hr2 = object_ids->Add(&pv);
|
||||||
pv.pwszVal = NULL;
|
pv.pwszVal = NULL;
|
||||||
if (FAILED(hr2)) { hresult_set_exc("Failed to add child ids to propvariantcollection", hr2); break; }
|
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], callback);
|
|
||||||
if (!ok) break;
|
|
||||||
}
|
}
|
||||||
for (i = 0; i < fetched; i++) { CoTaskMemFree(child_ids[i]); child_ids[i] = NULL; }
|
for (i = 0; i < fetched; i++) { CoTaskMemFree(child_ids[i]); child_ids[i] = NULL; }
|
||||||
if (FAILED(hr2) || !ok) { ok = 0; goto end; }
|
if (FAILED(hr2) || !ok) { ok = false; goto end; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,13 +333,8 @@ static PyObject* get_object_properties(IPortableDeviceProperties *devprops, IPor
|
|||||||
Py_END_ALLOW_THREADS;
|
Py_END_ALLOW_THREADS;
|
||||||
if (FAILED(hr)) { hresult_set_exc("Failed to get properties for object", hr); goto end; }
|
if (FAILED(hr)) { hresult_set_exc("Failed to get properties for object", hr); goto end; }
|
||||||
|
|
||||||
temp = wchar_to_unicode(object_id);
|
ans = Py_BuildValue("{s:N}", "id", wchar_to_unicode(object_id));
|
||||||
if (temp == NULL) goto end;
|
if (ans == NULL) goto end;
|
||||||
|
|
||||||
ans = PyDict_New();
|
|
||||||
if (ans == NULL) { PyErr_NoMemory(); goto end; }
|
|
||||||
if (PyDict_SetItemString(ans, "id", temp) != 0) { Py_DECREF(ans); ans = NULL; PyErr_NoMemory(); goto end; }
|
|
||||||
|
|
||||||
set_properties(ans, values);
|
set_properties(ans, values);
|
||||||
|
|
||||||
end:
|
end:
|
||||||
@ -355,12 +343,12 @@ end:
|
|||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject* single_get_filesystem(IPortableDeviceContent *content, const wchar_t *storage_id, IPortableDevicePropVariantCollection *object_ids, PyObject *callback) {
|
static bool single_get_filesystem(unsigned int level, IPortableDeviceContent *content, IPortableDevicePropVariantCollection *object_ids, PyObject *callback, PyObject *ans, PyObject *subfolders) {
|
||||||
DWORD num, i;
|
DWORD num, i;
|
||||||
PROPVARIANT pv;
|
PROPVARIANT pv;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
BOOL ok = 1;
|
bool ok = true;
|
||||||
PyObject *ans = NULL, *item = NULL;
|
PyObject *item = NULL, *r = NULL, *recurse = NULL;
|
||||||
IPortableDeviceProperties *devprops = NULL;
|
IPortableDeviceProperties *devprops = NULL;
|
||||||
IPortableDeviceKeyCollection *properties = NULL;
|
IPortableDeviceKeyCollection *properties = NULL;
|
||||||
|
|
||||||
@ -373,32 +361,36 @@ static PyObject* single_get_filesystem(IPortableDeviceContent *content, const wc
|
|||||||
hr = object_ids->GetCount(&num);
|
hr = object_ids->GetCount(&num);
|
||||||
if (FAILED(hr)) { hresult_set_exc("Failed to get object id count", hr); goto end; }
|
if (FAILED(hr)) { hresult_set_exc("Failed to get object id count", hr); goto end; }
|
||||||
|
|
||||||
ans = PyDict_New();
|
|
||||||
if (ans == NULL) goto end;
|
|
||||||
|
|
||||||
for (i = 0; i < num; i++) {
|
for (i = 0; i < num; i++) {
|
||||||
ok = 0;
|
ok = false;
|
||||||
|
recurse = NULL;
|
||||||
PropVariantInit(&pv);
|
PropVariantInit(&pv);
|
||||||
hr = object_ids->GetAt(i, &pv);
|
hr = object_ids->GetAt(i, &pv);
|
||||||
if (SUCCEEDED(hr) && pv.pwszVal != NULL) {
|
if (SUCCEEDED(hr) && pv.pwszVal != NULL) {
|
||||||
item = get_object_properties(devprops, properties, pv.pwszVal);
|
item = get_object_properties(devprops, properties, pv.pwszVal);
|
||||||
if (item != NULL) {
|
if (item != NULL) {
|
||||||
Py_XDECREF(PyObject_CallFunctionObjArgs(callback, item, NULL));
|
r = PyObject_CallFunction(callback, "OI", item, level);
|
||||||
|
if (r != NULL && PyObject_IsTrue(r)) recurse = item;
|
||||||
|
Py_XDECREF(r);
|
||||||
PyDict_SetItem(ans, PyDict_GetItemString(item, "id"), item);
|
PyDict_SetItem(ans, PyDict_GetItemString(item, "id"), item);
|
||||||
Py_DECREF(item); item = NULL;
|
Py_DECREF(item); item = NULL;
|
||||||
ok = 1;
|
ok = true;
|
||||||
}
|
}
|
||||||
} else hresult_set_exc("Failed to get item from IPortableDevicePropVariantCollection", hr);
|
} else hresult_set_exc("Failed to get item from IPortableDevicePropVariantCollection", hr);
|
||||||
|
|
||||||
PropVariantClear(&pv);
|
PropVariantClear(&pv);
|
||||||
if (!ok) { Py_DECREF(ans); ans = NULL; break; }
|
if (!ok) break;
|
||||||
|
if (recurse != NULL) {
|
||||||
|
if (PyList_Append(subfolders, PyDict_GetItemString(recurse, "id")) == -1) ok = false;
|
||||||
|
}
|
||||||
|
if (!ok) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
end:
|
end:
|
||||||
if (devprops != NULL) devprops->Release();
|
if (devprops != NULL) devprops->Release();
|
||||||
if (properties != NULL) properties->Release();
|
if (properties != NULL) properties->Release();
|
||||||
|
|
||||||
return ans;
|
return ok;
|
||||||
}
|
}
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
@ -438,35 +430,60 @@ end:
|
|||||||
return values;
|
return values;
|
||||||
} // }}}
|
} // }}}
|
||||||
|
|
||||||
PyObject* wpd::get_filesystem(IPortableDevice *device, const wchar_t *storage_id, IPortableDevicePropertiesBulk *bulk_properties, PyObject *callback) { // {{{
|
static bool get_files_and_folders(unsigned int level, IPortableDevice *device, IPortableDeviceContent *content, IPortableDevicePropertiesBulk *bulk_properties, const wchar_t *parent_id, PyObject *callback, PyObject *ans) {
|
||||||
PyObject *folders = NULL;
|
bool ok = true;
|
||||||
IPortableDevicePropVariantCollection *object_ids = NULL;
|
IPortableDevicePropVariantCollection *object_ids = NULL;
|
||||||
|
PyObject *subfolders = NULL;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
subfolders = PyList_New(0);
|
||||||
|
if (subfolders == NULL) { ok = false; 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); ok = false; goto end; }
|
||||||
|
|
||||||
|
ok = find_objects_in(content, object_ids, parent_id);
|
||||||
|
if (!ok) goto end;
|
||||||
|
|
||||||
|
if (bulk_properties != NULL) ok = bulk_get_filesystem(level, device, bulk_properties, object_ids, callback, ans, subfolders);
|
||||||
|
else ok = single_get_filesystem(level, content, object_ids, callback, ans, subfolders);
|
||||||
|
if (!ok) goto end;
|
||||||
|
|
||||||
|
for (Py_ssize_t i = 0; i < PyList_GET_SIZE(subfolders); i++) {
|
||||||
|
const wchar_t *child_id = unicode_to_wchar(PyList_GET_ITEM(subfolders, i));
|
||||||
|
if (child_id == NULL) { ok = false; break; }
|
||||||
|
ok = get_files_and_folders(level+1, device, content, bulk_properties, child_id, callback, ans);
|
||||||
|
if (!ok) break;
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
if (object_ids != NULL) object_ids->Release();
|
||||||
|
Py_XDECREF(subfolders);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject* wpd::get_filesystem(IPortableDevice *device, const wchar_t *storage_id, IPortableDevicePropertiesBulk *bulk_properties, PyObject *callback) { // {{{
|
||||||
|
PyObject *ans = NULL;
|
||||||
IPortableDeviceContent *content = NULL;
|
IPortableDeviceContent *content = NULL;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
BOOL ok;
|
|
||||||
|
ans = PyDict_New();
|
||||||
|
if (ans == NULL) return PyErr_NoMemory();
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
hr = device->Content(&content);
|
hr = device->Content(&content);
|
||||||
Py_END_ALLOW_THREADS;
|
Py_END_ALLOW_THREADS;
|
||||||
if (FAILED(hr)) { hresult_set_exc("Failed to create content interface", hr); goto end; }
|
if (FAILED(hr)) { hresult_set_exc("Failed to create content interface", hr); goto end; }
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
if (!get_files_and_folders(0, device, content, bulk_properties, storage_id, callback, ans)) {
|
||||||
hr = CoCreateInstance(CLSID_PortableDevicePropVariantCollection, NULL,
|
Py_DECREF(ans); ans = 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, callback);
|
|
||||||
if (!ok) goto end;
|
|
||||||
|
|
||||||
if (bulk_properties != NULL) folders = bulk_get_filesystem(device, bulk_properties, storage_id, object_ids, callback);
|
|
||||||
else folders = single_get_filesystem(content, storage_id, object_ids, callback);
|
|
||||||
|
|
||||||
end:
|
end:
|
||||||
if (content != NULL) content->Release();
|
if (content != NULL) content->Release();
|
||||||
if (object_ids != NULL) object_ids->Release();
|
return ans;
|
||||||
|
|
||||||
return folders;
|
|
||||||
} // }}}
|
} // }}}
|
||||||
|
|
||||||
PyObject* wpd::get_file(IPortableDevice *device, const wchar_t *object_id, PyObject *dest, PyObject *callback) { // {{{
|
PyObject* wpd::get_file(IPortableDevice *device, const wchar_t *object_id, PyObject *dest, PyObject *callback) { // {{{
|
||||||
|
@ -164,7 +164,7 @@ static PyMethodDef Device_methods[] = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
{"get_filesystem", (PyCFunction)py_get_filesystem, METH_VARARGS,
|
{"get_filesystem", (PyCFunction)py_get_filesystem, METH_VARARGS,
|
||||||
"get_filesystem(storage_id, callback) -> Get all files/folders on the storage identified by storage_id. Tries to use bulk operations when possible. callback must be a callable that accepts a single argument. It is called with every found id and then with the metadata for every id."
|
"get_filesystem(storage_id, callback) -> Get all files/folders on the storage identified by storage_id. Tries to use bulk operations when possible. callback must be a callable that is called as (object, level). It is called with every found object. If the callback returns False and the object is a folder, it is not recursed into."
|
||||||
},
|
},
|
||||||
|
|
||||||
{"get_file", (PyCFunction)py_get_file, METH_VARARGS,
|
{"get_file", (PyCFunction)py_get_file, METH_VARARGS,
|
||||||
|
@ -214,13 +214,14 @@ class MTP_DEVICE(MTPDeviceBase):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _filesystem_callback(self, obj):
|
def _filesystem_callback(self, obj, level):
|
||||||
if isinstance(obj, dict):
|
n = obj.get('name', '')
|
||||||
n = obj.get('name', '')
|
msg = _('Found object: %s')%n
|
||||||
msg = _('Found object: %s')%n
|
if (level == 0 and
|
||||||
else:
|
self.is_folder_ignored(self._currently_getting_sid, n)):
|
||||||
msg = _('Found id: %s')%obj
|
return False
|
||||||
self.filesystem_callback(msg)
|
self.filesystem_callback(msg)
|
||||||
|
return obj.get('is_folder', False)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def filesystem_cache(self):
|
def filesystem_cache(self):
|
||||||
@ -241,6 +242,7 @@ class MTP_DEVICE(MTPDeviceBase):
|
|||||||
break
|
break
|
||||||
storage = {'id':storage_id, 'size':capacity, 'name':name,
|
storage = {'id':storage_id, 'size':capacity, 'name':name,
|
||||||
'is_folder':True, 'can_delete':False, 'is_system':True}
|
'is_folder':True, 'can_delete':False, 'is_system':True}
|
||||||
|
self._currently_getting_sid = unicode(storage_id)
|
||||||
id_map = self.dev.get_filesystem(storage_id,
|
id_map = self.dev.get_filesystem(storage_id,
|
||||||
self._filesystem_callback)
|
self._filesystem_callback)
|
||||||
for x in id_map.itervalues(): x['storage_id'] = storage_id
|
for x in id_map.itervalues(): x['storage_id'] = storage_id
|
||||||
|
Loading…
x
Reference in New Issue
Block a user