diff --git a/resources/images/news/credit_slips.png b/resources/images/news/credit_slips.png new file mode 100644 index 0000000000..50ac1dc02e Binary files /dev/null and b/resources/images/news/credit_slips.png differ diff --git a/resources/recipes/credit_slips.recipe b/resources/recipes/credit_slips.recipe index 19e19ca2fb..d4fb3a94c0 100644 --- a/resources/recipes/credit_slips.recipe +++ b/resources/recipes/credit_slips.recipe @@ -1,35 +1,44 @@ #!/usr/bin/env python __license__ = 'GPL 3' -__copyright__ = 'zotzot' +__copyright__ = 'zotzo' __docformat__ = 'restructuredtext en' from calibre.web.feeds.news import BasicNewsRecipe class CreditSlips(BasicNewsRecipe): - __license__ = 'GPL v3' - __author__ = 'zotzot' language = 'en' - version = 1 + __author__ = 'zotzot' + version = 2 title = u'Credit Slips.org' publisher = u'Bankr-L' category = u'Economic blog' - description = u'All things about credit.' - cover_url = 'http://bit.ly/hyZSTr' - oldest_article = 50 + description = u'A discussion on credit and bankruptcy' + cover_url = 'http://bit.ly/eAKNCB' + oldest_article = 15 max_articles_per_feed = 100 use_embedded_content = True + no_stylesheets = True + remove_javascript = True + + conversion_options = { + 'comments': description, + 'tags': category, + 'language': 'en', + 'publisher': publisher, + } feeds = [ -(u'Credit Slips', u'http://www.creditslips.org/creditslips/atom.xml') -] - conversion_options = { -'comments': description, -'tags': category, -'language': 'en', -'publisher': publisher -} - extra_css = ''' - body{font-family:verdana,arial,helvetica,geneva,sans-serif;} - img {float: left; margin-right: 0.5em;} - ''' + (u'Credit Slips', u'http://www.creditslips.org/creditslips/atom.xml') + ] + + extra_css = ''' + .author {font-family:Helvetica,sans-serif; font-weight:normal;font-size:small;} + h1 {font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:large;} + p {font-family:Helvetica,Arial,sans-serif;font-size:small;} + body {font-family:Helvetica,Arial,sans-serif;font-size:small;} + ''' + + def populate_article_metadata(self, article, soup, first): + h2 = soup.find('h2') + h2.replaceWith(h2.prettify() + '

Posted by ' + article.author + '

