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.filesystem_cache = None
|
||||||
self.lock = RLock()
|
self.lock = RLock()
|
||||||
self.blacklisted_devices = set()
|
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):
|
def report_progress(self, sent, total):
|
||||||
try:
|
try:
|
||||||
@ -223,6 +229,10 @@ class MTP_DEVICE(MTPDeviceBase):
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
class PR:
|
||||||
|
def report_progress(self, sent, total):
|
||||||
|
print (sent, total, end=', ')
|
||||||
|
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
dev = MTP_DEVICE(None)
|
dev = MTP_DEVICE(None)
|
||||||
from calibre.devices.scanner import linux_scanner
|
from calibre.devices.scanner import linux_scanner
|
||||||
@ -234,5 +244,14 @@ if __name__ == '__main__':
|
|||||||
print ("Storage info:")
|
print ("Storage info:")
|
||||||
pprint(d.storage_info)
|
pprint(d.storage_info)
|
||||||
print("Free space:", dev.free_space())
|
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 {
|
typedef struct {
|
||||||
PyObject *obj;
|
PyObject *obj;
|
||||||
|
PyObject *extra;
|
||||||
PyThreadState *state;
|
PyThreadState *state;
|
||||||
} ProgressCallback;
|
} ProgressCallback;
|
||||||
|
|
||||||
@ -64,6 +65,48 @@ static void dump_errorstack(LIBMTP_mtpdevice_t *dev, PyObject *list) {
|
|||||||
LIBMTP_Clear_Errorstack(dev);
|
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 {{{
|
// Device object definition {{{
|
||||||
@ -287,9 +330,11 @@ libmtp_Device_get_filelist(libmtp_Device *self, PyObject *args, PyObject *kwargs
|
|||||||
errs = PyList_New(0);
|
errs = PyList_New(0);
|
||||||
if (ans == NULL || errs == NULL) { PyErr_NoMemory(); return NULL; }
|
if (ans == NULL || errs == NULL) { PyErr_NoMemory(); return NULL; }
|
||||||
|
|
||||||
|
Py_XINCREF(callback);
|
||||||
cb.state = PyEval_SaveThread();
|
cb.state = PyEval_SaveThread();
|
||||||
tf = LIBMTP_Get_Filelisting_With_Callback(self->device, report_progress, &cb);
|
tf = LIBMTP_Get_Filelisting_With_Callback(self->device, report_progress, &cb);
|
||||||
PyEval_RestoreThread(cb.state);
|
PyEval_RestoreThread(cb.state);
|
||||||
|
Py_XDECREF(callback);
|
||||||
|
|
||||||
if (tf == NULL) {
|
if (tf == NULL) {
|
||||||
dump_errorstack(self->device, errs);
|
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[] = {
|
static PyMethodDef libmtp_Device_methods[] = {
|
||||||
{"update_storage_info", (PyCFunction)libmtp_Device_update_storage_info, METH_VARARGS,
|
{"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.)"
|
"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", (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 */
|
{NULL} /* Sentinel */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user