From b95c532ba3f5eb8b645d9839cccf84d4de856cea Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 27 Nov 2011 07:42:57 +0530 Subject: [PATCH 01/23] ... --- resources/default_tweaks.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/default_tweaks.py b/resources/default_tweaks.py index 224038b0f9..c71e94a70e 100644 --- a/resources/default_tweaks.py +++ b/resources/default_tweaks.py @@ -219,7 +219,7 @@ per_language_title_sort_articles = { r'Una\s+', r'Unos\s+', r'Unas\s+'), # French 'fra' : (r'Le\s+', r'La\s+', r"L'", r'Les\s+', r'Un\s+', r'Une\s+', - r'Des\s+'), + r'Des\s+', r'De\s+', r'La\s+', r'De\s+La\s+', r"D'"), # Italian 'ita' : (r'Lo\s+', r'Il\s+', r"L'", r'La\s+', r'Gli\s+', r'I\s+', r'Le\s+', ), @@ -230,7 +230,7 @@ per_language_title_sort_articles = { 'ron' : (r'Un\s+', r'O\s+', r'Nişte\s+', ), # German 'deu' : (r'Der\s+', r'Die\s+', r'Das\s+', r'Den\s+', r'Ein\s+', - r'Eine\s+', r'Einen\s+', ), + r'Eine\s+', r'Einen\s+', r'Dem\s+', ), # Dutch 'nld' : (r'De\s+', r'Het\s+', r'Een\s+', r"'n\s+", r"'s\s+", r'Ene\s+', r'Ener\s+', r'Enes\s+', r'Den\s+', r'Der\s+', r'Des\s+', From 8e7a83fc9088f90bd6b4e5ccff66de4a9f6a6e9d Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 27 Nov 2011 07:47:27 +0530 Subject: [PATCH 02/23] Cosmopolitan UK by Dave Asbury --- recipes/cosmopolitan_uk.recipe | 51 ++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 recipes/cosmopolitan_uk.recipe diff --git a/recipes/cosmopolitan_uk.recipe b/recipes/cosmopolitan_uk.recipe new file mode 100644 index 0000000000..21317063ab --- /dev/null +++ b/recipes/cosmopolitan_uk.recipe @@ -0,0 +1,51 @@ +import re +from calibre.web.feeds.news import BasicNewsRecipe +#from calibre import __appname__ +from calibre.utils.magick import Image +class AdvancedUserRecipe1306097511(BasicNewsRecipe): + title = u'Cosmopolitan UK' + description = 'Fashion, beauty and Gossip for women from COSMOPOLITAN -UK' + + __author__ = 'Dave Asbury' + # greyscale code by Starson + cover_url = 'http://www.cosmopolitan.magazine.co.uk/files/4613/2085/8988/Cosmo_Cover3.jpg' + no_stylesheets = True + oldest_article = 7 + max_articles_per_feed = 20 + remove_empty_feeds = True + remove_javascript = True + + preprocess_regexps = [ + (re.compile(r'.*?', re.IGNORECASE | re.DOTALL), lambda match: '')] + language = 'en_GB' + + + masthead_url = 'http://www.cosmopolitan.co.uk/cm/cosmopolitanuk/site_images/header/cosmouk_logo_home.gif' + + + keep_only_tags = [ + dict(attrs={'class' : ['dateAuthor', 'publishDate']}), + dict(name='div',attrs ={'id' : ['main_content']}) + ] + remove_tags = [ + dict(name='div',attrs={'class' : ['blogInfo','viral_toolbar','comment_number','prevEntry nav']}), + dict(name='div',attrs={'class' : 'blog_module_about_the_authors'}), + dict(attrs={'id': ['breadcrumbs','comment','related_links_list','right_rail','content_sec_fb_more','content_sec_mostpopularstories','content-sec_fb_frame_viewfb_bot']}), + dict(attrs={'class' : ['read_liked_that_header','fb_back_next_area']}) + ] + + feeds = [ + (u'Love & Sex', u'http://www.cosmopolitan.co.uk/love-sex/rss/'), (u'Men', u'http://cosmopolitan.co.uk/men/rss/'), (u'Fashion', u'http://cosmopolitan.co.uk/fashion/rss/'), (u'Hair & Beauty', u'http://cosmopolitan.co.uk/beauty-hair/rss/'), (u'LifeStyle', u'http://cosmopolitan.co.uk/lifestyle/rss/'), (u'Cosmo On Campus', u'http://cosmopolitan.co.uk/campus/rss/'), (u'Celebrity Gossip', u'http://cosmopolitan.co.uk/celebrity-gossip/rss/')] + + def postprocess_html(self, soup, first): + #process all the images + for tag in soup.findAll(lambda tag: tag.name.lower()=='img' and tag.has_key('src')): + iurl = tag['src'] + img = Image() + img.open(iurl) + if img < 0: + raise RuntimeError('Out of memory') + img.type = "GrayscaleType" + img.save(iurl) + return soup + From f1fca7cbb984ce61ac68b983b8226e11bf6b9517 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 27 Nov 2011 07:59:12 +0530 Subject: [PATCH 03/23] ... --- resources/default_tweaks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/default_tweaks.py b/resources/default_tweaks.py index c71e94a70e..a359f73be1 100644 --- a/resources/default_tweaks.py +++ b/resources/default_tweaks.py @@ -219,7 +219,7 @@ per_language_title_sort_articles = { r'Una\s+', r'Unos\s+', r'Unas\s+'), # French 'fra' : (r'Le\s+', r'La\s+', r"L'", r'Les\s+', r'Un\s+', r'Une\s+', - r'Des\s+', r'De\s+', r'La\s+', r'De\s+La\s+', r"D'"), + r'Des\s+', r'De\s+La\s+', r'De\s+', r"D'"), # Italian 'ita' : (r'Lo\s+', r'Il\s+', r"L'", r'La\s+', r'Gli\s+', r'I\s+', r'Le\s+', ), From f55e5efa2a82a8f54f83775c732f6337130bb23e Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 27 Nov 2011 10:08:07 +0530 Subject: [PATCH 04/23] Fix #896620 (Not possible to include language in CSV catalogue) --- src/calibre/customize/__init__.py | 2 +- src/calibre/library/catalog.py | 6 ++++-- src/calibre/library/database2.py | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/calibre/customize/__init__.py b/src/calibre/customize/__init__.py index d087eb5351..e4f8bf99bf 100644 --- a/src/calibre/customize/__init__.py +++ b/src/calibre/customize/__init__.py @@ -449,7 +449,7 @@ class CatalogPlugin(Plugin): # {{{ ['author_sort','authors','comments','cover','formats', 'id','isbn','ondevice','pubdate','publisher','rating', 'series_index','series','size','tags','timestamp', - 'title_sort','title','uuid']) + 'title_sort','title','uuid','languages']) all_custom_fields = set(db.custom_field_keys()) all_fields = all_std_fields.union(all_custom_fields) diff --git a/src/calibre/library/catalog.py b/src/calibre/library/catalog.py index 53432af7b7..a9c4b1a309 100644 --- a/src/calibre/library/catalog.py +++ b/src/calibre/library/catalog.py @@ -29,7 +29,8 @@ from calibre.utils.zipfile import ZipFile FIELDS = ['all', 'title', 'title_sort', 'author_sort', 'authors', 'comments', 'cover', 'formats','id', 'isbn', 'ondevice', 'pubdate', 'publisher', - 'rating', 'series_index', 'series', 'size', 'tags', 'timestamp', 'uuid'] + 'rating', 'series_index', 'series', 'size', 'tags', 'timestamp', + 'uuid', 'languages'] #Allowed fields for template TEMPLATE_ALLOWED_FIELDS = [ 'author_sort', 'authors', 'id', 'isbn', 'pubdate', 'title_sort', @@ -601,7 +602,7 @@ class BIBTEX(CatalogPlugin): # {{{ bibtexc, db, citation_bibtex, addfiles_bibtex)) # }}} -class EPUB_MOBI(CatalogPlugin): +class EPUB_MOBI(CatalogPlugin): # {{{ 'ePub catalog generator' Option = namedtuple('Option', 'option, default, dest, action, help') @@ -5177,3 +5178,4 @@ Author '{0}': # returns to gui2.actions.catalog:catalog_generated() return catalog.error +# }}} diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index 3782149512..f99830ca5a 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -3378,7 +3378,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): prefix = self.library_path FIELDS = set(['title', 'sort', 'authors', 'author_sort', 'publisher', 'rating', 'timestamp', 'size', 'tags', 'comments', 'series', 'series_index', - 'uuid', 'pubdate', 'last_modified', 'identifiers']) + 'uuid', 'pubdate', 'last_modified', 'identifiers', 'languages']) for x in self.custom_column_num_map: FIELDS.add(x) data = [] From f31ac513d28a3d40be7d8cef5ee98dd5b55ffda1 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Sun, 27 Nov 2011 13:09:39 +0100 Subject: [PATCH 05/23] Fix (I hope) #896832 - datetimes - errors when sorting metadata --- src/calibre/ebooks/metadata/sources/identify.py | 3 ++- src/calibre/gui2/metadata/single_download.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/calibre/ebooks/metadata/sources/identify.py b/src/calibre/ebooks/metadata/sources/identify.py index 4987b8cead..be12aae800 100644 --- a/src/calibre/ebooks/metadata/sources/identify.py +++ b/src/calibre/ebooks/metadata/sources/identify.py @@ -305,7 +305,8 @@ class ISBNMerge(object): ans.pubdate = r.pubdate break if getattr(ans.pubdate, 'year', None) == min_year: - min_date = datetime(min_year, ans.pubdate.month, ans.pubdate.day) + min_date = datetime(min_year, ans.pubdate.month, ans.pubdate.day, + tzinfo=utc_tz) else: min_date = datetime(min_year, 1, 2, tzinfo=utc_tz) ans.pubdate = min_date diff --git a/src/calibre/gui2/metadata/single_download.py b/src/calibre/gui2/metadata/single_download.py index 70b32a78c6..912f4d3988 100644 --- a/src/calibre/gui2/metadata/single_download.py +++ b/src/calibre/gui2/metadata/single_download.py @@ -28,7 +28,7 @@ from calibre.ebooks.metadata.sources.identify import (identify, urls_from_identifiers) from calibre.ebooks.metadata.book.base import Metadata from calibre.gui2 import error_dialog, NONE -from calibre.utils.date import utcnow, fromordinal, format_date +from calibre.utils.date import utcnow, fromordinal, format_date, UNDEFINED_DATE from calibre.library.comments import comments_to_html from calibre import force_unicode # }}} @@ -201,7 +201,7 @@ class ResultsModel(QAbstractTableModel): # {{{ elif col == 1: key = attrgetter('title') elif col == 2: - key = attrgetter('pubdate') + key = lambda x: x.pubdate if x.pubdate else UNDEFINED_DATE elif col == 3: key = attrgetter('has_cached_cover_url') elif key == 4: From 6a84d88d0db066e820ea6283bd150e55d7d3247f Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 27 Nov 2011 17:49:08 +0530 Subject: [PATCH 06/23] Fix #896832 (datetimes - errors when sorting metadata) --- src/calibre/gui2/metadata/single_download.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/calibre/gui2/metadata/single_download.py b/src/calibre/gui2/metadata/single_download.py index 70b32a78c6..1c0f3c8042 100644 --- a/src/calibre/gui2/metadata/single_download.py +++ b/src/calibre/gui2/metadata/single_download.py @@ -28,7 +28,8 @@ from calibre.ebooks.metadata.sources.identify import (identify, urls_from_identifiers) from calibre.ebooks.metadata.book.base import Metadata from calibre.gui2 import error_dialog, NONE -from calibre.utils.date import utcnow, fromordinal, format_date +from calibre.utils.date import (utcnow, fromordinal, format_date, + UNDEFINED_DATE, as_utc) from calibre.library.comments import comments_to_html from calibre import force_unicode # }}} @@ -201,7 +202,12 @@ class ResultsModel(QAbstractTableModel): # {{{ elif col == 1: key = attrgetter('title') elif col == 2: - key = attrgetter('pubdate') + def dategetter(x): + x = getattr(x, 'pubdate', None) + if x is None: + x = UNDEFINED_DATE + return as_utc(x) + key = dategetter elif col == 3: key = attrgetter('has_cached_cover_url') elif key == 4: From fcf9772db36e7f1c6237a96713655bdcc6b319ae Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 27 Nov 2011 17:49:31 +0530 Subject: [PATCH 07/23] ... --- resources/default_tweaks.py | 3 ++- src/calibre/gui2/duplicates.py | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/default_tweaks.py b/resources/default_tweaks.py index a359f73be1..972552ad09 100644 --- a/resources/default_tweaks.py +++ b/resources/default_tweaks.py @@ -230,7 +230,8 @@ per_language_title_sort_articles = { 'ron' : (r'Un\s+', r'O\s+', r'Nişte\s+', ), # German 'deu' : (r'Der\s+', r'Die\s+', r'Das\s+', r'Den\s+', r'Ein\s+', - r'Eine\s+', r'Einen\s+', r'Dem\s+', ), + r'Eine\s+', r'Einen\s+', r'Dem\s+', r'Des\s+', r'Einem\s+', + r'Eines\s+'), # Dutch 'nld' : (r'De\s+', r'Het\s+', r'Een\s+', r"'n\s+", r"'s\s+", r'Ene\s+', r'Ener\s+', r'Enes\s+', r'Den\s+', r'Der\s+', r'Des\s+', diff --git a/src/calibre/gui2/duplicates.py b/src/calibre/gui2/duplicates.py index cc6da1e995..6e45b0e9e6 100644 --- a/src/calibre/gui2/duplicates.py +++ b/src/calibre/gui2/duplicates.py @@ -8,4 +8,3 @@ __copyright__ = '2011, Kovid Goyal ' __docformat__ = 'restructuredtext en' - From d3b728d5326a98efe5f80ff365b49fbe4d10ee86 Mon Sep 17 00:00:00 2001 From: GRiker Date: Sun, 27 Nov 2011 06:22:52 -0700 Subject: [PATCH 08/23] Added format check before calling _update_epub_metadata --- src/calibre/devices/apple/driver.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/calibre/devices/apple/driver.py b/src/calibre/devices/apple/driver.py index d7fc6e791a..d6dd5ccf73 100644 --- a/src/calibre/devices/apple/driver.py +++ b/src/calibre/devices/apple/driver.py @@ -1306,7 +1306,8 @@ class ITUNES(DriverBase): if DEBUG: self.log.info(" ITUNES._add_new_copy()") - self._update_epub_metadata(fpath, metadata) + if fpath.rpartition('.')[2].lower() == 'epub': + self._update_epub_metadata(fpath, metadata) db_added = None lb_added = None From 686b061b85873e20f39637ab2154e8932c9ee3bb Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 27 Nov 2011 19:38:37 +0530 Subject: [PATCH 09/23] Fix #896864 (installer crash in resources area) --- src/calibre/web/feeds/recipes/collection.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/calibre/web/feeds/recipes/collection.py b/src/calibre/web/feeds/recipes/collection.py index 6b9c3a2129..46d6c2db81 100644 --- a/src/calibre/web/feeds/recipes/collection.py +++ b/src/calibre/web/feeds/recipes/collection.py @@ -13,7 +13,7 @@ from datetime import timedelta from lxml import etree from lxml.builder import ElementMaker -from calibre import browser +from calibre import browser, force_unicode from calibre.utils.date import parse_date, now as nowf, utcnow, tzlocal, \ isoformat, fromordinal @@ -66,8 +66,9 @@ def serialize_collection(mapping_of_recipe_classes): x.title.decode('ascii') ''' for urn in sorted(mapping_of_recipe_classes.keys(), - key=lambda key: getattr(mapping_of_recipe_classes[key], 'title', - 'zzz')): + key=lambda key: force_unicode( + getattr(mapping_of_recipe_classes[key], 'title', 'zzz'), + 'utf-8')): recipe = serialize_recipe(urn, mapping_of_recipe_classes[urn]) collection.append(recipe) collection.set('count', str(len(collection))) From 97ddd245a7deded1de3b19ddc0941b1fc234e12a Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 27 Nov 2011 20:48:12 +0530 Subject: [PATCH 10/23] TechDirt by Krittika Goyal --- recipes/techdirt.recipe | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 recipes/techdirt.recipe diff --git a/recipes/techdirt.recipe b/recipes/techdirt.recipe new file mode 100644 index 0000000000..a936e1a216 --- /dev/null +++ b/recipes/techdirt.recipe @@ -0,0 +1,20 @@ +from calibre.web.feeds.news import BasicNewsRecipe + +class TechDirt(BasicNewsRecipe): + title = u'Tech Dirt' + language = 'en' + __author__ = 'Krittika Goyal' + oldest_article = 7 #days + max_articles_per_feed = 25 + use_embedded_content = False + + no_stylesheets = True + auto_cleanup = True + encoding = 'latin1' + + + feeds = [ +('News', + 'http://feeds.feedburner.com/techdirt/feed'), +] + From 735de1d229e786a55e81baefbd4bfce409e2cf71 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 28 Nov 2011 08:25:03 +0530 Subject: [PATCH 11/23] Fix update title sort in bulk metadata edit not using language information --- src/calibre/gui2/dialogs/metadata_bulk.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/calibre/gui2/dialogs/metadata_bulk.py b/src/calibre/gui2/dialogs/metadata_bulk.py index 84bf7f6f57..928be3843c 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.py +++ b/src/calibre/gui2/dialogs/metadata_bulk.py @@ -164,7 +164,14 @@ class MyBlockingBusy(QDialog): # {{{ self.db.set_title(id, titlecase(title), notify=False) if do_title_sort: title = self.db.title(id, index_is_id=True) - self.db.set_title_sort(id, title_sort(title), notify=False) + if languages: + lang = languages[0] + else: + lang = self.db.languages(id, index_is_id=True) + if lang: + lang = lang.partition(',')[0] + self.db.set_title_sort(id, title_sort(title, lang=lang), + notify=False) if au: self.db.set_authors(id, string_to_authors(au), notify=False) if cover_action == 'remove': From 3fd851a355f8fd1e5507abfd14ba5edf454b2b39 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 28 Nov 2011 09:29:07 +0530 Subject: [PATCH 12/23] Preserve capitalization of Scottish author names when downloading metadata --- src/calibre/ebooks/metadata/sources/base.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/calibre/ebooks/metadata/sources/base.py b/src/calibre/ebooks/metadata/sources/base.py index 532c97b624..045f9e44be 100644 --- a/src/calibre/ebooks/metadata/sources/base.py +++ b/src/calibre/ebooks/metadata/sources/base.py @@ -121,7 +121,15 @@ def cap_author_token(token): # Normalize tokens of the form J.K. to J. K. parts = token.split('.') return '. '.join(map(capitalize, parts)).strip() + scots_name = None + for x in ('mc', 'mac'): + if (token.lower().startswith(x) and len(token) > len(x) and + token[len(x)] == upper(token[len(x)])): + scots_name = len(x) + break ans = capitalize(token) + if scots_name is not None: + ans = ans[:scots_name] + upper(ans[scots_name]) + ans[scots_name+1:] for x in ('-', "'"): idx = ans.find(x) if idx > -1 and len(ans) > idx+2: From f130425da8e284aa8d8805527d544384579280e3 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 28 Nov 2011 09:33:16 +0530 Subject: [PATCH 13/23] ... --- src/calibre/ebooks/metadata/sources/base.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/calibre/ebooks/metadata/sources/base.py b/src/calibre/ebooks/metadata/sources/base.py index 045f9e44be..f04291eae9 100644 --- a/src/calibre/ebooks/metadata/sources/base.py +++ b/src/calibre/ebooks/metadata/sources/base.py @@ -124,7 +124,10 @@ def cap_author_token(token): scots_name = None for x in ('mc', 'mac'): if (token.lower().startswith(x) and len(token) > len(x) and - token[len(x)] == upper(token[len(x)])): + ( + token[len(x)] == upper(token[len(x)]) or + lt == token + )): scots_name = len(x) break ans = capitalize(token) From 8f16a5e02a07e7fc0f35f3c95b8fb59e40a70395 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 28 Nov 2011 20:17:45 +0530 Subject: [PATCH 14/23] Fix #855060 (calibre, version 0.8.19 ERROR: Unhandled exception: AttributeError:'MobileReadStore' object has no attribute 'lock' Traceback (most recent call last): File "site-packages/calibre/gui2/actions/store.py", line 130, in open_store File "site-packages/calibre/gui2/store/stores/mobileread/mobileread_plugin.py", line 40, in open File "site-packages/calibre/gui2/store/stores/mobileread/mobileread_plugin.py", line 57, in update_cache AttributeError: 'MobileReadStore' object has no attribute 'lock') --- .../stores/mobileread/mobileread_plugin.py | 24 ++++++++++--------- src/calibre/gui2/ui.py | 3 ++- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/calibre/gui2/store/stores/mobileread/mobileread_plugin.py b/src/calibre/gui2/store/stores/mobileread/mobileread_plugin.py index 1aabe86c50..9e41aa45a1 100644 --- a/src/calibre/gui2/store/stores/mobileread/mobileread_plugin.py +++ b/src/calibre/gui2/store/stores/mobileread/mobileread_plugin.py @@ -21,13 +21,14 @@ from calibre.gui2.store.stores.mobileread.cache_update_thread import CacheUpdate from calibre.gui2.store.stores.mobileread.store_dialog import MobileReadStoreDialog class MobileReadStore(BasicStoreConfig, StorePlugin): - - def genesis(self): + + def __init__(self, *args, **kwargs): + StorePlugin.__init__(self, *args, **kwargs) self.lock = Lock() - + def open(self, parent=None, detail_item=None, external=False): url = 'http://www.mobileread.com/' - + if external or self.config.get('open_external', False): open_url(QUrl(detail_item if detail_item else url)) else: @@ -44,7 +45,7 @@ class MobileReadStore(BasicStoreConfig, StorePlugin): def search(self, query, max_results=10, timeout=60): books = self.get_book_list() - + if not books: return @@ -56,24 +57,25 @@ class MobileReadStore(BasicStoreConfig, StorePlugin): book.drm = SearchResult.DRM_UNLOCKED yield book - def update_cache(self, parent=None, timeout=10, force=False, suppress_progress=False): + def update_cache(self, parent=None, timeout=10, force=False, + suppress_progress=False): if self.lock.acquire(False): try: update_thread = CacheUpdateThread(self.config, self.seralize_books, timeout) if not suppress_progress: progress = CacheProgressDialog(parent) progress.set_message(_('Updating MobileRead book cache...')) - + update_thread.total_changed.connect(progress.set_total) update_thread.update_progress.connect(progress.set_progress) update_thread.update_details.connect(progress.set_details) progress.rejected.connect(update_thread.abort) - + progress.open() update_thread.start() while update_thread.is_alive() and not progress.canceled: QCoreApplication.processEvents() - + if progress.isVisible(): progress.accept() return not progress.canceled @@ -84,7 +86,7 @@ class MobileReadStore(BasicStoreConfig, StorePlugin): def get_book_list(self): return self.deseralize_books(self.config.get('book_list', [])) - + def seralize_books(self, books): sbooks = [] for b in books: @@ -95,7 +97,7 @@ class MobileReadStore(BasicStoreConfig, StorePlugin): data['formats'] = b.formats sbooks.append(data) return sbooks - + def deseralize_books(self, sbooks): books = [] for s in sbooks: diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index c12a15829a..63db7a561c 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -195,7 +195,8 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{ for ac in self.iactions.values(): ac.do_genesis() - self.donate_action = QAction(QIcon(I('donate.png')), _('&Donate to support calibre'), self) + self.donate_action = QAction(QIcon(I('donate.png')), + _('&Donate to support calibre'), self) for st in self.istores.values(): st.do_genesis() MainWindowMixin.__init__(self, db) From d6ab402774bc16dac08b8c8685041af456dc28f0 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 29 Nov 2011 07:13:00 +0530 Subject: [PATCH 15/23] Daily Writing Tips by NotTaken --- recipes/daily_writing_tips.recipe | 18 ++++++++++++++++++ src/calibre/manual/faq.rst | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 recipes/daily_writing_tips.recipe diff --git a/recipes/daily_writing_tips.recipe b/recipes/daily_writing_tips.recipe new file mode 100644 index 0000000000..836f8ec4d1 --- /dev/null +++ b/recipes/daily_writing_tips.recipe @@ -0,0 +1,18 @@ +from calibre.web.feeds.news import BasicNewsRecipe + +class DailyWritingTips(BasicNewsRecipe): + title = u'Daily Writing Tips' + language = 'en_GB' + __author__ = 'NotTaken' + oldest_article = 7 #days + max_articles_per_feed = 40 + use_embedded_content = True + no_stylesheets = True + auto_cleanup = False + encoding = 'utf-8' + + + feeds = [ +('Latest tips', + 'http://feeds2.feedburner.com/DailyWritingTips'), +] diff --git a/src/calibre/manual/faq.rst b/src/calibre/manual/faq.rst index 3700451b2d..b58b87cc5e 100644 --- a/src/calibre/manual/faq.rst +++ b/src/calibre/manual/faq.rst @@ -265,7 +265,7 @@ How do I use |app| with my Android phone/tablet? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ There are two ways that you can connect your Android device to calibre. Using a USB cable-- or wirelessly, over the air. -The USB cable method only works if your Android device can act as a USB disk, which some Android tablets cannot. +**The USB cable method only works if your Android device can act as a USB disk, that means in windows it must have a drive letter, like K:**. Using a USB cable ^^^^^^^^^^^^^^^^^^^^ From 6b731fe3d5b016e26ab77eeee9266991fe22044e Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 29 Nov 2011 07:18:10 +0530 Subject: [PATCH 16/23] Fix #897330 (driver needed for android device (Motorola Electrify)) --- src/calibre/devices/android/driver.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/calibre/devices/android/driver.py b/src/calibre/devices/android/driver.py index 0ad36a460a..f3aa465476 100644 --- a/src/calibre/devices/android/driver.py +++ b/src/calibre/devices/android/driver.py @@ -167,12 +167,12 @@ class ANDROID(USBMS): 'MB525', 'ANDROID2.3', 'SGH-I997', 'GT-I5800_CARD', 'MB612', 'GT-S5830_CARD', 'GT-S5570_CARD', 'MB870', 'MID7015A', 'ALPANDIGITAL', 'ANDROID_MID', 'VTAB1008', 'EMX51_BBG_ANDROI', - 'UMS', '.K080', 'P990', 'LTE'] + 'UMS', '.K080', 'P990', 'LTE', 'MB853'] WINDOWS_CARD_A_MEM = ['ANDROID_PHONE', 'GT-I9000_CARD', 'SGH-I897', 'FILE-STOR_GADGET', 'SGH-T959', 'SAMSUNG_ANDROID', 'GT-P1000_CARD', 'A70S', 'A101IT', '7', 'INCREDIBLE', 'A7EB', 'SGH-T849_CARD', '__UMS_COMPOSITE', 'SGH-I997_CARD', 'MB870', 'ALPANDIGITAL', - 'ANDROID_MID', 'P990_SD_CARD', '.K080', 'LTE_CARD'] + 'ANDROID_MID', 'P990_SD_CARD', '.K080', 'LTE_CARD', 'MB853'] OSX_MAIN_MEM = 'Android Device Main Memory' From ee6554871d4d914f595787abb356285b834724e2 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 29 Nov 2011 08:25:25 +0530 Subject: [PATCH 17/23] Skylife by thomass --- recipes/skylife.recipe | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 recipes/skylife.recipe diff --git a/recipes/skylife.recipe b/recipes/skylife.recipe new file mode 100644 index 0000000000..7abd2f1f42 --- /dev/null +++ b/recipes/skylife.recipe @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- + +from calibre.web.feeds.news import BasicNewsRecipe + +class THY (BasicNewsRecipe): + + title = u'Skylife' + __author__ = u'thomass' + description = ' Türk Hava Yollarının yayınladığı aylık kültür dergisi (Fotoğrafları da içermesini isterseniz keep_only_tag''da belirttiğim kodu da ekleyin) ' + oldest_article =32 + max_articles_per_feed =100 + no_stylesheets = True + #delay = 1 + #use_embedded_content = False + encoding = 'utf-8' + publisher = 'thomass' + category = 'genel kültür, gezi,Türkçe' + language = 'tr' + publication_type = 'magazine' + + conversion_options = { + 'comment' : description + , 'tags' : category + , 'publisher' : publisher + , 'language' : language + } + keep_only_tags = [dict(name='h3', attrs={'id':['hpbaslik']}),dict(name='p', attrs={'id':['pyayin','hspot','picerik']})] #Fotoğrafları da eklemek için: dict(name='div', attrs={'id':['divResimler']}) + masthead_url = 'http://www.turkishairlines.com/static/img/skylife/logo.png' + remove_empty_feeds= True + remove_attributes = ['width','height'] + + feeds = [( u'SKYLIFE', u'http://feed43.com/7783278414103376.xml')] From b2c7c601c9dd6e68cb2452b7f96f4c964a2a1fb6 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 29 Nov 2011 08:26:39 +0530 Subject: [PATCH 18/23] ... --- recipes/icons/skylife.png | Bin 0 -> 3330 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 recipes/icons/skylife.png diff --git a/recipes/icons/skylife.png b/recipes/icons/skylife.png new file mode 100644 index 0000000000000000000000000000000000000000..6cfcf5c79747b148e62874f5c2d86a222abd25ba GIT binary patch literal 3330 zcmZ`+X*ASrAO4RKS+i9Wg*=KZS+k5iOEZ;Z-^wTLt! z2{G13hKR{d!+7U?zP%sb>->Jd>zw%KqS=Un%7r{2ADgNIX?6951nILyd`$>RTQ zJ~rn3YX#TDBsRBOH;j(|1&7_<6mx|G39}DjGVI?r>G#zI0B(J_k%5)ZOoM%-pVjDD z#*A{{WFhD#<%PvuU#XQ3`D=mzGWCQ|D&!jOx)XN_EUWl7? zJYbWOD=&Vs@kBWn3iXrQ8K+Y5c`Pz;CVG#-&}iWn%5D4yj(!SX>WJv1VWUxjl7pH{ z=f?;9w9c=uUzJuI0JHC|w;#umq2a$i=57X4bYn?XRj)H@VUp)}4ddF%U8>fPj{l)a+wtZ|+atu%&RXDQI#BE0G>y6) z@cnJn&LGC#-b}Z}Z{lNansQu>0jSGPT8Nvaae8`sf&&PBG%+!xOCNJgkZhUmPI7K> zr35^9-~;6K+upNp;&pl5u=BYv5!|V)e8qyXZ#aJX(s``%BAwQGw42D@n}t#F9xVRr z2BGmz$5<-Y+{A=JM|1Gv$6TV5UBOesh|O(8SK|?b>ebaagw+XQQyd_XCLOvI8~y3? z$(^oFd6IAztA^(0dLf9~uU1;zAwN=Mo#Z>y_Cl~!x>^R_^@Ib5fZU@oj&7mkoJq0K z5fQPmu}44p!C631pJ3`DSyqOz-~H36ZT}s6dYVV%whxOacVqqCO)j>6OCl$m;l+fl ztSlpzobsuuM=UNqDJ5}}b?iBk*4Cr1z;jcorh>4`>H#qao?WUDYm+S@zl|U!G9Mtw zm2U@IRYJ)1spa8=10J6I{LZ8B^|US%%2c z4oe0`Ykcx%M@^sqY@scWdlkAh^yBVz|DC-$J&Yj)e-SBGi3qHU|!ivC{fcW}u(b?nk(k$#W zyts4ncfPxu>1sk)r2Bl(WiWxc;C^BmAbM&k??b&^q3@ctaF^IXWsTDmcV*m{`5?t*WBJ-oCicE%zk1|Q z9CsI>8g%uVM!9TJXSp23r9i-6zs zy8%XT!uR>$P2Hi=7k(Wsiu0E&m zRIbz`JUtEL(-7-3&dxl5s+=>~PfO*xIa$7UjjZsNaK9NjfBjCD9OFZz>Lle>M2Rpu z-W#nJ&v88m)BF#ANIK=@B#piDvgL=u6awuW=~=#e3V_MvS@QM>C2a@gvXJ zOrHXdXWTQ)WtPq(p&`M+!BNrHaN%p!rCl_9uzJ|a-MV%~(^r+1ughzj%RQvc#4+Mp z(K{AJ{n3-?59uvOc+rU)kO=;67HNv7aguk!{6 z?9plQn;hcs2__6H_~)F)!!XdHF`KSNGYm9R;H}*J@!?hvhj8Z*_Qan*?_IlrGIKJ~ zUtGB2#Z}=3e=-aAV_gxpST)l$?vgicZEZ2Md)6tLRnKq;2bmM)BR{wG43MqU0pha0 zi=URTU?LHvaKBbUWx)9Yq`g3C*x^1e45(kDQgN37m?VS1oem9z)Iyf@l@XK-P?eA~ z%X}C{2_4XnA2DK`3vYGW*zZZ@IwNQI*7v!Ll})lc<1m_5Q>{Eu5XC3 z$)H|R;HN6Te$Vbsu35#&%HJexDl3`g=1m#d=L)mL4{L*DGCAEufl~stxL2a16@v30 z9~0FI->$44EY|cz$&rKO;^K5&C^a?m^6~5$x+>x8PT~OY=;x|?v8Bb>&cou6yzA%4 zfSKg-6G4usK`|%3j~^3}5?{pC)j!z8=t*$saanXpw!ARQ>Q4v9ZP8ckK2(@)D$; zvT7HW3!c%tR$ z5H*9tgEmqHWo<<@gMWN1*1UtKtc80=eR@^>ejdqu5o3ck6gsD(X=TRry=)P02x@UB zsvS*50;1Wt{$P_w0wW~J{^0l&7HR#jB7hwVVbLw2y=M5ZTl~%Hxw+6LV@bZ>8E4TF zpy%a>hiz>H0v-!}_W6=dle4Z!eC(0JQ1x&yS8`3Wu@3bsdwdIjML86+(nzpu91rU?N)bdt zBl%Z|x4WLpzakI_9kdQ5cQ57@Z>^L~CB#GcH#f5`q@T65v9Sil#XCB}`&0PKTUwli zz-SYt(rUM?&co`Ird%W%VR{0DE4(;o@n-e;cnHXDygwUa?%?1M^-oXUB?>cf+L#A5 z2#P6#-iPWi9mkmvOIHh+YTg)77ZFwqWNea`N+MbScrdiC?zFMB3TKA+^&i{@Nhwcc zQ^mX9<3|diaR_&JG&3JA|EXyrI5a#M?Gqcq(EqHy>10g$9?|y0q)IzE^7DIoc|_1f zO#wC4)s;D(-7vfkHbcnRwmkly&mKn^-f}8!DP#G2E-PbLA%ib_iI z%u?30Qq+JdUt^Z6q8e0Dk^SXI>i-D*13eI4k^f&1&Okaa1pwUmjuGLy%cK7Q8lh?# literal 0 HcmV?d00001 From 29041f74a77e73d0006edc82a9bedea4f1a4e8e0 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 29 Nov 2011 09:59:35 +0530 Subject: [PATCH 19/23] Fix #897523 (Cybook Odyssee does not show transferred books) --- src/calibre/devices/hanvon/driver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/devices/hanvon/driver.py b/src/calibre/devices/hanvon/driver.py index 2d6b825c37..fbee2565a0 100644 --- a/src/calibre/devices/hanvon/driver.py +++ b/src/calibre/devices/hanvon/driver.py @@ -175,7 +175,7 @@ class ODYSSEY(N516): FORMATS = ['epub', 'fb2', 'html', 'pdf', 'txt'] - EBOOK_DIR_MAIN = 'calibre' + EBOOK_DIR_MAIN = 'Digital Editions' def get_main_ebook_dir(self, for_upload=False): if for_upload: From 9fe008069283b9a193631196061cf2e4eb93dfa3 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 29 Nov 2011 10:24:02 +0530 Subject: [PATCH 20/23] Content server: When sending ebook files, respect the If-Modified-Since header and send the file as a stream, to reduce memory consumption when sending very large files. Fixes #897343 (Bad memory leak when accessing library over network) --- src/calibre/library/server/content.py | 32 +++++++++++++++++++-------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/calibre/library/server/content.py b/src/calibre/library/server/content.py index 983dae8aae..374ea6e345 100644 --- a/src/calibre/library/server/content.py +++ b/src/calibre/library/server/content.py @@ -8,6 +8,7 @@ __docformat__ = 'restructuredtext en' import re, os, posixpath import cherrypy +from cherrypy.lib import cptools from calibre import fit_image, guess_type from calibre.utils.date import fromtimestamp @@ -195,13 +196,26 @@ class ContentServer(object): return data - def get_format(self, id, format): format = format.upper() + fm = self.db.format_metadata(id, format, allow_cache=False) + if not fm: + raise cherrypy.HTTPError(404, 'book: %d does not have format: %s'%(id, format)) + cherrypy.response.headers['Last-Modified'] = \ + self.last_modified(fm['mtime']) + # Check the If-Modified-Since request header. Returns appropriate HTTP + # response + cptools.validate_since() + fmt = self.db.format(id, format, index_is_id=True, as_file=True, mode='rb') if fmt is None: raise cherrypy.HTTPError(404, 'book: %d does not have format: %s'%(id, format)) + mt = guess_type('dummy.'+format.lower())[0] + if mt is None: + mt = 'application/octet-stream' + cherrypy.response.headers['Content-Type'] = mt + mi = newmi = self.db.get_metadata(id, index_is_id=True) if format == 'EPUB': # Get the original metadata @@ -221,19 +235,19 @@ class ContentServer(object): set_metadata(fmt, newmi, format.lower()) fmt.seek(0) - mt = guess_type('dummy.'+format.lower())[0] - if mt is None: - mt = 'application/octet-stream' - au = authors_to_string(mi.authors if mi.authors else [_('Unknown')]) - title = mi.title if mi.title else _('Unknown') + fmt.seek(0, 2) + cherrypy.response.headers['Content-Length'] = fmt.tell() + fmt.seek(0) + + au = authors_to_string(newmi.authors if newmi.authors else + [_('Unknown')]) + title = newmi.title if newmi.title else _('Unknown') fname = u'%s - %s_%s.%s'%(title[:30], au[:30], id, format.lower()) fname = ascii_filename(fname).replace('"', '_') - cherrypy.response.headers['Content-Type'] = mt cherrypy.response.headers['Content-Disposition'] = \ b'attachment; filename="%s"'%fname + cherrypy.response.body = fmt cherrypy.response.timeout = 3600 - cherrypy.response.headers['Last-Modified'] = \ - self.last_modified(self.db.format_last_modified(id, format)) return fmt # }}} From 4cb1907a134edf505002a98ef53dc71e6cd49b8a Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 29 Nov 2011 10:35:45 +0530 Subject: [PATCH 21/23] Content server: On second thoughts dont honor If-Modified-Since as it will lead to hard to replicate conditions --- src/calibre/library/server/content.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/calibre/library/server/content.py b/src/calibre/library/server/content.py index 374ea6e345..dd3a964c27 100644 --- a/src/calibre/library/server/content.py +++ b/src/calibre/library/server/content.py @@ -8,7 +8,6 @@ __docformat__ = 'restructuredtext en' import re, os, posixpath import cherrypy -from cherrypy.lib import cptools from calibre import fit_image, guess_type from calibre.utils.date import fromtimestamp @@ -201,11 +200,10 @@ class ContentServer(object): fm = self.db.format_metadata(id, format, allow_cache=False) if not fm: raise cherrypy.HTTPError(404, 'book: %d does not have format: %s'%(id, format)) + mi = newmi = self.db.get_metadata(id, index_is_id=True) + cherrypy.response.headers['Last-Modified'] = \ - self.last_modified(fm['mtime']) - # Check the If-Modified-Since request header. Returns appropriate HTTP - # response - cptools.validate_since() + self.last_modified(max(fm['mtime'], mi.last_modified)) fmt = self.db.format(id, format, index_is_id=True, as_file=True, mode='rb') @@ -216,7 +214,6 @@ class ContentServer(object): mt = 'application/octet-stream' cherrypy.response.headers['Content-Type'] = mt - mi = newmi = self.db.get_metadata(id, index_is_id=True) if format == 'EPUB': # Get the original metadata From 2e5f38a5bc9bbf14500ae3c11fd2ddda5b01c149 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 29 Nov 2011 11:25:11 +0530 Subject: [PATCH 22/23] Fix #897531 (epub output do not add xml:lang from lang attribute) --- src/calibre/ebooks/epub/output.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/calibre/ebooks/epub/output.py b/src/calibre/ebooks/epub/output.py index bb515f95a4..52bbfb4a08 100644 --- a/src/calibre/ebooks/epub/output.py +++ b/src/calibre/ebooks/epub/output.py @@ -132,9 +132,11 @@ class EPUBOutput(OutputFormatPlugin): def upshift_markup(self): # {{{ 'Upgrade markup to comply with XHTML 1.1 where possible' - from calibre.ebooks.oeb.base import XPath + from calibre.ebooks.oeb.base import XPath, XML for x in self.oeb.spine: root = x.data + if (not root.get(XML('lang'))) and (root.get('lang')): + root.set(XML('lang'), root.get('lang')) body = XPath('//h:body')(root) if body: body = body[0] From 24fb85ea06f662bfdc48beaac39c8da1398dd2d2 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 29 Nov 2011 15:20:32 +0530 Subject: [PATCH 23/23] Fix Rolling Stones Mag --- recipes/rstones.recipe | 39 +++------------------------------------ 1 file changed, 3 insertions(+), 36 deletions(-) diff --git a/recipes/rstones.recipe b/recipes/rstones.recipe index fa09701e15..46b817876c 100644 --- a/recipes/rstones.recipe +++ b/recipes/rstones.recipe @@ -29,22 +29,7 @@ class RollingStones(BasicNewsRecipe): max_articles_per_feed = 25 use_embedded_content = False no_stylesheets = True - - remove_javascript = True - ##################################################################################### - # cleanup section # - ##################################################################################### - keep_only_tags = [ - dict(name='div', attrs={'class':['c65l']}), - dict(name='div', attrs={'id':['col1']}), - - - ] - remove_tags = [ - dict(name='div', attrs={'class': ['storyActions upper','storyActions lowerArticleNav']}), - dict(name='div', attrs={'id': ['comments','related']}), - ] - + auto_cleanup = True feeds = [ (u'News', u'http://www.rollingstone.com/siteServices/rss/allNews'), @@ -58,25 +43,7 @@ class RollingStones(BasicNewsRecipe): - def get_article_url(self, article): - return article.get('guid', None) - - - def append_page(self, soup, appendtag, position): - ''' - Some are the articles are multipage so the below function - will get the articles that have - ''' - pager = soup.find('li',attrs={'class':'next'}) - if pager: - nexturl = pager.a['href'] - soup2 = self.index_to_soup(nexturl) - texttag = soup2.find('div', attrs={'id':'storyTextContainer'}) - for it in texttag.findAll(style=True): - del it['style'] - newpos = len(texttag.contents) - self.append_page(soup2,texttag,newpos) - texttag.extract() - appendtag.insert(position,texttag) + def print_version(self, url): + return url +'?print=true'