Implement setting of identifiers

This commit is contained in:
Kovid Goyal 2016-06-17 20:07:39 +05:30
parent 5cd5ba746c
commit 1d7eaaafac
2 changed files with 57 additions and 6 deletions

View File

@ -11,8 +11,8 @@ from lxml import etree
from calibre.ebooks.metadata import check_isbn
from calibre.ebooks.metadata.book.base import Metadata
from calibre.ebooks.metadata.utils import parse_opf
from calibre.ebooks.oeb.base import OPF2_NSMAP, OPF
from calibre.ebooks.metadata.utils import parse_opf, pretty_print_opf
from calibre.ebooks.oeb.base import OPF2_NSMAP, OPF, DC
# Utils {{{
# http://www.idpf.org/epub/vocab/package/pfx/
@ -119,6 +119,32 @@ def read_identifiers(root, prefixes, refines):
if scheme and val:
ans[scheme].append(val)
return ans
def set_identifiers(root, prefixes, refines, new_identifiers, force_identifiers=False):
uid = root.get('unique-identifier')
package_identifier = None
for ident in XPath('./opf:metadata/dc:identifier')(root):
if uid is not None and uid == ident.get('id'):
package_identifier = ident
continue
val = (ident.text or '').strip()
if not val:
ident.getparent().remove(ident)
continue
scheme, val = parse_identifier(ident, val, refines)
if not scheme or not val or force_identifiers or scheme in new_identifiers:
ident.getparent().remove(ident)
continue
metadata = XPath('./opf:metadata')(root)[0]
for scheme, val in new_identifiers.iteritems():
ident = metadata.makeelement(DC('identifier'))
ident.text = '%s:%s' % (scheme, val)
if package_identifier is None:
metadata.append(ident)
else:
p = package_identifier.getparent()
p.insert(p.index(package_identifier), ident)
# }}}
def read_metadata(root):
@ -139,6 +165,18 @@ def get_metadata(stream):
root = parse_opf(stream)
return read_metadata(root)
def apply_metadata(root, mi, cover_prefix='', cover_data=None, apply_null=False, update_timestamp=False, force_identifiers=False):
prefixes, refines = read_prefixes(root), read_refines(root)
set_identifiers(root, prefixes, refines, mi.identifiers, force_identifiers=force_identifiers)
pretty_print_opf(root)
def set_metadata(stream, mi, cover_prefix='', cover_data=None, apply_null=False, update_timestamp=False, force_identifiers=False):
root = parse_opf(stream)
return apply_metadata(
root, mi, cover_prefix=cover_prefix, cover_data=cover_data,
apply_null=apply_null, update_timestamp=update_timestamp,
force_identifiers=force_identifiers)
if __name__ == '__main__':
import sys
print(get_metadata(open(sys.argv[-1], 'rb')))

View File

@ -10,10 +10,12 @@ import unittest
from lxml import etree
from calibre.ebooks.metadata.opf3 import (
parse_prefixes, reserved_prefixes, expand_prefix, read_identifiers, read_metadata
parse_prefixes, reserved_prefixes, expand_prefix, read_identifiers,
read_metadata, set_identifiers, XPath
)
TEMPLATE = '''<package xmlns="http://www.idpf.org/2007/opf" version="3.0" unique-identifier="uid"><metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">{metadata}</metadata></package>''' # noqa
default_refines = defaultdict(list)
class TestOPF3(unittest.TestCase):
@ -33,8 +35,11 @@ class TestOPF3(unittest.TestCase):
self.ae(expand_prefix(raw, reserved_prefixes), expanded)
def test_identifiers(self):
def idt(val, scheme=None):
return '<dc:identifier {scheme}>{val}</dc:identifier>'.format(scheme=('opf:scheme="%s"'%scheme if scheme else ''), val=val)
def idt(val, scheme=None, iid=''):
return '<dc:identifier id="{id}" {scheme}>{val}</dc:identifier>'.format(scheme=('opf:scheme="%s"'%scheme if scheme else ''), val=val, id=iid)
def ri(root):
return dict(read_identifiers(root, reserved_prefixes, default_refines))
for m, result in (
(idt('abc', 'ISBN'), {}),
(idt('isbn:9780230739581'), {'isbn':['9780230739581']}),
@ -45,11 +50,19 @@ class TestOPF3(unittest.TestCase):
(idt('url:http://x'), {'url':['http://x']}),
(idt('a:1')+idt('a:2'), {'a':['1', '2']}),
):
self.ae(result, dict(read_identifiers(self.get_opf(m), reserved_prefixes, defaultdict(list))))
self.ae(result, ri(self.get_opf(m)))
mi = read_metadata(self.get_opf(
metadata=idt('a:1')+idt('a:2')+idt('calibre:x')+idt('uuid:y')))
self.ae(mi.application_id, 'x')
root = self.get_opf(metadata=idt('i:1', iid='uid') + idt('r:1') + idt('o:1'))
set_identifiers(root, reserved_prefixes, default_refines, {'i':'2', 'o':'2'})
self.ae({'i':['2', '1'], 'r':['1'], 'o':['2']}, ri(root))
self.ae(1, len(XPath('//dc:identifier[@id="uid"]')(root)))
root = self.get_opf(metadata=idt('i:1', iid='uid') + idt('r:1') + idt('o:1'))
set_identifiers(root, reserved_prefixes, default_refines, {'i':'2', 'o':'2'}, force_identifiers=True)
self.ae({'i':['2', '1'], 'o':['2']}, ri(root))
class TestRunner(unittest.main):
def createTests(self):