Refactor the old save to disk code to use the new db api

This commit is contained in:
Kovid Goyal 2017-05-01 18:18:58 +05:30
parent ad5ba94f3a
commit bafc949526
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C

View File

@ -6,9 +6,11 @@ __license__ = 'GPL v3'
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>' __copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import os, traceback, re, shutil import os, traceback, re, errno
from io import BytesIO
from calibre.constants import DEBUG from calibre.constants import DEBUG
from calibre.db.errors import NoSuchFormat
from calibre.utils.config import Config, StringConfig, tweaks from calibre.utils.config import Config, StringConfig, tweaks
from calibre.utils.formatter import TemplateFormatter from calibre.utils.formatter import TemplateFormatter
from calibre.utils.filenames import shorten_components_to, supports_long_names, ascii_filename from calibre.utils.filenames import shorten_components_to, supports_long_names, ascii_filename
@ -17,7 +19,6 @@ from calibre.ebooks.metadata import fmt_sidx
from calibre.ebooks.metadata import title_sort from calibre.ebooks.metadata import title_sort
from calibre.utils.date import as_local_time from calibre.utils.date import as_local_time
from calibre import strftime, prints, sanitize_file_name_unicode from calibre import strftime, prints, sanitize_file_name_unicode
from calibre.ptempfile import SpooledTemporaryFile
from calibre.db.lazy import FormatsList from calibre.db.lazy import FormatsList
plugboard_any_device_value = 'any device' plugboard_any_device_value = 'any device'
@ -257,35 +258,22 @@ def get_components(template, mi, id, timefmt='%b %Y', length=250,
return shorten_components_to(length, components, last_has_extension=last_has_extension) return shorten_components_to(length, components, last_has_extension=last_has_extension)
def save_book_to_disk(id_, db, root, opts, length): def get_formats(available_formats, opts):
mi = db.get_metadata(id_, index_is_id=True) available_formats = {x.lower().strip() for x in available_formats}
cover = db.cover(id_, index_is_id=True) if opts.formats == 'all':
plugboards = db.prefs.get('plugboards', {}) asked_formats = available_formats
available_formats = db.formats(id_, index_is_id=True)
if not available_formats:
available_formats = []
else: else:
available_formats = [x.lower().strip() for x in asked_formats = {x.lower().strip() for x in opts.formats.split(',')}
available_formats.split(',')] return available_formats & asked_formats
formats = {}
fmts = db.formats(id_, index_is_id=True, verify_formats=False)
if fmts:
fmts = fmts.split(',')
for fmt in fmts:
fpath = db.format(id_, fmt, index_is_id=True, as_path=True)
if fpath is not None:
formats[fmt.lower()] = fpath
try:
return do_save_book_to_disk(id_, mi, cover, plugboards, def save_book_to_disk(book_id, db, root, opts, length):
formats, root, opts, length) db = db.new_api
finally: mi = db.get_metadata(book_id, index_is_id=True)
for temp in formats.itervalues(): plugboards = db.pref('plugboards', {})
try: formats = get_formats(db.formats(book_id), opts)
os.remove(temp) return do_save_book_to_disk(db, book_id, mi, plugboards,
except: formats, root, opts, length)
pass
def get_path_components(opts, mi, book_id, path_length): def get_path_components(opts, mi, book_id, path_length):
@ -332,70 +320,58 @@ def update_metadata(mi, fmt, stream, plugboards, cdata, error_report=None, plugb
error_report(fmt, traceback.format_exc()) error_report(fmt, traceback.format_exc())
def do_save_book_to_disk(id_, mi, cover, plugboards, def do_save_book_to_disk(db, book_id, mi, plugboards,
format_map, root, opts, length): formats, root, opts, length):
available_formats = [x.lower().strip() for x in format_map.keys()] originals = mi.cover, mi.pubdate, mi.timestamp
if mi.pubdate: formats_written = False
mi.pubdate = as_local_time(mi.pubdate)
if mi.timestamp:
mi.timestamp = as_local_time(mi.timestamp)
if opts.formats == 'all':
asked_formats = available_formats
else:
asked_formats = [x.lower().strip() for x in opts.formats.split(',')]
formats = set(available_formats).intersection(set(asked_formats))
if not formats:
return True, id_, mi.title
components = get_path_components(opts, mi, id_, length)
base_path = os.path.join(root, *components)
base_name = os.path.basename(base_path)
dirpath = os.path.dirname(base_path)
# Don't test for existence first as the test could fail but
# another worker process could create the directory before
# the call to makedirs
try: try:
os.makedirs(dirpath) if mi.pubdate:
except BaseException: mi.pubdate = as_local_time(mi.pubdate)
if not os.path.exists(dirpath): if mi.timestamp:
raise mi.timestamp = as_local_time(mi.timestamp)
ocover = mi.cover components = get_path_components(opts, mi, book_id, length)
if opts.save_cover and cover: base_path = os.path.join(root, *components)
with open(base_path+'.jpg', 'wb') as f: base_name = os.path.basename(base_path)
f.write(cover) dirpath = os.path.dirname(base_path)
mi.cover = base_name+'.jpg' try:
else: os.makedirs(dirpath)
mi.cover = None except EnvironmentError as err:
if err.errno != errno.EEXIST:
raise
if opts.write_opf: cdata = None
from calibre.ebooks.metadata.opf2 import metadata_to_opf if opts.save_cover or formats:
opf = metadata_to_opf(mi) cbuf = BytesIO()
with open(base_path+'.opf', 'wb') as f: if db.copy_cover_to(book_id, cbuf):
f.write(opf) cdata = cbuf.getvalue()
cpath = base_path + '.jpg'
with lopen(cpath, 'wb') as f:
f.write(cdata)
mi.cover = base_name+'.jpg'
if opts.write_opf:
from calibre.ebooks.metadata.opf2 import metadata_to_opf
opf = metadata_to_opf(mi)
with lopen(base_path+'.opf', 'wb') as f:
f.write(opf)
finally:
mi.cover, mi.pubdate, mi.timestamp = originals
mi.cover = ocover if not formats:
return not formats_written, book_id, mi.title
written = False
for fmt in formats: for fmt in formats:
fp = format_map.get(fmt, None)
if fp is None:
continue
stream = SpooledTemporaryFile(20*1024*1024, '_save_to_disk.'+(fmt or
'tmp'))
with open(fp, 'rb') as f:
shutil.copyfileobj(f, stream)
stream.seek(0)
written = True
if opts.update_metadata:
update_metadata(mi, fmt, stream, plugboards, cover)
stream.seek(0)
fmt_path = base_path+'.'+str(fmt) fmt_path = base_path+'.'+str(fmt)
with open(fmt_path, 'wb') as f: try:
shutil.copyfileobj(stream, f) db.copy_format_to(book_id, fmt, fmt_path)
formats_written = True
except NoSuchFormat:
continue
if opts.update_metadata:
with lopen(fmt_path, 'rb') as stream:
update_metadata(mi, fmt, stream, plugboards, cdata)
return not written, id_, mi.title return not formats_written, book_id, mi.title
def sanitize_args(root, opts): def sanitize_args(root, opts):