From b540537f30019ed965d4f7e74e0850f5054de315 Mon Sep 17 00:00:00 2001 From: Spedinfargo Date: Fri, 25 Feb 2011 16:05:02 -0600 Subject: [PATCH 1/4] Suggested patch for max issues per recipe --- src/calibre/gui2/actions/fetch_news.py | 10 +++++++ src/calibre/gui2/dialogs/scheduler.py | 14 +++++++--- src/calibre/gui2/dialogs/scheduler.ui | 30 +++++++++++++++++++++ src/calibre/library/database2.py | 12 +++++++++ src/calibre/web/feeds/recipes/collection.py | 9 +++++-- src/calibre/web/feeds/recipes/model.py | 5 ++-- 6 files changed, 73 insertions(+), 7 deletions(-) diff --git a/src/calibre/gui2/actions/fetch_news.py b/src/calibre/gui2/actions/fetch_news.py index 5c2a5e9663..009bf8b00b 100644 --- a/src/calibre/gui2/actions/fetch_news.py +++ b/src/calibre/gui2/actions/fetch_news.py @@ -58,6 +58,16 @@ class FetchNewsAction(InterfaceAction): self.scheduler.recipe_download_failed(arg) return self.gui.job_exception(job) id = self.gui.library_view.model().add_news(pt.name, arg) + + # Arg may contain a "keep_issues" variable. if it is non-zer, delete all but newest x issues. + try: + ikeep_issues = int(arg['keep_issues']) + except: + ikeep_issues = 0 + if ikeep_issues > 0: + ids2delete = self.gui.library_view.model().db.get_most_recent_by_tag(arg['keep_issues'], arg['title']) + self.gui.library_view.model().delete_books_by_id(ids2delete) + self.gui.library_view.model().reset() sync = self.gui.news_to_be_synced sync.add(id) diff --git a/src/calibre/gui2/dialogs/scheduler.py b/src/calibre/gui2/dialogs/scheduler.py index b6a3bed3eb..be2997a314 100644 --- a/src/calibre/gui2/dialogs/scheduler.py +++ b/src/calibre/gui2/dialogs/scheduler.py @@ -153,9 +153,10 @@ class SchedulerDialog(QDialog, Ui_Dialog): self.recipe_model.un_schedule_recipe(urn) add_title_tag = self.add_title_tag.isChecked() + keep_issues = unicode(self.keep_issues.text()) custom_tags = unicode(self.custom_tags.text()).strip() custom_tags = [x.strip() for x in custom_tags.split(',')] - self.recipe_model.customize_recipe(urn, add_title_tag, custom_tags) + self.recipe_model.customize_recipe(urn, add_title_tag, custom_tags, keep_issues) return True def initialize_detail_box(self, urn): @@ -215,9 +216,15 @@ class SchedulerDialog(QDialog, Ui_Dialog): if d < timedelta(days=366): self.last_downloaded.setText(_('Last downloaded')+': '+tm) - add_title_tag, custom_tags = customize_info + add_title_tag, custom_tags, keep_issues = customize_info self.add_title_tag.setChecked(add_title_tag) self.custom_tags.setText(u', '.join(custom_tags)) + try: + ikeep_issues = int(keep_issues) + except: + ikeep_issues = 0 + self.keep_issues.setValue(ikeep_issues) + class Scheduler(QObject): @@ -299,7 +306,7 @@ class Scheduler(QObject): un = pw = None if account_info is not None: un, pw = account_info - add_title_tag, custom_tags = customize_info + add_title_tag, custom_tags, keep_issues = customize_info script = self.recipe_model.get_recipe(urn) pt = PersistentTemporaryFile('_builtin.recipe') pt.write(script) @@ -312,6 +319,7 @@ class Scheduler(QObject): 'recipe':pt.name, 'title':recipe.get('title',''), 'urn':urn, + 'keep_issues':keep_issues } self.download_queue.add(urn) self.start_recipe_fetch.emit(arg) diff --git a/src/calibre/gui2/dialogs/scheduler.ui b/src/calibre/gui2/dialogs/scheduler.ui index 8e6ab37162..079a17dbb3 100644 --- a/src/calibre/gui2/dialogs/scheduler.ui +++ b/src/calibre/gui2/dialogs/scheduler.ui @@ -245,6 +245,36 @@ + + + + + + Maximum number of copies (issues) of this recipe to keep. Set to 0 to keep all (disable). + + + Maximum copies (0 to keep all): + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index dce0b34aef..234d1fcfc4 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -1476,6 +1476,18 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): ############# End get_categories + def get_most_recent_by_tag(self, number_to_keep, tag): + #Based on tag and number passed in, create a list of books matching that tag, keeping only the newest X versions + tag = tag.lower().strip() + idlist = [] + mycount = 0 + for myid in (self.conn.get('select a.book id from books_tags_link a inner join books b on a.book = b.id where a.tag in (select tags.id from tags where tags.name = ?) order by b.timestamp desc', [tag])): + myid = myid[0] + mycount = mycount + 1 + if mycount > int(number_to_keep): + idlist.append(myid) + return idlist + def tags_older_than(self, tag, delta): tag = tag.lower().strip() now = nowf() diff --git a/src/calibre/web/feeds/recipes/collection.py b/src/calibre/web/feeds/recipes/collection.py index 5dd360213b..6697a1f39f 100644 --- a/src/calibre/web/feeds/recipes/collection.py +++ b/src/calibre/web/feeds/recipes/collection.py @@ -201,12 +201,14 @@ class SchedulerConfig(object): self.root.append(sr) self.write_scheduler_file() - def customize_recipe(self, urn, add_title_tag, custom_tags): + # 'keep_issues' argument for recipe-specific number of copies to keep + def customize_recipe(self, urn, add_title_tag, custom_tags, keep_issues): with self.lock: for x in list(self.iter_customization()): if x.get('id') == urn: self.root.remove(x) cs = E.recipe_customization({ + 'keep_issues' : keep_issues, 'id' : urn, 'add_title_tag' : 'yes' if add_title_tag else 'no', 'custom_tags' : ','.join(custom_tags), @@ -316,17 +318,20 @@ class SchedulerConfig(object): if x.get('id', False) == urn: return x.get('username', ''), x.get('password', '') + # 'keep_issues' element for recipe-specific number of copies to keep (default 0 == all) def get_customize_info(self, urn): + keep_issues = 0 add_title_tag = True custom_tags = [] with self.lock: for x in self.iter_customization(): if x.get('id', False) == urn: + keep_issues = x.get('keep_issues',0) add_title_tag = x.get('add_title_tag', 'yes') == 'yes' custom_tags = [i.strip() for i in x.get('custom_tags', '').split(',')] break - return add_title_tag, custom_tags + return add_title_tag, custom_tags, keep_issues def get_schedule_info(self, urn): with self.lock: diff --git a/src/calibre/web/feeds/recipes/model.py b/src/calibre/web/feeds/recipes/model.py index 559a5c08dd..203f96b03d 100644 --- a/src/calibre/web/feeds/recipes/model.py +++ b/src/calibre/web/feeds/recipes/model.py @@ -354,9 +354,10 @@ class RecipeModel(QAbstractItemModel, SearchQueryParser): self.scheduler_config.schedule_recipe(self.recipe_from_urn(urn), sched_type, schedule) - def customize_recipe(self, urn, add_title_tag, custom_tags): + # 'keep_issues' argument for recipe-specific number of copies to keep + def customize_recipe(self, urn, add_title_tag, custom_tags, keep_issues): self.scheduler_config.customize_recipe(urn, add_title_tag, - custom_tags) + custom_tags, keep_issues) def get_to_be_downloaded_recipes(self): ans = self.scheduler_config.get_to_be_downloaded_recipes() From 9462edd460acb5af2fe6b144fd21cc4200b30cd7 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 26 Feb 2011 08:58:26 -0700 Subject: [PATCH 2/4] ... --- Changelog.yaml | 4 ++++ src/calibre/manual/faq.rst | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Changelog.yaml b/Changelog.yaml index dfc9b9efe6..b8b8f2b480 100644 --- a/Changelog.yaml +++ b/Changelog.yaml @@ -19,6 +19,10 @@ # new recipes: # - title: +# - title: "Launch of a new website that catalogues DRM free books. http://drmfree.calibre-ebook.com" +# description: "A growing catalogue of DRM free books. Books that you actually own after buying instead of renting." +# type: major + - version: 0.7.47 date: 2011-02-25 diff --git a/src/calibre/manual/faq.rst b/src/calibre/manual/faq.rst index cb7f4d62ff..8a78815751 100644 --- a/src/calibre/manual/faq.rst +++ b/src/calibre/manual/faq.rst @@ -81,7 +81,7 @@ Device Integration What devices does |app| support? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -At the moment |app| has full support for the SONY PRS line, Barnes & Noble Nook, Cybook Gen 3/Opus, Amazon Kindle line, Entourage Edge, Longshine ShineBook, Ectaco Jetbook, BeBook/BeBook Mini, Irex Illiad/DR1000, Foxit eSlick, PocketBook 360, Italica, eClicto, Iriver Story, Airis dBook, Hanvon N515, Binatone Readme, Teclast K3, SpringDesign Alex, Kobo Reader, various Android phones and the iPhone/iPad. In addition, using the :guilabel:`Save to disk` function you can use it with any ebook reader that exports itself as a USB disk. +At the moment |app| has full support for the SONY PRS line, Barnes & Noble Nook line, Cybook Gen 3/Opus, Amazon Kindle line, Entourage Edge, Longshine ShineBook, Ectaco Jetbook, BeBook/BeBook Mini, Irex Illiad/DR1000, Foxit eSlick, PocketBook line, Italica, eClicto, Iriver Story, Airis dBook, Hanvon N515, Binatone Readme, Teclast K3 and clones, SpringDesign Alex, Kobo Reader, various Android phones and the iPhone/iPad. In addition, using the :guilabel:`Connect to folder` function you can use it with any ebook reader that exports itself as a USB disk. How can I help get my device supported in |app|? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 66197505871bb75d8b888aa10ccdcbeedb774bfd Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 27 Feb 2011 09:05:56 -0700 Subject: [PATCH 3/4] Dotpod by Federico Escalada --- resources/recipes/dotpod.recipe | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 resources/recipes/dotpod.recipe diff --git a/resources/recipes/dotpod.recipe b/resources/recipes/dotpod.recipe new file mode 100644 index 0000000000..b04945e6d4 --- /dev/null +++ b/resources/recipes/dotpod.recipe @@ -0,0 +1,27 @@ +__license__ = 'GPL v3' +__copyright__ = '2011-2011, Federico Escalada ' + +from calibre.web.feeds.news import BasicNewsRecipe + +class Dotpod(BasicNewsRecipe): + __author__ = 'Federico Escalada' + description = 'Tecnologia y Comunicacion Audiovisual' + encoding = 'utf-8' + language = 'es' + max_articles_per_feed = 100 + no_stylesheets = True + oldest_article = 7 + publication_type = 'blog' + title = 'Dotpod' + authors = 'Federico Picone' + + conversion_options = { + 'authors' : authors + ,'comments' : description + ,'language' : language + } + + feeds = [('Dotpod', 'http://www.dotpod.com.ar/feed/')] + + remove_tags = [dict(name='div', attrs={'class':'feedflare'})] + From 72205310b6b455d9f8723b109d19f4dcbd584a42 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 27 Feb 2011 09:07:50 -0700 Subject: [PATCH 4/4] Buffalo News by ChappyOnIce --- resources/recipes/buffalo_news.recipe | 56 +++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 resources/recipes/buffalo_news.recipe diff --git a/resources/recipes/buffalo_news.recipe b/resources/recipes/buffalo_news.recipe new file mode 100644 index 0000000000..92c96757ae --- /dev/null +++ b/resources/recipes/buffalo_news.recipe @@ -0,0 +1,56 @@ +__license__ = 'GPL v3' +__author__ = 'Todd Chapman' +__copyright__ = 'Todd Chapman' +__version__ = 'v0.1' +__date__ = '26 February 2011' + +''' +http://www.buffalonews.com/RSS/ +''' + +from calibre.web.feeds.news import BasicNewsRecipe + +class AdvancedUserRecipe1298680852(BasicNewsRecipe): + title = u'Buffalo News' + __author__ = 'ChappyOnIce' + language = 'en' + oldest_article = 2 + max_articles_per_feed = 20 + encoding = 'utf-8' + remove_javascript = True + keep_only_tags = [ + dict(name='div', attrs={'class':['main-content-left']}) + ] + + remove_tags = [ + dict(name='div', attrs={'id':['commentCount']}), + dict(name='div', attrs={'class':['story-list-links']}) + ] + + remove_tags_after = dict(name='div', attrs={'class':['body storyContent']}) + conversion_options = { + 'base_font_size' : 14, + } + feeds = [(u'City of Buffalo', u'http://www.buffalonews.com/city/communities/buffalo/?widget=rssfeed&view=feed&contentId=77944'), + (u'Southern Erie County', u'http://www.buffalonews.com/city/communities/southern-erie/?widget=rssfeed&view=feed&contentId=77944'), + (u'Eastern Erie County', u'http://www.buffalonews.com/city/communities/eastern-erie/?widget=rssfeed&view=feed&contentId=77944'), + (u'Southern Tier', u'http://www.buffalonews.com/city/communities/southern-tier/?widget=rssfeed&view=feed&contentId=77944'), + (u'Niagara County', u'http://www.buffalonews.com/city/communities/niagara-county/?widget=rssfeed&view=feed&contentId=77944'), + (u'Business', u'http://www.buffalonews.com/business/?widget=rssfeed&view=feed&contentId=77944'), + (u'MoneySmart', u'http://www.buffalonews.com/business/moneysmart/?widget=rssfeed&view=feed&contentId=77944'), + (u'Bills & NFL', u'http://www.buffalonews.com/sports/bills-nfl/?widget=rssfeed&view=feed&contentId=77944'), + (u'Sabres & NHL', u'http://www.buffalonews.com/sports/sabres-nhl/?widget=rssfeed&view=feed&contentId=77944'), + (u'Bob DiCesare', u'http://www.buffalonews.com/sports/columns/bob-dicesare/?widget=rssfeed&view=feed&contentId=77944'), + (u'Bucky Gleason', u'http://www.buffalonews.com/sports/columns/bucky-gleason/?widget=rssfeed&view=feed&contentId=77944'), + (u'Mark Gaughan', u'http://www.buffalonews.com/sports/bills-nfl/inside-the-nfl/?widget=rssfeed&view=feed&contentId=77944'), + (u'Mike Harrington', u'http://www.buffalonews.com/sports/columns/mike-harrington/?widget=rssfeed&view=feed&contentId=77944'), + (u'Jerry Sullivan', u'http://www.buffalonews.com/sports/columns/jerry-sullivan/?widget=rssfeed&view=feed&contentId=77944'), + (u'Other Sports Columns', u'http://www.buffalonews.com/sports/columns/other-sports-columns/?widget=rssfeed&view=feed&contentId=77944'), + (u'Life', u'http://www.buffalonews.com/life/?widget=rssfeed&view=feed&contentId=77944'), + (u'Bruce Andriatch', u'http://www.buffalonews.com/city/columns/bruce-andriatch/?widget=rssfeed&view=feed&contentId=77944'), + (u'Donn Esmonde', u'http://www.buffalonews.com/city/columns/donn-esmonde/?widget=rssfeed&view=feed&contentId=77944'), + (u'Rod Watson', u'http://www.buffalonews.com/city/columns/rod-watson/?widget=rssfeed&view=feed&contentId=77944'), + (u'Entertainment', u'http://www.buffalonews.com/entertainment/?widget=rssfeed&view=feed&contentId=77944'), + (u'Off Main Street', u'http://www.buffalonews.com/city/columns/off-main-street/?widget=rssfeed&view=feed&contentId=77944'), + (u'Editorials', u'http://www.buffalonews.com/editorial-page/buffalo-news-editorials/?widget=rssfeed&view=feed&contentId=77944') + ]