mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Save to disk: When saving to a single directory, handle the case of the save to disk template containing path separators inside template expression correctly. Fixes #821912 (save only epub on disc using one folder file-name-error)
This commit is contained in:
commit
dc58208164
@ -50,7 +50,7 @@ class SaveToDiskAction(InterfaceAction):
|
|||||||
cm('single format', _('Save only %s format to disk')%
|
cm('single format', _('Save only %s format to disk')%
|
||||||
prefs['output_format'].upper(),
|
prefs['output_format'].upper(),
|
||||||
triggered=partial(self.save_single_format_to_disk, False))
|
triggered=partial(self.save_single_format_to_disk, False))
|
||||||
cm('fingle dir and format',
|
cm('single dir and format',
|
||||||
_('Save only %s format to disk in a single directory')%
|
_('Save only %s format to disk in a single directory')%
|
||||||
prefs['output_format'].upper(),
|
prefs['output_format'].upper(),
|
||||||
triggered=partial(self.save_single_fmt_to_single_dir, False))
|
triggered=partial(self.save_single_fmt_to_single_dir, False))
|
||||||
@ -115,10 +115,7 @@ class SaveToDiskAction(InterfaceAction):
|
|||||||
opts.save_cover = False
|
opts.save_cover = False
|
||||||
opts.write_opf = False
|
opts.write_opf = False
|
||||||
opts.template = opts.send_template
|
opts.template = opts.send_template
|
||||||
if single_dir:
|
opts.single_dir = single_dir
|
||||||
opts.template = opts.template.split('/')[-1].strip()
|
|
||||||
if not opts.template:
|
|
||||||
opts.template = '{title} - {authors}'
|
|
||||||
self._saver = Saver(self.gui, self.gui.library_view.model().db,
|
self._saver = Saver(self.gui, self.gui.library_view.model().db,
|
||||||
Dispatcher(self._books_saved), rows, path, opts,
|
Dispatcher(self._books_saved), rows, path, opts,
|
||||||
spare_server=self.gui.spare_server)
|
spare_server=self.gui.spare_server)
|
||||||
|
@ -121,6 +121,9 @@ def config(defaults=None):
|
|||||||
help=_('Convert paths to lowercase.'))
|
help=_('Convert paths to lowercase.'))
|
||||||
x('replace_whitespace', default=False,
|
x('replace_whitespace', default=False,
|
||||||
help=_('Replace whitespace with underscores.'))
|
help=_('Replace whitespace with underscores.'))
|
||||||
|
x('single_dir', default=False,
|
||||||
|
help=_('Save into a single directory, ignoring the template'
|
||||||
|
' directory structure'))
|
||||||
return c
|
return c
|
||||||
|
|
||||||
def preprocess_template(template):
|
def preprocess_template(template):
|
||||||
@ -131,7 +134,7 @@ def preprocess_template(template):
|
|||||||
template = template.decode(preferred_encoding, 'replace')
|
template = template.decode(preferred_encoding, 'replace')
|
||||||
return template
|
return template
|
||||||
|
|
||||||
class SafeFormat(TemplateFormatter):
|
class Formatter(TemplateFormatter):
|
||||||
'''
|
'''
|
||||||
Provides a format function that substitutes '' for any missing value
|
Provides a format function that substitutes '' for any missing value
|
||||||
'''
|
'''
|
||||||
@ -165,7 +168,7 @@ class SafeFormat(TemplateFormatter):
|
|||||||
|
|
||||||
def get_components(template, mi, id, timefmt='%b %Y', length=250,
|
def get_components(template, mi, id, timefmt='%b %Y', length=250,
|
||||||
sanitize_func=ascii_filename, replace_whitespace=False,
|
sanitize_func=ascii_filename, replace_whitespace=False,
|
||||||
to_lowercase=False):
|
to_lowercase=False, safe_format=True):
|
||||||
|
|
||||||
tsorder = tweaks['save_template_title_series_sorting']
|
tsorder = tweaks['save_template_title_series_sorting']
|
||||||
format_args = FORMAT_ARGS.copy()
|
format_args = FORMAT_ARGS.copy()
|
||||||
@ -225,8 +228,11 @@ def get_components(template, mi, id, timefmt='%b %Y', length=250,
|
|||||||
format_args[key] = unicode(format_args[key])
|
format_args[key] = unicode(format_args[key])
|
||||||
else:
|
else:
|
||||||
format_args[key] = ''
|
format_args[key] = ''
|
||||||
components = SafeFormat().safe_format(template, format_args,
|
if safe_format:
|
||||||
|
components = Formatter().safe_format(template, format_args,
|
||||||
'G_C-EXCEPTION!', mi)
|
'G_C-EXCEPTION!', mi)
|
||||||
|
else:
|
||||||
|
components = Formatter().unsafe_format(template, format_args, mi)
|
||||||
components = [x.strip() for x in components.split('/')]
|
components = [x.strip() for x in components.split('/')]
|
||||||
components = [sanitize_func(x) for x in components if x]
|
components = [sanitize_func(x) for x in components if x]
|
||||||
if not components:
|
if not components:
|
||||||
@ -283,10 +289,20 @@ def do_save_book_to_disk(id_, mi, cover, plugboards,
|
|||||||
if not formats:
|
if not formats:
|
||||||
return True, id_, mi.title
|
return True, id_, mi.title
|
||||||
|
|
||||||
components = get_components(opts.template, mi, id_, opts.timefmt, length,
|
try:
|
||||||
|
components = get_components(opts.template, mi, id_, opts.timefmt, length,
|
||||||
ascii_filename if opts.asciiize else sanitize_file_name_unicode,
|
ascii_filename if opts.asciiize else sanitize_file_name_unicode,
|
||||||
to_lowercase=opts.to_lowercase,
|
to_lowercase=opts.to_lowercase,
|
||||||
replace_whitespace=opts.replace_whitespace)
|
replace_whitespace=opts.replace_whitespace, safe_format=False)
|
||||||
|
except Exception, e:
|
||||||
|
raise ValueError(_('Failed to calculate path for '
|
||||||
|
'save to disk. Template: %s\n'
|
||||||
|
'Error: %s'%(opts.template, e)))
|
||||||
|
if opts.single_dir:
|
||||||
|
components = components[-1:]
|
||||||
|
if not components:
|
||||||
|
raise ValueError(_('Template evaluation resulted in no'
|
||||||
|
' path components. Template: %s')%opts.template)
|
||||||
base_path = os.path.join(root, *components)
|
base_path = os.path.join(root, *components)
|
||||||
base_name = os.path.basename(base_path)
|
base_name = os.path.basename(base_path)
|
||||||
dirpath = os.path.dirname(base_path)
|
dirpath = os.path.dirname(base_path)
|
||||||
|
@ -310,7 +310,16 @@ class TemplateFormatter(string.Formatter):
|
|||||||
ans = string.Formatter.vformat(self, fmt, args, kwargs)
|
ans = string.Formatter.vformat(self, fmt, args, kwargs)
|
||||||
return self.compress_spaces.sub(' ', ans).strip()
|
return self.compress_spaces.sub(' ', ans).strip()
|
||||||
|
|
||||||
########## a formatter guaranteed not to throw and exception ############
|
########## a formatter that throws exceptions ############
|
||||||
|
|
||||||
|
def unsafe_format(self, fmt, kwargs, book):
|
||||||
|
self.kwargs = kwargs
|
||||||
|
self.book = book
|
||||||
|
self.composite_values = {}
|
||||||
|
self.locals = {}
|
||||||
|
return self.vformat(fmt, [], kwargs).strip()
|
||||||
|
|
||||||
|
########## a formatter guaranteed not to throw an exception ############
|
||||||
|
|
||||||
def safe_format(self, fmt, kwargs, error_value, book):
|
def safe_format(self, fmt, kwargs, error_value, book):
|
||||||
self.kwargs = kwargs
|
self.kwargs = kwargs
|
||||||
|
Loading…
x
Reference in New Issue
Block a user