Move from gprefs to a store specific JSON config that each store automatically has access to use.

This commit is contained in:
John Schember 2011-04-22 07:42:07 -04:00
commit 4ff0747da0
85 changed files with 66840 additions and 41623 deletions

View File

@ -25,6 +25,7 @@ msprefs.defaults['max_tags'] = 20
msprefs.defaults['wait_after_first_identify_result'] = 30 # seconds msprefs.defaults['wait_after_first_identify_result'] = 30 # seconds
msprefs.defaults['wait_after_first_cover_result'] = 60 # seconds msprefs.defaults['wait_after_first_cover_result'] = 60 # seconds
msprefs.defaults['swap_author_names'] = False msprefs.defaults['swap_author_names'] = False
msprefs.defaults['fewer_tags'] = True
# Google covers are often poor quality (scans/errors) but they have high # Google covers are often poor quality (scans/errors) but they have high
# resolution, so they trump covers from better sources. So make sure they # resolution, so they trump covers from better sources. So make sure they

View File

@ -216,7 +216,7 @@ class ISBNMerge(object):
# We assume the smallest set of tags has the least cruft in it # We assume the smallest set of tags has the least cruft in it
ans.tags = self.length_merge('tags', results, ans.tags = self.length_merge('tags', results,
null_value=ans.tags) null_value=ans.tags, shortest=msprefs['fewer_tags'])
# We assume the longest series has the most info in it # We assume the longest series has the most info in it
ans.series = self.length_merge('series', results, ans.series = self.length_merge('series', results,

View File

@ -3,7 +3,7 @@ from __future__ import (unicode_literals, division, absolute_import,
print_function) print_function)
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net' __copyright__ = '2011, Kovid Goyal kovid@kovidgoyal.net'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
''' '''
@ -17,7 +17,7 @@ from lxml import html
from lxml.html import soupparser from lxml.html import soupparser
from calibre.ebooks.metadata import check_isbn from calibre.ebooks.metadata import check_isbn
from calibre.ebooks.metadata.sources.base import Source from calibre.ebooks.metadata.sources.base import Source, Option
from calibre.ebooks.metadata.book.base import Metadata from calibre.ebooks.metadata.book.base import Metadata
from calibre.ebooks.chardet import xml_to_unicode from calibre.ebooks.chardet import xml_to_unicode
from calibre.library.comments import sanitize_comments_html from calibre.library.comments import sanitize_comments_html
@ -40,6 +40,18 @@ class OverDrive(Source):
supports_gzip_transfer_encoding = False supports_gzip_transfer_encoding = False
cached_cover_url_is_reliable = True cached_cover_url_is_reliable = True
options = (
Option('get_full_metadata', 'bool', False,
_('Download all metadata (slow)'),
_('Enable this option to gather all metadata available from Overdrive.')),
)
config_help_message = '<p>'+_('Additional metadata can be taken from Overdrive\'s book detail'
' page. This includes a limited set of tags used by libraries, comments, language,'
' and the ebook ISBN. Collecting this data is disabled by default due to the extra'
' time required. Check the download all metadata option below to'
' enable downloading this data.')
def identify(self, log, result_queue, abort, title=None, authors=None, # {{{ def identify(self, log, result_queue, abort, title=None, authors=None, # {{{
identifiers={}, timeout=30): identifiers={}, timeout=30):
ovrdrv_id = identifiers.get('overdrive', None) ovrdrv_id = identifiers.get('overdrive', None)
@ -54,11 +66,13 @@ class OverDrive(Source):
self.parse_search_results(ovrdrv_data, mi) self.parse_search_results(ovrdrv_data, mi)
if ovrdrv_id is None: if ovrdrv_id is None:
ovrdrv_id = ovrdrv_data[7] ovrdrv_id = ovrdrv_data[7]
if self.prefs['get_full_metadata']:
self.get_book_detail(br, ovrdrv_data[1], mi, ovrdrv_id, log)
if isbn is not None: if isbn is not None:
self.cache_isbn_to_identifier(isbn, ovrdrv_id) self.cache_isbn_to_identifier(isbn, ovrdrv_id)
self.get_book_detail(br, ovrdrv_data[1], mi, ovrdrv_id, log)
result_queue.put(mi) result_queue.put(mi)
return None return None
@ -438,4 +452,3 @@ if __name__ == '__main__':
authors_test(['Agatha Christie'])] authors_test(['Agatha Christie'])]
), ),
]) ])

View File

