Implement #1068 (Multiple authors vs. Standards)

This commit is contained in:
Kovid Goyal 2008-10-05 20:00:02 -07:00
parent 0d8425469e
commit 206da41869
12 changed files with 74 additions and 36 deletions

View File

@ -15,6 +15,24 @@ from calibre.constants import __version__ as VERSION
from calibre import relpath
from calibre.utils.config import OptionParser
def string_to_authors(raw):
raw = raw.replace('&&', u'\uffff')
authors = [a.strip().replace(u'\uffff', '&') for a in raw.split('&')]
return authors
def authors_to_string(authors):
return ' & '.join([a.replace('&', '&&') for a in authors])
def author_to_author_sort(author):
tokens = author.split()
tokens = tokens[-1:] + tokens[:-1]
if len(tokens) > 1:
tokens[0] += ','
return ' '.join(tokens)
def authors_to_sort_string(authors):
return ' & '.join(map(author_to_author_sort, authors))
def get_parser(extension):
''' Return an option parser with the basic metadata options already setup'''
parser = OptionParser(usage='%prog [options] myfile.'+extension+'\n\nRead and write metadata from an ebook file.')

View File

@ -7,8 +7,10 @@ __docformat__ = 'restructuredtext en'
The GUI for conversion to EPUB.
'''
import os
from PyQt4.Qt import QDialog, QSpinBox, QDoubleSpinBox, QComboBox, QLineEdit, \
QTextEdit, QCheckBox, Qt, QPixmap, QIcon, QListWidgetItem, SIGNAL
from lxml.etree import XPath
from calibre.gui2.dialogs.choose_format import ChooseFormatDialog
from calibre.gui2.dialogs.epub_ui import Ui_Dialog
@ -17,7 +19,8 @@ from calibre.ebooks.epub.from_any import SOURCE_FORMATS, config
from calibre.ebooks.metadata import MetaInformation
from calibre.ptempfile import PersistentTemporaryFile
from calibre.ebooks.metadata.opf import OPFCreator
from lxml.etree import XPath
from calibre.ebooks.metadata import authors_to_string, string_to_authors
class Config(QDialog, Ui_Dialog):
@ -128,7 +131,10 @@ class Config(QDialog, Ui_Dialog):
if self.row is not None:
mi = self.db.get_metadata(self.id, index_is_id=True)
self.title.setText(mi.title)
self.author.setText(', '.join(mi.authors))
if mi.authors:
self.author.setText(authors_to_string(mi.authors))
else:
self.author.setText('')
self.publisher.setText(mi.publisher if mi.publisher else '')
self.author_sort.setText(mi.author_sort if mi.author_sort else '')
self.tags.setText(', '.join(mi.tags if mi.tags else []))
@ -149,9 +155,8 @@ class Config(QDialog, Ui_Dialog):
title = unicode(self.title.text()).strip()
if not title:
title = _('Unknown')
authors = [i.strip() for i in unicode(self.author.text()).strip().split(',')]
if not authors:
authors = [_('Unknown')]
authors = unicode(self.author.text()).strip()
authors = string_to_authors(authors) if authors else [_('Unknown')]
return title, authors
def get_metadata(self):

View File

@ -77,7 +77,7 @@
<item>
<widget class="QStackedWidget" name="stack" >
<property name="currentIndex" >
<number>3</number>
<number>0</number>
</property>
<widget class="QWidget" name="metadata_page" >
<layout class="QGridLayout" name="gridLayout_4" >
@ -221,7 +221,7 @@
</sizepolicy>
</property>
<property name="toolTip" >
<string>Change the author(s) of this book. Multiple authors should be separated by a comma</string>
<string>Change the author(s) of this book. Multiple authors should be separated by an &amp;. If the author name contains an &amp;, use &amp;&amp; to represent it.</string>
</property>
</widget>
</item>

View File

@ -14,6 +14,7 @@ from calibre.gui2.widgets import FontFamilyModel
from calibre.ebooks.lrf import option_parser
from calibre.ptempfile import PersistentTemporaryFile
from calibre.constants import __appname__
from calibre.ebooks.metadata import authors_to_string, string_to_authors, authors_to_sort_string
font_family_model = None
@ -199,7 +200,11 @@ class LRFSingleDialog(QDialog, Ui_LRFSingleDialog):
self.id = self.db.id(row)
self.gui_title.setText(db.title(row))
au = self.db.authors(row)
self.gui_author.setText(au if au else '')
if au:
au = [a.strip().replace('|', ',') for a in au.split(',')]
self.gui_author.setText(authors_to_string(au))
else:
self.gui_author.setText('')
aus = self.db.author_sort(row)
self.gui_author_sort.setText(aus if aus else '')
pub = self.db.publisher(row)
@ -350,14 +355,16 @@ class LRFSingleDialog(QDialog, Ui_LRFSingleDialog):
def write_metadata(self):
title = qstring_to_unicode(self.gui_title.text())
self.db.set_title(self.id, title)
au = qstring_to_unicode(self.gui_author.text()).split(',')
if au: self.db.set_authors(self.id, au)
au = unicode(self.gui_author.text())
if au:
self.db.set_authors(self.id, string_to_authors(au))
aus = qstring_to_unicode(self.gui_author_sort.text())
if not aus:
t = self.db.authors(self.id, index_is_id=True)
if not t:
t = 'Unknown'
aus = t.split(',')[0].strip()
t = _('Unknown')
aus = [a.strip().replace('|', ',') for a in t.split(',')]
aus = authors_to_sort_string(aus)
self.db.set_author_sort(self.id, aus)
self.db.set_publisher(self.id, qstring_to_unicode(self.gui_publisher.text()))
self.db.set_tags(self.id, qstring_to_unicode(self.tags.text()).split(','))

View File

@ -115,7 +115,7 @@
<item row="0" column="0" >
<widget class="QStackedWidget" name="stack" >
<property name="currentIndex" >
<number>3</number>
<number>0</number>
</property>
<widget class="QWidget" name="metadata_page" >
<layout class="QHBoxLayout" >
@ -255,7 +255,7 @@
</sizepolicy>
</property>
<property name="toolTip" >
<string>Change the author(s) of this book. Multiple authors should be separated by a comma</string>
<string>Change the author(s) of this book. Multiple authors should be separated by an &amp;. If the author name contains an &amp;, use &amp;&amp; to represent it.</string>
</property>
</widget>
</item>

View File

@ -9,6 +9,7 @@ from PyQt4.QtGui import QDialog
from calibre.gui2 import qstring_to_unicode
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
class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
def __init__(self, window, rows, db):
@ -51,7 +52,7 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
for id in self.ids:
au = qstring_to_unicode(self.authors.text())
if au:
au = au.split(',')
au = string_to_authors(au)
self.db.set_authors(id, au)
aus = qstring_to_unicode(self.author_sort.text())
if aus:

View File

@ -52,7 +52,7 @@
<item row="0" column="1" colspan="2" >
<widget class="QLineEdit" name="authors" >
<property name="toolTip" >
<string>Change the author(s) of this book. Multiple authors should be separated by a comma</string>
<string>Change the author(s) of this book. Multiple authors should be separated by an &amp;. If the author name contains an &amp;, use &amp;&amp; to represent it.</string>
</property>
</widget>
</item>
@ -84,6 +84,9 @@
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy" >
<cstring>rating</cstring>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2" >

View File

@ -17,6 +17,7 @@ from calibre.gui2.dialogs.fetch_metadata import FetchMetadata
from calibre.gui2.dialogs.tag_editor import TagEditor
from calibre.gui2.dialogs.password import PasswordDialog
from calibre.ebooks import BOOK_EXTENSIONS
from calibre.ebooks.metadata import authors_to_sort_string, string_to_authors, authors_to_string
from calibre.ebooks.metadata.library_thing import login, cover_from_isbn, LibraryThingError
from calibre import islinux
from calibre.utils.config import prefs
@ -155,7 +156,11 @@ class MetadataSingleDialog(QDialog, Ui_MetadataSingleDialog):
isbn = ''
self.isbn.setText(isbn)
au = self.db.authors(row)
self.authors.setText(au if au else '')
if au:
au = [a.strip().replace('|', ',') for a in au.split(',')]
self.authors.setText(authors_to_string(au))
else:
self.authors.setText('')
aus = self.db.author_sort(row)
self.author_sort.setText(aus if aus else '')
pub = self.db.publisher(row)
@ -199,13 +204,8 @@ class MetadataSingleDialog(QDialog, Ui_MetadataSingleDialog):
def deduce_author_sort(self):
au = unicode(self.authors.text())
tokens = au.split()
for x in (',', ';'):
if x in tokens:
tokens.remove(x)
if tokens:
tokens = [tokens[-1]+';'] + tokens[:-1]
self.author_sort.setText(u' '.join(tokens))
authors = string_to_authors(au)
self.author_sort.setText(authors_to_sort_string(authors))
def swap_title_author(self):
title = self.title.text()
@ -293,7 +293,7 @@ class MetadataSingleDialog(QDialog, Ui_MetadataSingleDialog):
def fetch_metadata(self):
isbn = qstring_to_unicode(self.isbn.text())
title = qstring_to_unicode(self.title.text())
author = qstring_to_unicode(self.authors.text()).split(',')[0]
author = string_to_authors(unicode(self.authors.text()))[0]
publisher = qstring_to_unicode(self.publisher.text())
if isbn or title or author or publisher:
d = FetchMetadata(self, isbn, title, author, publisher, self.timeout)
@ -302,7 +302,7 @@ class MetadataSingleDialog(QDialog, Ui_MetadataSingleDialog):
book = d.selected_book()
if book:
self.title.setText(book.title)
self.authors.setText(', '.join(book.authors))
self.authors.setText(authors_to_string(book.authors))
if book.author_sort: self.author_sort.setText(book.author_sort)
if book.publisher: self.publisher.setText(book.publisher)
if book.isbn: self.isbn.setText(book.isbn)
@ -335,8 +335,9 @@ class MetadataSingleDialog(QDialog, Ui_MetadataSingleDialog):
self.sync_formats()
title = qstring_to_unicode(self.title.text())
self.db.set_title(self.id, title)
au = qstring_to_unicode(self.authors.text()).split(',')
if au: self.db.set_authors(self.id, au)
au = unicode(self.authors.text())
if au:
self.db.set_authors(self.id, string_to_authors(au))
aus = qstring_to_unicode(self.author_sort.text())
if aus:
self.db.set_author_sort(self.id, aus)

View File

@ -98,7 +98,7 @@
<item row="1" column="1" >
<widget class="QLineEdit" name="authors" >
<property name="toolTip" >
<string>Change the author(s) of this book. Multiple authors should be separated by a comma</string>
<string>Change the author(s) of this book. Multiple authors should be separated by an &amp;. If the author name contains an &amp;, use &amp;&amp; to represent it.</string>
</property>
</widget>
</item>
@ -548,8 +548,6 @@
</widget>
</item>
</layout>
<zorder>af_group_box</zorder>
<zorder>groupBox_4</zorder>
</widget>
</widget>
</item>

View File

@ -381,7 +381,7 @@ class BooksModel(QAbstractTableModel):
elif col == 1:
au = self.db.authors(row)
if au:
au = au.split(',')
au = [a.strip().replace('|', ',') for a in au.split(',')]
return QVariant("\n".join(au))
elif col == 2:
size = self.db.max_size(row)

View File

@ -910,7 +910,10 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE;
return _('Unknown')
def authors(self, index, index_is_id=False):
''' Authors as a comma separated list or None'''
'''
Authors as a comma separated list or None.
In the comma separated list, commas in author names are replaced by | symbols
'''
if not index_is_id:
return self.data[index][2]
try:
@ -1361,7 +1364,7 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE;
Convenience method to return metadata as a L{MetaInformation} object.
'''
aum = self.authors(idx, index_is_id=index_is_id)
if aum: aum = aum.split(',')
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.comments = self.comments(idx, index_is_id=index_is_id)

