Edit Book: Automatically updated the modified timestamp when editing EPUB 3 books on save.

This commit is contained in:
Kovid Goyal 2018-04-13 09:24:49 +05:30
parent 0a94c5420c
commit b88c6580d7
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 60 additions and 13 deletions

View File

@ -2,23 +2,32 @@
# vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
from __future__ import (unicode_literals, division, absolute_import,
print_function)
from __future__ import absolute_import, division, print_function, unicode_literals
import json
import re
from collections import defaultdict, namedtuple
from functools import wraps
from future_builtins import map
import re, json
from lxml import etree
from calibre import prints
from calibre.ebooks.metadata import check_isbn, authors_to_string, string_to_authors
from calibre.ebooks.metadata import authors_to_string, check_isbn, string_to_authors
from calibre.ebooks.metadata.book.base import Metadata
from calibre.ebooks.metadata.book.json_codec import object_to_unicode, decode_is_multiple, encode_is_multiple
from calibre.ebooks.metadata.utils import parse_opf, pretty_print_opf, ensure_unique, normalize_languages, create_manifest_item
from calibre.ebooks.oeb.base import OPF2_NSMAP, OPF, DC
from calibre.ebooks.metadata.book.json_codec import (
decode_is_multiple, encode_is_multiple, object_to_unicode
)
from calibre.ebooks.metadata.utils import (
create_manifest_item, ensure_unique, normalize_languages, parse_opf,
pretty_print_opf
)
from calibre.ebooks.oeb.base import DC, OPF, OPF2_NSMAP
from calibre.utils.config import from_json, to_json
from calibre.utils.date import parse_date as parse_date_, fix_only_date, is_date_undefined, isoformat
from calibre.utils.date import (
fix_only_date, is_date_undefined, isoformat, parse_date as parse_date_, utcnow,
w3cdtf
)
from calibre.utils.iso8601 import parse_iso8601
from calibre.utils.localization import canonicalize_lang
@ -575,23 +584,23 @@ def read_timestamp(root, prefixes, refines):
continue
def create_timestamp(m, val):
def create_timestamp(root, prefixes, m, val):
if not is_date_undefined(val):
val = isoformat(val)
ensure_prefix(root, prefixes, 'calibre', CALIBRE_PREFIX)
ensure_prefix(root, prefixes, 'dcterms')
val = w3cdtf(val)
d = m.makeelement(OPF('meta'), attrib={'property':'calibre:timestamp', 'scheme':'dcterms:W3CDTF'})
d.text = val
m.append(d)
def set_timestamp(root, prefixes, refines, val):
ensure_prefix(root, prefixes, 'calibre', CALIBRE_PREFIX)
ensure_prefix(root, prefixes, 'dcterms')
pq = '%s:timestamp' % CALIBRE_PREFIX
for meta in XPath('./opf:metadata/opf:meta')(root):
prop = expand_prefix(meta.get('property'), prefixes)
if prop.lower() == pq or meta.get('name') == 'calibre:timestamp':
remove_element(meta, refines)
create_timestamp(XPath('./opf:metadata')(root)[0], val)
create_timestamp(root, prefixes, XPath('./opf:metadata')(root)[0], val)
def read_last_modified(root, prefixes, refines):
@ -607,6 +616,23 @@ def read_last_modified(root, prefixes, refines):
return parse_date(val, is_w3cdtf=scheme == sq)
except Exception:
continue
def set_last_modified(root, prefixes, refines, val=None):
pq = '%s:modified' % reserved_prefixes['dcterms']
sq = '%s:w3cdtf' % reserved_prefixes['dcterms']
val = w3cdtf(val or utcnow())
for meta in XPath('./opf:metadata/opf:meta[@property]')(root):
prop = expand_prefix(meta.get('property'), prefixes)
if prop.lower() == pq:
iid = meta.get('id')
if not iid or not refines[iid]:
break
else:
ensure_prefix(root, prefixes, 'dcterms')
m = XPath('./opf:metadata')(root)[0]
meta = m.makeelement(OPF('meta'), attrib={'property':'dcterms:modified', 'scheme':'dcterms:W3CDTF'})
m.append(meta)
meta.text = val
# }}}
# Comments {{{
@ -933,6 +959,11 @@ def first_spine_item(root, prefixes, refines):
return item.get('href') or None
def set_last_modified_in_opf(root):
prefixes, refines = read_prefixes(root), read_refines(root)
set_last_modified(root, prefixes, refines)
def read_metadata(root, ver=None, return_extra_data=False):
ans = Metadata(_('Unknown'), [_('Unknown')])
prefixes, refines = read_prefixes(root), read_refines(root)

View File

@ -1294,7 +1294,14 @@ class EpubContainer(Container):
f.write(raw)
self.obfuscated_fonts[font] = (alg, tkey)
def update_modified_timestamp(self):
from calibre.ebooks.metadata.opf3 import set_last_modified_in_opf
set_last_modified_in_opf(self.opf)
self.dirty(self.opf_name)
def commit(self, outpath=None, keep_parsed=False):
if self.opf_version_parsed.major == 3:
self.update_modified_timestamp()
super(EpubContainer, self).commit(keep_parsed=keep_parsed)
container_path = join(self.root, 'META-INF', 'container.xml')
if not exists(container_path):

View File

@ -193,6 +193,15 @@ def isoformat(date_time, assume_utc=False, as_utc=True, sep='T'):
return unicode(date_time.isoformat(str(sep)))
def w3cdtf(date_time, assume_utc=False):
if hasattr(date_time, 'tzinfo'):
if date_time.tzinfo is None:
date_time = date_time.replace(tzinfo=_utc_tz if assume_utc else
_local_tz)
date_time = date_time.astimezone(_utc_tz if as_utc else _local_tz)
return unicode(date_time.strftime('%Y-%M-%dT%H:%M:%SZ'))
def as_local_time(date_time, assume_utc=True):
if not hasattr(date_time, 'tzinfo'):
return date_time