From 1746aeafe00750113dbce50682010457ad15041e Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 10 Feb 2009 13:01:17 -0800 Subject: [PATCH] When saving to disk, also save the date. When importing from disk (ebook per directory), if an OPF file is present, use that to read metadata, including date. Adds new dependency on python-dateutil. Rewrite the Add books code for greateer speed and also fix the bug causing the Add books progress dialog to sometimes not close on windows. --- installer/linux/freeze.py | 3 ++- installer/osx/freeze.py | 1 + installer/windows/freeze.py | 3 ++- src/calibre/ebooks/metadata/__init__.py | 14 +++++++++----- src/calibre/ebooks/metadata/meta.py | 10 ++++++++-- src/calibre/ebooks/metadata/opf.xml | 2 +- src/calibre/ebooks/metadata/opf2.py | 2 ++ src/calibre/library/database2.py | 22 +++++++++++++++------- src/calibre/trac/plugins/download.py | 1 + 9 files changed, 41 insertions(+), 17 deletions(-) diff --git a/installer/linux/freeze.py b/installer/linux/freeze.py index c381041675..a6151c4931 100644 --- a/installer/linux/freeze.py +++ b/installer/linux/freeze.py @@ -81,7 +81,8 @@ def freeze(): 'PyQt4.QtScript.so', 'PyQt4.QtSql.so', 'PyQt4.QtTest.so', 'qt', 'glib', 'gobject'] - packages = ['calibre', 'encodings', 'cherrypy', 'cssutils', 'xdg'] + packages = ['calibre', 'encodings', 'cherrypy', 'cssutils', 'xdg', + 'dateutil'] includes += ['calibre.web.feeds.recipes.'+r for r in recipe_modules] diff --git a/installer/osx/freeze.py b/installer/osx/freeze.py index 3ec24d3aba..dbaad72748 100644 --- a/installer/osx/freeze.py +++ b/installer/osx/freeze.py @@ -342,6 +342,7 @@ def main(): 'calibre.ebooks.lrf.any.*', 'calibre.ebooks.lrf.feeds.*', 'keyword', 'codeop', 'pydoc', 'readline', 'BeautifulSoup', 'calibre.ebooks.lrf.fonts.prs500.*', + 'dateutil', ], 'packages' : ['PIL', 'Authorization', 'lxml'], 'excludes' : ['IPython'], diff --git a/installer/windows/freeze.py b/installer/windows/freeze.py index ab58fb669d..56486f6bd5 100644 --- a/installer/windows/freeze.py +++ b/installer/windows/freeze.py @@ -179,7 +179,8 @@ def main(args=sys.argv): 'calibre.ebooks.lrf.fonts.prs500.*', 'PyQt4.QtWebKit', 'PyQt4.QtNetwork', ], - 'packages' : ['PIL', 'lxml', 'cherrypy'], + 'packages' : ['PIL', 'lxml', 'cherrypy', + 'dateutil'], 'excludes' : ["Tkconstants", "Tkinter", "tcl", "_imagingtk", "ImageTk", "FixTk" ], diff --git a/src/calibre/ebooks/metadata/__init__.py b/src/calibre/ebooks/metadata/__init__.py index eabd082142..d9b0514362 100644 --- a/src/calibre/ebooks/metadata/__init__.py +++ b/src/calibre/ebooks/metadata/__init__.py @@ -192,7 +192,8 @@ class MetaInformation(object): for attr in ('author_sort', 'title_sort', 'comments', 'category', 'publisher', 'series', 'series_index', 'rating', 'isbn', 'tags', 'cover_data', 'application_id', 'guide', - 'manifest', 'spine', 'toc', 'cover', 'language', 'book_producer'): + 'manifest', 'spine', 'toc', 'cover', 'language', + 'book_producer', 'timestamp'): if hasattr(mi, attr): setattr(ans, attr, getattr(mi, attr)) @@ -217,7 +218,7 @@ class MetaInformation(object): for x in ('author_sort', 'title_sort', 'comments', 'category', 'publisher', 'series', 'series_index', 'rating', 'isbn', 'language', 'application_id', 'manifest', 'toc', 'spine', 'guide', 'cover', - 'book_producer', + 'book_producer', 'timestamp' ): setattr(self, x, getattr(mi, x, None)) @@ -235,7 +236,8 @@ class MetaInformation(object): for attr in ('author_sort', 'title_sort', 'comments', 'category', 'publisher', 'series', 'series_index', 'rating', 'isbn', 'application_id', 'manifest', 'spine', 'toc', - 'cover', 'language', 'guide', 'book_producer'): + 'cover', 'language', 'guide', 'book_producer', + 'timestamp'): if hasattr(mi, attr): val = getattr(mi, attr) if val is not None: @@ -276,6 +278,8 @@ class MetaInformation(object): ans += u'Series : '+unicode(self.series) + ' #%s\n'%self.format_series_index() if self.language: ans += u'Language : ' + unicode(self.language) + u'\n' + if self.timestamp is not None: + ans += u'Timestamp : ' + self.timestamp.isoformat(' ') return ans.strip() def to_html(self): @@ -289,12 +293,12 @@ class MetaInformation(object): if self.series: ans += [(_('Series'), unicode(self.series)+ ' #%s'%self.format_series_index())] ans += [(_('Language'), unicode(self.language))] + if self.timestamp is not None: + ans += [(_('Timestamp'), unicode(self.timestamp.isoformat(' ')))] for i, x in enumerate(ans): ans[i] = u'%s%s'%x return u'%s
'%u'\n'.join(ans) - - def __str__(self): return self.__unicode__().encode('utf-8') diff --git a/src/calibre/ebooks/metadata/meta.py b/src/calibre/ebooks/metadata/meta.py index d8116b33d3..1241238f26 100644 --- a/src/calibre/ebooks/metadata/meta.py +++ b/src/calibre/ebooks/metadata/meta.py @@ -31,8 +31,14 @@ def metadata_from_formats(formats): mi = MetaInformation(None, None) formats.sort(cmp=lambda x,y: cmp(METADATA_PRIORITIES[path_to_ext(x)], METADATA_PRIORITIES[path_to_ext(y)])) - for path in formats: - ext = path_to_ext(path) + extensions = list(map(path_to_ext, formats)) + if 'opf' in extensions: + opf = formats[extensions.index('opf')] + mi2 = opf_metadata(opf) + if mi2 is not None and mi2.title: + return mi2 + + for path, ext in zip(formats, extensions): stream = open(path, 'rb') try: mi.smart_update(get_metadata(stream, stream_type=ext, use_libprs_metadata=True)) diff --git a/src/calibre/ebooks/metadata/opf.xml b/src/calibre/ebooks/metadata/opf.xml index 94a8f63b3c..9dab4efbf4 100644 --- a/src/calibre/ebooks/metadata/opf.xml +++ b/src/calibre/ebooks/metadata/opf.xml @@ -10,7 +10,7 @@ ${author} ${'%s (%s)'%(__appname__, __version__)} [http://${__appname__}.kovidgoyal.net] ${mi.application_id} - + ${mi.timestamp.isoformat()} ${mi.language if mi.language else 'UND'} ${mi.category} ${mi.comments} diff --git a/src/calibre/ebooks/metadata/opf2.py b/src/calibre/ebooks/metadata/opf2.py index 32ba2cb45a..2e3b5ff047 100644 --- a/src/calibre/ebooks/metadata/opf2.py +++ b/src/calibre/ebooks/metadata/opf2.py @@ -12,6 +12,7 @@ from urllib import unquote from urlparse import urlparse from lxml import etree +from dateutil import parser from calibre.ebooks.chardet import xml_to_unicode from calibre import relpath @@ -436,6 +437,7 @@ class OPF(object): series = MetadataField('series', is_dc=False) series_index = MetadataField('series_index', is_dc=False, formatter=int, none_is=1) rating = MetadataField('rating', is_dc=False, formatter=int) + timestamp = MetadataField('date', formatter=parser.parse) def __init__(self, stream, basedir=os.getcwdu(), unquote_urls=True): diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index a7f522cad0..00da8f3e37 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -380,8 +380,10 @@ class LibraryDatabase2(LibraryDatabase): return row[loc] for prop in ('author_sort', 'authors', 'comment', 'comments', 'isbn', - 'publisher', 'rating', 'series', 'series_index', 'tags', 'title'): - setattr(self, prop, functools.partial(get_property, loc=FIELD_MAP['comments' if prop == 'comment' else prop])) + 'publisher', 'rating', 'series', 'series_index', 'tags', + 'title', 'timestamp'): + setattr(self, prop, functools.partial(get_property, + loc=FIELD_MAP['comments' if prop == 'comment' else prop])) def initialize_database(self): from calibre.resources import metadata_sqlite @@ -590,6 +592,7 @@ class LibraryDatabase2(LibraryDatabase): mi.author_sort = self.author_sort(idx, index_is_id=index_is_id) mi.comments = self.comments(idx, index_is_id=index_is_id) mi.publisher = self.publisher(idx, index_is_id=index_is_id) + mi.timestamp = self.timestamp(idx, index_is_id=index_is_id) tags = self.tags(idx, index_is_id=index_is_id) if tags: mi.tags = [i.strip() for i in tags.split(',')] @@ -884,6 +887,8 @@ class LibraryDatabase2(LibraryDatabase): self.set_isbn(id, mi.isbn, notify=False) if mi.series_index and mi.series_index > 0: self.set_series_index(id, mi.series_index, notify=False) + if getattr(mi, 'timestamp', None) is not None: + self.set_timestamp(id, mi.timestamp, notify=False) self.set_path(id, True) self.notify('metadata', [id]) @@ -1203,6 +1208,8 @@ class LibraryDatabase2(LibraryDatabase): self.set_metadata(id, mi) for path in formats: ext = os.path.splitext(path)[1][1:].lower() + if ext == 'opf': + continue stream = open(path, 'rb') self.add_format(id, ext, stream, index_is_id=True) self.conn.commit() @@ -1392,10 +1399,11 @@ books_series_link feeds f = open(os.path.join(base, sanitize_file_name(name)+'.opf'), 'wb') if not mi.authors: mi.authors = [_('Unknown')] - cdata = self.cover(id, index_is_id=True) - cname = sanitize_file_name(name)+'.jpg' - open(os.path.join(base, cname), 'wb').write(cdata) - mi.cover = cname + cdata = self.cover(int(id), index_is_id=True) + if cdata is not None: + cname = sanitize_file_name(name)+'.jpg' + open(os.path.join(base, cname), 'wb').write(cdata) + mi.cover = cname opf = OPFCreator(base, mi) opf.render(f) f.close() @@ -1472,7 +1480,7 @@ books_series_link feeds if not ext: continue ext = ext[1:].lower() - if ext not in BOOK_EXTENSIONS: + if ext not in BOOK_EXTENSIONS and ext != 'opf': continue formats.append(path) yield formats diff --git a/src/calibre/trac/plugins/download.py b/src/calibre/trac/plugins/download.py index 63bb4006e1..e63a7d8d0d 100644 --- a/src/calibre/trac/plugins/download.py +++ b/src/calibre/trac/plugins/download.py @@ -35,6 +35,7 @@ class Distribution(object): ('xdg-utils', '1.0.2', 'xdg-utils', 'xdg-utils', 'xdg-utils'), ('dbus-python', '0.82.2', 'dbus-python', 'python-dbus', 'dbus-python'), ('lxml', '2.0.5', 'lxml', 'python-lxml', 'python-lxml'), + ('python-dateutil', '1.4.1', 'python-dateutil', 'python-dateutil', 'python-dateutil') ('BeautifulSoup', '3.0.5', 'beautifulsoup', 'python-beautifulsoup', 'python-BeautifulSoup'), ('help2man', '1.36.4', 'help2man', 'help2man', 'help2man'), ]