From 5aa9fdb0e747e55a9a8668b947ec8c05a085ddf6 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 4 Oct 2008 21:02:11 -0700 Subject: [PATCH] Fix a couple of nasty regressions in EPUB output --- src/calibre/ebooks/epub/split.py | 2 +- src/calibre/ebooks/metadata/epub.py | 21 +++++++++++-- src/calibre/ebooks/metadata/opf2.py | 47 +++++++++++++++++++++-------- 3 files changed, 55 insertions(+), 15 deletions(-) diff --git a/src/calibre/ebooks/epub/split.py b/src/calibre/ebooks/epub/split.py index 30d3857941..1cdb97ec7c 100644 --- a/src/calibre/ebooks/epub/split.py +++ b/src/calibre/ebooks/epub/split.py @@ -391,7 +391,7 @@ def split(pathtoopf, opts, stylesheet_map): os.stat(content(f)).st_size > 5*opts.profile.flow_size))) except (SplitError, RuntimeError): if not always_remove: - changes.append(Splitter(f, opts, always_remove=True)) + changes.append(Splitter(f, opts, stylesheet_map, always_remove=True)) else: raise changes[-1].fix_opf(opf) diff --git a/src/calibre/ebooks/metadata/epub.py b/src/calibre/ebooks/metadata/epub.py index 6a1993d9f0..4346000289 100644 --- a/src/calibre/ebooks/metadata/epub.py +++ b/src/calibre/ebooks/metadata/epub.py @@ -111,6 +111,10 @@ def option_parser(): parser.remove_option('--category') parser.add_option('--tags', default=None, help=_('A comma separated list of tags to set')) + parser.add_option('--series', default=None, + help=_('The series to which this book belongs')) + parser.add_option('--series-index', default=None, + help=_('The series index')) return parser def main(args=sys.argv): @@ -121,18 +125,31 @@ def main(args=sys.argv): return 1 stream = open(args[1], 'r+b') mi = MetaInformation(OCFZipReader(stream, root=os.getcwdu()).opf) + changed = False if opts.title: mi.title = opts.title + changed = True if opts.authors: mi.authors = opts.authors.split(',') + changed = True if opts.tags: mi.tags = opts.tags.split(',') + changed = True if opts.comment: mi.comments = opts.comment + changed = True + if opts.series: + mi.series = opts.series + changed = True + if opts.series_index: + mi.series_index = opts.series_index + changed = True + if changed: + stream.seek(0) + set_metadata(stream, mi) stream.seek(0) - set_metadata(stream, mi) - print unicode(mi) + print unicode(MetaInformation(OCFZipReader(stream, root=os.getcwdu()).opf)) stream.close() return 0 diff --git a/src/calibre/ebooks/metadata/opf2.py b/src/calibre/ebooks/metadata/opf2.py index 18bcdde45f..8078660a28 100644 --- a/src/calibre/ebooks/metadata/opf2.py +++ b/src/calibre/ebooks/metadata/opf2.py @@ -362,12 +362,13 @@ class Guide(ResourceCollection): class MetadataField(object): - def __init__(self, name, is_dc=True, formatter=None): - self.name = name - self.is_dc = is_dc + def __init__(self, name, is_dc=True, formatter=None, none_is=None): + self.name = name + self.is_dc = is_dc self.formatter = formatter + self.none_is = none_is - def __get__(self, obj, type=None): + def __real_get__(self, obj, type=None): ans = obj.get_metadata_element(self.name) if ans is None: return None @@ -381,6 +382,12 @@ class MetadataField(object): return None return ans + def __get__(self, obj, type=None): + ans = self.__real_get__(obj, type) + if ans is None: + ans = self.none_is + return ans + def __set__(self, obj, val): elem = obj.get_metadata_element(self.name) if elem is None: @@ -393,9 +400,7 @@ class OPF(object): NAMESPACES = { None : "http://www.idpf.org/2007/opf", 'dc' : "http://purl.org/dc/elements/1.1/", - 'dc1' : 'http://purl.org/dc/elements/1.0/', 'opf' : "http://www.idpf.org/2007/opf", - 'oebpackage' : 'http://openebook.org/namespaces/oeb-package/1.0/', } xpn = NAMESPACES.copy() xpn.pop(None) @@ -406,6 +411,7 @@ class OPF(object): metadata_path = XPath('descendant::*[re:match(name(), "metadata", "i")]') metadata_elem_path = XPath('descendant::*[re:match(name(), $name, "i")]') + series_path = XPath('descendant::*[re:match(name(), "series(?!_)", "i")]') authors_path = XPath('descendant::*[re:match(name(), "creator", "i") and (@role="aut" or @opf:role="aut")]') bkp_path = XPath('descendant::*[re:match(name(), "contributor", "i") and (@role="bkp" or @opf:role="bkp")]') tags_path = XPath('descendant::*[re:match(name(), "subject", "i")]') @@ -420,8 +426,7 @@ class OPF(object): language = MetadataField('language') comments = MetadataField('description') category = MetadataField('category') - series = MetadataField('series', is_dc=False) - series_index = MetadataField('series_index', is_dc=False, formatter=int) + series_index = MetadataField('series_index', is_dc=False, formatter=int, none_is=1) rating = MetadataField('rating', is_dc=False, formatter=int) @@ -632,8 +637,26 @@ class OPF(object): matches = [self.create_metadata_element('identifier', ns='dc', attrib={'{%s}scheme'%self.NAMESPACES['opf']:'ISBN'})] matches[0].text = unicode(val) + return property(fget=fget, fset=fset) + @apply + def series(): + + def fget(self): + for match in self.series_path(self.metadata): + return match.text if match.text else None + + def fset(self, val): + matches = self.series_path(self.metadata) + if not matches: + matches = [self.create_metadata_element('series')] + matches[0].text = unicode(val) + + return property(fget=fget, fset=fset) + + + @apply def book_producer(): @@ -682,7 +705,6 @@ class OPF(object): return property(fget=fget, fset=fset) - def get_metadata_element(self, name): matches = self.metadata_elem_path(self.metadata, name=name) if matches: @@ -700,11 +722,12 @@ class OPF(object): def smart_update(self, mi): for attr in ('author_sort', 'title_sort', 'comments', 'category', 'publisher', 'series', 'series_index', 'rating', - 'isbn', 'language', 'tags'): + 'isbn', 'language', 'tags', 'title', 'authors'): val = getattr(mi, attr, None) - if val or val == []: + if val is not None and val != [] and val != (None, None): setattr(self, attr, val) - + + class OPFCreator(MetaInformation): def __init__(self, base_path, *args, **kwargs):