mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
...
This commit is contained in:
commit
e65d2f24bb
@ -12,7 +12,6 @@ from calibre.devices.interface import BookList as _BookList
|
||||
from calibre.constants import preferred_encoding
|
||||
from calibre import isbytestring
|
||||
from calibre.utils.config import prefs, tweaks
|
||||
from calibre.utils.date import format_date
|
||||
|
||||
class Book(Metadata):
|
||||
def __init__(self, prefix, lpath, size=None, other=None):
|
||||
@ -105,21 +104,7 @@ class CollectionsBookList(BookList):
|
||||
attr_name = ''
|
||||
elif attr_name != '':
|
||||
attr_name = '(%s)'%attr_name
|
||||
|
||||
if attr not in cust_field_meta:
|
||||
cat_name = '%s %s'%(category, attr_name)
|
||||
else:
|
||||
fm = cust_field_meta[attr]
|
||||
if fm['datatype'] == 'bool':
|
||||
if category:
|
||||
cat_name = '%s %s'%(_('Yes'), attr_name)
|
||||
else:
|
||||
cat_name = '%s %s'%(_('No'), attr_name)
|
||||
elif fm['datatype'] == 'datetime':
|
||||
cat_name = '%s %s'%(format_date(category,
|
||||
fm['display'].get('date_format','dd MMM yyyy')), attr_name)
|
||||
else:
|
||||
cat_name = '%s %s'%(category, attr_name)
|
||||
cat_name = '%s %s'%(category, attr_name)
|
||||
return cat_name.strip()
|
||||
|
||||
def get_collections(self, collection_attributes):
|
||||
@ -156,7 +141,7 @@ class CollectionsBookList(BookList):
|
||||
cust_field_meta = book.get_all_user_metadata(make_copy=False)
|
||||
for attr in attrs:
|
||||
attr = attr.strip()
|
||||
val = meta_vals.get(attr, None)
|
||||
ign, val = book.format_field(attr, ignore_series_index=True)
|
||||
if not val: continue
|
||||
if isbytestring(val):
|
||||
val = val.decode(preferred_encoding, 'replace')
|
||||
|
@ -101,16 +101,23 @@ STANDARD_METADATA_FIELDS = SOCIAL_METADATA_FIELDS.union(
|
||||
DEVICE_METADATA_FIELDS).union(
|
||||
CALIBRE_METADATA_FIELDS)
|
||||
|
||||
# Metadata fields that smart update must do special processing to copy.
|
||||
|
||||
SC_FIELDS_NOT_COPIED = frozenset(['title', 'title_sort', 'authors',
|
||||
'author_sort', 'author_sort_map',
|
||||
'cover_data', 'tags', 'language'])
|
||||
|
||||
# Metadata fields that smart update should copy only if the source is not None
|
||||
SC_FIELDS_COPY_NOT_NULL = frozenset(['lpath', 'size', 'comments', 'thumbnail'])
|
||||
|
||||
# Metadata fields that smart update should copy without special handling
|
||||
COPYABLE_METADATA_FIELDS = SOCIAL_METADATA_FIELDS.union(
|
||||
SC_COPYABLE_FIELDS = SOCIAL_METADATA_FIELDS.union(
|
||||
PUBLICATION_METADATA_FIELDS).union(
|
||||
BOOK_STRUCTURE_FIELDS).union(
|
||||
DEVICE_METADATA_FIELDS).union(
|
||||
CALIBRE_METADATA_FIELDS) - \
|
||||
frozenset(['title', 'title_sort', 'authors',
|
||||
'author_sort', 'author_sort_map' 'comments',
|
||||
'cover_data', 'tags', 'language', 'lpath',
|
||||
'size', 'thumbnail'])
|
||||
SC_FIELDS_NOT_COPIED.union(
|
||||
SC_FIELDS_COPY_NOT_NULL)
|
||||
|
||||
SERIALIZABLE_FIELDS = SOCIAL_METADATA_FIELDS.union(
|
||||
USER_METADATA_FIELDS).union(
|
||||
|
@ -9,9 +9,11 @@ import copy
|
||||
import traceback
|
||||
|
||||
from calibre import prints
|
||||
from calibre.ebooks.metadata.book import COPYABLE_METADATA_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 STANDARD_METADATA_FIELDS
|
||||
from calibre.ebooks.metadata.book import TOP_LEVEL_CLASSIFIERS
|
||||
from calibre.library.field_metadata import FieldMetadata
|
||||
from calibre.utils.date import isoformat, format_date
|
||||
|
||||
|
||||
@ -29,6 +31,8 @@ NULL_VALUES = {
|
||||
'language' : 'und'
|
||||
}
|
||||
|
||||
field_metadata = FieldMetadata()
|
||||
|
||||
class Metadata(object):
|
||||
|
||||
'''
|
||||
@ -111,6 +115,31 @@ class Metadata(object):
|
||||
_data = object.__getattribute__(self, '_data')
|
||||
return frozenset(_data['user_metadata'].iterkeys())
|
||||
|
||||
def get_standard_metadata(self, field, make_copy):
|
||||
'''
|
||||
return field metadata from the field if it is there. Otherwise return
|
||||
None. field is the key name, not the label. Return a copy if requested,
|
||||
just in case the user wants to change values in the dict.
|
||||
'''
|
||||
if field in field_metadata and field_metadata[field]['kind'] == 'field':
|
||||
if make_copy:
|
||||
return copy.deepcopy(field_metadata[field])
|
||||
return field_metadata[field]
|
||||
return None
|
||||
|
||||
def get_all_standard_metadata(self, make_copy):
|
||||
'''
|
||||
return a dict containing all the standard field metadata associated with
|
||||
the book.
|
||||
'''
|
||||
if not make_copy:
|
||||
return field_metadata
|
||||
res = {}
|
||||
for k in field_metadata:
|
||||
if field_metadata[k]['kind'] == 'field':
|
||||
res[k] = copy.deepcopy(field_metadata[k])
|
||||
return res
|
||||
|
||||
def get_all_user_metadata(self, make_copy):
|
||||
'''
|
||||
return a dict containing all the custom field metadata associated with
|
||||
@ -223,22 +252,23 @@ class Metadata(object):
|
||||
self.author_sort = other.author_sort
|
||||
|
||||
if replace_metadata:
|
||||
SPECIAL_FIELDS = frozenset(['lpath', 'size', 'comments', 'thumbnail'])
|
||||
for attr in COPYABLE_METADATA_FIELDS:
|
||||
# SPECIAL_FIELDS = frozenset(['lpath', 'size', 'comments', 'thumbnail'])
|
||||
for attr in SC_COPYABLE_FIELDS:
|
||||
setattr(self, attr, getattr(other, attr, 1.0 if \
|
||||
attr == 'series_index' else None))
|
||||
self.tags = other.tags
|
||||
self.cover_data = getattr(other, 'cover_data',
|
||||
NULL_VALUES['cover_data'])
|
||||
NULL_VALUES['cover_data'])
|
||||
self.set_all_user_metadata(other.get_all_user_metadata(make_copy=True))
|
||||
for x in SPECIAL_FIELDS:
|
||||
for x in SC_FIELDS_COPY_NOT_NULL:
|
||||
copy_not_none(self, other, x)
|
||||
# language is handled below
|
||||
else:
|
||||
for attr in COPYABLE_METADATA_FIELDS:
|
||||
if hasattr(other, attr):
|
||||
copy_not_none(self, other, attr)
|
||||
copy_not_none(self, other, 'thumbnail')
|
||||
for attr in SC_COPYABLE_FIELDS:
|
||||
copy_not_none(self, other, attr)
|
||||
for x in SC_FIELDS_COPY_NOT_NULL:
|
||||
copy_not_none(self, other, x)
|
||||
|
||||
if other.tags:
|
||||
# Case-insensitive but case preserving merging
|
||||
lotags = [t.lower() for t in other.tags]
|
||||
@ -249,6 +279,7 @@ class Metadata(object):
|
||||
oidx = lotags.index(t)
|
||||
self.tags[sidx] = other.tags[oidx]
|
||||
self.tags += [t for t in other.tags if t.lower() in ot-st]
|
||||
|
||||
if getattr(other, 'cover_data', False):
|
||||
other_cover = other.cover_data[-1]
|
||||
self_cover = self.cover_data[-1] if self.cover_data else ''
|
||||
@ -256,6 +287,7 @@ class Metadata(object):
|
||||
if not other_cover: other_cover = ''
|
||||
if len(other_cover) > len(self_cover):
|
||||
self.cover_data = other.cover_data
|
||||
|
||||
if getattr(other, 'user_metadata_keys', None):
|
||||
for x in other.user_metadata_keys:
|
||||
meta = other.get_user_metadata(x, make_copy=True)
|
||||
@ -274,6 +306,7 @@ class Metadata(object):
|
||||
self_tags[sidx] = other.tags[oidx]
|
||||
self_tags += [t for t in other.tags if t.lower() in ot-st]
|
||||
setattr(self, x, self_tags)
|
||||
|
||||
my_comments = getattr(self, 'comments', '')
|
||||
other_comments = getattr(other, 'comments', '')
|
||||
if not my_comments:
|
||||
@ -310,24 +343,49 @@ class Metadata(object):
|
||||
def format_rating(self):
|
||||
return unicode(self.rating)
|
||||
|
||||
def format_custom_field(self, key):
|
||||
def format_field(self, key, ignore_series_index=False):
|
||||
from calibre.ebooks.metadata import authors_to_string
|
||||
'''
|
||||
returns the tuple (field_name, formatted_value)
|
||||
'''
|
||||
cmeta = self.get_user_metadata(key, make_copy=False)
|
||||
name = unicode(cmeta['name'])
|
||||
res = self.get(key, None)
|
||||
if res is not None:
|
||||
if key in self.user_metadata_keys:
|
||||
res = self.get(key, None)
|
||||
if res is None or res == '':
|
||||
return (None, None)
|
||||
cmeta = self.get_user_metadata(key, make_copy=False)
|
||||
name = unicode(cmeta['name'])
|
||||
datatype = cmeta['datatype']
|
||||
if datatype == 'text' and cmeta['is_multiple']:
|
||||
res = u', '.join(res)
|
||||
elif datatype == 'series':
|
||||
res = res + ' [%s]'%self.format_series_index(val=self.get_extra(key))
|
||||
if not ignore_series_index:
|
||||
res = res + \
|
||||
' [%s]'%self.format_series_index(val=self.get_extra(key))
|
||||
elif datatype == 'datetime':
|
||||
res = format_date(res, cmeta['display'].get('date_format','dd MMM yyyy'))
|
||||
elif datatype == 'bool':
|
||||
res = _('Yes') if res else _('No')
|
||||
return (name, unicode(res))
|
||||
return (name, unicode(res))
|
||||
|
||||
if key in field_metadata and field_metadata[key]['kind'] == 'field':
|
||||
res = self.get(key, None)
|
||||
if res is None or res == '':
|
||||
return (None, None)
|
||||
fmeta = field_metadata[key]
|
||||
name = unicode(fmeta['name'])
|
||||
datatype = fmeta['datatype']
|
||||
if key == 'authors':
|
||||
res = authors_to_string(res)
|
||||
elif datatype == 'text' and fmeta['is_multiple']:
|
||||
res = u', '.join(res)
|
||||
elif datatype == 'series':
|
||||
if not ignore_series_index:
|
||||
res = res + ' [%s]'%self.format_series_index()
|
||||
elif datatype == 'datetime':
|
||||
res = format_date(res, fmeta['display'].get('date_format','dd MMM yyyy'))
|
||||
return (name, unicode(res))
|
||||
|
||||
return (None, None)
|
||||
|
||||
def __unicode__(self):
|
||||
from calibre.ebooks.metadata import authors_to_string
|
||||
@ -366,7 +424,7 @@ class Metadata(object):
|
||||
for key in self.user_metadata_keys:
|
||||
val = self.get(key, None)
|
||||
if val is not None:
|
||||
(name, val) = self.format_custom_field(key)
|
||||
(name, val) = self.format_field(key)
|
||||
fmt(name, unicode(val))
|
||||
return u'\n'.join(ans)
|
||||
|
||||
@ -391,7 +449,7 @@ class Metadata(object):
|
||||
for key in self.user_metadata_keys:
|
||||
val = self.get(key, None)
|
||||
if val is not None:
|
||||
(name, val) = self.format_custom_field(key)
|
||||
(name, val) = self.format_field(key)
|
||||
ans += [(name, val)]
|
||||
for i, x in enumerate(ans):
|
||||
ans[i] = u'<tr><td><b>%s</b></td><td>%s</td></tr>'%x
|
||||
|
@ -320,7 +320,7 @@ class BooksModel(QAbstractTableModel): # {{{
|
||||
(sidx, prepare_string_for_xml(series))
|
||||
mi = self.db.get_metadata(idx)
|
||||
for key in mi.user_metadata_keys:
|
||||
name, val = mi.format_custom_field(key)
|
||||
name, val = mi.format_field(key)
|
||||
if val is not None:
|
||||
data[name] = val
|
||||
return data
|
||||
|
@ -5,6 +5,7 @@ Created on 25 May 2010
|
||||
'''
|
||||
|
||||
from calibre.utils.ordered_dict import OrderedDict
|
||||
from calibre.utils.config import tweaks
|
||||
|
||||
class TagsIcons(dict):
|
||||
'''
|
||||
@ -213,7 +214,7 @@ class FieldMetadata(dict):
|
||||
'datatype':'text',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
'name':None,
|
||||
'name':_('On Device'),
|
||||
'search_terms':['ondevice'],
|
||||
'is_custom':False,
|
||||
'is_category':False}),
|
||||
@ -231,7 +232,7 @@ class FieldMetadata(dict):
|
||||
'datatype':'datetime',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
'name':None,
|
||||
'name':_('Published'),
|
||||
'search_terms':['pubdate'],
|
||||
'is_custom':False,
|
||||
'is_category':False}),
|
||||
@ -258,7 +259,7 @@ class FieldMetadata(dict):
|
||||
'datatype':'float',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
'name':None,
|
||||
'name':_('Size (MB)'),
|
||||
'search_terms':['size'],
|
||||
'is_custom':False,
|
||||
'is_category':False}),
|
||||
@ -267,7 +268,7 @@ class FieldMetadata(dict):
|
||||
'datatype':'datetime',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
'name':None,
|
||||
'name':_('Date'),
|
||||
'search_terms':['date'],
|
||||
'is_custom':False,
|
||||
'is_category':False}),
|
||||
@ -276,7 +277,7 @@ class FieldMetadata(dict):
|
||||
'datatype':'text',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
'name':None,
|
||||
'name':_('Title'),
|
||||
'search_terms':['title'],
|
||||
'is_custom':False,
|
||||
'is_category':False}),
|
||||
@ -310,6 +311,10 @@ class FieldMetadata(dict):
|
||||
self._tb_cats[k]['display'] = {}
|
||||
self._tb_cats[k]['is_editable'] = True
|
||||
self._add_search_terms_to_map(k, v['search_terms'])
|
||||
self._tb_cats['timestamp']['display'] = {
|
||||
'date_format': tweaks['gui_timestamp_display_format']}
|
||||
self._tb_cats['pubdate']['display'] = {
|
||||
'date_format': tweaks['gui_pubdate_display_format']}
|
||||
self.custom_field_prefix = '#'
|
||||
self.get = self._tb_cats.get
|
||||
|
||||
@ -410,7 +415,7 @@ class FieldMetadata(dict):
|
||||
if datatype == 'series':
|
||||
key += '_index'
|
||||
self._tb_cats[key] = {'table':None, 'column':None,
|
||||
'datatype':'float', 'is_multiple':False,
|
||||
'datatype':'float', 'is_multiple':None,
|
||||
'kind':'field', 'name':'',
|
||||
'search_terms':[key], 'label':label+'_index',
|
||||
'colnum':None, 'display':{},
|
||||
|
Loading…
x
Reference in New Issue
Block a user