View File

@ -16,6 +16,7 @@ from PyQt4.QtGui import QApplication, QPixmap, QImage
__app = None
from calibre.library.database import LibraryDatabase
from calibre.ebooks.metadata import string_to_authors
from calibre.constants import preferred_encoding
copyfile = os.link if hasattr(os, 'link') else shutil.copyfile
@ -732,7 +733,7 @@ class LibraryDatabase2(LibraryDatabase):
self.data.set(row, col, val)
if column == 'authors':
val = val.split('&,')
val = string_to_authors(val)
self.set_authors(id, val, notify=False)
elif column == 'title':
self.set_title(id, val, notify=False)
@ -742,6 +743,7 @@ class LibraryDatabase2(LibraryDatabase):
self.set_rating(id, val)
elif column == 'tags':
self.set_tags(id, val.split(','), append=False, notify=False)
self.data.refresh_ids(self.conn, [id])
self.set_path(id, True)
self.notify('metadata', [id])
@ -783,7 +785,7 @@ class LibraryDatabase2(LibraryDatabase):
for a in authors:
if not a:
continue
a = a.strip()
a = a.strip().replace(',', '|')
if not isinstance(a, unicode):
a = a.decode(preferred_encoding, 'replace')
author = self.conn.execute('SELECT id from authors WHERE name=?', (a,)).fetchone()