mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Subdir support for usbms and Cybook
This commit is contained in:
commit
a8b6b45ae6
@ -28,6 +28,7 @@ class CYBOOKG3(USBMS):
|
|||||||
STORAGE_CARD_VOLUME_LABEL = 'Cybook Gen 3 Storage Card'
|
STORAGE_CARD_VOLUME_LABEL = 'Cybook Gen 3 Storage Card'
|
||||||
|
|
||||||
EBOOK_DIR_MAIN = "eBooks"
|
EBOOK_DIR_MAIN = "eBooks"
|
||||||
|
SUPPORTS_SUB_DIRS = True
|
||||||
|
|
||||||
def delete_books(self, paths, end_session=True):
|
def delete_books(self, paths, end_session=True):
|
||||||
for path in paths:
|
for path in paths:
|
||||||
@ -46,3 +47,8 @@ class CYBOOKG3(USBMS):
|
|||||||
for filen in fnmatch.filter(files, filename + "*.t2b"):
|
for filen in fnmatch.filter(files, filename + "*.t2b"):
|
||||||
os.unlink(os.path.join(p, filen))
|
os.unlink(os.path.join(p, filen))
|
||||||
|
|
||||||
|
try:
|
||||||
|
os.removedirs(os.path.dirname(path))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@ -123,7 +123,8 @@ class Device(object):
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def upload_books(self, files, names, on_card=False, end_session=True):
|
def upload_books(self, files, names, on_card=False, end_session=True,
|
||||||
|
metadata=None):
|
||||||
'''
|
'''
|
||||||
Upload a list of books to the device. If a file already
|
Upload a list of books to the device. If a file already
|
||||||
exists on the device, it should be replaced.
|
exists on the device, it should be replaced.
|
||||||
@ -135,6 +136,10 @@ class Device(object):
|
|||||||
once uploaded to the device. len(names) == len(files)
|
once uploaded to the device. len(names) == len(files)
|
||||||
@return: A list of 3-element tuples. The list is meant to be passed
|
@return: A list of 3-element tuples. The list is meant to be passed
|
||||||
to L{add_books_to_metadata}.
|
to L{add_books_to_metadata}.
|
||||||
|
@param metadata: If not None, it is a list of dictionaries. Each dictionary
|
||||||
|
will have at least the key tags to allow the driver to choose book location
|
||||||
|
based on tags. len(metadata) == len(files). If your device does not support
|
||||||
|
hierarchical ebook folders, you can safely ignore this parameter.
|
||||||
'''
|
'''
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
@ -841,7 +841,8 @@ class PRS500(Device):
|
|||||||
self.upload_book_list(booklists[1], end_session=False)
|
self.upload_book_list(booklists[1], end_session=False)
|
||||||
|
|
||||||
@safe
|
@safe
|
||||||
def upload_books(self, files, names, on_card=False, end_session=True):
|
def upload_books(self, files, names, on_card=False, end_session=True,
|
||||||
|
metadata=None):
|
||||||
card = self.card(end_session=False)
|
card = self.card(end_session=False)
|
||||||
prefix = card + '/' + self.CARD_PATH_PREFIX +'/' if on_card else '/Data/media/books/'
|
prefix = card + '/' + self.CARD_PATH_PREFIX +'/' if on_card else '/Data/media/books/'
|
||||||
if on_card and not self._exists(prefix)[0]:
|
if on_card and not self._exists(prefix)[0]:
|
||||||
|
@ -407,7 +407,8 @@ class PRS505(Device):
|
|||||||
if not os.path.isdir(path):
|
if not os.path.isdir(path):
|
||||||
os.utime(path, None)
|
os.utime(path, None)
|
||||||
|
|
||||||
def upload_books(self, files, names, on_card=False, end_session=True):
|
def upload_books(self, files, names, on_card=False, end_session=True,
|
||||||
|
metadata=None):
|
||||||
if on_card and not self._card_prefix:
|
if on_card and not self._card_prefix:
|
||||||
raise ValueError(_('The reader has no storage card connected.'))
|
raise ValueError(_('The reader has no storage card connected.'))
|
||||||
path = os.path.join(self._card_prefix, self.CARD_PATH_PREFIX) if on_card \
|
path = os.path.join(self._card_prefix, self.CARD_PATH_PREFIX) if on_card \
|
||||||
|
@ -15,9 +15,10 @@ from calibre.devices.errors import FreeSpaceError
|
|||||||
from calibre.devices.mime import MIME_MAP
|
from calibre.devices.mime import MIME_MAP
|
||||||
|
|
||||||
class USBMS(Device):
|
class USBMS(Device):
|
||||||
|
FORMATS = []
|
||||||
EBOOK_DIR_MAIN = ''
|
EBOOK_DIR_MAIN = ''
|
||||||
EBOOK_DIR_CARD = ''
|
EBOOK_DIR_CARD = ''
|
||||||
FORMATS = []
|
SUPPORTS_SUB_DIRS = False
|
||||||
|
|
||||||
def __init__(self, key='-1', log_packets=False, report_progress=None):
|
def __init__(self, key='-1', log_packets=False, report_progress=None):
|
||||||
pass
|
pass
|
||||||
@ -48,7 +49,8 @@ class USBMS(Device):
|
|||||||
bl.append(Book(os.path.join(path, filename), title, author, mime))
|
bl.append(Book(os.path.join(path, filename), title, author, mime))
|
||||||
return bl
|
return bl
|
||||||
|
|
||||||
def upload_books(self, files, names, on_card=False, end_session=True):
|
def upload_books(self, files, names, on_card=False, end_session=True,
|
||||||
|
metadata=None):
|
||||||
if on_card and not self._card_prefix:
|
if on_card and not self._card_prefix:
|
||||||
raise ValueError(_('The reader has no storage card connected.'))
|
raise ValueError(_('The reader has no storage card connected.'))
|
||||||
|
|
||||||
@ -75,9 +77,25 @@ class USBMS(Device):
|
|||||||
|
|
||||||
paths = []
|
paths = []
|
||||||
names = iter(names)
|
names = iter(names)
|
||||||
|
metadata = iter(metadata)
|
||||||
|
|
||||||
for infile in files:
|
for infile in files:
|
||||||
filepath = os.path.join(path, names.next())
|
newpath = path
|
||||||
|
|
||||||
|
if self.SUPPORTS_SUB_DIRS:
|
||||||
|
mdata = metadata.next()
|
||||||
|
|
||||||
|
if 'tags' in mdata.keys():
|
||||||
|
for tag in mdata['tags']:
|
||||||
|
if tag.startswith('/'):
|
||||||
|
newpath += tag
|
||||||
|
newpath = os.path.normpath(newpath)
|
||||||
|
break
|
||||||
|
|
||||||
|
if not os.path.exists(newpath):
|
||||||
|
os.makedirs(newpath)
|
||||||
|
|
||||||
|
filepath = os.path.join(newpath, names.next())
|
||||||
paths.append(filepath)
|
paths.append(filepath)
|
||||||
|
|
||||||
if hasattr(infile, 'read'):
|
if hasattr(infile, 'read'):
|
||||||
@ -107,6 +125,10 @@ class USBMS(Device):
|
|||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
# Delete the ebook
|
# Delete the ebook
|
||||||
os.unlink(path)
|
os.unlink(path)
|
||||||
|
try:
|
||||||
|
os.removedirs(os.path.dirname(path))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def remove_books_from_metadata(cls, paths, booklists):
|
def remove_books_from_metadata(cls, paths, booklists):
|
||||||
@ -115,7 +137,6 @@ class USBMS(Device):
|
|||||||
for book in bl:
|
for book in bl:
|
||||||
if path.endswith(book.path):
|
if path.endswith(book.path):
|
||||||
bl.remove(book)
|
bl.remove(book)
|
||||||
break
|
|
||||||
|
|
||||||
def sync_booklists(self, booklists, end_session=True):
|
def sync_booklists(self, booklists, end_session=True):
|
||||||
# There is no meta data on the device to update. The device is treated
|
# There is no meta data on the device to update. The device is treated
|
||||||
|
@ -49,13 +49,17 @@ def main(args=sys.argv):
|
|||||||
input_pdf = PdfFileReader(file(source, "rb"))
|
input_pdf = PdfFileReader(file(source, "rb"))
|
||||||
except:
|
except:
|
||||||
print "Unable to read input"
|
print "Unable to read input"
|
||||||
return 2
|
return 2
|
||||||
info = input_pdf.getDocumentInfo()
|
title = _('Unknown')
|
||||||
title = 'Unknown'
|
author = _('Unknown')
|
||||||
author = 'Unknown'
|
try:
|
||||||
if info.title:
|
info = input_pdf.getDocumentInfo()
|
||||||
title = info.title
|
if info.title:
|
||||||
author = info.author
|
title = info.title
|
||||||
|
if info.author:
|
||||||
|
author = info.author
|
||||||
|
except:
|
||||||
|
pass
|
||||||
if opts.bounding != None:
|
if opts.bounding != None:
|
||||||
try:
|
try:
|
||||||
bounding = open( opts.bounding , 'r' )
|
bounding = open( opts.bounding , 'r' )
|
||||||
|
@ -136,16 +136,18 @@ class DeviceManager(Thread):
|
|||||||
return self.create_job(self._sync_booklists, done, args=[booklists],
|
return self.create_job(self._sync_booklists, done, args=[booklists],
|
||||||
description=_('Send metadata to device'))
|
description=_('Send metadata to device'))
|
||||||
|
|
||||||
def _upload_books(self, files, names, on_card=False):
|
def _upload_books(self, files, names, on_card=False, metadata=None):
|
||||||
'''Upload books to device: '''
|
'''Upload books to device: '''
|
||||||
return self.device.upload_books(files, names, on_card, end_session=False)
|
return self.device.upload_books(files, names, on_card,
|
||||||
|
metadata=metadata, end_session=False)
|
||||||
|
|
||||||
def upload_books(self, done, files, names, on_card=False, titles=None):
|
def upload_books(self, done, files, names, on_card=False, titles=None,
|
||||||
|
metadata=None):
|
||||||
desc = _('Upload %d books to device')%len(names)
|
desc = _('Upload %d books to device')%len(names)
|
||||||
if titles:
|
if titles:
|
||||||
desc += u':' + u', '.join(titles)
|
desc += u':' + u', '.join(titles)
|
||||||
return self.create_job(self._upload_books, done, args=[files, names],
|
return self.create_job(self._upload_books, done, args=[files, names],
|
||||||
kwargs={'on_card':on_card}, description=desc)
|
kwargs={'on_card':on_card,'metadata':metadata}, description=desc)
|
||||||
|
|
||||||
def add_books_to_metadata(self, locations, metadata, booklists):
|
def add_books_to_metadata(self, locations, metadata, booklists):
|
||||||
self.device.add_books_to_metadata(locations, metadata, booklists)
|
self.device.add_books_to_metadata(locations, metadata, booklists)
|
||||||
|
@ -385,13 +385,35 @@ class BooksModel(QAbstractTableModel):
|
|||||||
metadata.append(mi)
|
metadata.append(mi)
|
||||||
return metadata
|
return metadata
|
||||||
|
|
||||||
|
def get_preferred_formats_from_ids(self, ids, all_formats, mode='r+b'):
|
||||||
|
ans = []
|
||||||
|
for id in ids:
|
||||||
|
format = None
|
||||||
|
fmts = self.db.formats(id, index_is_id=True)
|
||||||
|
if not fmts:
|
||||||
|
fmts = ''
|
||||||
|
available_formats = set(fmts.lower().split(','))
|
||||||
|
for f in all_formats:
|
||||||
|
if f.lower() in available_formats:
|
||||||
|
format = f.lower()
|
||||||
|
break
|
||||||
|
if format is None:
|
||||||
|
ans.append(format)
|
||||||
|
else:
|
||||||
|
f = self.db.format(id, format, index_is_id=True, as_file=True,
|
||||||
|
mode=mode)
|
||||||
|
ans.append(f)
|
||||||
|
return ans
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_preferred_formats(self, rows, formats, paths=False):
|
def get_preferred_formats(self, rows, formats, paths=False):
|
||||||
ans = []
|
ans = []
|
||||||
for row in (row.row() for row in rows):
|
for row in (row.row() for row in rows):
|
||||||
format = None
|
format = None
|
||||||
fmts = self.db.formats(row)
|
fmts = self.db.formats(row)
|
||||||
if not fmts:
|
if not fmts:
|
||||||
return []
|
fmts = ''
|
||||||
db_formats = set(fmts.lower().split(','))
|
db_formats = set(fmts.lower().split(','))
|
||||||
available_formats = set([f.lower() for f in formats])
|
available_formats = set([f.lower() for f in formats])
|
||||||
u = available_formats.intersection(db_formats)
|
u = available_formats.intersection(db_formats)
|
||||||
|
@ -746,7 +746,7 @@ class Main(MainWindow, Ui_MainWindow):
|
|||||||
titles = [i['title'] for i in metadata]
|
titles = [i['title'] for i in metadata]
|
||||||
job = self.device_manager.upload_books(Dispatcher(self.books_uploaded),
|
job = self.device_manager.upload_books(Dispatcher(self.books_uploaded),
|
||||||
files, names, on_card=on_card,
|
files, names, on_card=on_card,
|
||||||
titles=titles
|
metadata=metadata, titles=titles
|
||||||
)
|
)
|
||||||
self.upload_memory[job] = (metadata, on_card, memory, files)
|
self.upload_memory[job] = (metadata, on_card, memory, files)
|
||||||
|
|
||||||
@ -887,7 +887,8 @@ class Main(MainWindow, Ui_MainWindow):
|
|||||||
if self.device_connected:
|
if self.device_connected:
|
||||||
ids = list(dynamic.get('news_to_be_synced', set([])))
|
ids = list(dynamic.get('news_to_be_synced', set([])))
|
||||||
ids = [id for id in ids if self.library_view.model().db.has_id(id)]
|
ids = [id for id in ids if self.library_view.model().db.has_id(id)]
|
||||||
files = [self.library_view.model().db.format(id, prefs['output_format'], index_is_id=True, as_file=True) for id in ids]
|
files = self.library_view.model().get_preferred_formats_from_ids(
|
||||||
|
ids, self.device_manager.device_class.FORMATS)
|
||||||
files = [f for f in files if f is not None]
|
files = [f for f in files if f is not None]
|
||||||
if not files:
|
if not files:
|
||||||
dynamic.set('news_to_be_synced', set([]))
|
dynamic.set('news_to_be_synced', set([]))
|
||||||
@ -922,7 +923,7 @@ class Main(MainWindow, Ui_MainWindow):
|
|||||||
if cdata:
|
if cdata:
|
||||||
mi['cover'] = self.cover_to_thumbnail(cdata)
|
mi['cover'] = self.cover_to_thumbnail(cdata)
|
||||||
metadata = iter(metadata)
|
metadata = iter(metadata)
|
||||||
_files = self.library_view.model().get_preferred_formats(rows,
|
_files = self.library_view.model().get_preferred_formats(rows,
|
||||||
self.device_manager.device_class.FORMATS, paths=True)
|
self.device_manager.device_class.FORMATS, paths=True)
|
||||||
files = [getattr(f, 'name', None) for f in _files]
|
files = [getattr(f, 'name', None) for f in _files]
|
||||||
bad, good, gf, names = [], [], [], []
|
bad, good, gf, names = [], [], [], []
|
||||||
|
5329
src/calibre/translations/zh.po
Normal file
5329
src/calibre/translations/zh.po
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user