From da5a1a1b22a24df35d4156e2eafc481036e6d267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20D=C5=82ugosz?= Date: Thu, 19 May 2011 22:37:30 +0200 Subject: [PATCH 1/7] Polish stores --- src/calibre/customize/builtins.py | 10 ++- src/calibre/gui2/store/gandalf_plugin.py | 78 ++++++++++++++++++++++++ src/calibre/gui2/store/nexto_plugin.py | 1 + 3 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 src/calibre/gui2/store/gandalf_plugin.py diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index b2d3a967df..5c93711e7d 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -1164,6 +1164,12 @@ class StoreFoylesUKStore(StoreBase): description = _('Foyles of London, online.') actual_plugin = 'calibre.gui2.store.foyles_uk_plugin:FoylesUKStore' +class StoreGandalfStore(StoreBase): + name = 'Gandalf' + author = 'Tomasz Długosz' + description = _('Zaczarowany świat książek') + actual_plugin = 'calibre.gui2.store.gandalf_plugin:GandalfStore' + class StoreGoogleBooksStore(StoreBase): name = 'Google Books' description = _('Google Books') @@ -1191,6 +1197,7 @@ class StoreMobileReadStore(StoreBase): class StoreNextoStore(StoreBase): name = 'Nexto' + author = 'Tomasz Długosz' description = _('Audiobooki mp3, ebooki, prasa - księgarnia internetowa.') actual_plugin = 'calibre.gui2.store.nexto_plugin:NextoStore' @@ -1229,7 +1236,8 @@ plugins += [StoreArchiveOrgStore, StoreAmazonKindleStore, StoreAmazonDEKindleSto StoreBeamEBooksDEStore, StoreBeWriteStore, StoreDieselEbooksStore, StoreEbookscomStore, StoreEPubBuyDEStore, StoreEHarlequinStore, StoreFeedbooksStore, - StoreFoylesUKStore, StoreGoogleBooksStore, StoreGutenbergStore, + StoreFoylesUKStore, StoreGandalfStore, + StoreGoogleBooksStore, StoreGutenbergStore, StoreKoboStore, StoreManyBooksStore, StoreMobileReadStore, StoreNextoStore, StoreOpenLibraryStore, StoreOReillyStore, StoreSmashwordsStore, diff --git a/src/calibre/gui2/store/gandalf_plugin.py b/src/calibre/gui2/store/gandalf_plugin.py new file mode 100644 index 0000000000..192484d764 --- /dev/null +++ b/src/calibre/gui2/store/gandalf_plugin.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- + +from __future__ import (unicode_literals, division, absolute_import, print_function) + +__license__ = 'GPL 3' +__copyright__ = '2011, Tomasz Długosz ' +__docformat__ = 'restructuredtext en' + +import re +import urllib +from contextlib import closing + +from lxml import html + +from PyQt4.Qt import QUrl + +from calibre import browser, url_slash_cleaner +from calibre.gui2 import open_url +from calibre.gui2.store import StorePlugin +from calibre.gui2.store.basic_config import BasicStoreConfig +from calibre.gui2.store.search_result import SearchResult +from calibre.gui2.store.web_store_dialog import WebStoreDialog + +class GandalfStore(BasicStoreConfig, StorePlugin): + + def open(self, parent=None, detail_item=None, external=False): + url = 'http://www.gandalf.com.pl/ebooks/' + + 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(self.config.get('tags', '')) + d.exec_() + + def search(self, query, max_results=10, timeout=60): + url = 'http://www.gandalf.com.pl/s/' + values={ + 'search': query, + 'dzialx':'11' + } + + br = browser() + + counter = max_results + with closing(br.open(url, data=urllib.urlencode(values), timeout=timeout)) as f: + doc = html.fromstring(f.read()) + for data in doc.xpath('//div[@class="box"]'): + if counter <= 0: + break + + id = ''.join(data.xpath('.//div[@class="info"]/h3/a/@href')) + if not id: + continue + + cover_url = ''.join(data.xpath('.//img/@src')) + title = ''.join(data.xpath('.//div[@class="info"]/h3/a/@title')) + temp = title.split() + title = ' '.join(temp[0:-1]) + formats = temp[-1] + author = ''.join(data.xpath('.//div[@class="info"]/h4/text()')) + price = ''.join(data.xpath('.//h3[@class="promocja"]/text()')) + price = re.sub('PLN', 'zł', price) + price = re.sub('\.', ',', price) + + counter -= 1 + + s = SearchResult() + s.cover_url = cover_url + s.title = title.strip() + s.author = author.strip() + s.price = price + s.detail_item = id.strip() + s.drm = SearchResult.DRM_UNKNOWN + s.formats = formats.upper().strip() + + yield s diff --git a/src/calibre/gui2/store/nexto_plugin.py b/src/calibre/gui2/store/nexto_plugin.py index d63cf18233..0009f39b1b 100644 --- a/src/calibre/gui2/store/nexto_plugin.py +++ b/src/calibre/gui2/store/nexto_plugin.py @@ -63,6 +63,7 @@ class NextoStore(BasicStoreConfig, StorePlugin): cover_url = ''.join(data.xpath('.//img[@class="cover"]/@src')) title = ''.join(data.xpath('.//a[@class="title"]/text()')) + title = re.sub(r' - ebook$', '', title) formats = ', '.join(data.xpath('.//ul[@class="formats_available"]/li//b/text()')) DrmFree = re.search(r'bez.DRM', formats) formats = re.sub(r'\(.+\)', '', formats) From 4257cf6e3b88123bee053288e4d4e0edaa2e471a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20D=C5=82ugosz?= Date: Thu, 19 May 2011 22:56:28 +0200 Subject: [PATCH 2/7] improved Gandlf recipe --- src/calibre/gui2/store/gandalf_plugin.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/calibre/gui2/store/gandalf_plugin.py b/src/calibre/gui2/store/gandalf_plugin.py index 192484d764..de8896428d 100644 --- a/src/calibre/gui2/store/gandalf_plugin.py +++ b/src/calibre/gui2/store/gandalf_plugin.py @@ -56,10 +56,9 @@ class GandalfStore(BasicStoreConfig, StorePlugin): cover_url = ''.join(data.xpath('.//img/@src')) title = ''.join(data.xpath('.//div[@class="info"]/h3/a/@title')) - temp = title.split() - title = ' '.join(temp[0:-1]) - formats = temp[-1] - author = ''.join(data.xpath('.//div[@class="info"]/h4/text()')) + formats = title.split() + formats = formats[-1] + author = ''.join(data.xpath('.//div[@class="info"]/h4/text() | .//div[@class="info"]/h4/span/text()')) price = ''.join(data.xpath('.//h3[@class="promocja"]/text()')) price = re.sub('PLN', 'zł', price) price = re.sub('\.', ',', price) From 51146643c9d2432ff937748c38493ee63e773847 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20D=C5=82ugosz?= Date: Thu, 19 May 2011 23:34:29 +0200 Subject: [PATCH 3/7] fix Gandalf's encoding --- src/calibre/gui2/store/gandalf_plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/gui2/store/gandalf_plugin.py b/src/calibre/gui2/store/gandalf_plugin.py index de8896428d..4bd8e9e747 100644 --- a/src/calibre/gui2/store/gandalf_plugin.py +++ b/src/calibre/gui2/store/gandalf_plugin.py @@ -37,7 +37,7 @@ class GandalfStore(BasicStoreConfig, StorePlugin): def search(self, query, max_results=10, timeout=60): url = 'http://www.gandalf.com.pl/s/' values={ - 'search': query, + 'search': query.encode('iso8859_2'), 'dzialx':'11' } From bd781f047ce716bdf2d045c310f2d4cf9bb185c7 Mon Sep 17 00:00:00 2001 From: John Schember Date: Thu, 19 May 2011 18:43:14 -0400 Subject: [PATCH 4/7] Store: Add Pragmatic Bookshelf store. --- src/calibre/customize/builtins.py | 46 +++++++--- .../gui2/store/pragmatic_bookshelf_plugin.py | 84 +++++++++++++++++++ 2 files changed, 119 insertions(+), 11 deletions(-) create mode 100644 src/calibre/gui2/store/pragmatic_bookshelf_plugin.py diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index 5c93711e7d..ac26544207 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -1211,6 +1211,11 @@ class StoreOReillyStore(StoreBase): description = _('DRM-Free tech ebooks.') actual_plugin = 'calibre.gui2.store.oreilly_plugin:OReillyStore' +class StorePragmaticBookshelfStore(StoreBase): + name = 'Pragmatic Bookshelf' + description = _('The Pragmatic Bookshelf') + actual_plugin = 'calibre.gui2.store.pragmatic_bookshelf_plugin:PragmaticBookshelfStore' + class StoreSmashwordsStore(StoreBase): name = 'Smashwords' description = _('Your ebook. Your way.') @@ -1231,16 +1236,35 @@ class StoreWizardsTowerBooksStore(StoreBase): description = 'Wizard\'s Tower Press.' actual_plugin = 'calibre.gui2.store.wizards_tower_books_plugin:WizardsTowerBooksStore' -plugins += [StoreArchiveOrgStore, StoreAmazonKindleStore, StoreAmazonDEKindleStore, - StoreAmazonUKKindleStore, StoreBaenWebScriptionStore, StoreBNStore, - StoreBeamEBooksDEStore, StoreBeWriteStore, - StoreDieselEbooksStore, StoreEbookscomStore, StoreEPubBuyDEStore, - StoreEHarlequinStore, StoreFeedbooksStore, - StoreFoylesUKStore, StoreGandalfStore, - StoreGoogleBooksStore, StoreGutenbergStore, - StoreKoboStore, StoreManyBooksStore, - StoreMobileReadStore, StoreNextoStore, StoreOpenLibraryStore, - StoreOReillyStore, StoreSmashwordsStore, - StoreWaterstonesUKStore, StoreWeightlessBooksStore, StoreWizardsTowerBooksStore] +plugins += [ + StoreArchiveOrgStore, + StoreAmazonKindleStore, + StoreAmazonDEKindleStore, + StoreAmazonUKKindleStore, + StoreBaenWebScriptionStore, + StoreBNStore, + StoreBeamEBooksDEStore, + StoreBeWriteStore, + StoreDieselEbooksStore, + StoreEbookscomStore, + StoreEPubBuyDEStore, + StoreEHarlequinStore, + StoreFeedbooksStore, + StoreFoylesUKStore, + StoreGandalfStore, + StoreGoogleBooksStore, + StoreGutenbergStore, + StoreKoboStore, + StoreManyBooksStore, + StoreMobileReadStore, + StoreNextoStore, + StoreOpenLibraryStore, + StoreOReillyStore, + StorePragmaticBookshelfStore, + StoreSmashwordsStore, + StoreWaterstonesUKStore, + StoreWeightlessBooksStore, + StoreWizardsTowerBooksStore +] # }}} diff --git a/src/calibre/gui2/store/pragmatic_bookshelf_plugin.py b/src/calibre/gui2/store/pragmatic_bookshelf_plugin.py new file mode 100644 index 0000000000..9521fbdb91 --- /dev/null +++ b/src/calibre/gui2/store/pragmatic_bookshelf_plugin.py @@ -0,0 +1,84 @@ +# -*- coding: utf-8 -*- + +from __future__ import (unicode_literals, division, absolute_import, print_function) + +__license__ = 'GPL 3' +__copyright__ = '2011, John Schember ' +__docformat__ = 'restructuredtext en' + +import urllib +from contextlib import closing + +from lxml import html + +from PyQt4.Qt import QUrl + +from calibre import browser, url_slash_cleaner +from calibre.gui2 import open_url +from calibre.gui2.store import StorePlugin +from calibre.gui2.store.basic_config import BasicStoreConfig +from calibre.gui2.store.search_result import SearchResult +from calibre.gui2.store.web_store_dialog import WebStoreDialog + +class PragmaticBookshelfStore(BasicStoreConfig, StorePlugin): + + def open(self, parent=None, detail_item=None, external=False): + url = 'http://weightlessbooks.com/' + + 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(self.config.get('tags', '')) + d.exec_() + + def search(self, query, max_results=10, timeout=60): + ''' + OPDS based search. + + We really should get the catelog from http://pragprog.com/catalog.opds + and look for the application/opensearchdescription+xml entry. + Then get the opensearch description to get the search url and + format. However, we are going to be lazy and hard code it. + ''' + url = 'http://pragprog.com/catalog/search?q=' + urllib.quote_plus(query) + + br = browser() + + counter = max_results + with closing(br.open(url, timeout=timeout)) as f: + # Use html instead of etree as html allows us + # to ignore the namespace easily. + doc = html.fromstring(f.read()) + for data in doc.xpath('//entry'): + if counter <= 0: + break + + id = ''.join(data.xpath('.//link[@rel="http://opds-spec.org/acquisition/buy"]/@href')) + if not id: + continue + + price = ''.join(data.xpath('.//price/@currencycode')).strip() + price += ' ' + price += ''.join(data.xpath('.//price/text()')).strip() + if not price.strip(): + continue + + cover_url = ''.join(data.xpath('.//link[@rel="http://opds-spec.org/cover"]/@href')) + + title = ''.join(data.xpath('.//title/text()')) + author = ''.join(data.xpath('.//author//text()')) + + counter -= 1 + + s = SearchResult() + s.cover_url = cover_url + s.title = title.strip() + s.author = author.strip() + s.price = price.strip() + s.detail_item = id.strip() + s.drm = SearchResult.DRM_UNLOCKED + s.formats = 'EPUB, PDF, MOBI' + + yield s From 2257b0b942722467321eb05aecf0b36d9f1ec68a Mon Sep 17 00:00:00 2001 From: John Schember Date: Thu, 19 May 2011 18:45:26 -0400 Subject: [PATCH 5/7] Store: Fix Pragmatic Bookshelf url. --- src/calibre/gui2/store/pragmatic_bookshelf_plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/gui2/store/pragmatic_bookshelf_plugin.py b/src/calibre/gui2/store/pragmatic_bookshelf_plugin.py index 9521fbdb91..f3803bbcea 100644 --- a/src/calibre/gui2/store/pragmatic_bookshelf_plugin.py +++ b/src/calibre/gui2/store/pragmatic_bookshelf_plugin.py @@ -23,7 +23,7 @@ from calibre.gui2.store.web_store_dialog import WebStoreDialog class PragmaticBookshelfStore(BasicStoreConfig, StorePlugin): def open(self, parent=None, detail_item=None, external=False): - url = 'http://weightlessbooks.com/' + url = 'http://pragprog.com/' if external or self.config.get('open_external', False): open_url(QUrl(url_slash_cleaner(detail_item if detail_item else url))) From 5c893aacb03a2fa1a008d8fa157dd40fdc5d841f Mon Sep 17 00:00:00 2001 From: John Schember Date: Thu, 19 May 2011 18:48:51 -0400 Subject: [PATCH 6/7] Store: Change default for open external in search dialog. --- src/calibre/gui2/store/search/search.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/gui2/store/search/search.py b/src/calibre/gui2/store/search/search.py index e0d0251f98..f9ac45e707 100644 --- a/src/calibre/gui2/store/search/search.py +++ b/src/calibre/gui2/store/search/search.py @@ -190,7 +190,7 @@ class SearchDialog(QDialog, Ui_Dialog): else: self.resize_columns() - self.open_external.setChecked(self.config.get('open_external', False)) + self.open_external.setChecked(self.config.get('open_external', True)) store_check = self.config.get('store_checked', None) if store_check: From c01627b64eddf76848c75cb5af9a74d5a1efd725 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 19 May 2011 17:33:37 -0600 Subject: [PATCH 7/7] More OS X hoops --- src/calibre/gui2/bars.py | 7 +++++++ src/calibre/gui2/layout.py | 4 ---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/calibre/gui2/bars.py b/src/calibre/gui2/bars.py index 7dc0567d95..58711f9096 100644 --- a/src/calibre/gui2/bars.py +++ b/src/calibre/gui2/bars.py @@ -249,6 +249,10 @@ class BarsManager(QObject): self.menu_bar = MenuBar(self.location_manager, self.parent()) self.parent().setMenuBar(self.menu_bar) + parent.addToolBar(Qt.TopToolBarArea, self.main_bars[0]) + parent.addToolBar(Qt.BottomToolBarArea, self.main_bars[1]) + parent.addToolBar(Qt.BottomToolBarArea, self.child_bars[0]) + self.apply_settings() self.init_bars() @@ -288,12 +292,15 @@ class BarsManager(QObject): ''' showing_device = self.location_manager.has_device main_bar = self.main_bars[1 if showing_device else 0] + hidden_bar = self.main_bars[0 if showing_device else 1] + self.parent().addToolBar(Qt.BottomToolBarArea, hidden_bar) child_bar = self.child_bars[0] for bar in self.bars: bar.setVisible(False) bar.update_lm_actions() if main_bar.added_actions: main_bar.setVisible(True) + self.parent().addToolBar(Qt.TopToolBarArea, main_bar) if child_bar.added_actions: child_bar.setVisible(True) diff --git a/src/calibre/gui2/layout.py b/src/calibre/gui2/layout.py index 46b6356a6e..85e79d66d3 100644 --- a/src/calibre/gui2/layout.py +++ b/src/calibre/gui2/layout.py @@ -259,10 +259,6 @@ class MainWindowMixin(object): # {{{ self.search_bar = SearchBar(self) self.bars_manager = BarsManager(self.donate_button, self.location_manager, self) - for bar in self.bars_manager.main_bars: - self.addToolBar(Qt.TopToolBarArea, bar) - for bar in self.bars_manager.child_bars: - self.addToolBar(Qt.BottomToolBarArea, bar) self.bars_manager.update_bars() self.setUnifiedTitleAndToolBarOnMac(True)