') diff --git a/resources/recipes/post_today.recipe b/resources/recipes/post_today.recipe new file mode 100644 index 0000000000..dc86e68191 --- /dev/null +++ b/resources/recipes/post_today.recipe @@ -0,0 +1,21 @@ +from calibre.web.feeds.news import BasicNewsRecipe + +class AdvancedUserRecipe1299061355(BasicNewsRecipe): + title = u'Post Today' + language = 'th' + __author__ = "Chotechai" + oldest_article = 7 + max_articles_per_feed = 100 + cover_url = 'http://upload.wikimedia.org/wikipedia/th/2/2e/Posttoday_Logo.png' + feeds = [(u'Breaking News', u'http://www.posttoday.com/rss/src/breakingnews.xml'), (u'\u0e02\u0e48\u0e32\u0e27', u'http://www.posttoday.com/rss/src/news.xml'), (u'\u0e27\u0e34\u0e40\u0e04\u0e23\u0e32\u0e30\u0e2b\u0e4c', u'http://www.posttoday.com/rss/src/analyse.xml'), (u'\u0e40\u0e21\u0e32\u0e17\u0e4c\u0e01\u0e31\u0e19\u0e43\u0e2b\u0e49 z', u'http://www.posttoday.com/rss/src/mouth.xml'), (u'\u0e44\u0e17\u0e22\u0e42\u0e0b\u0e44\u0e0b\u0e15\u0e35\u0e49', u'http://www.posttoday.com/rss/src/thaisociety.xml'), (u'\u0e44\u0e25\u0e1f\u0e4c\u0e2a\u0e44\u0e15\u0e25\u0e4c', u'http://www.posttoday.com/rss/src/lifestyle.xml'), (u'\u0e0a\u0e35\u0e49\u0e0a\u0e48\u0e2d\u0e07\u0e23\u0e27\u0e22', u'http://www.posttoday.com/rss/src/moneyguide.xml'), (u'\u0e1a\u0e49\u0e32\u0e19-\u0e04\u0e2d\u0e19\u0e42\u0e14', u'http://www.posttoday.com/rss/src/homecondo.xml'), (u'\u0e22\u0e32\u0e19\u0e22\u0e19\u0e15\u0e4c', u'http://www.posttoday.com/rss/src/motor.xml'), (u'\u0e14\u0e34\u0e08\u0e34\u0e15\u0e2d\u0e25\u0e44\u0e25\u0e1f\u0e4c', u'http://www.posttoday.com/rss/src/digitallife.xml'), (u'\u0e01\u0e35\u0e2c\u0e32', u'http://www.posttoday.com/rss/src/sport.xml'), (u'\u0e23\u0e2d\u0e1a\u0e42\u0e25\u0e01', u'http://www.posttoday.com/rss/src/world.xml'), (u'\u0e01\u0e34\u0e19-\u0e40\u0e17\u0e35\u0e48\u0e22\u0e27', u'http://www.posttoday.com/rss/src/eattravel.xml'), (u'Mind & Soul', u'http://www.posttoday.com/rss/src/mindsoul.xml'), (u'\u0e1a\u0e25\u0e47\u0e2d\u0e01 \u0e1a\u0e01.', u'http://www.posttoday.com/rss/src/blogs.xml')] + keep_only_tags = [] + keep_only_tags.append(dict(name = 'div', attrs = {'class' : +'articleContents'})) + + remove_tags = [] + remove_tags.append(dict(name = 'label')) + remove_tags.append(dict(name = 'span')) + remove_tags.append(dict(name = 'div', attrs = {'class' : +'socialBookmark'})) + remove_tags.append(dict(name = 'div', attrs = {'class' : +'misc'})) diff --git a/resources/recipes/rbc_ru.recipe b/resources/recipes/rbc_ru.recipe new file mode 100644 index 0000000000..4c377a334b --- /dev/null +++ b/resources/recipes/rbc_ru.recipe @@ -0,0 +1,49 @@ +from calibre.web.feeds.news import BasicNewsRecipe + +class AdvancedUserRecipe1286819935(BasicNewsRecipe): + title = u'RBC.ru' + __author__ = 'A. Chewi' + oldest_article = 7 + max_articles_per_feed = 100 + no_stylesheets = True + use_embedded_content = False + conversion_options = {'linearize_tables' : True} + remove_attributes = ['style'] + language = 'ru' + timefmt = ' [%a, %d %b, %Y]' + + keep_only_tags = [dict(name='h2', attrs={}), + dict(name='div', attrs={'class': 'box _ga1_on_'}), + dict(name='h1', attrs={'class': 'news_section'}), + dict(name='div', attrs={'class': 'news_body dotted_border_bottom'}), + dict(name='table', attrs={'class': 'newsBody'}), + dict(name='h2', attrs={'class': 'black'})] + + feeds = [(u'Главные новости', u'http://static.feed.rbc.ru/rbc/internal/rss.rbc.ru/rbc.ru/mainnews.rss'), + (u'Политика', u'http://static.feed.rbc.ru/rbc/internal/rss.rbc.ru/rbc.ru/politics.rss'), + (u'Экономика', u'http://static.feed.rbc.ru/rbc/internal/rss.rbc.ru/rbc.ru/economics.rss'), + (u'Общество', u'http://static.feed.rbc.ru/rbc/internal/rss.rbc.ru/rbc.ru/society.rss'), + (u'Происшествия', u'http://static.feed.rbc.ru/rbc/internal/rss.rbc.ru/rbc.ru/incidents.rss'), + (u'Финансовые новости Quote.rbc.ru', u'http://static.feed.rbc.ru/rbc/internal/rss.rbc.ru/quote.ru/mainnews.rss')] + + + remove_tags = [dict(name='div', attrs={'class': "video-frame"}), + dict(name='div', attrs={'class': "photo-container videoContainer videoSWFLinks videoPreviewSlideContainer notes"}), + dict(name='div', attrs={'class': "notes"}), + dict(name='div', attrs={'class': "publinks"}), + dict(name='a', attrs={'class': "print"}), + dict(name='div', attrs={'class': "photo-report_new notes newslider"}), + dict(name='div', attrs={'class': "videoContainer"}), + dict(name='div', attrs={'class': "videoPreviewSlideContainer"}), + dict(name='a', attrs={'class': "videoPreviewContainer"}), + dict(name='a', attrs={'class': "red"}),] + + def preprocess_html(self, soup): + for alink in soup.findAll('a'): + if alink.string is not None: + tstr = alink.string + alink.replaceWith(tstr) + return soup + + def print_version(self, url): + return url + '?print=true' diff --git a/resources/recipes/thai_post_daily.recipe b/resources/recipes/thai_post_daily.recipe new file mode 100644 index 0000000000..9cd943e593 --- /dev/null +++ b/resources/recipes/thai_post_daily.recipe @@ -0,0 +1,18 @@ +from calibre.web.feeds.news import BasicNewsRecipe + +class AdvancedUserRecipe1299054026(BasicNewsRecipe): + title = u'Thai Post Daily' + __author__ = 'Chotechai P.' + language = 'th' + oldest_article = 7 + max_articles_per_feed = 100 + + feeds = [(u'\u0e02\u0e48\u0e32\u0e27\u0e2b\u0e19\u0e49\u0e32\u0e2b\u0e19\u0e36\u0e48\u0e07', u'http://thaipost.net/taxonomy/term/1/all/feed'), (u'\u0e1a\u0e17\u0e1a\u0e23\u0e23\u0e13\u0e32\u0e18\u0e34\u0e01\u0e32\u0e23', u'http://thaipost.net/taxonomy/term/11/all/feed'), (u'\u0e40\u0e1b\u0e25\u0e27 \u0e2a\u0e35\u0e40\u0e07\u0e34\u0e19', u'http://thaipost.net/taxonomy/term/2/all/feed'), (u'\u0e2a\u0e20\u0e32\u0e1b\u0e23\u0e30\u0e0a\u0e32\u0e0a\u0e19', u'http://thaipost.net/taxonomy/term/3/all/feed'), (u'\u0e16\u0e39\u0e01\u0e17\u0e38\u0e01\u0e02\u0e49\u0e2d', u'http://thaipost.net/taxonomy/term/4/all/feed'), (u'\u0e01\u0e32\u0e23\u0e40\u0e21\u0e37\u0e2d\u0e07', u'http://thaipost.net/taxonomy/term/5/all/feed'), (u'\u0e17\u0e48\u0e32\u0e19\u0e02\u0e38\u0e19\u0e19\u0e49\u0e2d\u0e22', u'http://thaipost.net/taxonomy/term/12/all/feed'), (u'\u0e1a\u0e17\u0e04\u0e27\u0e32\u0e21\u0e1e\u0e34\u0e40\u0e28\u0e29', u'http://thaipost.net/taxonomy/term/66/all/feed'), (u'\u0e23\u0e32\u0e22\u0e07\u0e32\u0e19\u0e1e\u0e34\u0e40\u0e28\u0e29', u'http://thaipost.net/taxonomy/term/67/all/feed'), (u'\u0e1a\u0e31\u0e19\u0e17\u0e36\u0e01\u0e2b\u0e19\u0e49\u0e32 4', u'http://thaipost.net/taxonomy/term/13/all/feed'), (u'\u0e40\u0e2a\u0e35\u0e22\u0e1a\u0e0b\u0e36\u0e48\u0e07\u0e2b\u0e19\u0e49\u0e32', u'http://thaipost.net/taxonomy/term/64/all/feed'), (u'\u0e04\u0e31\u0e19\u0e1b\u0e32\u0e01\u0e2d\u0e22\u0e32\u0e01\u0e40\u0e25\u0e48\u0e32', u'http://thaipost.net/taxonomy/term/65/all/feed'), (u'\u0e40\u0e28\u0e23\u0e29\u0e10\u0e01\u0e34\u0e08', u'http://thaipost.net/taxonomy/term/6/all/feed'), (u'\u0e01\u0e23\u0e30\u0e08\u0e01\u0e44\u0e23\u0e49\u0e40\u0e07\u0e32', u'http://thaipost.net/taxonomy/term/14/all/feed'), (u'\u0e01\u0e23\u0e30\u0e08\u0e01\u0e2b\u0e31\u0e01\u0e21\u0e38\u0e21', u'http://thaipost.net/taxonomy/term/71/all/feed'), (u'\u0e04\u0e34\u0e14\u0e40\u0e2b\u0e19\u0e37\u0e2d\u0e01\u0e23\u0e30\u0e41\u0e2a', u'http://thaipost.net/taxonomy/term/69/all/feed'), (u'\u0e23\u0e32\u0e22\u0e07\u0e32\u0e19', u'http://thaipost.net/taxonomy/term/68/all/feed'), (u'\u0e2d\u0e34\u0e42\u0e04\u0e42\u0e1f\u0e01\u0e31\u0e2a', u'http://thaipost.net/taxonomy/term/10/all/feed'), (u'\u0e01\u0e32\u0e23\u0e28\u0e36\u0e01\u0e29\u0e32-\u0e2a\u0e32\u0e18\u0e32\u0e23\u0e13\u0e2a\u0e38\u0e02', u'http://thaipost.net/taxonomy/term/7/all/feed'), (u'\u0e15\u0e48\u0e32\u0e07\u0e1b\u0e23\u0e30\u0e40\u0e17\u0e28', u'http://thaipost.net/taxonomy/term/8/all/feed'), (u'\u0e01\u0e35\u0e2c\u0e32', u'http://thaipost.net/taxonomy/term/9/all/feed')] + + def print_version(self, url): + return url.replace(url, 'http://www.thaipost.net/print/' + url [32:]) + + remove_tags = [] + remove_tags.append(dict(name = 'div', attrs = {'class' : 'print-logo'})) + remove_tags.append(dict(name = 'div', attrs = {'class' : 'print-site_name'})) + remove_tags.append(dict(name = 'div', attrs = {'class' : 'print-breadcrumb'})) diff --git a/src/calibre/devices/misc.py b/src/calibre/devices/misc.py index 8cf0fb5a06..07b381d11a 100644 --- a/src/calibre/devices/misc.py +++ b/src/calibre/devices/misc.py @@ -272,6 +272,7 @@ class NEXTBOOK(USBMS): VENDOR_NAME = 'NEXT2' WINDOWS_MAIN_MEM = WINDOWS_CARD_A_MEM = '1.0.14' SUPPORTS_SUB_DIRS = True + THUMBNAIL_HEIGHT = 120 ''' def upload_cover(self, path, filename, metadata, filepath): diff --git a/src/calibre/gui2/actions/choose_library.py b/src/calibre/gui2/actions/choose_library.py index f3a7f1742d..6f4ca624cb 100644 --- a/src/calibre/gui2/actions/choose_library.py +++ b/src/calibre/gui2/actions/choose_library.py @@ -355,6 +355,7 @@ class ChooseLibraryAction(InterfaceAction): print print 'before:', self.before_mem print 'after:', memory()/1024**2 + print self.dbref = self.before_mem = None diff --git a/src/calibre/gui2/dialogs/metadata_bulk.ui b/src/calibre/gui2/dialogs/metadata_bulk.ui index ae3445998b..1654ff8261 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.ui +++ b/src/calibre/gui2/dialogs/metadata_bulk.ui @@ -341,7 +341,7 @@ from the value in the box 1 - 990000 + 99000000 1 diff --git a/src/calibre/gui2/dialogs/metadata_single.ui b/src/calibre/gui2/dialogs/metadata_single.ui index 5bcf268aaa..ced5030f94 100644 --- a/src/calibre/gui2/dialogs/metadata_single.ui +++ b/src/calibre/gui2/dialogs/metadata_single.ui @@ -419,7 +419,7 @@ If the box is colored green, then text matches the individual author's sort stri Book - 9999.989999999999782 + 99999999.989999994635582 diff --git a/src/calibre/gui2/metadata/basic_widgets.py b/src/calibre/gui2/metadata/basic_widgets.py index a135176daf..d5a8de7b67 100644 --- a/src/calibre/gui2/metadata/basic_widgets.py +++ b/src/calibre/gui2/metadata/basic_widgets.py @@ -351,7 +351,7 @@ class SeriesIndexEdit(QDoubleSpinBox): QDoubleSpinBox.__init__(self, parent) self.dialog = parent self.db = self.original_series_name = None - self.setMaximum(1000000) + self.setMaximum(10000000) self.series_edit = series_edit series_edit.currentIndexChanged.connect(self.enable) series_edit.editTextChanged.connect(self.enable) diff --git a/src/calibre/gui2/preferences/__init__.py b/src/calibre/gui2/preferences/__init__.py index 7267716ea8..54eb2f713c 100644 --- a/src/calibre/gui2/preferences/__init__.py +++ b/src/calibre/gui2/preferences/__init__.py @@ -8,7 +8,7 @@ __docformat__ = 'restructuredtext en' import textwrap from PyQt4.Qt import QWidget, pyqtSignal, QCheckBox, QAbstractSpinBox, \ - QLineEdit, QComboBox, QVariant + QLineEdit, QComboBox, QVariant, Qt from calibre.customize.ui import preferences_plugins from calibre.utils.config import ConfigProxy @@ -82,6 +82,8 @@ class ConfigWidgetInterface(object): class Setting(object): + CHOICES_SEARCH_FLAGS = Qt.MatchExactly | Qt.MatchCaseSensitive + def __init__(self, name, config_obj, widget, gui_name=None, empty_string_is_None=True, choices=None, restart_required=False): self.name, self.gui_name = name, gui_name @@ -168,7 +170,8 @@ class Setting(object): elif self.datatype == 'string': self.gui_obj.setText(val if val else '') elif self.datatype == 'choice': - idx = self.gui_obj.findData(QVariant(val)) + idx = self.gui_obj.findData(QVariant(val), role=Qt.UserRole, + flags=self.CHOICES_SEARCH_FLAGS) if idx == -1: idx = 0 self.gui_obj.setCurrentIndex(idx) diff --git a/src/calibre/gui2/preferences/behavior.py b/src/calibre/gui2/preferences/behavior.py index aeee6e5064..45a63ce529 100644 --- a/src/calibre/gui2/preferences/behavior.py +++ b/src/calibre/gui2/preferences/behavior.py @@ -9,7 +9,7 @@ import re from PyQt4.Qt import Qt, QVariant, QListWidgetItem -from calibre.gui2.preferences import ConfigWidgetBase, test_widget +from calibre.gui2.preferences import ConfigWidgetBase, test_widget, Setting from calibre.gui2.preferences.behavior_ui import Ui_Form from calibre.gui2 import config, info_dialog, dynamic from calibre.utils.config import prefs @@ -20,6 +20,10 @@ from calibre.ebooks.oeb.iterator import is_supported from calibre.constants import iswindows from calibre.utils.icu import sort_key +class OutputFormatSetting(Setting): + + CHOICES_SEARCH_FLAGS = Qt.MatchFixedString + class ConfigWidget(ConfigWidgetBase, Ui_Form): def genesis(self, gui): @@ -43,7 +47,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): output_formats = list(sorted(available_output_formats())) output_formats.remove('oeb') choices = [(x.upper(), x) for x in output_formats] - r('output_format', prefs, choices=choices) + r('output_format', prefs, choices=choices, setting=OutputFormatSetting) restrictions = sorted(saved_searches().names(), key=sort_key) choices = [('', '')] + [(x, x) for x in restrictions] diff --git a/src/calibre/gui2/tag_view.py b/src/calibre/gui2/tag_view.py index 6371f541a7..bd7f6fbe70 100644 --- a/src/calibre/gui2/tag_view.py +++ b/src/calibre/gui2/tag_view.py @@ -572,6 +572,13 @@ class TagTreeItem(object): # {{{ else: self.tooltip = '' + def break_cycles(self): + for x in self.children: + if hasattr(x, 'break_cycles'): + x.break_cycles() + self.parent = self.icon_state_map = self.bold_font = self.tag = \ + self.icon = self.children = None + def __str__(self): if self.type == self.ROOT: return 'ROOT' @@ -780,6 +787,7 @@ class TagsModel(QAbstractItemModel): # {{{ self.refresh(data=data) def break_cycles(self): + self.root_item.break_cycles() self.db = self.root_item = None def mimeTypes(self): diff --git a/src/calibre/gui2/wizard/__init__.py b/src/calibre/gui2/wizard/__init__.py index 5f9f1828fa..c629b10b5d 100644 --- a/src/calibre/gui2/wizard/__init__.py +++ b/src/calibre/gui2/wizard/__init__.py @@ -51,7 +51,7 @@ class Device(object): @classmethod def set_output_format(cls): if cls.output_format: - prefs.set('output_format', cls.output_format) + prefs.set('output_format', cls.output_format.lower()) @classmethod def commit(cls): diff --git a/src/calibre/library/caches.py b/src/calibre/library/caches.py index 4f2d80192a..659521da48 100644 --- a/src/calibre/library/caches.py +++ b/src/calibre/library/caches.py @@ -578,7 +578,7 @@ class ResultCache(SearchQueryParser): # {{{ # special case: colon-separated fields such as identifiers. isbn # is a special case within the case - if fm['is_csp']: + if fm.get('is_csp', False): if location == 'identifiers' and original_location == 'isbn': return self.get_keypair_matches('identifiers', '=isbn:'+query, candidates) diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index 4686b25821..ee7dcbe81a 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -1273,7 +1273,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): for category in tb_cats.keys(): cat = tb_cats[category] if not cat['is_category'] or cat['kind'] in ['user', 'search'] \ - or category in ['news', 'formats'] or cat['is_csp']: + or category in ['news', 'formats'] or cat.get('is_csp', + False): continue # Get the ids for the item values if not cat['is_custom']: diff --git a/src/calibre/library/field_metadata.py b/src/calibre/library/field_metadata.py index 965a28b0e7..d89322954f 100644 --- a/src/calibre/library/field_metadata.py +++ b/src/calibre/library/field_metadata.py @@ -459,7 +459,8 @@ class FieldMetadata(dict): return l def add_custom_field(self, label, table, column, datatype, colnum, name, - display, is_editable, is_multiple, is_category, is_csp): + display, is_editable, is_multiple, is_category, + is_csp=False): key = self.custom_field_prefix + label if key in self._tb_cats: raise ValueError('Duplicate custom field [%s]'%(label))