diff --git a/recipes/icons/prostamerika.png b/recipes/icons/prostamerika.png new file mode 100644 index 0000000000..f88c846bed Binary files /dev/null and b/recipes/icons/prostamerika.png differ diff --git a/recipes/icons/sb_nation.png b/recipes/icons/sb_nation.png new file mode 100644 index 0000000000..9d82e492de Binary files /dev/null and b/recipes/icons/sb_nation.png differ diff --git a/recipes/icons/wvhooligan.png b/recipes/icons/wvhooligan.png new file mode 100644 index 0000000000..81a59118c9 Binary files /dev/null and b/recipes/icons/wvhooligan.png differ diff --git a/recipes/prostamerika.recipe b/recipes/prostamerika.recipe new file mode 100644 index 0000000000..b216ee469d --- /dev/null +++ b/recipes/prostamerika.recipe @@ -0,0 +1,68 @@ +#!/usr/bin/env python +# encoding: utf-8 + +__license__ = 'GPL 3' +__copyright__ = 'zotzo' + +""" +http://www.prostamerika.com/ +""" + +from calibre.web.feeds.news import BasicNewsRecipe + + +class ProstAmerika(BasicNewsRecipe): + title = 'Prost Amerika' + language = 'en' + __author__ = 'rylsfan' + #authors = + description = 'Seattle soccer with a European accent. News, features, and match reports.' + publisher = 'ProstAmerika' # 4464 fremont avenue n, # 209, Seattle, 98103, United States + category = 'Sports' + + oldest_article = 7 + max_articles_per_feed = 100 + + cover_url = 'http://img17.imageshack.us/img17/9498/prostamerika.jpg' + masthead_url = 'http://www.prostamerika.com/soundersfc/wp-content/uploads/2011/02/PASoccer_taglinewhole.jpg' + + encoding = 'utf-8' + + no_stylesheets = True + use_embedded_content = False + remove_javascript = True + + feeds =[ + (u'Cascadia', u'http://www.prostamerika.com/category/localfootball/feed/' ), + (u'MLS', u'http://www.prostamerika.com/category/mls/feed/'), + (u'EPL', u'http://www.prostamerika.com/category/epl/feed/'), + (u'World', u'http://www.prostamerika.com/category/international-soccer/feed/'), + (u'Fan Culture',u'http://www.prostamerika.com/category/fan-culture/feed/') + + ] + + keep_only_tags = [dict(name='div', attrs={'id':'maincontent'})] + remove_tags = [ + {'class':'tweetmeme_button'}, + {'class':'wp-caption-text'} + ] + + + remove_tags_after =[ + {'class':'tweetmeme_button'} + ] + + extra_css = ''' + h1{font-family:Didot,Helvetica,sans-serif; font-weight:bold;font-size:large;} + h2{font-family:Arial,Helvetica,sans-serif; font-weight:normal;font-size:small;} + p{font-family:Arial,Helvetica,sans-serif;font-size:small;} + body{font-family:Helvetica,Arial,sans-serif;font-size:small;} + ''' + + def preprocess_html(self, soup): + return self.adeify_images(soup) + + + + + diff --git a/recipes/sb_nation.recipe b/recipes/sb_nation.recipe new file mode 100644 index 0000000000..19b828cdb7 --- /dev/null +++ b/recipes/sb_nation.recipe @@ -0,0 +1,56 @@ +#!/usr/bin/env python + +__license__ = 'GPL v3' +__copyright__ = 'Zotzo' +''' +http://www.stumptownfooty.com/ +http://www.eightysixforever.com +http://www.sounderatheart.com +http://www.dailysoccerfix.com/ + +''' +from calibre.web.feeds.news import BasicNewsRecipe + +class SBNation(BasicNewsRecipe): + title = u'SBNation' + __author__ = 'rylsfan' + description = u"More than 290 individual communities, each offering high quality year-round coverage and conversation led by fans who are passionate." + oldest_article = 3 + language = 'en' + max_articles_per_feed = 100 + no_stylesheets = True + use_embedded_content = False + + #cover_url = 'http://img132.imageshack.us/img132/4913/2hyggjegqqdywzn9.png' + + keep_only_tags = [ + dict(name='h2', attrs={'class':'title'}) + ,dict(name='div', attrs={'class':'entry-body'}) + ] + + remove_tags_after = dict(name='div', attrs={'class':'footline entry-actions'}) + remove_tags = [ + dict(name='div', attrs={'class':'footline entry-actions'}), + {'class': 'extend-divide'} + ] + # SBNation has 300 special blogs to choose from. These are just a couple! + feeds = [ + (u'Daily Fix', u'http://www.dailysoccerfix.com/rss/'), + (u"Stumptown Footy", u'http://www.stumptownfooty.com/rss/'), + (u'Sounders', u'http://www.sounderatheart.com/rss/'), + (u'Whitecaps', u'http://www.eightysixforever.com/rss/'), + ] + + extra_css = """ + h1{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:large;} + h2{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:large;} + p{font-family:Helvetica,sans-serif; display: block; text-align: left; text-decoration: none; text-indent: 0%;} + body{font-family:Helvetica,Arial,sans-serif;font-size:small;} + """ + + def preprocess_html(self, soup): + return self.adeify_images(soup) + + def populate_article_metadata(self, article, soup, first): + h2 = soup.find('h2') + h2.replaceWith(h2.prettify() + '

