mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Fix #7046 (Removing a publisher results in an error). Add tweak to control how articles in title sort are handled. Add a new format type 'device_db' to plugboards to control the metadata displayed in book lists on SONY devices.
This commit is contained in:
commit
113feab6d3
@ -83,6 +83,16 @@ title_series_sorting = 'library_order'
|
|||||||
# strictly_alphabetic, it would remain "The Client".
|
# strictly_alphabetic, it would remain "The Client".
|
||||||
save_template_title_series_sorting = 'library_order'
|
save_template_title_series_sorting = 'library_order'
|
||||||
|
|
||||||
|
# Set the list of words that are to be considered 'articles' when computing the
|
||||||
|
# title sort strings. The list is a regular expression, with the articles
|
||||||
|
# separated by 'or' bars. Comparisons are case insensitive, and that cannot be
|
||||||
|
# changed. Changes to this tweak won't have an effect until the book is modified
|
||||||
|
# in some way. If you enter an invalid pattern, it is silently ignored.
|
||||||
|
# To disable use the expression: '^$'
|
||||||
|
# Default: '^(A|The|An)\s+'
|
||||||
|
title_sort_articles=r'^(A|The|An)\s+'
|
||||||
|
|
||||||
|
|
||||||
# Specify a folder that calibre should connect to at startup using
|
# Specify a folder that calibre should connect to at startup using
|
||||||
# connect_to_folder. This must be a full path to the folder. If the folder does
|
# connect_to_folder. This must be a full path to the folder. If the folder does
|
||||||
# not exist when calibre starts, it is ignored. If there are '\' characters in
|
# not exist when calibre starts, it is ignored. If there are '\' characters in
|
||||||
|
@ -14,6 +14,7 @@ from calibre.devices.prs505 import CACHE_XML
|
|||||||
from calibre.devices.prs505.sony_cache import XMLCache
|
from calibre.devices.prs505.sony_cache import XMLCache
|
||||||
from calibre import __appname__
|
from calibre import __appname__
|
||||||
from calibre.devices.usbms.books import CollectionsBookList
|
from calibre.devices.usbms.books import CollectionsBookList
|
||||||
|
from calibre.utils.config import tweaks
|
||||||
|
|
||||||
class PRS505(USBMS):
|
class PRS505(USBMS):
|
||||||
|
|
||||||
@ -63,6 +64,8 @@ class PRS505(USBMS):
|
|||||||
'series, tags, authors'
|
'series, tags, authors'
|
||||||
EXTRA_CUSTOMIZATION_DEFAULT = ', '.join(['series', 'tags'])
|
EXTRA_CUSTOMIZATION_DEFAULT = ', '.join(['series', 'tags'])
|
||||||
|
|
||||||
|
plugboard = None
|
||||||
|
|
||||||
def windows_filter_pnp_id(self, pnp_id):
|
def windows_filter_pnp_id(self, pnp_id):
|
||||||
return '_LAUNCHER' in pnp_id
|
return '_LAUNCHER' in pnp_id
|
||||||
|
|
||||||
@ -150,7 +153,7 @@ class PRS505(USBMS):
|
|||||||
else:
|
else:
|
||||||
collections = []
|
collections = []
|
||||||
debug_print('PRS505: collection fields:', collections)
|
debug_print('PRS505: collection fields:', collections)
|
||||||
c.update(blists, collections)
|
c.update(blists, collections, self.plugboard)
|
||||||
c.write()
|
c.write()
|
||||||
|
|
||||||
USBMS.sync_booklists(self, booklists, end_session=end_session)
|
USBMS.sync_booklists(self, booklists, end_session=end_session)
|
||||||
@ -163,3 +166,9 @@ class PRS505(USBMS):
|
|||||||
c.write()
|
c.write()
|
||||||
debug_print('PRS505: finished rebuild_collections')
|
debug_print('PRS505: finished rebuild_collections')
|
||||||
|
|
||||||
|
def use_plugboard_ext(self):
|
||||||
|
return 'device_db'
|
||||||
|
|
||||||
|
def set_plugboard(self, pb):
|
||||||
|
debug_print('PRS505: use plugboard', pb)
|
||||||
|
self.plugboard = pb
|
@ -325,12 +325,6 @@ class XMLCache(object):
|
|||||||
for book in bl:
|
for book in bl:
|
||||||
record = lpath_map.get(book.lpath, None)
|
record = lpath_map.get(book.lpath, None)
|
||||||
if record is not None:
|
if record is not None:
|
||||||
title = record.get('title', None)
|
|
||||||
if title is not None and title != book.title:
|
|
||||||
debug_print('Renaming title', book.title, 'to', title)
|
|
||||||
book.title = title
|
|
||||||
# Don't set the author, because the reader strips all but
|
|
||||||
# the first author.
|
|
||||||
for thumbnail in record.xpath(
|
for thumbnail in record.xpath(
|
||||||
'descendant::*[local-name()="thumbnail"]'):
|
'descendant::*[local-name()="thumbnail"]'):
|
||||||
for img in thumbnail.xpath(
|
for img in thumbnail.xpath(
|
||||||
@ -350,7 +344,7 @@ class XMLCache(object):
|
|||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
# Update XML from JSON {{{
|
# Update XML from JSON {{{
|
||||||
def update(self, booklists, collections_attributes):
|
def update(self, booklists, collections_attributes, plugboard):
|
||||||
debug_print('Starting update', collections_attributes)
|
debug_print('Starting update', collections_attributes)
|
||||||
use_tz_var = False
|
use_tz_var = False
|
||||||
for i, booklist in booklists.items():
|
for i, booklist in booklists.items():
|
||||||
@ -365,8 +359,13 @@ class XMLCache(object):
|
|||||||
record = lpath_map.get(book.lpath, None)
|
record = lpath_map.get(book.lpath, None)
|
||||||
if record is None:
|
if record is None:
|
||||||
record = self.create_text_record(root, i, book.lpath)
|
record = self.create_text_record(root, i, book.lpath)
|
||||||
|
if plugboard is not None:
|
||||||
|
newmi = book.deepcopy()
|
||||||
|
newmi.template_to_attribute(book, plugboard)
|
||||||
|
else:
|
||||||
|
newmi = book
|
||||||
(gtz_count, ltz_count, use_tz_var) = \
|
(gtz_count, ltz_count, use_tz_var) = \
|
||||||
self.update_text_record(record, book, path, i,
|
self.update_text_record(record, newmi, path, i,
|
||||||
gtz_count, ltz_count, use_tz_var)
|
gtz_count, ltz_count, use_tz_var)
|
||||||
# Ensure the collections in the XML database are recorded for
|
# Ensure the collections in the XML database are recorded for
|
||||||
# this book
|
# this book
|
||||||
|
@ -44,7 +44,15 @@ def author_to_author_sort(author):
|
|||||||
def authors_to_sort_string(authors):
|
def authors_to_sort_string(authors):
|
||||||
return ' & '.join(map(author_to_author_sort, authors))
|
return ' & '.join(map(author_to_author_sort, authors))
|
||||||
|
|
||||||
_title_pat = re.compile('^(A|The|An)\s+', re.IGNORECASE)
|
try:
|
||||||
|
_title_pat = re.compile(tweaks.get('title_sort_articles',
|
||||||
|
r'^(A|The|An)\s+'), re.IGNORECASE)
|
||||||
|
except:
|
||||||
|
print 'Error in title sort pattern'
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
_title_pat = re.compile('^(A|The|An)\s+', re.IGNORECASE)
|
||||||
|
|
||||||
_ignore_starts = u'\'"'+u''.join(unichr(x) for x in range(0x2018, 0x201e)+[0x2032, 0x2033])
|
_ignore_starts = u'\'"'+u''.join(unichr(x) for x in range(0x2018, 0x201e)+[0x2032, 0x2033])
|
||||||
|
|
||||||
def title_sort(title):
|
def title_sort(title):
|
||||||
|
@ -8,6 +8,7 @@ __docformat__ = 'restructuredtext en'
|
|||||||
import copy, traceback
|
import copy, traceback
|
||||||
|
|
||||||
from calibre import prints
|
from calibre import prints
|
||||||
|
from calibre.constants import DEBUG
|
||||||
from calibre.ebooks.metadata.book import SC_COPYABLE_FIELDS
|
from calibre.ebooks.metadata.book import SC_COPYABLE_FIELDS
|
||||||
from calibre.ebooks.metadata.book import SC_FIELDS_COPY_NOT_NULL
|
from calibre.ebooks.metadata.book import SC_FIELDS_COPY_NOT_NULL
|
||||||
from calibre.ebooks.metadata.book import STANDARD_METADATA_FIELDS
|
from calibre.ebooks.metadata.book import STANDARD_METADATA_FIELDS
|
||||||
@ -50,6 +51,8 @@ class SafeFormat(TemplateFormatter):
|
|||||||
return ''
|
return ''
|
||||||
return v
|
return v
|
||||||
except:
|
except:
|
||||||
|
if DEBUG:
|
||||||
|
traceback.print_exc()
|
||||||
return key
|
return key
|
||||||
|
|
||||||
composite_formatter = SafeFormat()
|
composite_formatter = SafeFormat()
|
||||||
@ -320,8 +323,8 @@ class Metadata(object):
|
|||||||
else:
|
else:
|
||||||
self.set(dest, val)
|
self.set(dest, val)
|
||||||
except:
|
except:
|
||||||
|
if DEBUG:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
pass
|
|
||||||
|
|
||||||
# Old Metadata API {{{
|
# Old Metadata API {{{
|
||||||
def print_all_attributes(self):
|
def print_all_attributes(self):
|
||||||
|
@ -310,7 +310,13 @@ class DeviceManager(Thread): # {{{
|
|||||||
self.device.sync_booklists(booklists, end_session=False)
|
self.device.sync_booklists(booklists, end_session=False)
|
||||||
return self.device.card_prefix(end_session=False), self.device.free_space()
|
return self.device.card_prefix(end_session=False), self.device.free_space()
|
||||||
|
|
||||||
def sync_booklists(self, done, booklists):
|
def sync_booklists(self, done, booklists, plugboards):
|
||||||
|
if hasattr(self.connected_device, 'use_plugboard_ext') and \
|
||||||
|
callable(self.connected_device.use_plugboard_ext):
|
||||||
|
ext = self.connected_device.use_plugboard_ext()
|
||||||
|
if ext is not None:
|
||||||
|
self.connected_device.set_plugboard(
|
||||||
|
self.find_plugboard(ext, plugboards))
|
||||||
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'))
|
||||||
|
|
||||||
@ -319,12 +325,7 @@ class DeviceManager(Thread): # {{{
|
|||||||
args=[booklist, on_card],
|
args=[booklist, on_card],
|
||||||
description=_('Send collections to device'))
|
description=_('Send collections to device'))
|
||||||
|
|
||||||
def _upload_books(self, files, names, on_card=None, metadata=None, plugboards=None):
|
def find_plugboard(self, ext, plugboards):
|
||||||
'''Upload books to device: '''
|
|
||||||
if metadata and files and len(metadata) == len(files):
|
|
||||||
for f, mi in zip(files, metadata):
|
|
||||||
if isinstance(f, unicode):
|
|
||||||
ext = f.rpartition('.')[-1].lower()
|
|
||||||
dev_name = self.connected_device.__class__.__name__
|
dev_name = self.connected_device.__class__.__name__
|
||||||
cpb = None
|
cpb = None
|
||||||
if ext in plugboards:
|
if ext in plugboards:
|
||||||
@ -338,9 +339,17 @@ class DeviceManager(Thread): # {{{
|
|||||||
cpb = cpb[plugboard_any_device_value]
|
cpb = cpb[plugboard_any_device_value]
|
||||||
else:
|
else:
|
||||||
cpb = None
|
cpb = None
|
||||||
|
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
prints('Using plugboard', ext, dev_name, cpb)
|
prints('Device using plugboard', ext, dev_name, cpb)
|
||||||
|
return cpb
|
||||||
|
|
||||||
|
def _upload_books(self, files, names, on_card=None, metadata=None, plugboards=None):
|
||||||
|
'''Upload books to device: '''
|
||||||
|
if metadata and files and len(metadata) == len(files):
|
||||||
|
for f, mi in zip(files, metadata):
|
||||||
|
if isinstance(f, unicode):
|
||||||
|
ext = f.rpartition('.')[-1].lower()
|
||||||
|
cpb = self.find_plugboard(ext, plugboards)
|
||||||
if ext:
|
if ext:
|
||||||
try:
|
try:
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
@ -1247,8 +1256,9 @@ class DeviceMixin(object): # {{{
|
|||||||
'''
|
'''
|
||||||
Upload metadata to device.
|
Upload metadata to device.
|
||||||
'''
|
'''
|
||||||
|
plugboards = self.library_view.model().db.prefs.get('plugboards', {})
|
||||||
self.device_manager.sync_booklists(Dispatcher(self.metadata_synced),
|
self.device_manager.sync_booklists(Dispatcher(self.metadata_synced),
|
||||||
self.booklists())
|
self.booklists(), plugboards)
|
||||||
|
|
||||||
def metadata_synced(self, job):
|
def metadata_synced(self, job):
|
||||||
'''
|
'''
|
||||||
@ -1502,8 +1512,10 @@ class DeviceMixin(object): # {{{
|
|||||||
|
|
||||||
if update_metadata:
|
if update_metadata:
|
||||||
if self.device_manager.is_device_connected:
|
if self.device_manager.is_device_connected:
|
||||||
|
plugboards = self.library_view.model().db.prefs.get('plugboards', {})
|
||||||
self.device_manager.sync_booklists(
|
self.device_manager.sync_booklists(
|
||||||
Dispatcher(self.metadata_synced), booklists)
|
Dispatcher(self.metadata_synced), booklists,
|
||||||
|
plugboards)
|
||||||
return update_metadata
|
return update_metadata
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ class TextDelegate(QStyledItemDelegate): # {{{
|
|||||||
complete_items = [i[1] for i in self.auto_complete_function()]
|
complete_items = [i[1] for i in self.auto_complete_function()]
|
||||||
completer = QCompleter(complete_items, self)
|
completer = QCompleter(complete_items, self)
|
||||||
completer.setCaseSensitivity(Qt.CaseInsensitive)
|
completer.setCaseSensitivity(Qt.CaseInsensitive)
|
||||||
completer.setCompletionMode(QCompleter.InlineCompletion)
|
completer.setCompletionMode(QCompleter.PopupCompletion)
|
||||||
editor.setCompleter(completer)
|
editor.setCompleter(completer)
|
||||||
return editor
|
return editor
|
||||||
#}}}
|
#}}}
|
||||||
|
@ -39,6 +39,12 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
|||||||
|
|
||||||
ConfigWidgetBase.initialize(self)
|
ConfigWidgetBase.initialize(self)
|
||||||
|
|
||||||
|
if self.gui.device_manager.connected_device is not None:
|
||||||
|
self.device_label.setText(_('Device currently connected: ') +
|
||||||
|
self.gui.device_manager.connected_device.__class__.__name__)
|
||||||
|
else:
|
||||||
|
self.device_label.setText(_('Device currently connected: None'))
|
||||||
|
|
||||||
self.devices = ['']
|
self.devices = ['']
|
||||||
for device in device_plugins():
|
for device in device_plugins():
|
||||||
n = device.__class__.__name__
|
n = device.__class__.__name__
|
||||||
@ -54,6 +60,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
|||||||
for w in metadata_writers():
|
for w in metadata_writers():
|
||||||
for f in w.file_types:
|
for f in w.file_types:
|
||||||
self.formats.append(f)
|
self.formats.append(f)
|
||||||
|
self.formats.append('device_db')
|
||||||
self.formats.sort()
|
self.formats.sort()
|
||||||
self.formats.insert(1, plugboard_any_format_value)
|
self.formats.insert(1, plugboard_any_format_value)
|
||||||
self.new_format.addItems(self.formats)
|
self.new_format.addItems(self.formats)
|
||||||
|
@ -40,7 +40,18 @@ One possible use for a plugboard is to alter the title to contain series informa
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="2" column="0" colspan="2">
|
||||||
|
<widget class="QLabel" name="device_label">
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0" colspan="2">
|
||||||
|
<widget class="Line" name="line">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
<layout class="QGridLayout" name="gridLayout_2">
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="QLabel" name="label_6">
|
<widget class="QLabel" name="label_6">
|
||||||
@ -123,7 +134,7 @@ One possible use for a plugboard is to alter the title to contain series informa
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="4" column="1">
|
||||||
<layout class="QGridLayout" name="fields_layout">
|
<layout class="QGridLayout" name="fields_layout">
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QLabel" name="label_2">
|
<widget class="QLabel" name="label_2">
|
||||||
|
@ -1593,7 +1593,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
self.conn.commit()
|
self.conn.commit()
|
||||||
|
|
||||||
def delete_publisher_using_id(self, old_id):
|
def delete_publisher_using_id(self, old_id):
|
||||||
self.dirty_books_referencing('publisher', id, commit=False)
|
self.dirty_books_referencing('publisher', old_id, commit=False)
|
||||||
self.conn.execute('''DELETE FROM books_publishers_link
|
self.conn.execute('''DELETE FROM books_publishers_link
|
||||||
WHERE publisher=?''', (old_id,))
|
WHERE publisher=?''', (old_id,))
|
||||||
self.conn.execute('DELETE FROM publishers WHERE id=?', (old_id,))
|
self.conn.execute('DELETE FROM publishers WHERE id=?', (old_id,))
|
||||||
|
@ -8,6 +8,8 @@ __docformat__ = 'restructuredtext en'
|
|||||||
|
|
||||||
import os, traceback, cStringIO, re
|
import os, traceback, cStringIO, re
|
||||||
|
|
||||||
|
from calibre import prints
|
||||||
|
from calibre.constants import DEBUG
|
||||||
from calibre.utils.config import Config, StringConfig, tweaks
|
from calibre.utils.config import Config, StringConfig, tweaks
|
||||||
from calibre.utils.formatter import TemplateFormatter
|
from calibre.utils.formatter import TemplateFormatter
|
||||||
from calibre.utils.filenames import shorten_components_to, supports_long_names, \
|
from calibre.utils.filenames import shorten_components_to, supports_long_names, \
|
||||||
@ -118,7 +120,7 @@ class SafeFormat(TemplateFormatter):
|
|||||||
try:
|
try:
|
||||||
b = self.book.get_user_metadata(key, False)
|
b = self.book.get_user_metadata(key, False)
|
||||||
except:
|
except:
|
||||||
prints('save_to_disk get value exception')
|
if DEBUG:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
b = None
|
b = None
|
||||||
|
|
||||||
@ -129,13 +131,13 @@ class SafeFormat(TemplateFormatter):
|
|||||||
self.composite_values[key] = \
|
self.composite_values[key] = \
|
||||||
self.vformat(b['display']['composite_template'], [], kwargs)
|
self.vformat(b['display']['composite_template'], [], kwargs)
|
||||||
return self.composite_values[key]
|
return self.composite_values[key]
|
||||||
if kwargs[key]:
|
if key in kwargs:
|
||||||
return self.sanitize(kwargs[key])
|
return kwargs[key].replace('/', '_').replace('\\', '_')
|
||||||
return ''
|
return ''
|
||||||
except:
|
except:
|
||||||
print('save_to_disk general exception')
|
if DEBUG:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return ''
|
return key
|
||||||
|
|
||||||
safe_formatter = SafeFormat()
|
safe_formatter = SafeFormat()
|
||||||
|
|
||||||
@ -182,8 +184,8 @@ def get_components(template, mi, id, timefmt='%b %Y', length=250,
|
|||||||
elif custom_metadata[key]['datatype'] == 'bool':
|
elif custom_metadata[key]['datatype'] == 'bool':
|
||||||
format_args[key] = _('yes') if format_args[key] else _('no')
|
format_args[key] = _('yes') if format_args[key] else _('no')
|
||||||
|
|
||||||
components = safe_formatter.safe_format(template, format_args, '', mi,
|
components = safe_formatter.safe_format(template, format_args,
|
||||||
sanitize=sanitize_func)
|
'G_C-EXCEPTION!', mi)
|
||||||
components = [x.strip() for x in components.split('/') if x.strip()]
|
components = [x.strip() for x in components.split('/') if x.strip()]
|
||||||
components = [sanitize_func(x) for x in components if x]
|
components = [sanitize_func(x) for x in components if x]
|
||||||
if not components:
|
if not components:
|
||||||
@ -267,7 +269,8 @@ def save_book_to_disk(id, db, root, opts, length):
|
|||||||
cpb = cpb[dev_name]
|
cpb = cpb[dev_name]
|
||||||
else:
|
else:
|
||||||
cpb = None
|
cpb = None
|
||||||
#prints('Using plugboard:', fmt, cpb)
|
if DEBUG:
|
||||||
|
prints('Save-to-disk using plugboard:', fmt, cpb)
|
||||||
data = db.format(id, fmt, index_is_id=True)
|
data = db.format(id, fmt, index_is_id=True)
|
||||||
if data is None:
|
if data is None:
|
||||||
continue
|
continue
|
||||||
@ -285,6 +288,7 @@ def save_book_to_disk(id, db, root, opts, length):
|
|||||||
newmi = mi
|
newmi = mi
|
||||||
set_metadata(stream, newmi, fmt)
|
set_metadata(stream, newmi, fmt)
|
||||||
except:
|
except:
|
||||||
|
if DEBUG:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
stream.seek(0)
|
stream.seek(0)
|
||||||
data = stream.read()
|
data = stream.read()
|
||||||
|
@ -165,7 +165,9 @@ For tags, the result cut apart whereever |app| finds a comma. For example, if th
|
|||||||
|
|
||||||
The same thing happens for authors, but using a different character for the cut, a `&` (ampersand) instead of a comma. For example, if the template produces the value ``Blogs, Joe&Posts, Susan``, then the book will end up with two authors, ``Blogs, Joe`` and ``Posts, Susan``. If the template produces the value ``Blogs, Joe;Posts, Susan``, then the book will have one author with a rather strange name.
|
The same thing happens for authors, but using a different character for the cut, a `&` (ampersand) instead of a comma. For example, if the template produces the value ``Blogs, Joe&Posts, Susan``, then the book will end up with two authors, ``Blogs, Joe`` and ``Posts, Susan``. If the template produces the value ``Blogs, Joe;Posts, Susan``, then the book will have one author with a rather strange name.
|
||||||
|
|
||||||
Plugboards affect only the metadata written into the book. They do not affect calibre's metadata or the metadata used in ``save to disk`` and ``send to device`` templates. Plugboards also do not affect what is written into a Sony's database, so cannot be used for altering the metadata shown on a Sony's menu.
|
Plugboards affect the metadata written into the book when it is saved to disk or written to the device. Plugboards do not affect the metadata used by ``save to disk`` and ``send to device`` to create the file names. Instead, file names are constructed using the templates entered on the appropriate preferences window.
|
||||||
|
|
||||||
|
Plugboards also do not affect the metadata that is written into a Sony's database, because this metadata does not come from the book. As such, you cannot use plugboards for altering the metadata shown on a Sony's menu.
|
||||||
|
|
||||||
Helpful Tips
|
Helpful Tips
|
||||||
------------
|
------------
|
||||||
|
@ -4,7 +4,9 @@ Created on 23 Sep 2010
|
|||||||
@author: charles
|
@author: charles
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import re, string
|
import re, string, traceback
|
||||||
|
|
||||||
|
from calibre.constants import DEBUG
|
||||||
|
|
||||||
class TemplateFormatter(string.Formatter):
|
class TemplateFormatter(string.Formatter):
|
||||||
'''
|
'''
|
||||||
@ -19,7 +21,6 @@ class TemplateFormatter(string.Formatter):
|
|||||||
string.Formatter.__init__(self)
|
string.Formatter.__init__(self)
|
||||||
self.book = None
|
self.book = None
|
||||||
self.kwargs = None
|
self.kwargs = None
|
||||||
self.sanitize = None
|
|
||||||
|
|
||||||
def _lookup(self, val, field_if_set, field_not_set):
|
def _lookup(self, val, field_if_set, field_not_set):
|
||||||
if val:
|
if val:
|
||||||
@ -99,7 +100,7 @@ class TemplateFormatter(string.Formatter):
|
|||||||
return fmt, '', ''
|
return fmt, '', ''
|
||||||
return matches.groups()
|
return matches.groups()
|
||||||
except:
|
except:
|
||||||
import traceback
|
if DEBUG:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return fmt, '', ''
|
return fmt, '', ''
|
||||||
|
|
||||||
@ -139,14 +140,15 @@ class TemplateFormatter(string.Formatter):
|
|||||||
ans = string.Formatter.vformat(self, fmt, args, kwargs)
|
ans = string.Formatter.vformat(self, fmt, args, kwargs)
|
||||||
return self.compress_spaces.sub(' ', ans).strip()
|
return self.compress_spaces.sub(' ', ans).strip()
|
||||||
|
|
||||||
def safe_format(self, fmt, kwargs, error_value, book, sanitize=None):
|
def safe_format(self, fmt, kwargs, error_value, book):
|
||||||
self.kwargs = kwargs
|
self.kwargs = kwargs
|
||||||
self.book = book
|
self.book = book
|
||||||
self.sanitize = sanitize
|
|
||||||
self.composite_values = {}
|
self.composite_values = {}
|
||||||
try:
|
try:
|
||||||
ans = self.vformat(fmt, [], kwargs).strip()
|
ans = self.vformat(fmt, [], kwargs).strip()
|
||||||
except:
|
except:
|
||||||
|
if DEBUG:
|
||||||
|
traceback.print_exc()
|
||||||
ans = error_value
|
ans = error_value
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user