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_cover_result'] = 60 # seconds
msprefs.defaults['swap_author_names'] = False
msprefs.defaults['fewer_tags'] = True
# Google covers are often poor quality (scans/errors) but they have high
# 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
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
ans.series = self.length_merge('series', results,

View File

@ -3,7 +3,7 @@ from __future__ import (unicode_literals, division, absolute_import,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
__copyright__ = '2011, Kovid Goyal kovid@kovidgoyal.net'
__docformat__ = 'restructuredtext en'
'''
@ -17,7 +17,7 @@ from lxml import html
from lxml.html import soupparser
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.chardet import xml_to_unicode
from calibre.library.comments import sanitize_comments_html
@ -40,6 +40,18 @@ class OverDrive(Source):
supports_gzip_transfer_encoding = False
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, # {{{
identifiers={}, timeout=30):
ovrdrv_id = identifiers.get('overdrive', None)
@ -54,11 +66,13 @@ class OverDrive(Source):
self.parse_search_results(ovrdrv_data, mi)
if ovrdrv_id is None:
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:
self.cache_isbn_to_identifier(isbn, ovrdrv_id)
self.get_book_detail(br, ovrdrv_data[1], mi, ovrdrv_id, log)
result_queue.put(mi)
return None
@ -438,4 +452,3 @@ if __name__ == '__main__':
authors_test(['Agatha Christie'])]
),
])

View File

@ -10,8 +10,8 @@ from functools import partial
from PyQt4.Qt import QMenu
from calibre.gui2 import JSONConfig
from calibre.gui2.actions import InterfaceAction
from calibre.gui2.dialogs.confirm_delete import confirm
class StoreAction(InterfaceAction):
@ -19,8 +19,6 @@ class StoreAction(InterfaceAction):
action_spec = (_('Get books'), 'store.png', None, None)
def genesis(self):
self.config = JSONConfig('store/action')
self.qaction.triggered.connect(self.search)
self.store_menu = QMenu()
self.load_menu()
@ -34,34 +32,35 @@ class StoreAction(InterfaceAction):
self.qaction.setMenu(self.store_menu)
def search(self):
self.first_run_check()
self.show_disclaimer()
from calibre.gui2.store.search import SearchDialog
sd = SearchDialog(self.gui.istores, self.gui)
sd.exec_()
def open_store(self, store_plugin):
self.first_run_check()
self.show_disclaimer()
store_plugin.open(self.gui)
def first_run_check(self):
if self.config.get('first_run', True):
self.config['first_run'] = False
from calibre.gui2 import info_dialog
info_dialog(self.gui, _('About Get Books'), '<p>' +
def show_disclaimer(self):
confirm(('<p>' +
_('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.') +
'<p>' +
_('Using the integrated search you can easily find which '
'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>' +
_('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 '
'to a purchase should be directed to the website you are '
'buying from. Be sure to double check that any books you get '
'will work with your e-book reader, especially if the book you '
'are buying has '
'<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,
show_cancel_button=True):
show_cancel_button=True, confirm_msg=None):
if not dynamic.get(confirm_config_name(name), True):
return True
d = Dialog(msg, name, parent)
@ -35,5 +35,7 @@ def confirm(msg, name, parent=None, pixmap='dialog_warning.png', title=None,
d.setWindowTitle(title)
if not show_cancel_button:
d.buttonBox.button(d.buttonBox.Cancel).setVisible(False)
if confirm_msg is not None:
d.again.setText(confirm_msg)
d.resize(d.sizeHint())
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_cover_result', msprefs)
r('swap_author_names', msprefs)
r('fewer_tags', msprefs)
self.configure_plugin_button.clicked.connect(self.configure_plugin)
self.sources_model = SourcesModel(self)

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>781</width>
<height>300</height>
<height>394</height>
</rect>
</property>
<property name="windowTitle">
@ -21,7 +21,7 @@
<widget class="QStackedWidget" name="stack">
<widget class="QWidget" name="page">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" rowspan="6">
<item row="0" column="0" rowspan="7">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Metadata sources</string>
@ -105,7 +105,7 @@
</property>
</widget>
</item>
<item row="3" column="1">
<item row="4" column="1">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Max. number of &amp;tags to download:</string>
@ -115,10 +115,10 @@
</property>
</widget>
</item>
<item row="3" column="2">
<item row="4" column="2">
<widget class="QSpinBox" name="opt_max_tags"/>
</item>
<item row="4" column="1">
<item row="5" column="1">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Max. &amp;time to wait after first match is found:</string>
@ -128,14 +128,14 @@
</property>
</widget>
</item>
<item row="4" column="2">
<item row="5" column="2">
<widget class="QSpinBox" name="opt_wait_after_first_identify_result">
<property name="suffix">
<string> secs</string>
</property>
</widget>
</item>
<item row="5" column="1">
<item row="6" column="1">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Max. time to wait after first &amp;cover is found:</string>
@ -145,13 +145,24 @@
</property>
</widget>
</item>
<item row="5" column="2">
<item row="6" column="2">
<widget class="QSpinBox" name="opt_wait_after_first_cover_result">
<property name="suffix">
<string> secs</string>
</property>
</widget>
</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>
</widget>
<widget class="QWidget" name="page_2"/>

View File

@ -46,9 +46,12 @@ class StorePlugin(object): # {{{
'''
def __init__(self, gui, name):
from calibre.gui2 import JSONConfig
self.gui = gui
self.name = name
self.base_plugin = None
self.config = JSONConfig('store/stores/' + self.name)
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 calibre.gui2 import gprefs
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):
def __init__(self, store):
@ -27,10 +21,10 @@ class BasicStoreConfigWidget(QWidget, Ui_Form):
self.load_setings()
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.tags.setText(settings.get(self.store.name + '_tags', ''))
self.open_external.setChecked(config.get('open_external', False))
self.tags.setText(config.get('tags', ''))
class BasicStoreConfig(object):
@ -41,12 +35,6 @@ class BasicStoreConfig(object):
return BasicStoreConfigWidget(self)
def save_settings(self, config_widget):
save_settings(config_widget)
def get_settings(self):
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
self.config['open_external'] = config_widget.open_external.isChecked()
tags = unicode(config_widget.tags.text())
self.config['tags'] = tags

View File

@ -23,10 +23,9 @@ from calibre.gui2.store.web_store_dialog import WebStoreDialog
class BeWriteStore(BasicStoreConfig, StorePlugin):
def open(self, parent=None, detail_item=None, external=False):
settings = self.get_settings()
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:
url = url + detail_item
open_url(QUrl(url_slash_cleaner(url)))
@ -36,7 +35,7 @@ class BeWriteStore(BasicStoreConfig, StorePlugin):
detail_url = url + detail_item
d = WebStoreDialog(self.gui, url, parent, detail_url)
d.setWindowTitle(self.name)
d.set_tags(settings.get(self.name + '_tags', ''))
d.set_tags(self.config.get('tags', ''))
d.exec_()
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):
def open(self, parent=None, detail_item=None, external=False):
settings = self.get_settings()
pub_id = '21000000000352219'
# Use Kovid's affiliate id 30% of the time.
if random.randint(1, 10) in (1, 2, 3):
@ -40,12 +38,12 @@ class BNStore(BasicStoreConfig, StorePlugin):
isbn = mo.group('isbn')
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)))
else:
d = WebStoreDialog(self.gui, url, parent, detail_item)
d.setWindowTitle(self.name)
d.set_tags(settings.get(self.name + '_tags', ''))
d.set_tags(self.config.get('tags', ''))
d.exec_()
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):
def open(self, parent=None, detail_item=None, external=False):
settings = self.get_settings()
url = 'http://www.diesel-ebooks.com/'
aff_id = '?aid=2049'
@ -37,12 +36,12 @@ class DieselEbooksStore(BasicStoreConfig, StorePlugin):
detail_url = url + detail_item + 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)))
else:
d = WebStoreDialog(self.gui, url, parent, detail_url)
d.setWindowTitle(self.name)
d.set_tags(settings.get(self.name + '_tags', ''))
d.set_tags(self.config.get('tags', ''))
d.exec_()
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):
def open(self, parent=None, detail_item=None, external=False):
settings = self.get_settings()
m_url = 'http://www.dpbolvw.net/'
h_click = 'click-4879827-10364500'
d_click = 'click-4879827-10281551'
@ -40,12 +38,12 @@ class EbookscomStore(BasicStoreConfig, StorePlugin):
if 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)))
else:
d = WebStoreDialog(self.gui, url, parent, detail_url)
d.setWindowTitle(self.name)
d.set_tags(settings.get(self.name + '_tags', ''))
d.set_tags(self.config.get('tags', ''))
d.exec_()
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):
def open(self, parent=None, detail_item=None, external=False):
settings = self.get_settings()
m_url = 'http://www.dpbolvw.net/'
h_click = 'click-4879827-534091'
d_click = 'click-4879827-10375439'
@ -40,12 +38,12 @@ class EHarlequinStore(BasicStoreConfig, StorePlugin):
if 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)))
else:
d = WebStoreDialog(self.gui, url, parent, detail_url)
d.setWindowTitle(self.name)
d.set_tags(settings.get(self.name + '_tags', ''))
d.set_tags(self.config.get('tags', ''))
d.exec_()
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):
def open(self, parent=None, detail_item=None, external=False):
settings = self.get_settings()
url = 'http://m.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:
ext_url = ext_url + detail_item
open_url(QUrl(url_slash_cleaner(ext_url)))
@ -37,7 +36,7 @@ class FeedbooksStore(BasicStoreConfig, StorePlugin):
detail_url = url + detail_item
d = WebStoreDialog(self.gui, url, parent, detail_url)
d.setWindowTitle(self.name)
d.set_tags(settings.get(self.name + '_tags', ''))
d.set_tags(self.config.get('tags', ''))
d.exec_()
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):
def open(self, parent=None, detail_item=None, external=False):
settings = self.get_settings()
url = 'http://m.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:
ext_url = ext_url + detail_item
open_url(QUrl(url_slash_cleaner(ext_url)))
@ -37,7 +36,7 @@ class GutenbergStore(BasicStoreConfig, StorePlugin):
detail_url = url + detail_item
d = WebStoreDialog(self.gui, url, parent, detail_url)
d.setWindowTitle(self.name)
d.set_tags(settings.get(self.name + '_tags', ''))
d.set_tags(self.config.get('tags', ''))
d.exec_()
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):
def open(self, parent=None, detail_item=None, external=False):
settings = self.get_settings()
m_url = 'http://www.dpbolvw.net/'
h_click = 'click-4879827-10762497'
d_click = 'click-4879827-10772898'
@ -39,12 +37,12 @@ class KoboStore(BasicStoreConfig, StorePlugin):
if 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)))
else:
d = WebStoreDialog(self.gui, url, parent, detail_url)
d.setWindowTitle(self.name)
d.set_tags(settings.get(self.name + '_tags', ''))
d.set_tags(self.config.get('tags', ''))
d.exec_()
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):
def open(self, parent=None, detail_item=None, external=False):
settings = self.get_settings()
url = 'http://manybooks.net/'
detail_url = None
if 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)))
else:
d = WebStoreDialog(self.gui, url, parent, detail_url)
d.setWindowTitle(self.name)
d.set_tags(settings.get(self.name + '_tags', ''))
d.set_tags(self.config.get('tags', ''))
d.exec_()
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
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.basic_config import BasicStoreConfig
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):
def genesis(self):
self.config = JSONConfig('store/store/' + self.name)
self.rlock = RLock()
def open(self, parent=None, detail_item=None, external=False):
settings = self.get_settings()
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))
else:
if detail_item:
d = WebStoreDialog(self.gui, url, parent, detail_item)
d.setWindowTitle(self.name)
d.set_tags(settings.get(self.name + '_tags', ''))
d.set_tags(self.config.get('tags', ''))
d.exec_()
else:
d = MobeReadStoreDialog(self, parent)