By ' + article.author + '

') diff --git a/recipes/wvhooligan.recipe b/recipes/wvhooligan.recipe new file mode 100644 index 0000000000..680ac6f244 --- /dev/null +++ b/recipes/wvhooligan.recipe @@ -0,0 +1,61 @@ +#!/usr/bin/env python +__license__ = 'GPL 3' +__copyright__ = 'zotzo' +__docformat__ = 'restructuredtext en' +''' +http://wvhooligan.com/ +''' +from calibre.web.feeds.news import BasicNewsRecipe +#import re + +class wvHooligan(BasicNewsRecipe): + authors = u'Drew Epperley' + __author__ = 'rylsfan' + language = 'en' + version = 2 + + title = u'WV Hooligan' + publisher = u'Drew Epperley' + publication_type = 'Blog' + category = u'Soccer' + description = u'A look at Major League Soccer (MLS) through the eyes of a MLS writer and fan.' + + cover_url = 'http://wvhooligan.com/wp-content/themes/urbanelements/images/logo3.png' + + oldest_article = 15 + max_articles_per_feed = 150 + use_embedded_content = True + no_stylesheets = True + remove_javascript = True + encoding = 'utf8' + + conversion_options = { + 'comment' : description + , 'tags' : category + , 'publisher' : publisher + , 'language' : language + } + + remove_tags = [ + {'class': 'feedflare'}, + {'class': 'tweetmeme_button'}, + ] + + def preprocess_html(self, soup): + return self.adeify_images(soup) + + feeds =[ + (u'Stories', u'http://feeds2.feedburner.com/wvhooligan'), + (u'MLS', u'http://wvhooligan.com/category/mls/feed/'), + (u'MLS Power Rankings', u'http://wvhooligan.com/category/power-rankings/feed/'), + (u'MLS Expansion', u'http://wvhooligan.com/category/mls/expansion-talk/feed/'), + (u'US National Team', u'http://wvhooligan.com/category/us-national-team/feed/'), + (u'College', u'http://wvhooligan.com/category/college-soccer/feed/'), + ] + + extra_css = ''' + h1{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:large;} + h2{font-family:Arial,Helvetica,sans-serif; font-weight:normal;font-size:small;} + p{font-family:Arial,Helvetica,sans-serif;font-size:small;} + body{font-family:Helvetica,Arial,sans-serif;font-size:small;} + ''' diff --git a/resources/fonts/liberation/LiberationMono-Bold.ttf b/resources/fonts/liberation/LiberationMono-Bold.ttf index 95de75300f..42941e57b1 100644 Binary files a/resources/fonts/liberation/LiberationMono-Bold.ttf and b/resources/fonts/liberation/LiberationMono-Bold.ttf differ diff --git a/resources/fonts/liberation/LiberationMono-BoldItalic.ttf b/resources/fonts/liberation/LiberationMono-BoldItalic.ttf index 11ec3e7793..4682e4de1f 100644 Binary files a/resources/fonts/liberation/LiberationMono-BoldItalic.ttf and b/resources/fonts/liberation/LiberationMono-BoldItalic.ttf differ diff --git a/resources/fonts/liberation/LiberationMono-Italic.ttf b/resources/fonts/liberation/LiberationMono-Italic.ttf index 08f55d6367..e19f08cfb7 100644 Binary files a/resources/fonts/liberation/LiberationMono-Italic.ttf and b/resources/fonts/liberation/LiberationMono-Italic.ttf differ diff --git a/resources/fonts/liberation/LiberationMono-Regular.ttf b/resources/fonts/liberation/LiberationMono-Regular.ttf index e3024a09d8..dea96958a1 100644 Binary files a/resources/fonts/liberation/LiberationMono-Regular.ttf and b/resources/fonts/liberation/LiberationMono-Regular.ttf differ diff --git a/resources/fonts/liberation/LiberationSans-Bold.ttf b/resources/fonts/liberation/LiberationSans-Bold.ttf index 53200d956c..b29a5640e4 100644 Binary files a/resources/fonts/liberation/LiberationSans-Bold.ttf and b/resources/fonts/liberation/LiberationSans-Bold.ttf differ diff --git a/resources/fonts/liberation/LiberationSans-BoldItalic.ttf b/resources/fonts/liberation/LiberationSans-BoldItalic.ttf index d06deca60d..0b0bf94a57 100644 Binary files a/resources/fonts/liberation/LiberationSans-BoldItalic.ttf and b/resources/fonts/liberation/LiberationSans-BoldItalic.ttf differ diff --git a/resources/fonts/liberation/LiberationSans-Italic.ttf b/resources/fonts/liberation/LiberationSans-Italic.ttf index 07275adf6c..4a430cdddd 100644 Binary files a/resources/fonts/liberation/LiberationSans-Italic.ttf and b/resources/fonts/liberation/LiberationSans-Italic.ttf differ diff --git a/resources/fonts/liberation/LiberationSans-Regular.ttf b/resources/fonts/liberation/LiberationSans-Regular.ttf index 09fac2ff94..2de10634e0 100644 Binary files a/resources/fonts/liberation/LiberationSans-Regular.ttf and b/resources/fonts/liberation/LiberationSans-Regular.ttf differ diff --git a/resources/fonts/liberation/LiberationSerif-Bold.ttf b/resources/fonts/liberation/LiberationSerif-Bold.ttf index 3a4ab92ac4..892746e128 100644 Binary files a/resources/fonts/liberation/LiberationSerif-Bold.ttf and b/resources/fonts/liberation/LiberationSerif-Bold.ttf differ diff --git a/resources/fonts/liberation/LiberationSerif-BoldItalic.ttf b/resources/fonts/liberation/LiberationSerif-BoldItalic.ttf index dc75de89c0..ad754700fd 100644 Binary files a/resources/fonts/liberation/LiberationSerif-BoldItalic.ttf and b/resources/fonts/liberation/LiberationSerif-BoldItalic.ttf differ diff --git a/resources/fonts/liberation/LiberationSerif-Italic.ttf b/resources/fonts/liberation/LiberationSerif-Italic.ttf index d92b5e3929..e81544aab2 100644 Binary files a/resources/fonts/liberation/LiberationSerif-Italic.ttf and b/resources/fonts/liberation/LiberationSerif-Italic.ttf differ diff --git a/resources/fonts/liberation/LiberationSerif-Regular.ttf b/resources/fonts/liberation/LiberationSerif-Regular.ttf index d100691a25..155675f711 100644 Binary files a/resources/fonts/liberation/LiberationSerif-Regular.ttf and b/resources/fonts/liberation/LiberationSerif-Regular.ttf differ diff --git a/src/calibre/devices/bambook/libbambookcore.py b/src/calibre/devices/bambook/libbambookcore.py index 35d04ba4ac..e77ac1da7b 100644 --- a/src/calibre/devices/bambook/libbambookcore.py +++ b/src/calibre/devices/bambook/libbambookcore.py @@ -10,7 +10,7 @@ Sanda library wrapper import ctypes, uuid, hashlib, os, sys from threading import Event, Lock -from calibre.constants import iswindows, islinux, isosx +from calibre.constants import iswindows from calibre import load_library try: @@ -29,12 +29,9 @@ try: except: lib_handle = None +text_encoding = 'utf-8' if iswindows: text_encoding = 'mbcs' -elif islinux: - text_encoding = 'utf-8' -elif isosx: - text_encoding = 'utf-8' def is_bambook_lib_ready(): return lib_handle != None diff --git a/src/calibre/ebooks/metadata/sources/amazon.py b/src/calibre/ebooks/metadata/sources/amazon.py index abf35a9465..c9c742f88c 100644 --- a/src/calibre/ebooks/metadata/sources/amazon.py +++ b/src/calibre/ebooks/metadata/sources/amazon.py @@ -483,7 +483,6 @@ class Amazon(Source): log.exception('Failed to download cover from:', cached_url) # }}} - if __name__ == '__main__': # tests {{{ # To run these test use: calibre-debug -e # src/calibre/ebooks/metadata/sources/amazon.py diff --git a/src/calibre/ebooks/metadata/sources/identify.py b/src/calibre/ebooks/metadata/sources/identify.py index 5bc0c5b256..ed7d8f2203 100644 --- a/src/calibre/ebooks/metadata/sources/identify.py +++ b/src/calibre/ebooks/metadata/sources/identify.py @@ -42,6 +42,7 @@ def is_worker_alive(workers): return False def identify(log, abort, title=None, authors=None, identifiers=[], timeout=30): + start_time = time.time() plugins = list(metadata_plugins['identify']) kwargs = { @@ -105,3 +106,21 @@ def identify(log, abort, title=None, authors=None, identifiers=[], timeout=30): log(plog) log('\n'+'*'*80) + for i, result in enumerate(results): + result.relevance_in_source = i + result.has_cached_cover_url = \ + plugin.get_cached_cover_url(result.identifiers) is not None + result.identify_plugin = plugin + + log('The identify phase took %.2f seconds'%(time.time() - start_time)) + log('Merging results from different sources and finding earliest', + 'publication dates') + start_time = time.time() + merged_results = merge_identify_results(results, log) + log('We have %d merged results, merging took: %.2f seconds' % + (len(merged_results), time.time() - start_time)) + +def merge_identify_results(result_map, log): + pass + + diff --git a/src/calibre/ebooks/metadata/xisbn.py b/src/calibre/ebooks/metadata/xisbn.py index aaeb1c6b98..2864fba323 100644 --- a/src/calibre/ebooks/metadata/xisbn.py +++ b/src/calibre/ebooks/metadata/xisbn.py @@ -76,9 +76,9 @@ class xISBN(object): xisbn = xISBN() if __name__ == '__main__': - import sys + import sys, pprint isbn = sys.argv[-1] - print xisbn.get_data(isbn) + print pprint.pprint(xisbn.get_data(isbn)) print print xisbn.get_associated_isbns(isbn) diff --git a/src/calibre/gui2/actions/fetch_news.py b/src/calibre/gui2/actions/fetch_news.py index f7756efbab..f94dfbc88c 100644 --- a/src/calibre/gui2/actions/fetch_news.py +++ b/src/calibre/gui2/actions/fetch_news.py @@ -5,6 +5,8 @@ __license__ = 'GPL v3' __copyright__ = '2010, Kovid Goyal ' __docformat__ = 'restructuredtext en' +import gc + from PyQt4.Qt import Qt from calibre.gui2 import Dispatcher @@ -53,11 +55,11 @@ class FetchNewsAction(InterfaceAction): def scheduled_recipe_fetched(self, job): temp_files, fmt, arg = self.conversion_jobs.pop(job) - pt = temp_files[0] + fname = temp_files[0].name if job.failed: self.scheduler.recipe_download_failed(arg) return self.gui.job_exception(job) - id = self.gui.library_view.model().add_news(pt.name, arg) + id = self.gui.library_view.model().add_news(fname, arg) # Arg may contain a "keep_issues" variable. If it is non-zero, # delete all but newest x issues. @@ -81,5 +83,6 @@ class FetchNewsAction(InterfaceAction): self.gui.status_bar.show_message(arg['title'] + _(' fetched.'), 3000) self.gui.email_news(id) self.gui.sync_news() + gc.collect() diff --git a/src/calibre/gui2/viewer/documentview.py b/src/calibre/gui2/viewer/documentview.py index 4102aea412..06964cda1c 100644 --- a/src/calibre/gui2/viewer/documentview.py +++ b/src/calibre/gui2/viewer/documentview.py @@ -171,10 +171,11 @@ class Document(QWebPage): # {{{ self.misc_config() self.after_load() - def __init__(self, shortcuts, parent=None): + def __init__(self, shortcuts, parent=None, resize_callback=lambda: None): QWebPage.__init__(self, parent) self.setObjectName("py_bridge") self.debug_javascript = False + self.resize_callback = resize_callback self.current_language = None self.loaded_javascript = False @@ -237,6 +238,12 @@ class Document(QWebPage): # {{{ if self.loaded_javascript: return self.loaded_javascript = True + self.javascript( + ''' + window.onresize = function(event) { + window.py_bridge.window_resized(); + } + ''') if jquery is None: jquery = P('content_server/jquery.js', data=True) self.javascript(jquery) @@ -298,6 +305,10 @@ class Document(QWebPage): # {{{ def debug(self, msg): prints(msg) + @pyqtSignature('') + def window_resized(self): + self.resize_callback() + def reference_mode(self, enable): self.javascript(('enter' if enable else 'leave')+'_reference_mode()') @@ -424,12 +435,19 @@ class Document(QWebPage): # {{{ def xpos(self): return self.mainFrame().scrollPosition().x() - @property + @dynamic_property def scroll_fraction(self): - try: - return float(self.ypos)/(self.height-self.window_height) - except ZeroDivisionError: - return 0. + def fget(self): + try: + return float(self.ypos)/(self.height-self.window_height) + except ZeroDivisionError: + return 0. + def fset(self, val): + npos = val * (self.height - self.window_height) + if npos < 0: + npos = 0 + self.scroll_to(x=self.xpos, y=npos) + return property(fget=fget, fset=fset) @property def hscroll_fraction(self): @@ -493,7 +511,8 @@ class DocumentView(QWebView): # {{{ self._size_hint = QSize(510, 680) self.initial_pos = 0.0 self.to_bottom = False - self.document = Document(self.shortcuts, parent=self) + self.document = Document(self.shortcuts, parent=self, + resize_callback=self.viewport_resized) self.setPage(self.document) self.manager = None self._reference_mode = False @@ -630,9 +649,13 @@ class DocumentView(QWebView): # {{{ def sizeHint(self): return self._size_hint - @property + @dynamic_property def scroll_fraction(self): - return self.document.scroll_fraction + def fget(self): + return self.document.scroll_fraction + def fset(self, val): + self.document.scroll_fraction = float(val) + return property(fget=fget, fset=fset) @property def hscroll_fraction(self): @@ -968,9 +991,11 @@ class DocumentView(QWebView): # {{{ def resizeEvent(self, event): ret = QWebView.resizeEvent(self, event) QTimer.singleShot(10, self.initialize_scrollbar) + return ret + + def viewport_resized(self): if self.manager is not None: self.manager.viewport_resized(self.scroll_fraction) - return ret def event(self, ev): typ = ev.type() diff --git a/src/calibre/gui2/viewer/main.py b/src/calibre/gui2/viewer/main.py index c704b98dc9..303d73dc11 100644 --- a/src/calibre/gui2/viewer/main.py +++ b/src/calibre/gui2/viewer/main.py @@ -240,7 +240,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer): self.connect(self.action_reference_mode, SIGNAL('triggered(bool)'), lambda x: self.view.reference_mode(x)) self.connect(self.action_metadata, SIGNAL('triggered(bool)'), lambda x:self.metadata.setVisible(x)) - self.connect(self.action_table_of_contents, SIGNAL('toggled(bool)'), lambda x:self.toc.setVisible(x)) + self.action_table_of_contents.toggled[bool].connect(self.set_toc_visible) self.connect(self.action_copy, SIGNAL('triggered(bool)'), self.copy) self.connect(self.action_font_size_larger, SIGNAL('triggered(bool)'), self.font_size_larger) @@ -310,6 +310,9 @@ class EbookViewer(MainWindow, Ui_EbookViewer): self.restore_state() + def set_toc_visible(self, yes): + self.toc.setVisible(yes) + def clear_recent_history(self, *args): vprefs.set('viewer_open_history', []) self.build_recent_menu()