From 009090c99eee1fa83f028ac7dc8a21fbe8c62703 Mon Sep 17 00:00:00 2001 From: John Schember Date: Tue, 10 May 2011 18:23:18 -0400 Subject: [PATCH] Store: Add Wizards Tower Books plugin. --- src/calibre/customize/builtins.py | 7 +- .../gui2/store/wizards_tower_books_plugin.py | 88 +++++++++++++++++++ 2 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 src/calibre/gui2/store/wizards_tower_books_plugin.py diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index 2c516f22c0..579403f6ba 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -1186,6 +1186,11 @@ class StoreWeightlessBooksStore(StoreBase): description = '(e)Books That Don\'t Weigh You Down' actual_plugin = 'calibre.gui2.store.weightless_books_plugin:WeightlessBooksStore' +class StoreWizardsTowerBooksStore(StoreBase): + name = 'Wizards Tower Books' + description = 'Wizard\'s Tower Press' + actual_plugin = 'calibre.gui2.store.wizards_tower_books_plugin:WizardsTowerBooksStore' + plugins += [StoreAmazonKindleStore, StoreAmazonDEKindleStore, StoreAmazonUKKindleStore, StoreBaenWebScriptionStore, StoreBNStore, StoreBeWriteStore, @@ -1193,6 +1198,6 @@ plugins += [StoreAmazonKindleStore, StoreAmazonDEKindleStore, StoreAmazonUKKindl StoreEHarlequinStoretore, StoreFeedbooksStore, StoreFoylesUKStore, StoreGutenbergStore, StoreKoboStore, StoreManyBooksStore, StoreMobileReadStore, StoreOpenLibraryStore, StoreSmashwordsStore, - StoreWaterstonesUKStore, StoreWeightlessBooksStore] + StoreWaterstonesUKStore, StoreWeightlessBooksStore, StoreWizardsTowerBooksStore] # }}} diff --git a/src/calibre/gui2/store/wizards_tower_books_plugin.py b/src/calibre/gui2/store/wizards_tower_books_plugin.py new file mode 100644 index 0000000000..56bb00ff7e --- /dev/null +++ b/src/calibre/gui2/store/wizards_tower_books_plugin.py @@ -0,0 +1,88 @@ +# -*- 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 WizardsTowerBooksStore(BasicStoreConfig, StorePlugin): + + url = 'http://www.wizardstowerbooks.com/' + + def open(self, parent=None, detail_item=None, external=False): + if detail_item: + detail_item = self.url + detail_item + + 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, self.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.wizardstowerbooks.com/search.html?for=' + urllib.quote(query) + + br = browser() + + counter = max_results + with closing(br.open(url, timeout=timeout)) as f: + doc = html.fromstring(f.read()) + for data in doc.xpath('//table[@class="gridp"]//td'): + if counter <= 0: + break + + id = ''.join(data.xpath('.//span[@class="prti"]/a/@href')) + id = id.strip() + if not id: + continue + + cover_url = ''.join(data.xpath('.//div[@class="prim"]/a/img/@src')) + cover_url = url_slash_cleaner(self.url + cover_url.strip()) + + price = ''.join(data.xpath('.//font[@class="selling_price"]//text()')) + price = price.strip() + if not price: + continue + + title = ''.join(data.xpath('.//span[@class="prti"]/a/b/text()')) + author = ''.join(data.xpath('.//p[@class="last"]/text()')) + a, b, author = author.partition(' by ') + + 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 + + yield s + + def get_details(self, search_result, timeout): + br = browser() + with closing(br.open(url_slash_cleaner(self.url + search_result.detail_item), timeout=timeout)) as nf: + idata = html.fromstring(nf.read()) + + formats = ', '.join(idata.xpath('//select[@id="N1_"]//option//text()')) + search_result.formats = formats.upper() + + return True