From e6a5517cea826d84384b186c5da153d959950feb Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 10 Nov 2008 10:02:38 -0800 Subject: [PATCH] Fix #1247 (Can't set rating in the main window) --- src/calibre/ebooks/epub/from_html.py | 1 + src/calibre/ebooks/metadata/__init__.py | 2 +- src/calibre/ebooks/metadata/meta.py | 10 ++-- src/calibre/ebooks/metadata/opf.xml | 2 +- src/calibre/ebooks/metadata/opf2.py | 75 +++++++++++++++++++++++-- src/calibre/gui2/library.py | 4 +- src/calibre/library/server.py | 8 +-- src/calibre/linux.py | 2 +- 8 files changed, 87 insertions(+), 17 deletions(-) diff --git a/src/calibre/ebooks/epub/from_html.py b/src/calibre/ebooks/epub/from_html.py index a7a4b8f568..609a909086 100644 --- a/src/calibre/ebooks/epub/from_html.py +++ b/src/calibre/ebooks/epub/from_html.py @@ -313,6 +313,7 @@ def convert(htmlfile, opts, notification=None): logger.info('Output written to %s'%opts.output) if opts.extract_to is not None: epub.extractall(opts.extract_to) + epub.close() def main(args=sys.argv): diff --git a/src/calibre/ebooks/metadata/__init__.py b/src/calibre/ebooks/metadata/__init__.py index f1b70b13ad..4a01a14f13 100644 --- a/src/calibre/ebooks/metadata/__init__.py +++ b/src/calibre/ebooks/metadata/__init__.py @@ -250,7 +250,7 @@ class MetaInformation(object): ans += u'Title : ' + unicode(self.title) + u'\n' if self.authors: ans += u'Author : ' + (', '.join(self.authors) if self.authors is not None else u'None') - ans += ((' (' + self.author_sort + ')') if self.author_sort else '') + u'\n' + ans += ((' [' + self.author_sort + ']') if self.author_sort else '') + u'\n' if self.publisher: ans += u'Publisher: '+ unicode(self.publisher) + u'\n' if self.book_producer: diff --git a/src/calibre/ebooks/metadata/meta.py b/src/calibre/ebooks/metadata/meta.py index 419b5df167..41e95dfcb7 100644 --- a/src/calibre/ebooks/metadata/meta.py +++ b/src/calibre/ebooks/metadata/meta.py @@ -16,7 +16,7 @@ from calibre.ebooks.metadata.epub import get_metadata as epub_metadata from calibre.ebooks.metadata.html import get_metadata as html_metadata from calibre.ebooks.mobi.reader import get_metadata as mobi_metadata from calibre.ebooks.metadata.odt import get_metadata as odt_metadata -from calibre.ebooks.metadata.opf import OPFReader +from calibre.ebooks.metadata.opf2 import OPF from calibre.ebooks.metadata.rtf import set_metadata as set_rtf_metadata from calibre.ebooks.lrf.meta import set_metadata as set_lrf_metadata from calibre.ebooks.metadata.epub import set_metadata as set_epub_metadata @@ -174,13 +174,13 @@ def metadata_from_filename(name, pat=None): def opf_metadata(opfpath): if hasattr(opfpath, 'read'): f = opfpath - opfpath = getattr(f, 'name', '') + opfpath = getattr(f, 'name', os.getcwd()) else: f = open(opfpath, 'rb') try: - opf = OPFReader(f, os.path.dirname(opfpath)) + opf = OPF(f, os.path.dirname(opfpath)) if opf.application_id is not None: - mi = MetaInformation(opf, None) + mi = MetaInformation(opf) if hasattr(opf, 'cover') and opf.cover: cpath = os.path.join(os.path.dirname(opfpath), opf.cover) if os.access(cpath, os.R_OK): @@ -189,4 +189,6 @@ def opf_metadata(opfpath): mi.cover_data = (fmt, data) return mi except: + import traceback + traceback.print_exc() pass diff --git a/src/calibre/ebooks/metadata/opf.xml b/src/calibre/ebooks/metadata/opf.xml index 6bf52a83d3..f8aa09b64e 100644 --- a/src/calibre/ebooks/metadata/opf.xml +++ b/src/calibre/ebooks/metadata/opf.xml @@ -7,7 +7,7 @@ > ${mi.title} - ${author} + ${author} ${'%s (%s)'%(__appname__, __version__)} [http://${__appname__}.kovidgoyal.net] ${mi.application_id} diff --git a/src/calibre/ebooks/metadata/opf2.py b/src/calibre/ebooks/metadata/opf2.py index b49f1e102b..64b0e88dcb 100644 --- a/src/calibre/ebooks/metadata/opf2.py +++ b/src/calibre/ebooks/metadata/opf2.py @@ -7,7 +7,7 @@ __docformat__ = 'restructuredtext en' lxml based OPF parser. ''' -import sys, unittest, functools, os, mimetypes, uuid, glob +import sys, unittest, functools, os, mimetypes, uuid, glob, cStringIO from urllib import unquote from urlparse import urlparse @@ -17,7 +17,7 @@ from calibre.ebooks.chardet import xml_to_unicode from calibre import relpath from calibre.constants import __appname__, __version__ from calibre.ebooks.metadata.toc import TOC -from calibre.ebooks.metadata import MetaInformation +from calibre.ebooks.metadata import MetaInformation, get_parser class Resource(object): @@ -418,6 +418,8 @@ class OPF(object): tags_path = XPath('descendant::*[re:match(name(), "subject", "i")]') isbn_path = XPath('descendant::*[re:match(name(), "identifier", "i") and '+ '(re:match(@scheme, "isbn", "i") or re:match(@opf:scheme, "isbn", "i"))]') + application_id_path= XPath('descendant::*[re:match(name(), "identifier", "i") and '+ + '(re:match(@opf:scheme, "calibre|libprs500", "i") or re:match(@scheme, "calibre|libprs500", "i"))]') manifest_path = XPath('descendant::*[re:match(name(), "manifest", "i")]/*[re:match(name(), "item", "i")]') manifest_ppath = XPath('descendant::*[re:match(name(), "manifest", "i")]') spine_path = XPath('descendant::*[re:match(name(), "spine", "i")]/*[re:match(name(), "itemref", "i")]') @@ -619,8 +621,12 @@ class OPF(object): def fget(self): matches = self.authors_path(self.metadata) if matches: - ans = matches[0].get('opf:file-as', None) - return ans if ans else matches[0].get('file-as', None) + for match in matches: + ans = match.get('{%s}file-as'%self.NAMESPACES['opf'], None) + if not ans: + ans = match.get('file-as', None) + if ans: + return ans def fset(self, val): matches = self.authors_path(self.metadata) @@ -662,6 +668,23 @@ class OPF(object): matches[0].text = unicode(val) return property(fget=fget, fset=fset) + + @apply + def application_id(): + + def fget(self): + for match in self.application_id_path(self.metadata): + return match.text if match.text else None + + def fset(self, val): + matches = self.application_id_path(self.metadata) + if not matches: + matches = [self.create_metadata_element('identifier', ns='dc', + attrib={'{%s}scheme'%self.NAMESPACES['opf']:'calibre'})] + matches[0].text = unicode(val) + + return property(fget=fget, fset=fset) + @apply def series(): @@ -911,5 +934,49 @@ def suite(): def test(): unittest.TextTestRunner(verbosity=2).run(suite()) +def option_parser(): + return get_parser('opf') + +def main(args=sys.argv): + parser = option_parser() + opts, args = parser.parse_args(args) + if len(args) != 2: + parser.print_help() + return 1 + opfpath = os.path.abspath(args[1]) + basedir = os.path.dirname(opfpath) + mi = MetaInformation(OPF(open(opfpath, 'rb'), basedir)) + write = False + if opts.title is not None: + mi.title = opts.title + write = True + if opts.authors is not None: + aus = [i.strip() for i in opts.authors.split(',')] + mi.authors = aus + write = True + if opts.category is not None: + mi.category = opts.category + write = True + if opts.comment is not None: + mi.comments = opts.comment + write = True + if write: + mo = OPFCreator(basedir, mi) + ncx = cStringIO.StringIO() + mo.render(open(args[1], 'wb'), ncx) + ncx = ncx.getvalue() + if ncx: + f = glob.glob(os.path.join(os.path.dirname(args[1]), '*.ncx')) + if f: + f = open(f[0], 'wb') + else: + f = open(os.path.splitext(args[1])[0]+'.ncx', 'wb') + f.write(ncx) + f.close() + print MetaInformation(OPF(open(opfpath, 'rb'), basedir)) + return 0 + + + if __name__ == '__main__': sys.exit(test()) \ No newline at end of file diff --git a/src/calibre/gui2/library.py b/src/calibre/gui2/library.py index b64a002a71..ff72601d2e 100644 --- a/src/calibre/gui2/library.py +++ b/src/calibre/gui2/library.py @@ -479,10 +479,10 @@ class BooksModel(QAbstractTableModel): return False val = unicode(value.toString().toUtf8(), 'utf-8').strip() if column != 'rating' else \ int(value.toInt()[0]) - if col == 'rating': + if column == 'rating': val = 0 if val < 0 else 5 if val > 5 else val val *= 2 - if col == 'series': + if column == 'series': pat = re.compile(r'\[(\d+)\]') match = pat.search(val) id = self.db.id(row) diff --git a/src/calibre/library/server.py b/src/calibre/library/server.py index a967195037..8fad2da593 100644 --- a/src/calibre/library/server.py +++ b/src/calibre/library/server.py @@ -242,11 +242,11 @@ class LibraryServer(object): ' Feeds to read calibre books on a ipod with stanza.' books = [] for record in iter(self.db): - if 'EPUB' in record['formats'].upper(): + if 'EPUB' in record[FIELD_MAP['formats']].upper(): authors = ' & '.join([i.replace('|', ',') for i in record[2].split(',')]) - books.append(self.STANZA_ENTRY.generate(authors=authors, + books.append(self.STANZA_ENTRY.generate(authors=authors, record=record, - port=self.opts.port, + port=self.opts.port, server=self.opts.hostname, ).render('xml').decode('utf8')) @@ -254,7 +254,7 @@ class LibraryServer(object): cherrypy.response.headers['Last-Modified'] = self.last_modified(updated) cherrypy.response.headers['Content-Type'] = 'text/xml' - return self.STANZA.generate(subtitle='', data=books, + return self.STANZA.generate(subtitle='', data=books, updated=updated, id='urn:calibre:main').render('xml') @expose diff --git a/src/calibre/linux.py b/src/calibre/linux.py index 8ae5f4f9bf..94c306db43 100644 --- a/src/calibre/linux.py +++ b/src/calibre/linux.py @@ -23,7 +23,7 @@ entry_points = { 'lit-meta = calibre.ebooks.metadata.lit:main', 'imp-meta = calibre.ebooks.metadata.imp:main', 'rb-meta = calibre.ebooks.metadata.rb:main', - 'opf-meta = calibre.ebooks.metadata.opf:main', + 'opf-meta = calibre.ebooks.metadata.opf2:main', 'odt-meta = calibre.ebooks.metadata.odt:main', 'epub-meta = calibre.ebooks.metadata.epub:main', 'txt2lrf = calibre.ebooks.lrf.txt.convert_from:main',