diff --git a/src/libprs500/ebooks/metadata/__init__.py b/src/libprs500/ebooks/metadata/__init__.py index 337a0facf6..3f1d8a86eb 100644 --- a/src/libprs500/ebooks/metadata/__init__.py +++ b/src/libprs500/ebooks/metadata/__init__.py @@ -62,12 +62,13 @@ class MetaInformation(object): def __str__(self): ans = '' - ans += 'Title : ' + unicode(self.title) + '\n' - ans += 'Author : ' + (', '.join(self.authors) if self.authors is not None else 'None') - ans += ((' (' + self.author_sort + ')') if self.author_sort else '') + '\n' - ans += 'Category: ' + unicode(self.category) + '\n' - ans += 'Comments: ' + unicode(self.comments) + '\n' - ans += 'ISBN : ' + unicode(self.isbn) + '\n' + ans += 'Title : ' + unicode(self.title) + '\n' + ans += 'Author : ' + (', '.join(self.authors) if self.authors is not None else 'None') + ans += ((' (' + self.author_sort + ')') if self.author_sort else '') + '\n' + ans += 'Publisher: '+ unicode(self.publisher) + '\n' + ans += 'Category : ' + unicode(self.category) + '\n' + ans += 'Comments : ' + unicode(self.comments) + '\n' + ans += 'ISBN : ' + unicode(self.isbn) + '\n' return ans.strip() def __nonzero__(self): diff --git a/src/libprs500/ebooks/metadata/isbndb.py b/src/libprs500/ebooks/metadata/isbndb.py index be905ee139..59a6132ca1 100644 --- a/src/libprs500/ebooks/metadata/isbndb.py +++ b/src/libprs500/ebooks/metadata/isbndb.py @@ -56,14 +56,18 @@ class ISBNDBMetadata(MetaInformation): self.title = book.find('titlelong').string if not self.title: self.title = book.find('title').string - self.title = self.title.strip - au = book.find('authorstext').string + self.title = unicode(self.title).strip() + au = unicode(book.find('authorstext').string).strip() temp = au.split(',') self.authors = [] for au in temp: + if not au: continue self.authors.extend([a.strip() for a in au.split('&')]) - self.author_sort = book.find('authors').find('person').string + try: + self.author_sort = book.find('authors').find('person').string + except: + pass self.publisher = book.find('publishertext').string diff --git a/src/libprs500/gui2/Makefile b/src/libprs500/gui2/Makefile index fddb1cdd7c..fde86b6f73 100644 --- a/src/libprs500/gui2/Makefile +++ b/src/libprs500/gui2/Makefile @@ -1,6 +1,7 @@ UI = main_ui.py dialogs/metadata_single_ui.py dialogs/metadata_bulk_ui.py dialogs/jobs_ui.py \ dialogs/conversion_error_ui.py dialogs/lrf_single_ui.py dialogs/choose_format_ui.py \ - dialogs/password_ui.py lrf_renderer/main_ui.py lrf_renderer/config_ui.py + dialogs/password_ui.py lrf_renderer/main_ui.py lrf_renderer/config_ui.py \ + dialogs/fetch_metadata_ui.py RC = images_rc.pyc PYUIC = $(shell which pyuic4) diff --git a/src/libprs500/gui2/dialogs/fetch_metadata.py b/src/libprs500/gui2/dialogs/fetch_metadata.py new file mode 100644 index 0000000000..6bd4cf86c6 --- /dev/null +++ b/src/libprs500/gui2/dialogs/fetch_metadata.py @@ -0,0 +1,135 @@ +## Copyright (C) 2007 Kovid Goyal kovid@kovidgoyal.net +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License along +## with this program; if not, write to the Free Software Foundation, Inc., +## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +''' +GUI for fetching metadata from servers. +''' + +from PyQt4.QtCore import Qt, QObject, SIGNAL, QSettings, QVariant, \ + QAbstractTableModel, QCoreApplication +from PyQt4.QtGui import QDialog, QItemSelectionModel + +from libprs500.gui2.dialogs.fetch_metadata_ui import Ui_FetchMetadata +from libprs500.gui2 import error_dialog, NONE +from libprs500.ebooks.metadata.isbndb import create_books, option_parser + +class Matches(QAbstractTableModel): + + def __init__(self, matches): + self.matches = matches + QAbstractTableModel.__init__(self) + + def rowCount(self, *args): + return len(self.matches) + + def columnCount(self, *args): + return 5 + + def headerData(self, section, orientation, role): + if role != Qt.DisplayRole: + return NONE + text = "" + if orientation == Qt.Horizontal: + if section == 0: text = "Title" + elif section == 1: text = "Author(s)" + elif section == 2: text = "Author Sort" + elif section == 3: text = "Publisher" + elif section == 4: text = "ISBN" + + return QVariant(self.trUtf8(text)) + else: + return QVariant(section+1) + + def data(self, index, role): + row, col = index.row(), index.column() + if role == Qt.DisplayRole: + book = self.matches[row] + res = None + if col == 0: + res = book.title + elif col == 1: + res = ', '.join(book.authors) + elif col == 2: + res = book.author_sort + elif col == 3: + res = book.publisher + elif col == 4: + res = book.isbn + if not res: + return NONE + return QVariant(res) + return NONE + +class FetchMetadata(QDialog, Ui_FetchMetadata): + + def __init__(self, parent, isbn, title, author, publisher): + QDialog.__init__(self, parent) + Ui_FetchMetadata.__init__(self) + self.setupUi(self) + + QObject.connect(self.fetch, SIGNAL('clicked()'), self.fetch_metadata) + + self.key.setText(QSettings().value('isbndb.com key', QVariant('')).toString()) + + self.setWindowTitle(title if title else 'Unknown') + self.tlabel.setText(self.tlabel.text().arg(title if title else 'Unknown')) + self.isbn = isbn + self.title = title + self.author = author + self.publisher = publisher + + def fetch_metadata(self): + key = str(self.key.text()) + if not key: + error_dialog(self, 'Cannot connect', + 'You must specify a valid access key for isndb.com') + return + else: + QSettings().setValue('isbndb.com key', QVariant(self.key.text())) + + args = ['isbndb'] + if self.isbn: + args.extend(('--isbn', self.isbn)) + if self.title: + args.extend(('--title', self.title)) + if self.author: + args.extend(('--author', self.author)) + #if self.publisher: + # args.extend(('--publisher', self.publisher)) + + self.fetch.setEnabled(False) + + QCoreApplication.instance().processEvents() + + args.append(key) + parser = option_parser() + opts, args = parser.parse_args(args) + + books = create_books(opts, args) + + self.model = Matches(books) + + self.matches.setModel(self.model) + self.model.reset() + self.matches.selectionModel().select(self.model.index(0, 0), + QItemSelectionModel.Select | QItemSelectionModel.Rows) + self.fetch.setEnabled(True) + + + + def selected_book(self): + try: + return self.matches.model().matches[self.matches.currentIndex().row()] + except: + return None diff --git a/src/libprs500/gui2/dialogs/fetch_metadata.ui b/src/libprs500/gui2/dialogs/fetch_metadata.ui new file mode 100644 index 0000000000..259c77b657 --- /dev/null +++ b/src/libprs500/gui2/dialogs/fetch_metadata.ui @@ -0,0 +1,144 @@ + + FetchMetadata + + + Qt::WindowModal + + + + 0 + 0 + 830 + 622 + + + + Fetch metadata + + + :/images/metadata.svg + + + + + + Fetching metadata for <b>%1</b> + + + Qt::AlignCenter + + + + + + + Sign up for a free account from <a href="http://www.isndb.com">isndb.com</a> to get an access key. + + + Qt::AlignCenter + + + true + + + + + + + + + &Access Key; + + + key + + + + + + + + + + Fetch + + + + + + + + + Matches + + + + + + Select the book that most closely matches your copy from the list below + + + + + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok + + + + + + + + + + + buttonBox + accepted() + FetchMetadata + accept() + + + 460 + 599 + + + 657 + 530 + + + + + buttonBox + rejected() + FetchMetadata + reject() + + + 417 + 599 + + + 0 + 491 + + + + + diff --git a/src/libprs500/gui2/dialogs/lrf_single.py b/src/libprs500/gui2/dialogs/lrf_single.py index 456fdc942c..7c29e501bc 100644 --- a/src/libprs500/gui2/dialogs/lrf_single.py +++ b/src/libprs500/gui2/dialogs/lrf_single.py @@ -73,7 +73,8 @@ class LRFSingleDialog(QDialog, Ui_LRFSingleDialog): except ValueError: pass if not formats: - d = error_dialog(window, 'No available formats', 'Cannot convert %s as this book has no supported formats'%(self.gui_title.text())) + d = error_dialog(window, 'No available formats', + 'Cannot convert %s as this book has no supported formats'%(self.gui_title.text())) d.exec_() if len(formats) > 1: diff --git a/src/libprs500/gui2/dialogs/metadata_single.py b/src/libprs500/gui2/dialogs/metadata_single.py index cd76934cf6..d114d8da43 100644 --- a/src/libprs500/gui2/dialogs/metadata_single.py +++ b/src/libprs500/gui2/dialogs/metadata_single.py @@ -12,6 +12,7 @@ ## You should have received a copy of the GNU General Public License along ## with this program; if not, write to the Free Software Foundation, Inc., ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +from libprs500.gui2.dialogs.fetch_metadata import FetchMetadata ''' The dialog used to edit meta information for a book as well as add/remove formats @@ -137,8 +138,14 @@ class MetadataSingleDialog(QDialog, Ui_MetadataSingleDialog): self.add_format) QObject.connect(self.remove_format_button, SIGNAL("clicked(bool)"), \ self.remove_format) + QObject.connect(self.fetch_metadata_button, SIGNAL('clicked()'), + self.fetch_metadata) self.title.setText(db.title(row)) + isbn = db.isbn(self.id) + if not isbn: + isbn = '' + self.isbn.setText(isbn) au = self.db.authors(row) self.authors.setText(au if au else '') aus = self.db.author_sort(row) @@ -188,6 +195,25 @@ class MetadataSingleDialog(QDialog, Ui_MetadataSingleDialog): self.exec_() + 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] + publisher = qstring_to_unicode(self.publisher.text()) + if isbn or title or author or publisher: + d = FetchMetadata(self, isbn, title, author, publisher) + d.exec_() + if d.result() == QDialog.Accepted: + book = d.selected_book() + if book: + self.title.setText(book.title) + self.authors.setText(', '.join(book.authors)) + if book.author_sort: self.author_sort.setText(book.author_sort) + self.publisher.setText(book.publisher) + self.isbn.setText(book.isbn) + else: + error_dialog(self, 'Cannot fetch metadata', 'You must specify at least one of ISBN, Title, Authors or Publisher') + def enable_series_index(self, *args): self.series_index.setEnabled(True) @@ -201,6 +227,7 @@ class MetadataSingleDialog(QDialog, Ui_MetadataSingleDialog): aus = qstring_to_unicode(self.author_sort.text()) if aus: self.db.set_author_sort(self.id, aus) + self.db.set_isbn(self.id, qstring_to_unicode(self.isbn.text())) self.db.set_rating(self.id, 2*self.rating.value()) self.db.set_publisher(self.id, qstring_to_unicode(self.publisher.text())) self.db.set_tags(self.id, qstring_to_unicode(self.tags.text()).split(',')) diff --git a/src/libprs500/gui2/dialogs/metadata_single.ui b/src/libprs500/gui2/dialogs/metadata_single.ui index c175d65b8c..f016381223 100644 --- a/src/libprs500/gui2/dialogs/metadata_single.ui +++ b/src/libprs500/gui2/dialogs/metadata_single.ui @@ -218,6 +218,22 @@ + + + + + + + IS&BN: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + isbn + + + @@ -233,6 +249,13 @@ + + + + Fetch metadata from server + + + @@ -503,8 +526,8 @@ accept() - 248 - 254 + 257 + 646 157 @@ -519,8 +542,8 @@ reject() - 316 - 260 + 325 + 646 286 diff --git a/src/libprs500/library/database.py b/src/libprs500/library/database.py index 374b0e0cd5..4568b7ee49 100644 --- a/src/libprs500/library/database.py +++ b/src/libprs500/library/database.py @@ -653,7 +653,17 @@ class LibraryDatabase(object): ) conn.execute('pragma user_version=2') conn.commit() - + + @staticmethod + def upgrade_version2(conn): + conn.executescript( +''' +/***** Add ISBN column ******/ +ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE; +''') + conn.execute('pragma user_version=3') + conn.commit() + def __del__(self): global _lock_file import os @@ -669,6 +679,8 @@ class LibraryDatabase(object): LibraryDatabase.create_version1(self.conn) if self.user_version == 1: # Upgrade to 2 LibraryDatabase.upgrade_version1(self.conn) + if self.user_version == 2: # Upgrade to 3 + LibraryDatabase.upgrade_version2(self.conn) @apply def user_version(): @@ -740,6 +752,9 @@ class LibraryDatabase(object): return self.data[index][2] return self.conn.execute('SELECT authors FROM meta WHERE id=?',(index,)).fetchone()[0] + def isbn(self, id): + return self.conn.execute('SELECT isbn FROM books WHERE id=?',(id,)).fetchone()[0] + def author_sort(self, index): id = self.id(index) return self.conn.execute('SELECT author_sort FROM books WHERE id=?', (id,)).fetchone()[0] @@ -909,6 +924,10 @@ class LibraryDatabase(object): self.conn.execute('UPDATE books SET title=? WHERE id=?', (title, id)) self.conn.commit() + def set_isbn(self, id, isbn): + self.conn.execute('UPDATE books SET isbn=? WHERE id=?', (isbn, id)) + self.conn.commit() + def set_publisher(self, id, publisher): self.conn.execute('DELETE FROM books_publishers_link WHERE book=?',(id,)) if publisher: