mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Merge branch 'master' of https://github.com/cbhaley/calibre
This commit is contained in:
commit
6a15163b1d
@ -184,6 +184,9 @@ class Cache(object):
|
|||||||
|
|
||||||
def _get_metadata(self, book_id, get_user_categories=True): # {{{
|
def _get_metadata(self, book_id, get_user_categories=True): # {{{
|
||||||
mi = Metadata(None, template_cache=self.formatter_template_cache)
|
mi = Metadata(None, template_cache=self.formatter_template_cache)
|
||||||
|
|
||||||
|
mi._proxy_metadata = ProxyMetadata(self, book_id, formatter=mi.formatter)
|
||||||
|
|
||||||
author_ids = self._field_ids_for('authors', book_id)
|
author_ids = self._field_ids_for('authors', book_id)
|
||||||
adata = self._author_data(author_ids)
|
adata = self._author_data(author_ids)
|
||||||
aut_list = [adata[i] for i in author_ids]
|
aut_list = [adata[i] for i in author_ids]
|
||||||
@ -211,8 +214,6 @@ class Cache(object):
|
|||||||
default_value='dummy')
|
default_value='dummy')
|
||||||
mi.title_sort = self._field_for('sort', book_id,
|
mi.title_sort = self._field_for('sort', book_id,
|
||||||
default_value=_('Unknown'))
|
default_value=_('Unknown'))
|
||||||
mi.book_size = self._field_for('size', book_id, default_value=0)
|
|
||||||
mi.ondevice_col = self._field_for('ondevice', book_id, default_value='')
|
|
||||||
mi.last_modified = self._field_for('last_modified', book_id,
|
mi.last_modified = self._field_for('last_modified', book_id,
|
||||||
default_value=n)
|
default_value=n)
|
||||||
formats = self._field_for('formats', book_id)
|
formats = self._field_for('formats', book_id)
|
||||||
@ -223,8 +224,14 @@ class Cache(object):
|
|||||||
else:
|
else:
|
||||||
mi.format_metadata = FormatMetadata(self, book_id, formats)
|
mi.format_metadata = FormatMetadata(self, book_id, formats)
|
||||||
good_formats = FormatsList(formats, mi.format_metadata)
|
good_formats = FormatsList(formats, mi.format_metadata)
|
||||||
|
# These three attributes are returned by the db2 get_metadata(),
|
||||||
|
# however, we dont actually use them anywhere other than templates, so
|
||||||
|
# they have been removed, to avoid unnecessary overhead. The templates
|
||||||
|
# all use _proxy_metadata.
|
||||||
|
# mi.book_size = self._field_for('size', book_id, default_value=0)
|
||||||
|
# mi.ondevice_col = self._field_for('ondevice', book_id, default_value='')
|
||||||
|
# mi.db_approx_formats = formats
|
||||||
mi.formats = good_formats
|
mi.formats = good_formats
|
||||||
mi.db_approx_formats = formats
|
|
||||||
mi.has_cover = _('Yes') if self._field_for('cover', book_id,
|
mi.has_cover = _('Yes') if self._field_for('cover', book_id,
|
||||||
default_value=False) else ''
|
default_value=False) else ''
|
||||||
mi.tags = list(self._field_for('tags', book_id, default_value=()))
|
mi.tags = list(self._field_for('tags', book_id, default_value=()))
|
||||||
@ -1410,6 +1417,7 @@ class Cache(object):
|
|||||||
def refresh_ondevice(self):
|
def refresh_ondevice(self):
|
||||||
self.fields['ondevice'].clear_caches()
|
self.fields['ondevice'].clear_caches()
|
||||||
self.clear_search_caches()
|
self.clear_search_caches()
|
||||||
|
self.clear_composite_caches()
|
||||||
|
|
||||||
@read_api
|
@read_api
|
||||||
def tags_older_than(self, tag, delta=None, must_have_tag=None, must_have_authors=None):
|
def tags_older_than(self, tag, delta=None, must_have_tag=None, must_have_authors=None):
|
||||||
|
@ -278,9 +278,9 @@ for field in ('formats', 'format_metadata'):
|
|||||||
|
|
||||||
class ProxyMetadata(Metadata):
|
class ProxyMetadata(Metadata):
|
||||||
|
|
||||||
def __init__(self, db, book_id):
|
def __init__(self, db, book_id, formatter=None):
|
||||||
sa(self, 'template_cache', db.formatter_template_cache)
|
sa(self, 'template_cache', db.formatter_template_cache)
|
||||||
sa(self, 'formatter', SafeFormat())
|
sa(self, 'formatter', SafeFormat() if formatter is None else formatter)
|
||||||
sa(self, '_db', weakref.ref(db))
|
sa(self, '_db', weakref.ref(db))
|
||||||
sa(self, '_book_id', book_id)
|
sa(self, '_book_id', book_id)
|
||||||
sa(self, '_cache', {'user_categories':{}, 'cover_data':(None,None), 'device_collections':[]})
|
sa(self, '_cache', {'user_categories':{}, 'cover_data':(None,None), 'device_collections':[]})
|
||||||
@ -354,4 +354,6 @@ class ProxyMetadata(Metadata):
|
|||||||
um = ga(self, '_user_metadata')
|
um = ga(self, '_user_metadata')
|
||||||
return frozenset(ALL_METADATA_FIELDS.union(um.iterkeys()))
|
return frozenset(ALL_METADATA_FIELDS.union(um.iterkeys()))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _proxy_metadata(self):
|
||||||
|
return self
|
||||||
|
@ -66,7 +66,8 @@ class Metadata(object):
|
|||||||
becomes a reserved field name.
|
becomes a reserved field name.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
def __init__(self, title, authors=(_('Unknown'),), other=None, template_cache=None):
|
def __init__(self, title, authors=(_('Unknown'),), other=None, template_cache=None,
|
||||||
|
formatter=None):
|
||||||
'''
|
'''
|
||||||
@param title: title or ``_('Unknown')``
|
@param title: title or ``_('Unknown')``
|
||||||
@param authors: List of strings or []
|
@param authors: List of strings or []
|
||||||
@ -85,7 +86,7 @@ class Metadata(object):
|
|||||||
self.author = list(authors) if authors else [] # Needed for backward compatibility
|
self.author = list(authors) if authors else [] # Needed for backward compatibility
|
||||||
self.authors = list(authors) if authors else []
|
self.authors = list(authors) if authors else []
|
||||||
from calibre.ebooks.metadata.book.formatter import SafeFormat
|
from calibre.ebooks.metadata.book.formatter import SafeFormat
|
||||||
self.formatter = SafeFormat()
|
self.formatter = SafeFormat() if formatter is None else formatter
|
||||||
self.template_cache = template_cache
|
self.template_cache = template_cache
|
||||||
|
|
||||||
def is_null(self, field):
|
def is_null(self, field):
|
||||||
|
@ -453,7 +453,7 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
|
|
||||||
def get_book_display_info(self, idx):
|
def get_book_display_info(self, idx):
|
||||||
mi = self.db.get_metadata(idx)
|
mi = self.db.get_metadata(idx)
|
||||||
mi.size = mi.book_size
|
mi.size = mi._proxy_metadata.book_size
|
||||||
mi.cover_data = ('jpg', self.cover(idx))
|
mi.cover_data = ('jpg', self.cover(idx))
|
||||||
mi.id = self.db.id(idx)
|
mi.id = self.db.id(idx)
|
||||||
mi.field_metadata = self.db.field_metadata
|
mi.field_metadata = self.db.field_metadata
|
||||||
|
@ -8,7 +8,7 @@ The database used to store ebook metadata
|
|||||||
'''
|
'''
|
||||||
import os, sys, shutil, cStringIO, glob, time, functools, traceback, re, \
|
import os, sys, shutil, cStringIO, glob, time, functools, traceback, re, \
|
||||||
json, uuid, hashlib, copy, types
|
json, uuid, hashlib, copy, types
|
||||||
from collections import defaultdict
|
from collections import defaultdict, namedtuple
|
||||||
import threading, random
|
import threading, random
|
||||||
from itertools import repeat
|
from itertools import repeat
|
||||||
|
|
||||||
@ -52,6 +52,8 @@ from calibre.utils.localization import (canonicalize_lang,
|
|||||||
copyfile = os.link if hasattr(os, 'link') else shutil.copyfile
|
copyfile = os.link if hasattr(os, 'link') else shutil.copyfile
|
||||||
SPOOL_SIZE = 30*1024*1024
|
SPOOL_SIZE = 30*1024*1024
|
||||||
|
|
||||||
|
ProxyMetadata = namedtuple('ProxyMetadata', 'book_size ondevice_col db_approx_formats')
|
||||||
|
|
||||||
class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||||
'''
|
'''
|
||||||
An ebook metadata database that stores references to ebook files on disk.
|
An ebook metadata database that stores references to ebook files on disk.
|
||||||
@ -1009,8 +1011,6 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
mi.pubdate = row[fm['pubdate']]
|
mi.pubdate = row[fm['pubdate']]
|
||||||
mi.uuid = row[fm['uuid']]
|
mi.uuid = row[fm['uuid']]
|
||||||
mi.title_sort = row[fm['sort']]
|
mi.title_sort = row[fm['sort']]
|
||||||
mi.book_size = row[fm['size']]
|
|
||||||
mi.ondevice_col= row[fm['ondevice']]
|
|
||||||
mi.last_modified = row[fm['last_modified']]
|
mi.last_modified = row[fm['last_modified']]
|
||||||
formats = row[fm['formats']]
|
formats = row[fm['formats']]
|
||||||
mi.format_metadata = {}
|
mi.format_metadata = {}
|
||||||
@ -1022,6 +1022,9 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
good_formats = FormatsList(formats, mi.format_metadata)
|
good_formats = FormatsList(formats, mi.format_metadata)
|
||||||
mi.formats = good_formats
|
mi.formats = good_formats
|
||||||
mi.db_approx_formats = formats
|
mi.db_approx_formats = formats
|
||||||
|
mi._proxy_metadata = p = ProxyMetadata(row[fm['size']], row[fm['ondevice']], formats)
|
||||||
|
mi.book_size = p.book_size
|
||||||
|
mi.ondevice_col= p.ondevice_col
|
||||||
tags = row[fm['tags']]
|
tags = row[fm['tags']]
|
||||||
if tags:
|
if tags:
|
||||||
mi.tags = [i.strip() for i in tags.split(',')]
|
mi.tags = [i.strip() for i in tags.split(',')]
|
||||||
|
@ -640,15 +640,22 @@ class BuiltinApproximateFormats(BuiltinFormatterFunction):
|
|||||||
'although it probably is. '
|
'although it probably is. '
|
||||||
'This function can be called in template program mode using '
|
'This function can be called in template program mode using '
|
||||||
'the template "{:\'approximate_formats()\'}". '
|
'the template "{:\'approximate_formats()\'}". '
|
||||||
'Note that format names are always uppercase, as in EPUB.'
|
'Note that format names are always uppercase, as in EPUB. '
|
||||||
|
'This function works only in the GUI. If you want to use these values '
|
||||||
|
'in save-to-disk or send-to-device templates then you '
|
||||||
|
'must make a custom "Column built from other columns", use '
|
||||||
|
'the function in that column\'s template, and use that '
|
||||||
|
'column\'s value in your save/send templates'
|
||||||
)
|
)
|
||||||
|
|
||||||
def evaluate(self, formatter, kwargs, mi, locals):
|
def evaluate(self, formatter, kwargs, mi, locals):
|
||||||
fmt_data = mi.get('db_approx_formats', [])
|
if hasattr(mi, '_proxy_metadata'):
|
||||||
if not fmt_data:
|
fmt_data = mi._proxy_metadata.db_approx_formats
|
||||||
return ''
|
if not fmt_data:
|
||||||
data = sorted(fmt_data)
|
return ''
|
||||||
return ','.join(v.upper() for v in data)
|
data = sorted(fmt_data)
|
||||||
|
return ','.join(v.upper() for v in data)
|
||||||
|
return _('This function can be used only in the GUI')
|
||||||
|
|
||||||
class BuiltinFormatsModtimes(BuiltinFormatterFunction):
|
class BuiltinFormatsModtimes(BuiltinFormatterFunction):
|
||||||
name = 'formats_modtimes'
|
name = 'formats_modtimes'
|
||||||
@ -902,27 +909,42 @@ class BuiltinBooksize(BuiltinFormatterFunction):
|
|||||||
name = 'booksize'
|
name = 'booksize'
|
||||||
arg_count = 0
|
arg_count = 0
|
||||||
category = 'Get values from metadata'
|
category = 'Get values from metadata'
|
||||||
__doc__ = doc = _('booksize() -- return value of the size field')
|
__doc__ = doc = _('booksize() -- return value of the size field. '
|
||||||
|
'This function works only in the GUI. If you want to use this value '
|
||||||
|
'in save-to-disk or send-to-device templates then you '
|
||||||
|
'must make a custom "Column built from other columns", use '
|
||||||
|
'the function in that column\'s template, and use that '
|
||||||
|
'column\'s value in your save/send templates')
|
||||||
|
|
||||||
def evaluate(self, formatter, kwargs, mi, locals):
|
def evaluate(self, formatter, kwargs, mi, locals):
|
||||||
if mi.book_size is not None:
|
if hasattr(mi, '_proxy_metadata'):
|
||||||
try:
|
try:
|
||||||
return str(mi.book_size)
|
v = mi._proxy_metadata.book_size
|
||||||
|
if v is not None:
|
||||||
|
return str(mi._proxy_metadata.book_size)
|
||||||
|
return ''
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
return ''
|
return ''
|
||||||
|
return _('This function can be used only in the GUI')
|
||||||
|
|
||||||
class BuiltinOndevice(BuiltinFormatterFunction):
|
class BuiltinOndevice(BuiltinFormatterFunction):
|
||||||
name = 'ondevice'
|
name = 'ondevice'
|
||||||
arg_count = 0
|
arg_count = 0
|
||||||
category = 'Get values from metadata'
|
category = 'Get values from metadata'
|
||||||
__doc__ = doc = _('ondevice() -- return Yes if ondevice is set, otherwise return '
|
__doc__ = doc = _('ondevice() -- return Yes if ondevice is set, otherwise return '
|
||||||
'the empty string')
|
'the empty string. This function works only in the GUI. If you want to '
|
||||||
|
'use this value in save-to-disk or send-to-device templates then you '
|
||||||
|
'must make a custom "Column built from other columns", use '
|
||||||
|
'the function in that column\'s template, and use that '
|
||||||
|
'column\'s value in your save/send templates')
|
||||||
|
|
||||||
def evaluate(self, formatter, kwargs, mi, locals):
|
def evaluate(self, formatter, kwargs, mi, locals):
|
||||||
if mi.ondevice_col:
|
if hasattr(mi, '_proxy_metadata'):
|
||||||
return _('Yes')
|
if mi._proxy_metadata.ondevice_col:
|
||||||
return ''
|
return _('Yes')
|
||||||
|
return ''
|
||||||
|
return _('This function can be used only in the GUI')
|
||||||
|
|
||||||
class BuiltinSeriesSort(BuiltinFormatterFunction):
|
class BuiltinSeriesSort(BuiltinFormatterFunction):
|
||||||
name = 'series_sort'
|
name = 'series_sort'
|
||||||
@ -1246,6 +1268,23 @@ class BuiltinFinishFormatting(BuiltinFormatterFunction):
|
|||||||
return val
|
return val
|
||||||
return prefix + formatter._do_format(val, fmt) + suffix
|
return prefix + formatter._do_format(val, fmt) + suffix
|
||||||
|
|
||||||
|
class BuiltinVirtualLibraries(BuiltinFormatterFunction):
|
||||||
|
name = 'virtual_libraries'
|
||||||
|
arg_count = 0
|
||||||
|
category = 'Get values from metadata'
|
||||||
|
__doc__ = doc = _('virtual_libraries() -- return a comma-separated list of '
|
||||||
|
'virtual libraries that contain this book. This function '
|
||||||
|
'works only in the GUI. If you want to use these values '
|
||||||
|
'in save-to-disk or send-to-device templates then you '
|
||||||
|
'must make a custom "Column built from other columns", use '
|
||||||
|
'the function in that column\'s template, and use that '
|
||||||
|
'column\'s value in your save/send templates')
|
||||||
|
|
||||||
|
def evaluate(self, formatter, kwargs, mi, locals_):
|
||||||
|
if hasattr(mi, '_proxy_metadata'):
|
||||||
|
return mi._proxy_metadata.virtual_libraries
|
||||||
|
return _('This function can be used only in the GUI')
|
||||||
|
|
||||||
_formatter_builtins = [
|
_formatter_builtins = [
|
||||||
BuiltinAdd(), BuiltinAnd(), BuiltinApproximateFormats(),
|
BuiltinAdd(), BuiltinAnd(), BuiltinApproximateFormats(),
|
||||||
BuiltinAssign(), BuiltinBooksize(),
|
BuiltinAssign(), BuiltinBooksize(),
|
||||||
@ -1267,7 +1306,7 @@ _formatter_builtins = [
|
|||||||
BuiltinStrcmp(), BuiltinStrInList(), BuiltinStrlen(), BuiltinSubitems(),
|
BuiltinStrcmp(), BuiltinStrInList(), BuiltinStrlen(), BuiltinSubitems(),
|
||||||
BuiltinSublist(),BuiltinSubstr(), BuiltinSubtract(), BuiltinSwapAroundComma(),
|
BuiltinSublist(),BuiltinSubstr(), BuiltinSubtract(), BuiltinSwapAroundComma(),
|
||||||
BuiltinSwitch(), BuiltinTemplate(), BuiltinTest(), BuiltinTitlecase(),
|
BuiltinSwitch(), BuiltinTemplate(), BuiltinTest(), BuiltinTitlecase(),
|
||||||
BuiltinToday(), BuiltinUppercase(),
|
BuiltinToday(), BuiltinUppercase(), BuiltinVirtualLibraries()
|
||||||
]
|
]
|
||||||
|
|
||||||
class FormatterUserFunction(FormatterFunction):
|
class FormatterUserFunction(FormatterFunction):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user