@ -10,8 +10,8 @@ from functools import partial
from PyQt4.Qt import QMenu from PyQt4.Qt import QMenu
from calibre.gui2 import JSONConfig
from calibre.gui2.actions import InterfaceAction from calibre.gui2.actions import InterfaceAction
from calibre.gui2.dialogs.confirm_delete import confirm
class StoreAction(InterfaceAction): class StoreAction(InterfaceAction):
@ -19,8 +19,6 @@ class StoreAction(InterfaceAction):
action_spec = (_('Get books'), 'store.png', None, None) action_spec = (_('Get books'), 'store.png', None, None)
def genesis(self): def genesis(self):
self.config = JSONConfig('store/action')
self.qaction.triggered.connect(self.search) self.qaction.triggered.connect(self.search)
self.store_menu = QMenu() self.store_menu = QMenu()
self.load_menu() self.load_menu()
@ -34,34 +32,35 @@ class StoreAction(InterfaceAction):
self.qaction.setMenu(self.store_menu) self.qaction.setMenu(self.store_menu)
def search(self): def search(self):
self.first_run_check() self.show_disclaimer()
from calibre.gui2.store.search import SearchDialog from calibre.gui2.store.search import SearchDialog
sd = SearchDialog(self.gui.istores, self.gui) sd = SearchDialog(self.gui.istores, self.gui)
sd.exec_() sd.exec_()
def open_store(self, store_plugin): def open_store(self, store_plugin):
self.first_run_check() self.show_disclaimer()
store_plugin.open(self.gui) store_plugin.open(self.gui)
def first_run_check(self): def show_disclaimer(self):
if self.config.get('first_run', True): confirm(('<p>' +
self.config['first_run'] = False
from calibre.gui2 import info_dialog
info_dialog(self.gui, _('About Get Books'), '<p>' +
_('Calibre helps you find the ebooks you want by searching ' _('Calibre helps you find the ebooks you want by searching '
'the websites of a variety of commercial and public domain ' 'the websites of various commercial and public domain '
'book sources for you.') + 'book sources for you.') +
'<p>' + '<p>' +
_('Using the integrated search you can easily find which ' _('Using the integrated search you can easily find which '
'store has the book you are looking for, at the best price. ' 'store has the book you are looking for, at the best price. '
'You will also get DRM status and other useful information.') 'You also get DRM status and other useful information.')
+ '<p>' + + '<p>' +
_('All transactions (paid or otherwise) are handled between ' _('All transactions (paid or otherwise) are handled between '
'you and the particular website. ' 'you and the book seller. '
'Calibre is not part of this process and any issues related ' 'Calibre is not part of this process and any issues related '
'to a purchase should be directed to the website you are ' 'to a purchase should be directed to the website you are '
'buying from. Be sure to double check that any books you get ' 'buying from. Be sure to double check that any books you get '
'will work with your e-book reader, especially if the book you ' 'will work with your e-book reader, especially if the book you '
'are buying has ' 'are buying has '
'<a href="http://drmfree.calibre-ebook.com/about#drm">DRM</a>.' '<a href="http://drmfree.calibre-ebook.com/about#drm">DRM</a>.'
), show=True, show_copy_button=False) )), 'about_get_books_msg',
parent=self.gui, show_cancel_button=False,
confirm_msg=_('Show this message again'),
pixmap='dialog_information.png', title=_('About Get Books'))

View File

