mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-23 15:30:45 -04:00
Edit book: When bulk renaming files add an option to rename by the order in which the files appear in the book.
This commit is contained in:
parent
3462cd4653
commit
4dc44f144f
@ -102,7 +102,10 @@ want to rename all the HTML files to have names Chapter-1.html, Chapter-2.html
|
|||||||
and so on. Select the files you want bulk renamed by holding down the Shift or
|
and so on. Select the files you want bulk renamed by holding down the Shift or
|
||||||
Ctrl key and clicking the files. Then right click and select :guilabel:`Bulk
|
Ctrl key and clicking the files. Then right click and select :guilabel:`Bulk
|
||||||
rename`. Enter a prefix and what number you would like the automatic numbering
|
rename`. Enter a prefix and what number you would like the automatic numbering
|
||||||
to start at, click OK and you are done.
|
to start at, click OK and you are done. The bulk rename dialog also lets you
|
||||||
|
rename files by the order they appear int he book instead of the order you
|
||||||
|
selected them in, useful, for instance to rename all images by the order
|
||||||
|
they appear.
|
||||||
|
|
||||||
Finally, you can bulk change the file extension for all selected files. Select
|
Finally, you can bulk change the file extension for all selected files. Select
|
||||||
multiple files, as above, and right click and choose :guilabel:`Change the file
|
multiple files, as above, and right click and choose :guilabel:`Change the file
|
||||||
|
@ -386,3 +386,19 @@ def remove_links_to(container, predicate):
|
|||||||
changed.add(name)
|
changed.add(name)
|
||||||
tuple(map(container.dirty, changed))
|
tuple(map(container.dirty, changed))
|
||||||
return changed
|
return changed
|
||||||
|
|
||||||
|
|
||||||
|
def get_spine_order_for_all_files(container):
|
||||||
|
linear_names, non_linear_names = [], []
|
||||||
|
for name, is_linear in container.spine_names:
|
||||||
|
(linear_names if is_linear else non_linear_names).append(name)
|
||||||
|
all_names = linear_names + non_linear_names
|
||||||
|
spine_names = frozenset(all_names)
|
||||||
|
ans = {}
|
||||||
|
for spine_pos, name in enumerate(all_names):
|
||||||
|
ans.setdefault(name, (spine_pos, -1))
|
||||||
|
for i, href in enumerate(container.iterlinks(name, get_line_numbers=False)):
|
||||||
|
lname = container.href_to_name(href, name)
|
||||||
|
if lname not in spine_names:
|
||||||
|
ans.setdefault(lname, (spine_pos, i))
|
||||||
|
return ans
|
||||||
|
@ -5,6 +5,8 @@ from __future__ import absolute_import, division, print_function, unicode_litera
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import posixpath
|
import posixpath
|
||||||
|
import sys
|
||||||
|
import textwrap
|
||||||
from binascii import hexlify
|
from binascii import hexlify
|
||||||
from collections import Counter, OrderedDict, defaultdict
|
from collections import Counter, OrderedDict, defaultdict
|
||||||
from functools import partial
|
from functools import partial
|
||||||
@ -24,7 +26,9 @@ from calibre.ebooks.oeb.polish.cover import (
|
|||||||
get_cover_page_name, get_raster_cover_name, is_raster_image
|
get_cover_page_name, get_raster_cover_name, is_raster_image
|
||||||
)
|
)
|
||||||
from calibre.ebooks.oeb.polish.css import add_stylesheet_links
|
from calibre.ebooks.oeb.polish.css import add_stylesheet_links
|
||||||
from calibre.ebooks.oeb.polish.replace import get_recommended_folders
|
from calibre.ebooks.oeb.polish.replace import (
|
||||||
|
get_recommended_folders, get_spine_order_for_all_files
|
||||||
|
)
|
||||||
from calibre.gui2 import (
|
from calibre.gui2 import (
|
||||||
choose_dir, choose_files, choose_save_file, elided_text, error_dialog,
|
choose_dir, choose_files, choose_save_file, elided_text, error_dialog,
|
||||||
question_dialog
|
question_dialog
|
||||||
@ -69,7 +73,8 @@ def name_is_ok(name, show_error):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def get_bulk_rename_settings(parent, number, msg=None, sanitize=sanitize_file_name_unicode, leading_zeros=True, prefix=None, category='text'): # {{{
|
def get_bulk_rename_settings(parent, number, msg=None, sanitize=sanitize_file_name_unicode,
|
||||||
|
leading_zeros=True, prefix=None, category='text', allow_spine_order=False): # {{{
|
||||||
d = QDialog(parent)
|
d = QDialog(parent)
|
||||||
d.setWindowTitle(_('Bulk rename items'))
|
d.setWindowTitle(_('Bulk rename items'))
|
||||||
d.l = l = QFormLayout(d)
|
d.l = l = QFormLayout(d)
|
||||||
@ -87,6 +92,11 @@ def get_bulk_rename_settings(parent, number, msg=None, sanitize=sanitize_file_na
|
|||||||
d.num = num = QSpinBox(d)
|
d.num = num = QSpinBox(d)
|
||||||
num.setMinimum(0), num.setValue(1), num.setMaximum(1000)
|
num.setMinimum(0), num.setValue(1), num.setMaximum(1000)
|
||||||
l.addRow(_('Starting &number:'), num)
|
l.addRow(_('Starting &number:'), num)
|
||||||
|
if allow_spine_order:
|
||||||
|
d.spine_order = QCheckBox(_('Rename files according to their book order'))
|
||||||
|
d.spine_order.setToolTip(textwrap.fill(_(
|
||||||
|
'Rename the selected files according to the order they appear in the book, instead of the order they were selected in.')))
|
||||||
|
l.addRow(d.spine_order)
|
||||||
d.bb = bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
|
d.bb = bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
|
||||||
bb.accepted.connect(d.accept), bb.rejected.connect(d.reject)
|
bb.accepted.connect(d.accept), bb.rejected.connect(d.reject)
|
||||||
l.addRow(bb)
|
l.addRow(bb)
|
||||||
@ -103,6 +113,8 @@ def get_bulk_rename_settings(parent, number, msg=None, sanitize=sanitize_file_na
|
|||||||
fmt = '%0{0}d'.format(len(str(largest)))
|
fmt = '%0{0}d'.format(len(str(largest)))
|
||||||
ans['prefix'] = prefix + fmt
|
ans['prefix'] = prefix + fmt
|
||||||
ans['start'] = num
|
ans['start'] = num
|
||||||
|
if allow_spine_order:
|
||||||
|
ans['spine_order'] = d.spine_order.isChecked()
|
||||||
return ans
|
return ans
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
@ -591,7 +603,7 @@ class FileList(QTreeWidget):
|
|||||||
names = self.request_rename_common()
|
names = self.request_rename_common()
|
||||||
if names is not None:
|
if names is not None:
|
||||||
categories = Counter(unicode(item.data(0, CATEGORY_ROLE) or '') for item in self.selectedItems())
|
categories = Counter(unicode(item.data(0, CATEGORY_ROLE) or '') for item in self.selectedItems())
|
||||||
settings = get_bulk_rename_settings(self, len(names), category=categories.most_common(1)[0][0])
|
settings = get_bulk_rename_settings(self, len(names), category=categories.most_common(1)[0][0], allow_spine_order=True)
|
||||||
fmt, num = settings['prefix'], settings['start']
|
fmt, num = settings['prefix'], settings['start']
|
||||||
if fmt is not None:
|
if fmt is not None:
|
||||||
def change_name(name, num):
|
def change_name(name, num):
|
||||||
@ -599,7 +611,15 @@ class FileList(QTreeWidget):
|
|||||||
base, ext = parts[-1].rpartition('.')[0::2]
|
base, ext = parts[-1].rpartition('.')[0::2]
|
||||||
parts[-1] = (fmt % num) + '.' + ext
|
parts[-1] = (fmt % num) + '.' + ext
|
||||||
return '/'.join(parts)
|
return '/'.join(parts)
|
||||||
name_map = {n:change_name(n, num + i) for i, n in enumerate(names)}
|
if settings['spine_order']:
|
||||||
|
order_map = get_spine_order_for_all_files(current_container())
|
||||||
|
select_map = {n:i for i, n in enumerate(names)}
|
||||||
|
|
||||||
|
def key(n):
|
||||||
|
return order_map.get(n, (sys.maxsize, select_map[n]))
|
||||||
|
name_map = {n: change_name(n, num + i) for i, n in enumerate(sorted(names, key=key))}
|
||||||
|
else:
|
||||||
|
name_map = {n:change_name(n, num + i) for i, n in enumerate(names)}
|
||||||
self.bulk_rename_requested.emit(name_map)
|
self.bulk_rename_requested.emit(name_map)
|
||||||
|
|
||||||
def request_change_ext(self):
|
def request_change_ext(self):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user