Device drivers use file path template.

This commit is contained in:
John Schember 2009-08-20 21:05:47 -04:00
parent 76b10fcac3
commit ff74cd460d
9 changed files with 86 additions and 131 deletions

View File

@ -45,24 +45,25 @@ class CYBOOKG3(USBMS):
DELETE_EXTS = ['.mbp', '.dat', '_6090.t2b'] DELETE_EXTS = ['.mbp', '.dat', '_6090.t2b']
SUPPORTS_SUB_DIRS = True SUPPORTS_SUB_DIRS = True
def upload_books(self, files, names, on_card=None, end_session=True, def upload_books(self, files, metadatas, ids, on_card=None,
metadata=None): end_session=True):
path = self._sanity_check(on_card, files) path = self._sanity_check(on_card, files)
paths = [] paths = []
names = iter(names) metadatas = iter(metadatas)
metadata = iter(metadata) ids = iter(ids)
for i, infile in enumerate(files): for i, infile in enumerate(files):
mdata, fname = metadata.next(), names.next() mdata, id = metadatas.next(), ids.next()
filepath = self.create_upload_path(path, mdata, fname) ext = os.path.splitext(infile)[1]
filepath = self.create_upload_path(path, mdata, ext, id)
paths.append(filepath) paths.append(filepath)
self.put_file(infile, filepath, replace_file=True) self.put_file(infile, filepath, replace_file=True)
coverdata = None coverdata = None
cover = mdata.get('cover', None) cover = mdata.cover
if cover: if cover:
coverdata = cover[2] coverdata = cover[2]

View File

@ -15,7 +15,7 @@ from itertools import cycle
from calibre.devices.usbms.driver import USBMS from calibre.devices.usbms.driver import USBMS
from calibre.utils.filenames import ascii_filename as sanitize from calibre.utils.filenames import ascii_filename as sanitize
from calibre.ebooks.metadata import string_to_authors from calibre.ebooks.metadata import authors_to_string, string_to_authors
class JETBOOK(USBMS): class JETBOOK(USBMS):
name = 'Ectaco JetBook Device Interface' name = 'Ectaco JetBook Device Interface'
@ -50,23 +50,22 @@ class JETBOOK(USBMS):
r'(?P<authors>.+)#(?P<title>.+)' r'(?P<authors>.+)#(?P<title>.+)'
) )
def upload_books(self, files, names, on_card=False, end_session=True, def upload_books(self, files, metadatas, ids, on_card=None,
metadata=None): end_session=True):
path = self._sanity_check(on_card, files) path = self._sanity_check(on_card, files)
paths = [] paths = []
names = iter(names) metadatas = iter(metadatas)
metadata = iter(metadata) ids = iter(ids)
for i, infile in enumerate(files): for i, infile in enumerate(files):
mdata, fname = metadata.next(), names.next() mdata, id = metadatas.next(), ids.next()
path = os.path.dirname(self.create_upload_path(path, mdata, fname)) ext = os.path.splitext(infile)[1]
path = self.create_upload_path(path, mdata, ext, id)
author = sanitize(mdata.get('authors','Unknown')).replace(' ', '_') author = sanitize(authors_to_string(mdata.authors)).replace(' ', '_')
title = sanitize(mdata.get('title', 'Unknown')).replace(' ', '_') title = sanitize(mdata.title).replace(' ', '_')
fileext = os.path.splitext(os.path.basename(fname))[1] fname = '%s#%s%s' % (author, title, ext)
fname = '%s#%s%s' % (author, title, fileext)
filepath = os.path.join(path, fname) filepath = os.path.join(path, fname)
paths.append(filepath) paths.append(filepath)

View File

