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',