diff --git a/src/calibre/gui2/convert/metadata.py b/src/calibre/gui2/convert/metadata.py index 2026f1cee5..3ddd5674bb 100644 --- a/src/calibre/gui2/convert/metadata.py +++ b/src/calibre/gui2/convert/metadata.py @@ -13,7 +13,7 @@ from PyQt4.Qt import QPixmap, SIGNAL from calibre.gui2 import choose_images, error_dialog from calibre.gui2.convert.metadata_ui import Ui_Form from calibre.ebooks.metadata import authors_to_string, string_to_authors, \ - MetaInformation, authors_to_sort_string + MetaInformation from calibre.ebooks.metadata.opf2 import metadata_to_opf from calibre.ptempfile import PersistentTemporaryFile from calibre.gui2.convert import Widget @@ -57,7 +57,7 @@ class MetadataWidget(Widget, Ui_Form): au = unicode(self.author.currentText()) au = re.sub(r'\s+et al\.$', '', au) authors = string_to_authors(au) - self.author_sort.setText(authors_to_sort_string(authors)) + self.author_sort.setText(self.db.author_sort_from_authors(authors)) def initialize_metadata_options(self): diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py index cf54e6c1f3..c8eb4c2403 100644 --- a/src/calibre/gui2/device.py +++ b/src/calibre/gui2/device.py @@ -23,7 +23,7 @@ from calibre.devices.scanner import DeviceScanner from calibre.gui2 import config, error_dialog, Dispatcher, dynamic, \ pixmap_to_data, warning_dialog, \ question_dialog, info_dialog, choose_dir -from calibre.ebooks.metadata import authors_to_string, authors_to_sort_string +from calibre.ebooks.metadata import authors_to_string from calibre import preferred_encoding, prints from calibre.utils.filenames import ascii_filename from calibre.devices.errors import FreeSpaceError @@ -1409,7 +1409,7 @@ class DeviceMixin(object): # {{{ # Set author_sort if it isn't already asort = getattr(book, 'author_sort', None) if not asort and book.authors: - book.author_sort = authors_to_sort_string(book.authors) + book.author_sort = self.db.author_sort_from_authors(book.authors) resend_metadata = True if resend_metadata: diff --git a/src/calibre/gui2/dialogs/metadata_bulk.py b/src/calibre/gui2/dialogs/metadata_bulk.py index eca7fe9c15..8b27ff1999 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.py +++ b/src/calibre/gui2/dialogs/metadata_bulk.py @@ -8,7 +8,7 @@ from PyQt4.QtGui import QDialog, QGridLayout from calibre.gui2.dialogs.metadata_bulk_ui import Ui_MetadataBulkDialog from calibre.gui2.dialogs.tag_editor import TagEditor -from calibre.ebooks.metadata import string_to_authors, authors_to_sort_string, \ +from calibre.ebooks.metadata import string_to_authors, \ authors_to_string from calibre.gui2.custom_column_widgets import populate_bulk_metadata_page @@ -110,10 +110,7 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): au = string_to_authors(au) self.db.set_authors(id, au, notify=False) if self.auto_author_sort.isChecked(): - aut = self.db.authors(id, index_is_id=True) - aut = aut if aut else '' - aut = [a.strip().replace('|', ',') for a in aut.strip().split(',')] - x = authors_to_sort_string(aut) + x = self.db.author_sort_from_book(id, index_is_id=True) if x: self.db.set_author_sort(id, x, notify=False) aus = unicode(self.author_sort.text()) diff --git a/src/calibre/gui2/dialogs/metadata_single.py b/src/calibre/gui2/dialogs/metadata_single.py index 0241e1b542..1543df458e 100644 --- a/src/calibre/gui2/dialogs/metadata_single.py +++ b/src/calibre/gui2/dialogs/metadata_single.py @@ -23,7 +23,7 @@ from calibre.gui2.dialogs.fetch_metadata import FetchMetadata from calibre.gui2.dialogs.tag_editor import TagEditor from calibre.gui2.widgets import ProgressIndicator from calibre.ebooks import BOOK_EXTENSIONS -from calibre.ebooks.metadata import authors_to_sort_string, string_to_authors, \ +from calibre.ebooks.metadata import string_to_authors, \ authors_to_string, check_isbn from calibre.ebooks.metadata.library_thing import cover_from_isbn from calibre import islinux, isfreebsd @@ -459,7 +459,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog): au = unicode(self.authors.text()) au = re.sub(r'\s+et al\.$', '', au) authors = string_to_authors(au) - self.author_sort.setText(authors_to_sort_string(authors)) + self.author_sort.setText(self.db.author_sort_from_authors(authors)) def swap_title_author(self): title = self.title.text() diff --git a/src/calibre/gui2/dialogs/sort_field_dialog.py b/src/calibre/gui2/dialogs/sort_field_dialog.py new file mode 100644 index 0000000000..d1c6d45ed3 --- /dev/null +++ b/src/calibre/gui2/dialogs/sort_field_dialog.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python +__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net' +__docformat__ = 'restructuredtext en' +__license__ = 'GPL v3' + +from PyQt4.Qt import QDialog +from calibre.gui2.dialogs.sort_field_dialog_ui import Ui_SortFieldDialog + +class SortFieldDialog(QDialog, Ui_SortFieldDialog): + + def __init__(self, parent, text): + QDialog.__init__(self, parent) + Ui_SortFieldDialog.__init__(self) + self.setupUi(self) + if text is not None: + self.textbox.setText(text) diff --git a/src/calibre/gui2/dialogs/sort_field_dialog.ui b/src/calibre/gui2/dialogs/sort_field_dialog.ui new file mode 100644 index 0000000000..3fc386d1ef --- /dev/null +++ b/src/calibre/gui2/dialogs/sort_field_dialog.ui @@ -0,0 +1,83 @@ + + + SortFieldDialog + + + + 0 + 0 + 334 + 135 + + + + + 0 + 0 + + + + Edit sort field + + + + + 10 + 10 + 311 + 111 + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + buttonBox + accepted() + SortFieldDialog + accept() + + + 229 + 211 + + + 157 + 234 + + + + + buttonBox + rejected() + SortFieldDialog + reject() + + + 297 + 217 + + + 286 + 234 + + + + + diff --git a/src/calibre/gui2/tag_view.py b/src/calibre/gui2/tag_view.py index 9919ef97a2..bae81c79cd 100644 --- a/src/calibre/gui2/tag_view.py +++ b/src/calibre/gui2/tag_view.py @@ -23,6 +23,7 @@ from calibre.utils.search_query_parser import saved_searches from calibre.gui2 import error_dialog from calibre.gui2.dialogs.tag_categories import TagCategories from calibre.gui2.dialogs.tag_list_editor import TagListEditor +from calibre.gui2.dialogs.sort_field_dialog import SortFieldDialog class TagDelegate(QItemDelegate): @@ -90,6 +91,7 @@ class TagsView(QTreeView): # {{{ user_category_edit = pyqtSignal(object) tag_list_edit = pyqtSignal(object, object) saved_search_edit = pyqtSignal(object) + author_sort_edit = pyqtSignal(object, object, object) tag_item_renamed = pyqtSignal() search_item_renamed = pyqtSignal() @@ -173,6 +175,9 @@ class TagsView(QTreeView): # {{{ if action == 'manage_searches': self.saved_search_edit.emit(category) return + if action == 'edit_author_sort': + self.author_sort_edit.emit(self, category, index) + return if action == 'hide': self.hidden_categories.add(category) elif action == 'show': @@ -193,6 +198,8 @@ class TagsView(QTreeView): # {{{ if item.type == TagTreeItem.TAG: tag_item = item tag_name = item.tag.name + tag_id = item.tag.id + tag_sort = item.tag.sort item = item.parent if item.type == TagTreeItem.CATEGORY: category = unicode(item.name.toString()) @@ -211,6 +218,10 @@ class TagsView(QTreeView): # {{{ self.context_menu.addAction(_('Rename') + " '" + tag_name + "'", partial(self.context_menu_handler, action='edit_item', category=tag_item, index=index)) + if key == 'authors': + self.context_menu.addAction(_('Edit sort for') + " '" + tag_name + "'", + partial(self.context_menu_handler, action='edit_author_sort', + category=tag_sort, index=tag_id)) self.context_menu.addSeparator() # Hide/Show/Restore categories self.context_menu.addAction(_('Hide category %s') % category, @@ -684,6 +695,7 @@ class TagBrowserMixin(object): # {{{ self.tags_view.tag_list_edit.connect(self.do_tags_list_edit) self.tags_view.user_category_edit.connect(self.do_user_categories_edit) self.tags_view.saved_search_edit.connect(self.do_saved_search_edit) + self.tags_view.author_sort_edit.connect(self.do_author_sort_edit) self.tags_view.tag_item_renamed.connect(self.do_tag_item_renamed) self.tags_view.search_item_renamed.connect(self.saved_search.clear_to_help) self.edit_categories.clicked.connect(lambda x: @@ -713,6 +725,15 @@ class TagBrowserMixin(object): # {{{ self.saved_search.clear_to_help() self.search.clear_to_help() + def do_author_sort_edit(self, parent, text, id): + editor = SortFieldDialog(parent, text) + d = editor.exec_() + if d: + print editor.textbox.text() + self.library_view.model().db.set_sort_field_for_author \ + (id, unicode(editor.textbox.text())) + self.tags_view.recount() + # }}} class TagBrowserWidget(QWidget): # {{{ diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index 939ab92f38..144b66b5e4 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -12,7 +12,7 @@ from math import floor from PyQt4.QtGui import QImage -from calibre.ebooks.metadata import title_sort +from calibre.ebooks.metadata import title_sort, author_to_author_sort from calibre.library.database import LibraryDatabase from calibre.library.field_metadata import FieldMetadata, TagsIcons from calibre.library.schema_upgrades import SchemaUpgrade @@ -20,7 +20,7 @@ from calibre.library.caches import ResultCache from calibre.library.custom_columns import CustomColumns from calibre.library.sqlite import connect, IntegrityError, DBThread from calibre.ebooks.metadata import string_to_authors, authors_to_string, \ - MetaInformation, authors_to_sort_string + MetaInformation from calibre.ebooks.metadata.meta import get_metadata, metadata_from_formats from calibre.constants import preferred_encoding, iswindows, isosx, filesystem_encoding from calibre.ptempfile import PersistentTemporaryFile @@ -56,12 +56,14 @@ copyfile = os.link if hasattr(os, 'link') else shutil.copyfile class Tag(object): - def __init__(self, name, id=None, count=0, state=0, avg=0, tooltip=None, icon=None): + def __init__(self, name, id=None, count=0, state=0, avg=0, sort=None, + tooltip=None, icon=None): self.name = name self.id = id self.count = count self.state = state self.avg_rating = avg/2.0 if avg is not None else 0 + self.sort = sort self.tooltip = tooltip self.icon = icon @@ -135,7 +137,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): id, name, (SELECT COUNT(books_tags_link.id) FROM books_tags_link WHERE tag=x.id) count, - (0) as avg_rating + (0) as avg_rating, + (null) as sort FROM tags as x WHERE name!="{0}" AND id IN (SELECT DISTINCT tag FROM books_tags_link WHERE book IN (SELECT DISTINCT book FROM books_tags_link WHERE tag IN @@ -147,7 +150,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): id, name, (SELECT COUNT(books_tags_link.id) FROM books_tags_link WHERE tag=x.id and books_list_filter(book)) count, - (0) as avg_rating + (0) as avg_rating, + (null) as sort FROM tags as x WHERE name!="{0}" AND id IN (SELECT DISTINCT tag FROM books_tags_link WHERE book IN (SELECT DISTINCT book FROM books_tags_link WHERE tag IN @@ -425,6 +429,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): if aum: aum = [a.strip().replace('|', ',') for a in aum.split(',')] mi = MetaInformation(self.title(idx, index_is_id=index_is_id), aum) mi.author_sort = self.author_sort(idx, index_is_id=index_is_id) + mi.authors_sort_strings = self.authors_sort_strings(idx, index_is_id) mi.comments = self.comments(idx, index_is_id=index_is_id) mi.publisher = self.publisher(idx, index_is_id=index_is_id) mi.timestamp = self.timestamp(idx, index_is_id=index_is_id) @@ -701,12 +706,16 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): continue cn = cat['column'] if ids is None: - query = 'SELECT id, {0}, count, avg_rating FROM tag_browser_{1}'.format(cn, tn) + query = '''SELECT id, {0}, count, avg_rating, sort + FROM tag_browser_{1}'''.format(cn, tn) else: - query = 'SELECT id, {0}, count, avg_rating FROM tag_browser_filtered_{1}'.format(cn, tn) + query = '''SELECT id, {0}, count, avg_rating + FROM tag_browser_filtered_{1}'''.format(cn, tn) if sort_on_count: query += ' ORDER BY count DESC' else: + if 'category_sort' in cat: + cn = cat['category_sort'] query += ' ORDER BY {0} ASC'.format(cn) data = self.conn.get(query) @@ -736,7 +745,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): formatter = (lambda x:unicode(x)) categories[category] = [Tag(formatter(r[1]), count=r[2], id=r[0], - avg=r[3], icon=icon, tooltip=tooltip) + avg=r[3], sort=r[4], + icon=icon, tooltip=tooltip) for r in data if item_not_zero_func(r)] if category == 'series' and not sort_on_count: if tweaks['title_series_sorting'] == 'library_order': @@ -912,6 +922,38 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): self.set_path(id, True) self.notify('metadata', [id]) + # Given a book, return the list of author sort strings for the book's authors + def authors_sort_strings(self, id, index_is_id=False): + id = id if index_is_id else self.id(id) + aut_strings = self.conn.get(''' + SELECT sort + FROM authors, books_authors_link as bl + WHERE bl.book=? and authors.id=bl.author + ORDER BY bl.id''', (id,)) + result = [] + for (sort,) in aut_strings: + result.append(sort) + return result + + # Given a book, return the author_sort string for authors of the book + def author_sort_from_book(self, id, index_is_id=False): + auts = self.authors_sort_strings(id, index_is_id) + return ' & '.join(auts).replace('|', ',') + + # Given a list of authors, return the author_sort string for the authors, + # preferring the author sort associated with the author over the computed + # string + def author_sort_from_authors(self, authors): + result = [] + for aut in authors: + aut = aut.replace(',', '|') + r = self.conn.get('SELECT sort FROM authors WHERE name=?', (aut,), all=False) + if r is None: + result.append(author_to_author_sort(aut)) + else: + result.append(r) + return ' & '.join(result).replace('|', ',') + def set_authors(self, id, authors, notify=True): ''' `authors`: A list of authors. @@ -938,7 +980,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): (id, aid)) except IntegrityError: # Sometimes books specify the same author twice in their metadata pass - ss = authors_to_sort_string(authors) + self.conn.commit() + ss = self.author_sort_from_book(id, index_is_id=True) self.conn.execute('UPDATE books SET author_sort=? WHERE id=?', (ss, id)) self.conn.commit() @@ -1117,7 +1160,13 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): self.conn.commit() # There is no editor for author, so we do not need get_authors_with_ids or - # delete_author_using_id. + # delete_author_using_id. However, we can change the author's sort field, so + # we provide that setter + + def set_sort_field_for_author(self, old_id, new_sort): + self.conn.execute('UPDATE authors SET sort=? WHERE id=?', \ + (new_sort, old_id)) + self.conn.commit() def rename_author(self, old_id, new_name): # Make sure that any commas in new_name are changed to '|'! @@ -1187,22 +1236,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): # now fix the filesystem paths self.set_path(book_id, index_is_id=True) # Next fix the author sort. Reset it to the default - authors = self.conn.get(''' - SELECT authors.name - FROM authors, books_authors_link as bl - WHERE bl.book = ? and bl.author = authors.id - ORDER BY bl.id - ''' , (book_id,)) - # unpack the double-list structure - for i,aut in enumerate(authors): - authors[i] = aut[0] - ss = authors_to_sort_string(authors) - # Change the '|'s to ',' - ss = ss.replace('|', ',') - self.conn.execute('''UPDATE books - SET author_sort=? - WHERE id=?''', (ss, book_id)) - self.conn.commit() + ss = self.author_sort_from_book(book_id, index_is_id=True) + self.set_author_sort(book_id, ss) # the caller will do a general refresh, so we don't need to # do one here @@ -1439,7 +1474,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): if not add_duplicates and self.has_book(mi): return None series_index = 1.0 if mi.series_index is None else mi.series_index - aus = mi.author_sort if mi.author_sort else ', '.join(mi.authors) + aus = mi.author_sort if mi.author_sort else self.author_sort_from_authors(mi.authors) title = mi.title if isinstance(aus, str): aus = aus.decode(preferred_encoding, 'replace') @@ -1479,7 +1514,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): duplicates.append((path, format, mi)) continue series_index = 1.0 if mi.series_index is None else mi.series_index - aus = mi.author_sort if mi.author_sort else ', '.join(mi.authors) + aus = mi.author_sort if mi.author_sort else self.author_sort_from_authors(mi.authors) title = mi.title if isinstance(aus, str): aus = aus.decode(preferred_encoding, 'replace') @@ -1518,7 +1553,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): mi.title = _('Unknown') if not mi.authors: mi.authors = [_('Unknown')] - aus = mi.author_sort if mi.author_sort else authors_to_sort_string(mi.authors) + aus = mi.author_sort if mi.author_sort else self.author_sort_from_authors(mi.authors) if isinstance(aus, str): aus = aus.decode(preferred_encoding, 'replace') title = mi.title if isinstance(mi.title, unicode) else \ diff --git a/src/calibre/library/field_metadata.py b/src/calibre/library/field_metadata.py index 82e4edfdf2..535893b24c 100644 --- a/src/calibre/library/field_metadata.py +++ b/src/calibre/library/field_metadata.py @@ -72,7 +72,8 @@ class FieldMetadata(dict): 'name':_('Authors'), 'search_terms':['authors', 'author'], 'is_custom':False, - 'is_category':True}), + 'is_category':True, + 'category_sort':'sort'}), ('series', {'table':'series', 'column':'name', 'link_column':'series', diff --git a/src/calibre/library/schema_upgrades.py b/src/calibre/library/schema_upgrades.py index 870254f999..5763cbad70 100644 --- a/src/calibre/library/schema_upgrades.py +++ b/src/calibre/library/schema_upgrades.py @@ -295,7 +295,8 @@ class SchemaUpgrade(object): def upgrade_version_11(self): 'Add average rating to tag browser views' - def create_std_tag_browser_view(table_name, column_name, view_column_name): + def create_std_tag_browser_view(table_name, column_name, + view_column_name, sort_column_name): script = (''' DROP VIEW IF EXISTS tag_browser_{tn}; CREATE VIEW tag_browser_{tn} AS SELECT @@ -305,22 +306,25 @@ class SchemaUpgrade(object): (SELECT AVG(ratings.rating) FROM books_{tn}_link as tl, books_ratings_link as bl, ratings WHERE tl.{cn}={tn}.id and bl.book=tl.book and - ratings.id = bl.rating and ratings.rating <> 0) avg_rating + ratings.id = bl.rating and ratings.rating <> 0) avg_rating, + {scn} as sort FROM {tn}; DROP VIEW IF EXISTS tag_browser_filtered_{tn}; CREATE VIEW tag_browser_filtered_{tn} AS SELECT id, - {vcn}, + {vcn} as sort, (SELECT COUNT(books_{tn}_link.id) FROM books_{tn}_link WHERE {cn}={tn}.id AND books_list_filter(book)) count, (SELECT AVG(ratings.rating) FROM books_{tn}_link as tl, books_ratings_link as bl, ratings WHERE tl.{cn}={tn}.id and bl.book=tl.book and ratings.id = bl.rating and ratings.rating <> 0 AND - books_list_filter(bl.book)) avg_rating + books_list_filter(bl.book)) avg_rating, + {scn} as sort FROM {tn}; - '''.format(tn=table_name, cn=column_name, vcn=view_column_name)) + '''.format(tn=table_name, cn=column_name, + vcn=view_column_name, scn= sort_column_name)) self.conn.executescript(script) def create_cust_tag_browser_view(table_name, link_table_name): @@ -335,7 +339,8 @@ class SchemaUpgrade(object): books_ratings_link as bl, ratings as r WHERE {lt}.value={table}.id and bl.book={lt}.book and - r.id = bl.rating and r.rating <> 0) avg_rating + r.id = bl.rating and r.rating <> 0) avg_rating, + value as sort FROM {table}; DROP VIEW IF EXISTS tag_browser_filtered_{table}; @@ -350,20 +355,21 @@ class SchemaUpgrade(object): ratings as r WHERE {lt}.value={table}.id AND bl.book={lt}.book AND r.id = bl.rating AND r.rating <> 0 AND - books_list_filter(bl.book)) avg_rating + books_list_filter(bl.book)) avg_rating, + value as sort FROM {table}; '''.format(lt=link_table_name, table=table_name) self.conn.executescript(script) STANDARD_TAG_BROWSER_TABLES = [ - ('authors', 'author', 'name'), - ('publishers', 'publisher', 'name'), - ('ratings', 'rating', 'rating'), - ('series', 'series', 'name'), - ('tags', 'tag', 'name'), + ('authors', 'author', 'name', 'sort'), + ('publishers', 'publisher', 'name', 'name'), + ('ratings', 'rating', 'rating', 'rating'), + ('series', 'series', 'name', 'name'), + ('tags', 'tag', 'name', 'name'), ] - for table, column, view_column in STANDARD_TAG_BROWSER_TABLES: - create_std_tag_browser_view(table, column, view_column) + for table, column, view_column, sort_column in STANDARD_TAG_BROWSER_TABLES: + create_std_tag_browser_view(table, column, view_column, sort_column) db_tables = self.conn.get('''SELECT name FROM sqlite_master WHERE type='table' @@ -374,5 +380,28 @@ class SchemaUpgrade(object): for table in tables: link_table = 'books_%s_link'%table if table.startswith('custom_column_') and link_table in tables: - print table - create_cust_tag_browser_view(table, link_table) \ No newline at end of file + create_cust_tag_browser_view(table, link_table) + + from calibre.ebooks.metadata import author_to_author_sort + + aut = self.conn.get('SELECT id, name FROM authors'); + records = [] + for (id, author) in aut: + records.append((id, author.replace('|', ','))) + for id,author in records: + self.conn.execute('UPDATE authors SET sort=? WHERE id=?', + (author_to_author_sort(author.replace('|', ',')).strip(), id)) + self.conn.commit() + self.conn.executescript(''' + CREATE TRIGGER author_insert_trg + AFTER INSERT ON authors + BEGIN + UPDATE authors SET sort=author_to_author_sort(NEW.name) WHERE id=NEW.id; + END; + CREATE TRIGGER author_update_trg + BEFORE UPDATE ON authors + BEGIN + UPDATE authors SET sort=author_to_author_sort(NEW.name) + WHERE id=NEW.id and name <> NEW.name; + END; + ''') \ No newline at end of file diff --git a/src/calibre/library/sqlite.py b/src/calibre/library/sqlite.py index adf6691671..9aab71ab79 100644 --- a/src/calibre/library/sqlite.py +++ b/src/calibre/library/sqlite.py @@ -14,7 +14,7 @@ from Queue import Queue from threading import RLock from datetime import datetime -from calibre.ebooks.metadata import title_sort +from calibre.ebooks.metadata import title_sort, author_to_author_sort from calibre.utils.config import tweaks from calibre.utils.date import parse_date, isoformat @@ -120,6 +120,8 @@ class DBThread(Thread): self.conn.create_function('title_sort', 1, title_sort) else: self.conn.create_function('title_sort', 1, lambda x:x) + self.conn.create_function('author_to_author_sort', 1, + lambda x: author_to_author_sort(x.replace('|', ','))) self.conn.create_function('uuid4', 0, lambda : str(uuid.uuid4())) # Dummy functions for dynamically created filters self.conn.create_function('books_list_filter', 1, lambda x: 1)