@ -9,6 +9,7 @@ from base64 import b64decode as decode
from base64 import b64encode as encode from base64 import b64encode as encode
import re import re
from calibre.ebooks.metadata import authors_to_string
from calibre.devices.interface import BookList as _BookList from calibre.devices.interface import BookList as _BookList
from calibre.devices import strftime, strptime from calibre.devices import strftime, strptime
@ -262,9 +263,9 @@ class BookList(_BookList):
cid = self.max_id()+1 cid = self.max_id()+1
sourceid = str(self[0].sourceid) if len(self) else "1" sourceid = str(self[0].sourceid) if len(self) else "1"
attrs = { attrs = {
"title" : info["title"], "title" : info.title,
'titleSorter' : sortable_title(info['title']), 'titleSorter' : sortable_title(info.title),
"author" : info["authors"] if info['authors'] else 'Unknown', \ "author" : authors_to_string(info.authors), \
"page":"0", "part":"0", "scale":"0", \ "page":"0", "part":"0", "scale":"0", \
"sourceid":sourceid, "id":str(cid), "date":"", \ "sourceid":sourceid, "id":str(cid), "date":"", \
"mime":mime, "path":name, "size":str(size) "mime":mime, "path":name, "size":str(size)
@ -273,7 +274,7 @@ class BookList(_BookList):
node.setAttributeNode(self.document.createAttribute(attr)) node.setAttributeNode(self.document.createAttribute(attr))
node.setAttribute(attr, attrs[attr]) node.setAttribute(attr, attrs[attr])
try: try:
w, h, data = info["cover"] w, h, data = info.cover
except TypeError: except TypeError:
w, h, data = None, None, None w, h, data = None, None, None
@ -290,10 +291,7 @@ class BookList(_BookList):
book.datetime = ctime book.datetime = ctime
self.append(book) self.append(book)
self.set_next_id(cid+1) self.set_next_id(cid+1)
if self.prefix and info.has_key('tags'): # Playlists only supportted in main memory self.set_playlists(book.id, info.tags
if info.has_key('tag order'):
self.tag_order.update(info['tag order'])
self.set_playlists(book.id, info['tags'])
def playlist_by_title(self, title): def playlist_by_title(self, title):

View File

@ -863,14 +863,14 @@ class PRS500(DeviceConfig, DevicePlugin):
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, metadatas, ids, on_card=None,
metadata=None): end_session=True):
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]:
self.mkdir(prefix[:-1], False) self.mkdir(prefix[:-1], False)
paths, ctimes = [], [] paths, ctimes = [], []
names = iter(names) names = iter([m.title for m in metatdatas])
infiles = [file if hasattr(file, 'read') else open(file, 'rb') for file in files] infiles = [file if hasattr(file, 'read') else open(file, 'rb') for file in files]
for f in infiles: f.seek(0, 2) for f in infiles: f.seek(0, 2)
sizes = [f.tell() for f in infiles] sizes = [f.tell() for f in infiles]

View File