@ -25,7 +25,7 @@ class Dialog(QDialog, Ui_Dialog):
def confirm(msg, name, parent=None, pixmap='dialog_warning.png', title=None, def confirm(msg, name, parent=None, pixmap='dialog_warning.png', title=None,
show_cancel_button=True): show_cancel_button=True, confirm_msg=None):
if not dynamic.get(confirm_config_name(name), True): if not dynamic.get(confirm_config_name(name), True):
return True return True
d = Dialog(msg, name, parent) d = Dialog(msg, name, parent)
@ -35,5 +35,7 @@ def confirm(msg, name, parent=None, pixmap='dialog_warning.png', title=None,
d.setWindowTitle(title) d.setWindowTitle(title)
if not show_cancel_button: if not show_cancel_button:
d.buttonBox.button(d.buttonBox.Cancel).setVisible(False) d.buttonBox.button(d.buttonBox.Cancel).setVisible(False)
if confirm_msg is not None:
d.again.setText(confirm_msg)
d.resize(d.sizeHint()) d.resize(d.sizeHint())
return d.exec_() == d.Accepted return d.exec_() == d.Accepted

View File

@ -259,6 +259,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
r('wait_after_first_identify_result', msprefs) r('wait_after_first_identify_result', msprefs)
r('wait_after_first_cover_result', msprefs) r('wait_after_first_cover_result', msprefs)
r('swap_author_names', msprefs) r('swap_author_names', msprefs)
r('fewer_tags', msprefs)
self.configure_plugin_button.clicked.connect(self.configure_plugin) self.configure_plugin_button.clicked.connect(self.configure_plugin)
self.sources_model = SourcesModel(self) self.sources_model = SourcesModel(self)

View File

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>781</width> <width>781</width>
<height>300</height> <height>394</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -21,7 +21,7 @@
<widget class="QStackedWidget" name="stack"> <widget class="QStackedWidget" name="stack">
<widget class="QWidget" name="page"> <widget class="QWidget" name="page">
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" rowspan="6"> <item row="0" column="0" rowspan="7">
<widget class="QGroupBox" name="groupBox"> <widget class="QGroupBox" name="groupBox">
<property name="title"> <property name="title">
<string>Metadata sources</string> <string>Metadata sources</string>
@ -105,7 +105,7 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="1"> <item row="4" column="1">
<widget class="QLabel" name="label_2"> <widget class="QLabel" name="label_2">
<property name="text"> <property name="text">
<string>Max. number of &amp;tags to download:</string> <string>Max. number of &amp;tags to download:</string>
@ -115,10 +115,10 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="2"> <item row="4" column="2">
<widget class="QSpinBox" name="opt_max_tags"/> <widget class="QSpinBox" name="opt_max_tags"/>
</item> </item>
<item row="4" column="1"> <item row="5" column="1">
<widget class="QLabel" name="label_3"> <widget class="QLabel" name="label_3">
<property name="text"> <property name="text">
<string>Max. &amp;time to wait after first match is found:</string> <string>Max. &amp;time to wait after first match is found:</string>
@ -128,14 +128,14 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="2"> <item row="5" column="2">
<widget class="QSpinBox" name="opt_wait_after_first_identify_result"> <widget class="QSpinBox" name="opt_wait_after_first_identify_result">
<property name="suffix"> <property name="suffix">
<string> secs</string> <string> secs</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="1"> <item row="6" column="1">
<widget class="QLabel" name="label_4"> <widget class="QLabel" name="label_4">
<property name="text"> <property name="text">
<string>Max. time to wait after first &amp;cover is found:</string> <string>Max. time to wait after first &amp;cover is found:</string>
@ -145,13 +145,24 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="2"> <item row="6" column="2">
<widget class="QSpinBox" name="opt_wait_after_first_cover_result"> <widget class="QSpinBox" name="opt_wait_after_first_cover_result">
<property name="suffix"> <property name="suffix">
<string> secs</string> <string> secs</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="1" colspan="2">
<widget class="QCheckBox" name="opt_fewer_tags">
<property name="toolTip">
<string>&lt;p&gt;Different metadata sources have different sets of tags for the same book. If this option is checked, then calibre will use the smaller tag sets. These tend to be more like genres, while the larger tag sets tend to describe the books content.
&lt;p&gt;Note that this option will only make a practical difference if one of the metadata sources has a genre like tag set for the book you are searching for. Most often, they all have large tag sets.</string>
</property>
<property name="text">
<string>Prefer &amp;fewer tags</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="page_2"/> <widget class="QWidget" name="page_2"/>

View File

@ -46,9 +46,12 @@ class StorePlugin(object): # {{{
''' '''
def __init__(self, gui, name): def __init__(self, gui, name):
from calibre.gui2 import JSONConfig
self.gui = gui self.gui = gui
self.name = name self.name = name
self.base_plugin = None self.base_plugin = None
self.config = JSONConfig('store/stores/' + self.name)
def open(self, gui, parent=None, detail_item=None, external=False): def open(self, gui, parent=None, detail_item=None, external=False):
''' '''

View File

@ -8,14 +8,8 @@ __docformat__ = 'restructuredtext en'
from PyQt4.Qt import QWidget from PyQt4.Qt import QWidget
from calibre.gui2 import gprefs
from calibre.gui2.store.basic_config_widget_ui import Ui_Form from calibre.gui2.store.basic_config_widget_ui import Ui_Form
def save_settings(config_widget):
gprefs[config_widget.store.name + '_open_external'] = config_widget.open_external.isChecked()
tags = unicode(config_widget.tags.text())
gprefs[config_widget.store.name + '_tags'] = tags
class BasicStoreConfigWidget(QWidget, Ui_Form): class BasicStoreConfigWidget(QWidget, Ui_Form):
def __init__(self, store): def __init__(self, store):
@ -27,10 +21,10 @@ class BasicStoreConfigWidget(QWidget, Ui_Form):
self.load_setings() self.load_setings()
def load_setings(self): def load_setings(self):
settings = self.store.get_settings() config = self.store.config
self.open_external.setChecked(settings.get(self.store.name + '_open_external')) self.open_external.setChecked(config.get('open_external', False))
self.tags.setText(settings.get(self.store.name + '_tags', '')) self.tags.setText(config.get('tags', ''))
class BasicStoreConfig(object): class BasicStoreConfig(object):
@ -41,12 +35,6 @@ class BasicStoreConfig(object):
return BasicStoreConfigWidget(self) return BasicStoreConfigWidget(self)
def save_settings(self, config_widget): def save_settings(self, config_widget):
save_settings(config_widget) self.config['open_external'] = config_widget.open_external.isChecked()
tags = unicode(config_widget.tags.text())
def get_settings(self): self.config['tags'] = tags
settings = {}
settings[self.name + '_open_external'] = gprefs.get(self.name + '_open_external', False)
settings[self.name + '_tags'] = gprefs.get(self.name + '_tags', self.name + ', store, download')
return settings

View File

@ -23,10 +23,9 @@ from calibre.gui2.store.web_store_dialog import WebStoreDialog
class BeWriteStore(BasicStoreConfig, StorePlugin): class BeWriteStore(BasicStoreConfig, StorePlugin):
def open(self, parent=None, detail_item=None, external=False): def open(self, parent=None, detail_item=None, external=False):
settings = self.get_settings()
url = 'http://www.bewrite.net/mm5/merchant.mvc?Screen=SFNT' url = 'http://www.bewrite.net/mm5/merchant.mvc?Screen=SFNT'
if external or settings.get(self.name + '_open_external', False): if external or self.config.get('open_external', False):
if detail_item: if detail_item:
url = url + detail_item url = url + detail_item
open_url(QUrl(url_slash_cleaner(url))) open_url(QUrl(url_slash_cleaner(url)))
@ -36,7 +35,7 @@ class BeWriteStore(BasicStoreConfig, StorePlugin):
detail_url = url + detail_item detail_url = url + detail_item
d = WebStoreDialog(self.gui, url, parent, detail_url) d = WebStoreDialog(self.gui, url, parent, detail_url)
d.setWindowTitle(self.name) d.setWindowTitle(self.name)
d.set_tags(settings.get(self.name + '_tags', '')) d.set_tags(self.config.get('tags', ''))
d.exec_() d.exec_()
def search(self, query, max_results=10, timeout=60): def search(self, query, max_results=10, timeout=60):

View File

@ -25,8 +25,6 @@ from calibre.gui2.store.web_store_dialog import WebStoreDialog
class BNStore(BasicStoreConfig, StorePlugin): class BNStore(BasicStoreConfig, StorePlugin):
def open(self, parent=None, detail_item=None, external=False): def open(self, parent=None, detail_item=None, external=False):
settings = self.get_settings()
pub_id = '21000000000352219' pub_id = '21000000000352219'
# Use Kovid's affiliate id 30% of the time. # Use Kovid's affiliate id 30% of the time.
if random.randint(1, 10) in (1, 2, 3): if random.randint(1, 10) in (1, 2, 3):
@ -40,12 +38,12 @@ class BNStore(BasicStoreConfig, StorePlugin):
isbn = mo.group('isbn') isbn = mo.group('isbn')
detail_item = 'http://gan.doubleclick.net/gan_click?lid=41000000012871747&pid=' + isbn + '&adurl=' + detail_item + '&pubid=' + pub_id detail_item = 'http://gan.doubleclick.net/gan_click?lid=41000000012871747&pid=' + isbn + '&adurl=' + detail_item + '&pubid=' + pub_id
if external or settings.get(self.name + '_open_external', False): if external or self.config.get('open_external', False):
open_url(QUrl(url_slash_cleaner(detail_item if detail_item else url))) open_url(QUrl(url_slash_cleaner(detail_item if detail_item else url)))
else: else:
d = WebStoreDialog(self.gui, url, parent, detail_item) d = WebStoreDialog(self.gui, url, parent, detail_item)
d.setWindowTitle(self.name) d.setWindowTitle(self.name)
d.set_tags(settings.get(self.name + '_tags', '')) d.set_tags(self.config.get('tags', ''))
d.exec_() d.exec_()
def search(self, query, max_results=10, timeout=60): def search(self, query, max_results=10, timeout=60):

View File

@ -24,7 +24,6 @@ from calibre.gui2.store.web_store_dialog import WebStoreDialog
class DieselEbooksStore(BasicStoreConfig, StorePlugin): class DieselEbooksStore(BasicStoreConfig, StorePlugin):
def open(self, parent=None, detail_item=None, external=False): def open(self, parent=None, detail_item=None, external=False):
settings = self.get_settings()
url = 'http://www.diesel-ebooks.com/' url = 'http://www.diesel-ebooks.com/'
aff_id = '?aid=2049' aff_id = '?aid=2049'
@ -37,12 +36,12 @@ class DieselEbooksStore(BasicStoreConfig, StorePlugin):
detail_url = url + detail_item + aff_id detail_url = url + detail_item + aff_id
url = url + aff_id url = url + aff_id
if external or settings.get(self.name + '_open_external', False): if external or self.config.get('open_external', False):
open_url(QUrl(url_slash_cleaner(detail_url if detail_url else url))) open_url(QUrl(url_slash_cleaner(detail_url if detail_url else url)))
else: else:
d = WebStoreDialog(self.gui, url, parent, detail_url) d = WebStoreDialog(self.gui, url, parent, detail_url)
d.setWindowTitle(self.name) d.setWindowTitle(self.name)
d.set_tags(settings.get(self.name + '_tags', '')) d.set_tags(self.config.get('tags', ''))
d.exec_() d.exec_()
def search(self, query, max_results=10, timeout=60): def search(self, query, max_results=10, timeout=60):

View File

@ -25,8 +25,6 @@ from calibre.gui2.store.web_store_dialog import WebStoreDialog
class EbookscomStore(BasicStoreConfig, StorePlugin): class EbookscomStore(BasicStoreConfig, StorePlugin):
def open(self, parent=None, detail_item=None, external=False): def open(self, parent=None, detail_item=None, external=False):
settings = self.get_settings()
m_url = 'http://www.dpbolvw.net/' m_url = 'http://www.dpbolvw.net/'
h_click = 'click-4879827-10364500' h_click = 'click-4879827-10364500'
d_click = 'click-4879827-10281551' d_click = 'click-4879827-10281551'
@ -40,12 +38,12 @@ class EbookscomStore(BasicStoreConfig, StorePlugin):
if detail_item: if detail_item:
detail_url = m_url + d_click + detail_item detail_url = m_url + d_click + detail_item
if external or settings.get(self.name + '_open_external', False): if external or self.config.get('open_external', False):
open_url(QUrl(url_slash_cleaner(detail_url if detail_url else url))) open_url(QUrl(url_slash_cleaner(detail_url if detail_url else url)))
else: else:
d = WebStoreDialog(self.gui, url, parent, detail_url) d = WebStoreDialog(self.gui, url, parent, detail_url)
d.setWindowTitle(self.name) d.setWindowTitle(self.name)
d.set_tags(settings.get(self.name + '_tags', '')) d.set_tags(self.config.get('tags', ''))
d.exec_() d.exec_()
def search(self, query, max_results=10, timeout=60): def search(self, query, max_results=10, timeout=60):

View File

@ -25,8 +25,6 @@ from calibre.gui2.store.web_store_dialog import WebStoreDialog
class EHarlequinStore(BasicStoreConfig, StorePlugin): class EHarlequinStore(BasicStoreConfig, StorePlugin):
def open(self, parent=None, detail_item=None, external=False): def open(self, parent=None, detail_item=None, external=False):
settings = self.get_settings()
m_url = 'http://www.dpbolvw.net/' m_url = 'http://www.dpbolvw.net/'
h_click = 'click-4879827-534091' h_click = 'click-4879827-534091'
d_click = 'click-4879827-10375439' d_click = 'click-4879827-10375439'
@ -40,12 +38,12 @@ class EHarlequinStore(BasicStoreConfig, StorePlugin):
if detail_item: if detail_item:
detail_url = m_url + d_click + detail_item detail_url = m_url + d_click + detail_item
if external or settings.get(self.name + '_open_external', False): if external or self.config.get('open_external', False):
open_url(QUrl(url_slash_cleaner(detail_url if detail_url else url))) open_url(QUrl(url_slash_cleaner(detail_url if detail_url else url)))
else: else:
d = WebStoreDialog(self.gui, url, parent, detail_url) d = WebStoreDialog(self.gui, url, parent, detail_url)
d.setWindowTitle(self.name) d.setWindowTitle(self.name)
d.set_tags(settings.get(self.name + '_tags', '')) d.set_tags(self.config.get('tags', ''))
d.exec_() d.exec_()
def search(self, query, max_results=10, timeout=60): def search(self, query, max_results=10, timeout=60):

View File

@ -23,11 +23,10 @@ from calibre.gui2.store.web_store_dialog import WebStoreDialog
class FeedbooksStore(BasicStoreConfig, StorePlugin): class FeedbooksStore(BasicStoreConfig, StorePlugin):
def open(self, parent=None, detail_item=None, external=False): def open(self, parent=None, detail_item=None, external=False):
settings = self.get_settings()
url = 'http://m.feedbooks.com/' url = 'http://m.feedbooks.com/'
ext_url = 'http://feedbooks.com/' ext_url = 'http://feedbooks.com/'
if external or settings.get(self.name + '_open_external', False): if external or self.config.get('open_external', False):
if detail_item: if detail_item:
ext_url = ext_url + detail_item ext_url = ext_url + detail_item
open_url(QUrl(url_slash_cleaner(ext_url))) open_url(QUrl(url_slash_cleaner(ext_url)))
@ -37,7 +36,7 @@ class FeedbooksStore(BasicStoreConfig, StorePlugin):
detail_url = url + detail_item detail_url = url + detail_item
d = WebStoreDialog(self.gui, url, parent, detail_url) d = WebStoreDialog(self.gui, url, parent, detail_url)
d.setWindowTitle(self.name) d.setWindowTitle(self.name)
d.set_tags(settings.get(self.name + '_tags', '')) d.set_tags(self.config.get('tags', ''))
d.exec_() d.exec_()
def search(self, query, max_results=10, timeout=60): def search(self, query, max_results=10, timeout=60):

View File

@ -23,11 +23,10 @@ from calibre.gui2.store.web_store_dialog import WebStoreDialog
class GutenbergStore(BasicStoreConfig, StorePlugin): class GutenbergStore(BasicStoreConfig, StorePlugin):
def open(self, parent=None, detail_item=None, external=False): def open(self, parent=None, detail_item=None, external=False):
settings = self.get_settings()
url = 'http://m.gutenberg.org/' url = 'http://m.gutenberg.org/'
ext_url = 'http://gutenberg.org/' ext_url = 'http://gutenberg.org/'
if external or settings.get(self.name + '_open_external', False): if external or self.config.get('open_external', False):
if detail_item: if detail_item:
ext_url = ext_url + detail_item ext_url = ext_url + detail_item
open_url(QUrl(url_slash_cleaner(ext_url))) open_url(QUrl(url_slash_cleaner(ext_url)))
@ -37,7 +36,7 @@ class GutenbergStore(BasicStoreConfig, StorePlugin):
detail_url = url + detail_item detail_url = url + detail_item
d = WebStoreDialog(self.gui, url, parent, detail_url) d = WebStoreDialog(self.gui, url, parent, detail_url)
d.setWindowTitle(self.name) d.setWindowTitle(self.name)
d.set_tags(settings.get(self.name + '_tags', '')) d.set_tags(self.config.get('tags', ''))
d.exec_() d.exec_()
def search(self, query, max_results=10, timeout=60): def search(self, query, max_results=10, timeout=60):

View File

@ -24,8 +24,6 @@ from calibre.gui2.store.web_store_dialog import WebStoreDialog
class KoboStore(BasicStoreConfig, StorePlugin): class KoboStore(BasicStoreConfig, StorePlugin):
def open(self, parent=None, detail_item=None, external=False): def open(self, parent=None, detail_item=None, external=False):
settings = self.get_settings()
m_url = 'http://www.dpbolvw.net/' m_url = 'http://www.dpbolvw.net/'
h_click = 'click-4879827-10762497' h_click = 'click-4879827-10762497'
d_click = 'click-4879827-10772898' d_click = 'click-4879827-10772898'
@ -39,12 +37,12 @@ class KoboStore(BasicStoreConfig, StorePlugin):
if detail_item: if detail_item:
detail_url = m_url + d_click + detail_item detail_url = m_url + d_click + detail_item
if external or settings.get(self.name + '_open_external', False): if external or self.config.get('open_external', False):
open_url(QUrl(url_slash_cleaner(detail_url if detail_url else url))) open_url(QUrl(url_slash_cleaner(detail_url if detail_url else url)))
else: else:
d = WebStoreDialog(self.gui, url, parent, detail_url) d = WebStoreDialog(self.gui, url, parent, detail_url)
d.setWindowTitle(self.name) d.setWindowTitle(self.name)
d.set_tags(settings.get(self.name + '_tags', '')) d.set_tags(self.config.get('tags', ''))
d.exec_() d.exec_()
def search(self, query, max_results=10, timeout=60): def search(self, query, max_results=10, timeout=60):

View File

@ -24,19 +24,18 @@ from calibre.gui2.store.web_store_dialog import WebStoreDialog
class ManyBooksStore(BasicStoreConfig, StorePlugin): class ManyBooksStore(BasicStoreConfig, StorePlugin):
def open(self, parent=None, detail_item=None, external=False): def open(self, parent=None, detail_item=None, external=False):
settings = self.get_settings()
url = 'http://manybooks.net/' url = 'http://manybooks.net/'
detail_url = None detail_url = None
if detail_item: if detail_item:
detail_url = url + detail_item detail_url = url + detail_item
if external or settings.get(self.name + '_open_external', False): if external or self.config.get('open_external', False):
open_url(QUrl(url_slash_cleaner(detail_url if detail_url else url))) open_url(QUrl(url_slash_cleaner(detail_url if detail_url else url)))
else: else:
d = WebStoreDialog(self.gui, url, parent, detail_url) d = WebStoreDialog(self.gui, url, parent, detail_url)
d.setWindowTitle(self.name) d.setWindowTitle(self.name)
d.set_tags(settings.get(self.name + '_tags', '')) d.set_tags(self.config.get('tags', ''))
d.exec_() d.exec_()
def search(self, query, max_results=10, timeout=60): def search(self, query, max_results=10, timeout=60):

View File

@ -18,7 +18,7 @@ from PyQt4.Qt import Qt, QUrl, QDialog, QAbstractItemModel, QModelIndex, QVarian
pyqtSignal pyqtSignal
from calibre import browser from calibre import browser
from calibre.gui2 import open_url, NONE, JSONConfig from calibre.gui2 import open_url, NONE
from calibre.gui2.store import StorePlugin from calibre.gui2.store import StorePlugin
from calibre.gui2.store.basic_config import BasicStoreConfig from calibre.gui2.store.basic_config import BasicStoreConfig
from calibre.gui2.store.mobileread_store_dialog_ui import Ui_Dialog from calibre.gui2.store.mobileread_store_dialog_ui import Ui_Dialog
@ -29,20 +29,18 @@ from calibre.utils.icu import sort_key
class MobileReadStore(BasicStoreConfig, StorePlugin): class MobileReadStore(BasicStoreConfig, StorePlugin):
def genesis(self): def genesis(self):
self.config = JSONConfig('store/store/' + self.name)
self.rlock = RLock() self.rlock = RLock()
def open(self, parent=None, detail_item=None, external=False): def open(self, parent=None, detail_item=None, external=False):
settings = self.get_settings()
url = 'http://www.mobileread.com/' url = 'http://www.mobileread.com/'
if external or settings.get(self.name + '_open_external', False): if external or self.config.get('open_external', False):
open_url(QUrl(detail_item if detail_item else url)) open_url(QUrl(detail_item if detail_item else url))
else: else:
if detail_item: if detail_item:
d = WebStoreDialog(self.gui, url, parent, detail_item) d = WebStoreDialog(self.gui, url, parent, detail_item)
d.setWindowTitle(self.name) d.setWindowTitle(self.name)
d.set_tags(settings.get(self.name + '_tags', '')) d.set_tags(self.config.get('tags', ''))
d.exec_() d.exec_()
else: else:
d = MobeReadStoreDialog(self, parent) d = MobeReadStoreDialog(self, parent)

View File

@ -23,10 +23,9 @@ from calibre.gui2.store.web_store_dialog import WebStoreDialog
class OpenLibraryStore(BasicStoreConfig, StorePlugin): class OpenLibraryStore(BasicStoreConfig, StorePlugin):
def open(self, parent=None, detail_item=None, external=False): def open(self, parent=None, detail_item=None, external=False):
settings = self.get_settings()
url = 'http://openlibrary.org/' url = 'http://openlibrary.org/'
if external or settings.get(self.name + '_open_external', False): if external or self.config.get('open_external', False):
if detail_item: if detail_item:
url = url + detail_item url = url + detail_item
open_url(QUrl(url_slash_cleaner(url))) open_url(QUrl(url_slash_cleaner(url)))
@ -36,7 +35,7 @@ class OpenLibraryStore(BasicStoreConfig, StorePlugin):
detail_url = url + detail_item detail_url = url + detail_item
d = WebStoreDialog(self.gui, url, parent, detail_url) d = WebStoreDialog(self.gui, url, parent, detail_url)
d.setWindowTitle(self.name) d.setWindowTitle(self.name)
d.set_tags(settings.get(self.name + '_tags', '')) d.set_tags(self.config.get('tags', ''))
d.exec_() d.exec_()
def search(self, query, max_results=10, timeout=60): def search(self, query, max_results=10, timeout=60):

View File

@ -396,7 +396,7 @@ class DetailsThreadPool(GenericDownloadThreadPool):
class DetailsThread(Thread): class DetailsThread(Thread):
def __init__(self, tasks, results): def __init__(self, tasks, results):
Thread.__init__(self) Thread.__init__(self)
self.daemon = True self.daemon = True
@ -428,11 +428,14 @@ class Matches(QAbstractItemModel):
def __init__(self): def __init__(self):
QAbstractItemModel.__init__(self) QAbstractItemModel.__init__(self)
self.DRM_LOCKED_ICON = QPixmap(I('drm-locked.png')).scaledToHeight(64) self.DRM_LOCKED_ICON = QPixmap(I('drm-locked.png')).scaledToHeight(64,
self.DRM_UNLOCKED_ICON = QPixmap(I('drm-unlocked.png')).scaledToHeight(64) Qt.SmoothTransformation)
self.DRM_UNKNOWN_ICON = QPixmap(I('dialog_warning.png')).scaledToHeight(64) self.DRM_UNLOCKED_ICON = QPixmap(I('drm-unlocked.png')).scaledToHeight(64,
Qt.SmoothTransformation)
self.DRM_UNKNOWN_ICON = QPixmap(I('dialog_question.png')).scaledToHeight(64,
Qt.SmoothTransformation)
# All matches. Used to determine the order to display # All matches. Used to determine the order to display
# self.matches because the SearchFilter returns # self.matches because the SearchFilter returns
# matches unordered. # matches unordered.
@ -482,7 +485,7 @@ class Matches(QAbstractItemModel):
return self.matches[row] return self.matches[row]
else: else:
return None return None
def filter_results(self): def filter_results(self):
self.layoutAboutToBeChanged.emit() self.layoutAboutToBeChanged.emit()
if self.query: if self.query:
@ -611,13 +614,13 @@ class Matches(QAbstractItemModel):
self.reorder_matches() self.reorder_matches()
if reset: if reset:
self.reset() self.reset()
def reorder_matches(self): def reorder_matches(self):
self.matches = sorted(self.matches, key=lambda x: self.all_matches.index(x)) self.matches = sorted(self.matches, key=lambda x: self.all_matches.index(x))
class SearchFilter(SearchQueryParser): class SearchFilter(SearchQueryParser):
USABLE_LOCATIONS = [ USABLE_LOCATIONS = [
'all', 'all',
'author', 'author',
@ -637,7 +640,7 @@ class SearchFilter(SearchQueryParser):
def add_search_result(self, search_result): def add_search_result(self, search_result):
self.srs.add(search_result) self.srs.add(search_result)
def clear_search_results(self): def clear_search_results(self):
self.srs = set([]) self.srs = set([])
@ -710,7 +713,7 @@ class SearchFilter(SearchQueryParser):
m = CONTAINS_MATCH m = CONTAINS_MATCH
else: else:
m = matchkind m = matchkind
if locvalue == 'format': if locvalue == 'format':
vals = accessor(sr).split(',') vals = accessor(sr).split(',')
else: else:

View File

@ -25,7 +25,6 @@ from calibre.gui2.store.web_store_dialog import WebStoreDialog
class SmashwordsStore(BasicStoreConfig, StorePlugin): class SmashwordsStore(BasicStoreConfig, StorePlugin):
def open(self, parent=None, detail_item=None, external=False): def open(self, parent=None, detail_item=None, external=False):
settings = self.get_settings()
url = 'http://www.smashwords.com/' url = 'http://www.smashwords.com/'
aff_id = '?ref=usernone' aff_id = '?ref=usernone'
@ -38,12 +37,12 @@ class SmashwordsStore(BasicStoreConfig, StorePlugin):
detail_url = url + detail_item + aff_id detail_url = url + detail_item + aff_id
url = url + aff_id url = url + aff_id
if external or settings.get(self.name + '_open_external', False): if external or self.config.get('open_external', False):
open_url(QUrl(url_slash_cleaner(detail_url if detail_url else url))) open_url(QUrl(url_slash_cleaner(detail_url if detail_url else url)))
else: else:
d = WebStoreDialog(self.gui, url, parent, detail_url) d = WebStoreDialog(self.gui, url, parent, detail_url)
d.setWindowTitle(self.name) d.setWindowTitle(self.name)
d.set_tags(settings.get(self.name + '_tags', '')) d.set_tags(self.config.get('tags', ''))
d.exec_() d.exec_()
def search(self, query, max_results=10, timeout=60): def search(self, query, max_results=10, timeout=60):

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

63
src/calibre/utils/text2int.py Executable file
View File

@ -0,0 +1,63 @@
#!/usr/bin/env python
__author__ = "stackoverflow community"
__docformat__ = 'restructuredtext en'
"""
Takes english numeric words and converts them to integers.
Returns False if the word isn't a number.
implementation courtesy of the stackoverflow community:
http://stackoverflow.com/questions/493174/is-there-a-way-to-convert-number-words-to-integers-python
"""
import re
numwords = {}
def text2int(textnum):
if not numwords:
units = [ "zero", "one", "two", "three", "four", "five", "six",
"seven", "eight", "nine", "ten", "eleven", "twelve",
"thirteen", "fourteen", "fifteen", "sixteen", "seventeen",
"eighteen", "nineteen"]
tens = ["", "", "twenty", "thirty", "forty", "fifty", "sixty",
"seventy", "eighty", "ninety"]
scales = ["hundred", "thousand", "million", "billion", "trillion",
'quadrillion', 'quintillion', 'sexillion', 'septillion',
'octillion', 'nonillion', 'decillion' ]
numwords["and"] = (1, 0)
for idx, word in enumerate(units): numwords[word] = (1, idx)
for idx, word in enumerate(tens): numwords[word] = (1, idx * 10)
for idx, word in enumerate(scales): numwords[word] = (10 ** (idx * 3 or 2), 0)
ordinal_words = {'first':1, 'second':2, 'third':3, 'fifth':5,
'eighth':8, 'ninth':9, 'twelfth':12}
ordinal_endings = [('ieth', 'y'), ('th', '')]
current = result = 0
tokens = re.split(r"[\s-]+", textnum)
for word in tokens:
if word in ordinal_words:
scale, increment = (1, ordinal_words[word])
else:
for ending, replacement in ordinal_endings:
if word.endswith(ending):
word = "%s%s" % (word[:-len(ending)], replacement)
if word not in numwords:
#raise Exception("Illegal word: " + word)
return False
scale, increment = numwords[word]
if scale > 1:
current = max(1, current)
current = current * scale + increment
if scale > 100:
result += current
current = 0
return result + current