mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Author link first try
This commit is contained in:
parent
52edcbe991
commit
034e289ef3
@ -86,6 +86,8 @@ CALIBRE_METADATA_FIELDS = frozenset([
|
|||||||
# a dict of user category names, where the value is a list of item names
|
# a dict of user category names, where the value is a list of item names
|
||||||
# from the book that are in that category
|
# from the book that are in that category
|
||||||
'user_categories',
|
'user_categories',
|
||||||
|
# a dict of author to an associated hyperlink
|
||||||
|
'author_link_map',
|
||||||
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
@ -34,6 +34,7 @@ NULL_VALUES = {
|
|||||||
'authors' : [_('Unknown')],
|
'authors' : [_('Unknown')],
|
||||||
'title' : _('Unknown'),
|
'title' : _('Unknown'),
|
||||||
'user_categories' : {},
|
'user_categories' : {},
|
||||||
|
'author_link_map' : {},
|
||||||
'language' : 'und'
|
'language' : 'und'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -538,7 +538,8 @@ class OPF(object): # {{{
|
|||||||
user_categories = MetadataField('user_categories', is_dc=False,
|
user_categories = MetadataField('user_categories', is_dc=False,
|
||||||
formatter=json.loads,
|
formatter=json.loads,
|
||||||
renderer=dump_user_categories)
|
renderer=dump_user_categories)
|
||||||
|
author_link_map = MetadataField('author_link_map', is_dc=False,
|
||||||
|
formatter=json.loads)
|
||||||
|
|
||||||
def __init__(self, stream, basedir=os.getcwdu(), unquote_urls=True,
|
def __init__(self, stream, basedir=os.getcwdu(), unquote_urls=True,
|
||||||
populate_spine=True):
|
populate_spine=True):
|
||||||
@ -1039,7 +1040,7 @@ class OPF(object): # {{{
|
|||||||
for attr in ('title', 'authors', 'author_sort', 'title_sort',
|
for attr in ('title', 'authors', 'author_sort', 'title_sort',
|
||||||
'publisher', 'series', 'series_index', 'rating',
|
'publisher', 'series', 'series_index', 'rating',
|
||||||
'isbn', 'tags', 'category', 'comments',
|
'isbn', 'tags', 'category', 'comments',
|
||||||
'pubdate', 'user_categories'):
|
'pubdate', 'user_categories', 'author_link_map'):
|
||||||
val = getattr(mi, attr, None)
|
val = getattr(mi, attr, None)
|
||||||
if val is not None and val != [] and val != (None, None):
|
if val is not None and val != [] and val != (None, None):
|
||||||
setattr(self, attr, val)
|
setattr(self, attr, val)
|
||||||
@ -1336,6 +1337,8 @@ def metadata_to_opf(mi, as_string=True):
|
|||||||
for tag in mi.tags:
|
for tag in mi.tags:
|
||||||
factory(DC('subject'), tag)
|
factory(DC('subject'), tag)
|
||||||
meta = lambda n, c: factory('meta', name='calibre:'+n, content=c)
|
meta = lambda n, c: factory('meta', name='calibre:'+n, content=c)
|
||||||
|
if getattr(mi, 'author_link_map', None) is not None:
|
||||||
|
meta('author_link_map', json.dumps(mi.author_link_map))
|
||||||
if mi.series:
|
if mi.series:
|
||||||
meta('series', mi.series)
|
meta('series', mi.series)
|
||||||
if mi.series_index is not None:
|
if mi.series_index is not None:
|
||||||
|
@ -121,6 +121,16 @@ def render_data(mi, use_roman_numbers=True, all_fields=False):
|
|||||||
if links:
|
if links:
|
||||||
ans.append((field, u'<td class="title">%s</td><td>%s</td>'%(
|
ans.append((field, u'<td class="title">%s</td><td>%s</td>'%(
|
||||||
_('Ids')+':', links)))
|
_('Ids')+':', links)))
|
||||||
|
elif field == 'authors' and not isdevice:
|
||||||
|
authors = []
|
||||||
|
for aut in mi.authors:
|
||||||
|
if mi.author_link_map[aut]:
|
||||||
|
authors.append(u'<a href="%s">%s</a>' %
|
||||||
|
(mi.author_link_map[aut], aut))
|
||||||
|
else:
|
||||||
|
authors.append(aut)
|
||||||
|
ans.append((field, u'<td class="title">%s</td><td>%s</td>'%(name,
|
||||||
|
u' & '.join(authors))))
|
||||||
else:
|
else:
|
||||||
val = mi.format_field(field)[-1]
|
val = mi.format_field(field)[-1]
|
||||||
if val is None:
|
if val is None:
|
||||||
|
@ -33,7 +33,7 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
|
|||||||
|
|
||||||
# Set up the column headings
|
# Set up the column headings
|
||||||
self.table.setSelectionMode(QAbstractItemView.SingleSelection)
|
self.table.setSelectionMode(QAbstractItemView.SingleSelection)
|
||||||
self.table.setColumnCount(2)
|
self.table.setColumnCount(3)
|
||||||
self.down_arrow_icon = QIcon(I('arrow-down.png'))
|
self.down_arrow_icon = QIcon(I('arrow-down.png'))
|
||||||
self.up_arrow_icon = QIcon(I('arrow-up.png'))
|
self.up_arrow_icon = QIcon(I('arrow-up.png'))
|
||||||
self.blank_icon = QIcon(I('blank.png'))
|
self.blank_icon = QIcon(I('blank.png'))
|
||||||
@ -43,26 +43,33 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
|
|||||||
self.aus_col = QTableWidgetItem(_('Author sort'))
|
self.aus_col = QTableWidgetItem(_('Author sort'))
|
||||||
self.table.setHorizontalHeaderItem(1, self.aus_col)
|
self.table.setHorizontalHeaderItem(1, self.aus_col)
|
||||||
self.aus_col.setIcon(self.up_arrow_icon)
|
self.aus_col.setIcon(self.up_arrow_icon)
|
||||||
|
self.aul_col = QTableWidgetItem(_('Link'))
|
||||||
|
self.table.setHorizontalHeaderItem(2, self.aul_col)
|
||||||
|
self.aus_col.setIcon(self.blank_icon)
|
||||||
|
|
||||||
# Add the data
|
# Add the data
|
||||||
self.authors = {}
|
self.authors = {}
|
||||||
auts = db.get_authors_with_ids()
|
auts = db.get_authors_with_ids()
|
||||||
self.table.setRowCount(len(auts))
|
self.table.setRowCount(len(auts))
|
||||||
select_item = None
|
select_item = None
|
||||||
for row, (id, author, sort) in enumerate(auts):
|
for row, (id, author, sort, link) in enumerate(auts):
|
||||||
author = author.replace('|', ',')
|
author = author.replace('|', ',')
|
||||||
self.authors[id] = (author, sort)
|
self.authors[id] = (author, sort, link)
|
||||||
aut = tableItem(author)
|
aut = tableItem(author)
|
||||||
aut.setData(Qt.UserRole, id)
|
aut.setData(Qt.UserRole, id)
|
||||||
sort = tableItem(sort)
|
sort = tableItem(sort)
|
||||||
|
link = tableItem(link)
|
||||||
self.table.setItem(row, 0, aut)
|
self.table.setItem(row, 0, aut)
|
||||||
self.table.setItem(row, 1, sort)
|
self.table.setItem(row, 1, sort)
|
||||||
|
self.table.setItem(row, 2, link)
|
||||||
if id == id_to_select:
|
if id == id_to_select:
|
||||||
if select_sort:
|
if select_sort:
|
||||||
select_item = sort
|
select_item = sort
|
||||||
else:
|
else:
|
||||||
select_item = aut
|
select_item = aut
|
||||||
self.table.resizeColumnsToContents()
|
self.table.resizeColumnsToContents()
|
||||||
|
if self.table.columnWidth(2) < 200:
|
||||||
|
self.table.setColumnWidth(2, 200)
|
||||||
|
|
||||||
# set up the cellChanged signal only after the table is filled
|
# set up the cellChanged signal only after the table is filled
|
||||||
self.table.cellChanged.connect(self.cell_changed)
|
self.table.cellChanged.connect(self.cell_changed)
|
||||||
@ -236,9 +243,10 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
|
|||||||
id = self.table.item(row, 0).data(Qt.UserRole).toInt()[0]
|
id = self.table.item(row, 0).data(Qt.UserRole).toInt()[0]
|
||||||
aut = unicode(self.table.item(row, 0).text()).strip()
|
aut = unicode(self.table.item(row, 0).text()).strip()
|
||||||
sort = unicode(self.table.item(row, 1).text()).strip()
|
sort = unicode(self.table.item(row, 1).text()).strip()
|
||||||
orig_aut,orig_sort = self.authors[id]
|
link = unicode(self.table.item(row, 2).text()).strip()
|
||||||
if orig_aut != aut or orig_sort != sort:
|
orig_aut,orig_sort,orig_link = self.authors[id]
|
||||||
self.result.append((id, orig_aut, aut, sort))
|
if orig_aut != aut or orig_sort != sort or orig_link != link:
|
||||||
|
self.result.append((id, orig_aut, aut, sort, link))
|
||||||
|
|
||||||
def do_recalc_author_sort(self):
|
def do_recalc_author_sort(self):
|
||||||
self.table.cellChanged.disconnect()
|
self.table.cellChanged.disconnect()
|
||||||
@ -276,6 +284,6 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
|
|||||||
c.setText(author_to_author_sort(aut))
|
c.setText(author_to_author_sort(aut))
|
||||||
item = c
|
item = c
|
||||||
else:
|
else:
|
||||||
item = self.table.item(row, 1)
|
item = self.table.item(row, col)
|
||||||
self.table.setCurrentItem(item)
|
self.table.setCurrentItem(item)
|
||||||
self.table.scrollToItem(item)
|
self.table.scrollToItem(item)
|
||||||
|
@ -90,6 +90,7 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
self.ids_to_highlight_set = set()
|
self.ids_to_highlight_set = set()
|
||||||
self.current_highlighted_idx = None
|
self.current_highlighted_idx = None
|
||||||
self.highlight_only = False
|
self.highlight_only = False
|
||||||
|
self.current_row = -1
|
||||||
self.colors = frozenset([unicode(c) for c in QColor.colorNames()])
|
self.colors = frozenset([unicode(c) for c in QColor.colorNames()])
|
||||||
self.read_config()
|
self.read_config()
|
||||||
|
|
||||||
@ -172,6 +173,7 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
self.color_cache = defaultdict(dict)
|
self.color_cache = defaultdict(dict)
|
||||||
for row in rows:
|
for row in rows:
|
||||||
if row == current_row:
|
if row == current_row:
|
||||||
|
self.current_row = row
|
||||||
self.new_bookdisplay_data.emit(
|
self.new_bookdisplay_data.emit(
|
||||||
self.get_book_display_info(row))
|
self.get_book_display_info(row))
|
||||||
self.dataChanged.emit(self.index(row, 0), self.index(row,
|
self.dataChanged.emit(self.index(row, 0), self.index(row,
|
||||||
@ -329,6 +331,8 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
def refresh(self, reset=True):
|
def refresh(self, reset=True):
|
||||||
self.db.refresh(field=None)
|
self.db.refresh(field=None)
|
||||||
self.resort(reset=reset)
|
self.resort(reset=reset)
|
||||||
|
if self.current_row >= 0:
|
||||||
|
self.new_bookdisplay_data.emit(self.get_book_display_info(self.current_row))
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
self.color_cache = defaultdict(dict)
|
self.color_cache = defaultdict(dict)
|
||||||
@ -368,12 +372,14 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
|
|
||||||
def current_changed(self, current, previous, emit_signal=True):
|
def current_changed(self, current, previous, emit_signal=True):
|
||||||
if current.isValid():
|
if current.isValid():
|
||||||
idx = current.row()
|
self.current_row = idx = current.row()
|
||||||
data = self.get_book_display_info(idx)
|
data = self.get_book_display_info(idx)
|
||||||
if emit_signal:
|
if emit_signal:
|
||||||
self.new_bookdisplay_data.emit(data)
|
self.new_bookdisplay_data.emit(data)
|
||||||
else:
|
else:
|
||||||
return data
|
return data
|
||||||
|
else:
|
||||||
|
self.current_row = -1
|
||||||
|
|
||||||
def get_book_info(self, index):
|
def get_book_info(self, index):
|
||||||
if isinstance(index, int):
|
if isinstance(index, int):
|
||||||
|
@ -2081,12 +2081,14 @@ class TagBrowserMixin(object): # {{{
|
|||||||
editor = EditAuthorsDialog(parent, db, id, select_sort)
|
editor = EditAuthorsDialog(parent, db, id, select_sort)
|
||||||
d = editor.exec_()
|
d = editor.exec_()
|
||||||
if d:
|
if d:
|
||||||
for (id, old_author, new_author, new_sort) in editor.result:
|
for (id, old_author, new_author, new_sort, new_link) in editor.result:
|
||||||
if old_author != new_author:
|
if old_author != new_author:
|
||||||
# The id might change if the new author already exists
|
# The id might change if the new author already exists
|
||||||
id = db.rename_author(id, new_author)
|
id = db.rename_author(id, new_author)
|
||||||
db.set_sort_field_for_author(id, unicode(new_sort),
|
db.set_sort_field_for_author(id, unicode(new_sort),
|
||||||
commit=False, notify=False)
|
commit=False, notify=False)
|
||||||
|
db.set_link_field_for_author(id, unicode(new_link),
|
||||||
|
commit=False, notify=False)
|
||||||
db.commit()
|
db.commit()
|
||||||
self.library_view.model().refresh()
|
self.library_view.model().refresh()
|
||||||
self.tags_view.recount()
|
self.tags_view.recount()
|
||||||
|
@ -367,7 +367,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
'uuid',
|
'uuid',
|
||||||
'has_cover',
|
'has_cover',
|
||||||
('au_map', 'authors', 'author',
|
('au_map', 'authors', 'author',
|
||||||
'aum_sortconcat(link.id, authors.name, authors.sort)'),
|
'aum_sortconcat(link.id, authors.name, authors.sort, authors.link)'),
|
||||||
'last_modified',
|
'last_modified',
|
||||||
'(SELECT identifiers_concat(type, val) FROM identifiers WHERE identifiers.book=books.id) identifiers',
|
'(SELECT identifiers_concat(type, val) FROM identifiers WHERE identifiers.book=books.id) identifiers',
|
||||||
]
|
]
|
||||||
@ -894,13 +894,17 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
aut_list = []
|
aut_list = []
|
||||||
aum = []
|
aum = []
|
||||||
aus = {}
|
aus = {}
|
||||||
for (author, author_sort) in aut_list:
|
aul = {}
|
||||||
aum.append(author.replace('|', ','))
|
for (author, author_sort, link) in aut_list:
|
||||||
aus[author] = author_sort.replace('|', ',')
|
aut = author.replace('|', ',')
|
||||||
|
aum.append(aut)
|
||||||
|
aus[aut] = author_sort.replace('|', ',')
|
||||||
|
aul[aut] = link
|
||||||
mi.title = row[fm['title']]
|
mi.title = row[fm['title']]
|
||||||
mi.authors = aum
|
mi.authors = aum
|
||||||
mi.author_sort = row[fm['author_sort']]
|
mi.author_sort = row[fm['author_sort']]
|
||||||
mi.author_sort_map = aus
|
mi.author_sort_map = aus
|
||||||
|
mi.author_link_map = aul
|
||||||
mi.comments = row[fm['comments']]
|
mi.comments = row[fm['comments']]
|
||||||
mi.publisher = row[fm['publisher']]
|
mi.publisher = row[fm['publisher']]
|
||||||
mi.timestamp = row[fm['timestamp']]
|
mi.timestamp = row[fm['timestamp']]
|
||||||
@ -2002,13 +2006,13 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
def authors_with_sort_strings(self, id, index_is_id=False):
|
def authors_with_sort_strings(self, id, index_is_id=False):
|
||||||
id = id if index_is_id else self.id(id)
|
id = id if index_is_id else self.id(id)
|
||||||
aut_strings = self.conn.get('''
|
aut_strings = self.conn.get('''
|
||||||
SELECT authors.id, authors.name, authors.sort
|
SELECT authors.id, authors.name, authors.sort, authors.link
|
||||||
FROM authors, books_authors_link as bl
|
FROM authors, books_authors_link as bl
|
||||||
WHERE bl.book=? and authors.id=bl.author
|
WHERE bl.book=? and authors.id=bl.author
|
||||||
ORDER BY bl.id''', (id,))
|
ORDER BY bl.id''', (id,))
|
||||||
result = []
|
result = []
|
||||||
for (id_, author, sort,) in aut_strings:
|
for (id_, author, sort, link) in aut_strings:
|
||||||
result.append((id_, author.replace('|', ','), sort))
|
result.append((id_, author.replace('|', ','), sort, link))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
# Given a book, return the author_sort string for authors of the book
|
# Given a book, return the author_sort string for authors of the book
|
||||||
@ -2048,7 +2052,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
|
|
||||||
aum = self.authors_with_sort_strings(id_, index_is_id=True)
|
aum = self.authors_with_sort_strings(id_, index_is_id=True)
|
||||||
self.data.set(id_, self.FIELD_MAP['au_map'],
|
self.data.set(id_, self.FIELD_MAP['au_map'],
|
||||||
':#:'.join([':::'.join((au.replace(',', '|'), aus)) for (_, au, aus) in aum]),
|
':#:'.join([':::'.join((au.replace(',', '|'), aus, aul))
|
||||||
|
for (_, au, aus, aul) in aum]),
|
||||||
row_is_id=True)
|
row_is_id=True)
|
||||||
|
|
||||||
def _set_authors(self, id, authors, allow_case_change=False):
|
def _set_authors(self, id, authors, allow_case_change=False):
|
||||||
@ -2399,7 +2404,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
self.conn.commit()
|
self.conn.commit()
|
||||||
|
|
||||||
def get_authors_with_ids(self):
|
def get_authors_with_ids(self):
|
||||||
result = self.conn.get('SELECT id,name,sort FROM authors')
|
result = self.conn.get('SELECT id,name,sort,link FROM authors')
|
||||||
if not result:
|
if not result:
|
||||||
return []
|
return []
|
||||||
return result
|
return result
|
||||||
@ -2410,6 +2415,13 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
(author,), all=False)
|
(author,), all=False)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def set_link_field_for_author(self, aid, link, commit=True, notify=False):
|
||||||
|
if not link:
|
||||||
|
link = ''
|
||||||
|
self.conn.execute('UPDATE authors SET link=? WHERE id=?', (link.strip(), aid))
|
||||||
|
if commit:
|
||||||
|
self.conn.commit()
|
||||||
|
|
||||||
def set_sort_field_for_author(self, old_id, new_sort, commit=True, notify=False):
|
def set_sort_field_for_author(self, old_id, new_sort, commit=True, notify=False):
|
||||||
self.conn.execute('UPDATE authors SET sort=? WHERE id=?', \
|
self.conn.execute('UPDATE authors SET sort=? WHERE id=?', \
|
||||||
(new_sort.strip(), old_id))
|
(new_sort.strip(), old_id))
|
||||||
|
@ -600,4 +600,14 @@ class SchemaUpgrade(object):
|
|||||||
with open(os.path.join(bdir, fname), 'wb') as f:
|
with open(os.path.join(bdir, fname), 'wb') as f:
|
||||||
f.write(script)
|
f.write(script)
|
||||||
|
|
||||||
|
def upgrade_version_20(self):
|
||||||
|
'''
|
||||||
|
Add a link column to the authors table.
|
||||||
|
'''
|
||||||
|
|
||||||
|
script = '''
|
||||||
|
ALTER TABLE authors ADD COLUMN link TEXT NON NULL DEFAULT "";
|
||||||
|
'''
|
||||||
|
self.conn.executescript(script)
|
||||||
|
|
||||||
|
|
||||||
|
@ -144,9 +144,9 @@ class AumSortedConcatenate(object):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.ans = {}
|
self.ans = {}
|
||||||
|
|
||||||
def step(self, ndx, author, sort):
|
def step(self, ndx, author, sort, link):
|
||||||
if author is not None:
|
if author is not None:
|
||||||
self.ans[ndx] = author + ':::' + sort
|
self.ans[ndx] = ':::'.join((author, sort, link))
|
||||||
|
|
||||||
def finalize(self):
|
def finalize(self):
|
||||||
keys = self.ans.keys()
|
keys = self.ans.keys()
|
||||||
@ -229,7 +229,7 @@ class DBThread(Thread):
|
|||||||
load_c_extensions(self.conn)
|
load_c_extensions(self.conn)
|
||||||
self.conn.row_factory = sqlite.Row if self.row_factory else lambda cursor, row : list(row)
|
self.conn.row_factory = sqlite.Row if self.row_factory else lambda cursor, row : list(row)
|
||||||
self.conn.create_aggregate('concat', 1, Concatenate)
|
self.conn.create_aggregate('concat', 1, Concatenate)
|
||||||
self.conn.create_aggregate('aum_sortconcat', 3, AumSortedConcatenate)
|
self.conn.create_aggregate('aum_sortconcat', 4, AumSortedConcatenate)
|
||||||
self.conn.create_collation('PYNOCASE', partial(pynocase,
|
self.conn.create_collation('PYNOCASE', partial(pynocase,
|
||||||
encoding=encoding))
|
encoding=encoding))
|
||||||
self.conn.create_function('title_sort', 1, title_sort)
|
self.conn.create_function('title_sort', 1, title_sort)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user