diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index c4e0a4d1f9..2213b7f6bf 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -907,6 +907,12 @@ class ActionTagMapper(InterfaceActionBase): description = _('Filter/transform the tags for books in the library') +class ActionAuthorMapper(InterfaceActionBase): + name = 'Author Mapper' + actual_plugin = 'calibre.gui2.actions.author_mapper:AuthorMapAction' + description = _('Transform the authors for books in the library') + + class ActionTemplateTester(InterfaceActionBase): name = 'Template Tester' actual_plugin = 'calibre.gui2.actions.show_template_tester:ShowTemplateTesterAction' @@ -1076,7 +1082,7 @@ plugins += [ActionAdd, ActionFetchAnnotations, ActionGenerateCatalog, ActionAddToLibrary, ActionEditCollections, ActionMatchBooks, ActionChooseLibrary, ActionCopyToLibrary, ActionTweakEpub, ActionUnpackBook, ActionNextMatch, ActionStore, ActionPluginUpdater, ActionPickRandom, ActionEditToC, ActionSortBy, - ActionMarkBooks, ActionEmbed, ActionTemplateTester, ActionTagMapper, + ActionMarkBooks, ActionEmbed, ActionTemplateTester, ActionTagMapper, ActionAuthorMapper, ActionVirtualLibrary] # }}} diff --git a/src/calibre/ebooks/metadata/author_mapper.py b/src/calibre/ebooks/metadata/author_mapper.py index d4e10d118b..95ace59f23 100644 --- a/src/calibre/ebooks/metadata/author_mapper.py +++ b/src/calibre/ebooks/metadata/author_mapper.py @@ -6,6 +6,7 @@ from __future__ import absolute_import, division, print_function, unicode_litera import re from collections import deque +from future_builtins import map from calibre.utils.icu import capitalize, lower, upper diff --git a/src/calibre/gui2/actions/author_mapper.py b/src/calibre/gui2/actions/author_mapper.py new file mode 100644 index 0000000000..1763344541 --- /dev/null +++ b/src/calibre/gui2/actions/author_mapper.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python2 +# vim:fileencoding=utf-8 +# License: GPLv3 Copyright: 2015, Kovid Goyal + +from __future__ import (unicode_literals, division, absolute_import, + print_function) +from future_builtins import map + +from calibre.gui2 import gprefs +from calibre.gui2.actions import InterfaceAction + + +class AuthorMapAction(InterfaceAction): + + name = 'Author Mapper' + action_spec = (_('Author mapper'), 'user_profile.png', _('Transform the authors for books in the library'), None) + action_type = 'current' + + def genesis(self): + self.qaction.triggered.connect(self.start_map) + + def start_map(self): + rows = self.gui.library_view.selectionModel().selectedRows() + selected = True + if not rows or len(rows) < 2: + selected = False + rows = xrange(self.gui.library_view.model().rowCount(None)) + ids = set(map(self.gui.library_view.model().id, rows)) + self.do_map(ids, selected) + + def do_map(self, book_ids, selected): + from calibre.ebooks.metadata.author_mapper import map_authors, compile_rules + from calibre.gui2.author_mapper import RulesDialog + from calibre.gui2.device import BusyCursor + d = RulesDialog(self.gui) + d.setWindowTitle(ngettext( + 'Map authors for one book in the library', + 'Map authors for {} books in the library', len(book_ids)).format(len(book_ids))) + d.rules = gprefs.get('library-author-mapper-ruleset', ()) + txt = ngettext( + 'The changes will be applied to the selected book', + 'The changes will be applied to the {} selected books', len(book_ids)) if selected else ngettext( + 'The changes will be applied to one book in the library', + 'The changes will be applied to {} books in the library', len(book_ids)) + d.edit_widget.msg_label.setText(d.edit_widget.msg_label.text() + '

' + txt.format(len(book_ids))) + if d.exec_() != d.Accepted: + return + with BusyCursor(): + rules = d.rules + gprefs.set('library-author-mapper-ruleset', rules) + rules = compile_rules(rules) + db = self.gui.current_db.new_api + author_map = db.all_field_for('authors', book_ids) + changed_author_map = {} + changed_author_sort_map = {} + for book_id, authors in author_map.iteritems(): + authors = list(authors) + new_authors = map_authors(authors, rules) + if authors != new_authors: + changed_author_map[book_id] = new_authors + changed_author_sort_map[book_id] = db.author_sort_from_authors(new_authors) + if changed_author_map: + db.set_field('authors', changed_author_map) + db.set_field('author_sort', changed_author_sort_map) + self.gui.library_view.model().refresh_ids(tuple(changed_author_map), current_row=self.gui.library_view.currentIndex().row())