@ -8,7 +8,7 @@ import xml.dom.minidom as dom
from base64 import b64decode as decode from base64 import b64decode as decode
from base64 import b64encode as encode from base64 import b64encode as encode
from calibre.ebooks.metadata import authors_to_string
from calibre.devices.interface import BookList as _BookList from calibre.devices.interface import BookList as _BookList
from calibre.devices import strftime as _strftime from calibre.devices import strftime as _strftime
from calibre.devices import strptime from calibre.devices import strptime
@ -194,9 +194,9 @@ class BookList(_BookList):
except: except:
sourceid = '1' sourceid = '1'
attrs = { attrs = {
"title" : info["title"], "title" : info.title,
'titleSorter' : sortable_title(info['title']), 'titleSorter' : sortable_title(info.title),
"author" : info["authors"] if info['authors'] else _('Unknown'), "author" : authors_to_string(info.authors),
"page":"0", "part":"0", "scale":"0", \ "page":"0", "part":"0", "scale":"0", \
"sourceid":sourceid, "id":str(cid), "date":"", \ "sourceid":sourceid, "id":str(cid), "date":"", \
"mime":mime, "path":name, "size":str(size) "mime":mime, "path":name, "size":str(size)
@ -205,7 +205,7 @@ class BookList(_BookList):
node.setAttributeNode(self.document.createAttribute(attr)) node.setAttributeNode(self.document.createAttribute(attr))
node.setAttribute(attr, attrs[attr]) node.setAttribute(attr, attrs[attr])
try: try:
w, h, data = info["cover"] w, h, data = info.cover
except TypeError: except TypeError:
w, h, data = None, None, None w, h, data = None, None, None
@ -221,10 +221,7 @@ class BookList(_BookList):
book = Book(node, self.mountpath, [], prefix=self.prefix) book = Book(node, self.mountpath, [], prefix=self.prefix)
book.datetime = ctime book.datetime = ctime
self.append(book) self.append(book)
if info.has_key('tags'): self.set_tags(book, info.tags)
if info.has_key('tag order'):
self.tag_order.update(info['tag order'])
self.set_tags(book, info['tags'])
def _delete_book(self, node): def _delete_book(self, node):
nid = node.getAttribute('id') nid = node.getAttribute('id')

View File

@ -109,20 +109,22 @@ class PRS505(CLI, Device):
self.report_progress(1.0, _('Getting list of books on device...')) self.report_progress(1.0, _('Getting list of books on device...'))
return bl return bl
def upload_books(self, files, names, on_card=None, end_session=True, def upload_books(self, files, metadatas, ids, on_card=None,
metadata=None): end_session=True):
path = self._sanity_check(on_card, files) path = self._sanity_check(on_card, files)
paths, ctimes, sizes = [], [], [] paths = []
names = iter(names) metadatas = iter(metadatas)
metadata = iter(metadata) ids = iter(ids)
for i, infile in enumerate(files):
mdata, fname = metadata.next(), names.next()
filepath = self.create_upload_path(path, mdata, fname)
for i, infile in enumerate(files):
mdata, id = metadatas.next(), ids.next()
ext = os.path.splitext(infile)[1]
filepath = self.create_upload_path(path, mdata, ext, id)
paths.append(filepath) paths.append(filepath)
self.put_file(infile, paths[-1], replace_file=True)
self.put_file(infile, filepath, replace_file=True)
ctimes.append(os.path.getctime(paths[-1])) ctimes.append(os.path.getctime(paths[-1]))
sizes.append(os.stat(paths[-1]).st_size) sizes.append(os.stat(paths[-1]).st_size)

View File

@ -23,7 +23,7 @@ from calibre.devices.interface import DevicePlugin
from calibre.devices.errors import DeviceError, FreeSpaceError from calibre.devices.errors import DeviceError, FreeSpaceError
from calibre.devices.usbms.deviceconfig import DeviceConfig from calibre.devices.usbms.deviceconfig import DeviceConfig
from calibre import iswindows, islinux, isosx, __appname__ from calibre import iswindows, islinux, isosx, __appname__
from calibre.utils.filenames import ascii_filename as sanitize, shorten_components_to from calibre.utils.filenames import shorten_components_to
class Device(DeviceConfig, DevicePlugin): class Device(DeviceConfig, DevicePlugin):
@ -667,46 +667,18 @@ class Device(DeviceConfig, DevicePlugin):
raise FreeSpaceError(_("There is insufficient free space on the storage card")) raise FreeSpaceError(_("There is insufficient free space on the storage card"))
return path return path
def create_upload_path(self, path, mdata, fname): def create_upload_path(self, root, mdata, ext, id):
path = os.path.abspath(path) from calibre.library.save_to_disk import config, get_components
newpath = path opts = config().parse()
extra_components = [] components = get_components(opts.template, mdata, id, opts.timefmt, 250)
components = [str(x) for x in components]
if self.SUPPORTS_SUB_DIRS and self.settings().use_subdirs: components = shorten_components_to(250 - len(root), components)
if 'tags' in mdata.keys(): filepath = '%s%s' % (os.path.join(root, *components), ext)
for tag in mdata['tags']:
if tag.startswith(_('News')):
extra_components.append('news')
c = sanitize(mdata.get('title', ''))
if c:
extra_components.append(c)
c = sanitize(mdata.get('timestamp', ''))
if c:
extra_components.append(c)
break
elif tag.startswith('/'):
for c in tag.split('/'):
c = sanitize(c)
if not c: continue
extra_components.append(c)
break
if not extra_components:
c = sanitize(mdata.get('authors', _('Unknown')))
if c:
extra_components.append(c)
c = sanitize(mdata.get('title', _('Unknown')))
if c:
extra_components.append(c)
newpath = os.path.join(newpath, c)
fname = sanitize(fname)
extra_components.append(fname)
extra_components = [str(x) for x in extra_components]
components = shorten_components_to(250 - len(path), extra_components)
filepath = os.path.join(path, *components)
filedir = os.path.dirname(filepath) filedir = os.path.dirname(filepath)
if not self.SUPPORTS_SUB_DIRS or not self.settings().use_subdirs:
filedir = root
filepath = os.path.join(root, os.path.basename(filepath))
if not os.path.exists(filedir): if not os.path.exists(filedir):
os.makedirs(filedir) os.makedirs(filedir)

View File

@ -79,19 +79,19 @@ class USBMS(CLI, Device):
return bl return bl
def upload_books(self, files, names, on_card=None, end_session=True, def upload_books(self, files, metadatas, ids, on_card=None,
metadata=None): end_session=True):
path = self._sanity_check(on_card, files) path = self._sanity_check(on_card, files)
paths = [] paths = []
names = iter(names) metadatas = iter(metadatas)
metadata = iter(metadata) ids = iter(ids)
for i, infile in enumerate(files): for i, infile in enumerate(files):
mdata, fname = metadata.next(), names.next() mdata, id = metadatas.next(), ids.next()
filepath = self.create_upload_path(path, mdata, fname) ext = os.path.splitext(infile)[1]
filepath = self.create_upload_path(path, mdata, ext, id)
paths.append(filepath) paths.append(filepath)
self.put_file(infile, filepath, replace_file=True) self.put_file(infile, filepath, replace_file=True)

View File

@ -214,18 +214,17 @@ 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=None, metadata=None): def _upload_books(self, files, metadata, ids, on_card=None):
'''Upload books to device: ''' '''Upload books to device: '''
return self.device.upload_books(files, names, on_card, return self.device.upload_books(files, metadata, ids, on_card,
metadata=metadata, end_session=False) end_session=False)
def upload_books(self, done, files, names, on_card=None, titles=None, def upload_books(self, done, files, metadata, ids, on_card=None, titles=None):
metadata=None): desc = _('Upload %d books to device')%len(files)
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, metadata, ids],
kwargs={'on_card':on_card,'metadata':metadata}, description=desc) kwargs={'on_card':on_card}, 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)
@ -698,18 +697,18 @@ class DeviceGUI(object):
dynamic.set('news_to_be_synced', set([])) dynamic.set('news_to_be_synced', set([]))
return return
metadata = self.library_view.model().get_metadata(ids, metadata = self.library_view.model().get_metadata(ids,
rows_are_ids=True) rows_are_ids=True, full_metadata=True)[1]
names = [] names = []
for mi in metadata: for mi in metadata:
prefix = ascii_filename(mi['title']) prefix = ascii_filename(mi.title)
if not isinstance(prefix, unicode): if not isinstance(prefix, unicode):
prefix = prefix.decode(preferred_encoding, 'replace') prefix = prefix.decode(preferred_encoding, 'replace')
prefix = ascii_filename(prefix) prefix = ascii_filename(prefix)
names.append('%s_%d%s'%(prefix, id, names.append('%s_%d%s'%(prefix, id,
os.path.splitext(f.name)[1])) os.path.splitext(f.name)[1]))
cdata = mi['cover'] cdata = mi.cover
if cdata: if cdata:
mi['cover'] = self.cover_to_thumbnail(cdata) mi.cover = self.cover_to_thumbnail(cdata)
dynamic.set('news_to_be_synced', set([])) dynamic.set('news_to_be_synced', set([]))
if config['upload_news_to_device'] and files: if config['upload_news_to_device'] and files:
remove = ids if \ remove = ids if \
@ -718,8 +717,7 @@ class DeviceGUI(object):
self.location_view.model().free[1] : 'carda', self.location_view.model().free[1] : 'carda',
self.location_view.model().free[2] : 'cardb' } self.location_view.model().free[2] : 'cardb' }
on_card = space.get(sorted(space.keys(), reverse=True)[0], None) on_card = space.get(sorted(space.keys(), reverse=True)[0], None)
self.upload_books(files, names, metadata, self.upload_books(files, metadata, ids, on_card=on_card,
on_card=on_card,
memory=[[f.name for f in files], remove]) memory=[[f.name for f in files], remove])
self.status_bar.showMessage(_('Sending news to device.'), 5000) self.status_bar.showMessage(_('Sending news to device.'), 5000)
@ -741,38 +739,28 @@ class DeviceGUI(object):
else: else:
_auto_ids = [] _auto_ids = []
metadata = self.library_view.model().get_metadata(ids, True) metadata = self.library_view.model().get_metadata(ids, True, full_metadata=True)[1]
ids = iter(ids) ids = iter(ids)
for mi in metadata: for mi in metadata:
cdata = mi['cover'] cdata = mi.cover
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 = [getattr(f, 'name', None) for f in _files] files = [getattr(f, 'name', None) for f in _files]
bad, good, gf, names, remove_ids = [], [], [], [], [] bad, mdata, gf, fids, remove_ids = [], [], [], [], []
for f in files: for f in files:
mi = metadata.next() mi = metadata.next()
id = ids.next() id = ids.next()
if f is None: if f is None:
bad.append(mi['title']) bad.append(mi.title)
else: else:
remove_ids.append(id) remove_ids.append(id)
good.append(mi)
gf.append(f) gf.append(f)
t = mi['title'] mdata.append(mi)
if not t: fids.append(id)
t = _('Unknown')
a = mi['authors']
if not a:
a = _('Unknown')
prefix = ascii_filename(t+' - '+a)
if not isinstance(prefix, unicode):
prefix = prefix.decode(preferred_encoding, 'replace')
prefix = ascii_filename(prefix)
names.append('%s_%d%s'%(prefix, id, os.path.splitext(f)[1]))
remove = remove_ids if delete_from_library else [] remove = remove_ids if delete_from_library else []
self.upload_books(gf, names, good, on_card, memory=(_files, remove)) self.upload_books(gf, mdata, fids, on_card, memory=(_files, remove))
self.status_bar.showMessage(_('Sending books to device.'), 5000) self.status_bar.showMessage(_('Sending books to device.'), 5000)
auto = [] auto = []
@ -834,17 +822,15 @@ class DeviceGUI(object):
cp, fs = job.result cp, fs = job.result
self.location_view.model().update_devices(cp, fs) self.location_view.model().update_devices(cp, fs)
def upload_books(self, files, names, metadata, on_card=None, memory=None): def upload_books(self, files, metadata, ids, on_card=None, memory=None):
''' '''
Upload books to device. Upload books to device.
:param files: List of either paths to files or file like objects :param files: List of either paths to files or file like objects
''' '''
titles = [i['title'] for i in metadata] titles = [i.title for i in metadata]
job = self.device_manager.upload_books( job = self.device_manager.upload_books(
Dispatcher(self.books_uploaded), Dispatcher(self.books_uploaded),
files, names, on_card=on_card, files, metadata, ids, 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)
def books_uploaded(self, job): def books_uploaded(self, job):
@ -857,7 +843,7 @@ class DeviceGUI(object):
if isinstance(job.exception, FreeSpaceError): if isinstance(job.exception, FreeSpaceError):
where = 'in main memory.' if 'memory' in str(job.exception) \ where = 'in main memory.' if 'memory' in str(job.exception) \
else 'on the storage card.' else 'on the storage card.'
titles = '\n'.join(['<li>'+mi['title']+'</li>' \ titles = '\n'.join(['<li>'+mi.title+'</li>' \
for mi in metadata]) for mi in metadata])
d = error_dialog(self, _('No space on device'), d = error_dialog(self, _('No space on device'),
_('<p>Cannot upload books to device there ' _('<p>Cannot upload books to device there '