View File

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

View File

@ -429,9 +429,12 @@ class Matches(QAbstractItemModel):
def __init__(self):
QAbstractItemModel.__init__(self)
self.DRM_LOCKED_ICON = QPixmap(I('drm-locked.png')).scaledToHeight(64)
self.DRM_UNLOCKED_ICON = QPixmap(I('drm-unlocked.png')).scaledToHeight(64)
self.DRM_UNKNOWN_ICON = QPixmap(I('dialog_warning.png')).scaledToHeight(64)
self.DRM_LOCKED_ICON = QPixmap(I('drm-locked.png')).scaledToHeight(64,
Qt.SmoothTransformation)
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
# self.matches because the SearchFilter returns

View File

@ -25,7 +25,6 @@ from calibre.gui2.store.web_store_dialog import WebStoreDialog
class SmashwordsStore(BasicStoreConfig, StorePlugin):
def open(self, parent=None, detail_item=None, external=False):
settings = self.get_settings()
url = 'http://www.smashwords.com/'
aff_id = '?ref=usernone'
@ -38,12 +37,12 @@ class SmashwordsStore(BasicStoreConfig, StorePlugin):
detail_url = url + detail_item + 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)))
else:
d = WebStoreDialog(self.gui, url, parent, detail_url)
d.setWindowTitle(self.name)
d.set_tags(settings.get(self.name + '_tags', ''))
d.set_tags(self.config.get('tags', ''))
d.exec_()
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