mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
MTP driver: Implement getting files from the device
This commit is contained in:
parent
8e3092b78b
commit
a476e82183
@ -91,6 +91,12 @@ class MTP_DEVICE(MTPDeviceBase):
|
||||
self.filesystem_cache = None
|
||||
self.lock = RLock()
|
||||
self.blacklisted_devices = set()
|
||||
for x in vars(self.detect.libmtp):
|
||||
if x.startswith('LIBMTP'):
|
||||
setattr(self, x, getattr(self.detect.libmtp, x))
|
||||
|
||||
def set_debug_level(self, lvl):
|
||||
self.detect.libmtp.set_debug_level(lvl)
|
||||
|
||||
def report_progress(self, sent, total):
|
||||
try:
|
||||
@ -223,6 +229,10 @@ class MTP_DEVICE(MTPDeviceBase):
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
class PR:
|
||||
def report_progress(self, sent, total):
|
||||
print (sent, total, end=', ')
|
||||
|
||||
from pprint import pprint
|
||||
dev = MTP_DEVICE(None)
|
||||
from calibre.devices.scanner import linux_scanner
|
||||
@ -234,5 +244,14 @@ if __name__ == '__main__':
|
||||
print ("Storage info:")
|
||||
pprint(d.storage_info)
|
||||
print("Free space:", dev.free_space())
|
||||
dev.filesystem_cache.dump_filesystem()
|
||||
# dev.filesystem_cache.dump_filesystem()
|
||||
# with open('/tmp/flint.epub', 'wb') as f:
|
||||
# print(d.get_file(786, f, PR()))
|
||||
# print()
|
||||
# with open('/tmp/bleak.epub', 'wb') as f:
|
||||
# print(d.get_file(601, f, PR()))
|
||||
# print()
|
||||
dev.set_debug_level(dev.LIBMTP_DEBUG_ALL)
|
||||
del d
|
||||
dev.shutdown()
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
|
||||
typedef struct {
|
||||
PyObject *obj;
|
||||
PyObject *extra;
|
||||
PyThreadState *state;
|
||||
} ProgressCallback;
|
||||
|
||||
@ -64,6 +65,48 @@ static void dump_errorstack(LIBMTP_mtpdevice_t *dev, PyObject *list) {
|
||||
LIBMTP_Clear_Errorstack(dev);
|
||||
}
|
||||
|
||||
static uint16_t data_to_python(void *params, void *priv, uint32_t sendlen, unsigned char *data, uint32_t *putlen) {
|
||||
PyObject *res;
|
||||
ProgressCallback *cb;
|
||||
uint16_t ret = LIBMTP_HANDLER_RETURN_OK;
|
||||
|
||||
cb = (ProgressCallback *)priv;
|
||||
*putlen = sendlen;
|
||||
PyEval_RestoreThread(cb->state);
|
||||
res = PyObject_CallMethod(cb->extra, "write", "s#", data, sendlen);
|
||||
if (res == NULL) {
|
||||
ret = LIBMTP_HANDLER_RETURN_ERROR;
|
||||
*putlen = 0;
|
||||
PyErr_Print();
|
||||
} else Py_DECREF(res);
|
||||
|
||||
cb->state = PyEval_SaveThread();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint16_t data_from_python(void *params, void *priv, uint32_t wantlen, unsigned char *data, uint32_t *gotlen) {
|
||||
PyObject *res;
|
||||
ProgressCallback *cb;
|
||||
char *buf = NULL;
|
||||
Py_ssize_t len = 0;
|
||||
uint16_t ret = LIBMTP_HANDLER_RETURN_ERROR;
|
||||
|
||||
*gotlen = 0;
|
||||
|
||||
cb = (ProgressCallback *)priv;
|
||||
PyEval_RestoreThread(cb->state);
|
||||
res = PyObject_CallMethod(cb->extra, "read", "k", wantlen);
|
||||
if (res != NULL && PyBytes_AsStringAndSize(res, &buf, &len) != -1 && len <= wantlen) {
|
||||
memcpy(data, buf, len);
|
||||
*gotlen = len;
|
||||
ret = LIBMTP_HANDLER_RETURN_OK;
|
||||
} else PyErr_Print();
|
||||
|
||||
Py_XDECREF(res);
|
||||
cb->state = PyEval_SaveThread();
|
||||
return ret;
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
// Device object definition {{{
|
||||
@ -287,9 +330,11 @@ libmtp_Device_get_filelist(libmtp_Device *self, PyObject *args, PyObject *kwargs
|
||||
errs = PyList_New(0);
|
||||
if (ans == NULL || errs == NULL) { PyErr_NoMemory(); return NULL; }
|
||||
|
||||
Py_XINCREF(callback);
|
||||
cb.state = PyEval_SaveThread();
|
||||
tf = LIBMTP_Get_Filelisting_With_Callback(self->device, report_progress, &cb);
|
||||
PyEval_RestoreThread(cb.state);
|
||||
Py_XDECREF(callback);
|
||||
|
||||
if (tf == NULL) {
|
||||
dump_errorstack(self->device, errs);
|
||||
@ -380,6 +425,36 @@ libmtp_Device_get_folderlist(libmtp_Device *self, PyObject *args, PyObject *kwar
|
||||
|
||||
} // }}}
|
||||
|
||||
// Device.get_file {{{
|
||||
static PyObject *
|
||||
libmtp_Device_get_file(libmtp_Device *self, PyObject *args, PyObject *kwargs) {
|
||||
PyObject *stream, *callback = NULL, *errs;
|
||||
ProgressCallback cb;
|
||||
uint32_t fileid;
|
||||
int ret;
|
||||
|
||||
ENSURE_DEV(NULL); ENSURE_STORAGE(NULL);
|
||||
|
||||
|
||||
if (!PyArg_ParseTuple(args, "kO|O", &fileid, &stream, &callback)) return NULL;
|
||||
errs = PyList_New(0);
|
||||
if (errs == NULL) { PyErr_NoMemory(); return NULL; }
|
||||
|
||||
cb.obj = callback; cb.extra = stream;
|
||||
Py_XINCREF(callback); Py_INCREF(stream);
|
||||
cb.state = PyEval_SaveThread();
|
||||
ret = LIBMTP_Get_File_To_Handler(self->device, fileid, data_to_python, &cb, report_progress, &cb);
|
||||
PyEval_RestoreThread(cb.state);
|
||||
Py_XDECREF(callback); Py_DECREF(stream);
|
||||
|
||||
if (ret != 0) {
|
||||
dump_errorstack(self->device, errs);
|
||||
}
|
||||
Py_XDECREF(PyObject_CallMethod(stream, "flush", NULL));
|
||||
return Py_BuildValue("ON", (ret == 0) ? Py_True : Py_False, errs);
|
||||
|
||||
} // }}}
|
||||
|
||||
static PyMethodDef libmtp_Device_methods[] = {
|
||||
{"update_storage_info", (PyCFunction)libmtp_Device_update_storage_info, METH_VARARGS,
|
||||
"update_storage_info() -> Reread the storage info from the device (total, space, free space, storage locations, etc.)"
|
||||
@ -390,7 +465,11 @@ static PyMethodDef libmtp_Device_methods[] = {
|
||||
},
|
||||
|
||||
{"get_folderlist", (PyCFunction)libmtp_Device_get_folderlist, METH_VARARGS,
|
||||
"get_folderlist() -> Get the list of folders on the device. Returns files, erros."
|
||||
"get_folderlist() -> Get the list of folders on the device. Returns files, errors."
|
||||
},
|
||||
|
||||
{"get_file", (PyCFunction)libmtp_Device_get_file, METH_VARARGS,
|
||||
"get_file(fileid, stream, callback=None) -> Get the file specified by fileid from the device. stream must be a file-like object. The file will be written to it. callback works the same as in get_filelist(). Returns ok, errs, where errs is a list of errors (if any)."
|
||||
},
|
||||
|
||||
{NULL} /* Sentinel */
|
||||
|
Loading…
x
Reference in New Issue
Block a user