diff --git a/src/calibre/ebooks/metadata/__init__.py b/src/calibre/ebooks/metadata/__init__.py
index fd7622a5d2..26d52cc3f2 100644
--- a/src/calibre/ebooks/metadata/__init__.py
+++ b/src/calibre/ebooks/metadata/__init__.py
@@ -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.')
diff --git a/src/calibre/gui2/dialogs/epub.py b/src/calibre/gui2/dialogs/epub.py
index 78a2be0f51..c044eb0f01 100644
--- a/src/calibre/gui2/dialogs/epub.py
+++ b/src/calibre/gui2/dialogs/epub.py
@@ -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):
diff --git a/src/calibre/gui2/dialogs/epub.ui b/src/calibre/gui2/dialogs/epub.ui
index 3ecc0991e8..5aff8b5227 100644
--- a/src/calibre/gui2/dialogs/epub.ui
+++ b/src/calibre/gui2/dialogs/epub.ui
@@ -77,7 +77,7 @@
-
- 3
+ 0
@@ -221,7 +221,7 @@
- Change the author(s) of this book. Multiple authors should be separated by a comma
+ Change the author(s) of this book. Multiple authors should be separated by an &. If the author name contains an &, use && to represent it.
diff --git a/src/calibre/gui2/dialogs/lrf_single.py b/src/calibre/gui2/dialogs/lrf_single.py
index 787df4d080..9f905c4458 100644
--- a/src/calibre/gui2/dialogs/lrf_single.py
+++ b/src/calibre/gui2/dialogs/lrf_single.py
@@ -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(','))
diff --git a/src/calibre/gui2/dialogs/lrf_single.ui b/src/calibre/gui2/dialogs/lrf_single.ui
index c0e17a1e0e..f08265fe9e 100644
--- a/src/calibre/gui2/dialogs/lrf_single.ui
+++ b/src/calibre/gui2/dialogs/lrf_single.ui
@@ -115,7 +115,7 @@
-
- 3
+ 0
@@ -255,7 +255,7 @@
- Change the author(s) of this book. Multiple authors should be separated by a comma
+ Change the author(s) of this book. Multiple authors should be separated by an &. If the author name contains an &, use && to represent it.
diff --git a/src/calibre/gui2/dialogs/metadata_bulk.py b/src/calibre/gui2/dialogs/metadata_bulk.py
index 98ec115e51..fac7d7be85 100644
--- a/src/calibre/gui2/dialogs/metadata_bulk.py
+++ b/src/calibre/gui2/dialogs/metadata_bulk.py
@@ -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:
diff --git a/src/calibre/gui2/dialogs/metadata_bulk.ui b/src/calibre/gui2/dialogs/metadata_bulk.ui
index 334ce1b42b..b4a4106d87 100644
--- a/src/calibre/gui2/dialogs/metadata_bulk.ui
+++ b/src/calibre/gui2/dialogs/metadata_bulk.ui
@@ -52,7 +52,7 @@
-
- Change the author(s) of this book. Multiple authors should be separated by a comma
+ Change the author(s) of this book. Multiple authors should be separated by an &. If the author name contains an &, use && to represent it.
@@ -84,6 +84,9 @@
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+ rating
+
-
diff --git a/src/calibre/gui2/dialogs/metadata_single.py b/src/calibre/gui2/dialogs/metadata_single.py
index 342bf25cd3..c6e26e86dc 100644
--- a/src/calibre/gui2/dialogs/metadata_single.py
+++ b/src/calibre/gui2/dialogs/metadata_single.py
@@ -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)
diff --git a/src/calibre/gui2/dialogs/metadata_single.ui b/src/calibre/gui2/dialogs/metadata_single.ui
index 3aeea0ed32..3f82f81039 100644
--- a/src/calibre/gui2/dialogs/metadata_single.ui
+++ b/src/calibre/gui2/dialogs/metadata_single.ui
@@ -98,7 +98,7 @@
-
- Change the author(s) of this book. Multiple authors should be separated by a comma
+ Change the author(s) of this book. Multiple authors should be separated by an &. If the author name contains an &, use && to represent it.
@@ -548,8 +548,6 @@
- af_group_box
- groupBox_4
diff --git a/src/calibre/gui2/library.py b/src/calibre/gui2/library.py
index 520a08e36a..3c1b669d78 100644
--- a/src/calibre/gui2/library.py
+++ b/src/calibre/gui2/library.py
@@ -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)
diff --git a/src/calibre/library/database.py b/src/calibre/library/database.py
index 84ae9ba8e9..4b2b515808 100644
--- a/src/calibre/library/database.py
+++ b/src/calibre/library/database.py
@@ -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)
diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py
index b8ad998b3a..55966dcde5 100644
--- a/src/calibre/library/database2.py
+++ b/src/calibre/library/database2.py
@@ -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()