From c890651806fa99b9a23d1c8c1323f0c4c849fdec Mon Sep 17 00:00:00 2001 From: John Schember Date: Fri, 25 Feb 2011 08:47:09 -0500 Subject: [PATCH] web_control downloads ebook links. Add Project Gutenberg store plugin. --- src/calibre/customize/builtins.py | 5 +- src/calibre/gui2/store/amazon/__init__.py | 0 src/calibre/gui2/store/amazon/web_control.py | 19 ------- .../gui2/store/{amazon => }/amazon_plugin.py | 9 ++-- src/calibre/gui2/store/gutenberg_plugin.py | 50 +++++++++++++++++ src/calibre/gui2/store/web_control.py | 53 +++++++++++++++++++ ...n_kindle_dialog.py => web_store_dialog.py} | 26 ++++----- ...n_kindle_dialog.ui => web_store_dialog.ui} | 2 +- src/calibre/gui2/store_download.py | 11 ++-- src/calibre/gui2/ui.py | 1 + 10 files changed, 133 insertions(+), 43 deletions(-) delete mode 100644 src/calibre/gui2/store/amazon/__init__.py delete mode 100644 src/calibre/gui2/store/amazon/web_control.py rename src/calibre/gui2/store/{amazon => }/amazon_plugin.py (88%) create mode 100644 src/calibre/gui2/store/gutenberg_plugin.py create mode 100644 src/calibre/gui2/store/web_control.py rename src/calibre/gui2/store/{amazon/amazon_kindle_dialog.py => web_store_dialog.py} (62%) rename src/calibre/gui2/store/{amazon/amazon_kindle_dialog.ui => web_store_dialog.ui} (98%) diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index 22b337915c..38aff09eb0 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -1041,8 +1041,9 @@ plugins += [GoogleBooks] # }}} # Store plugins {{{ -from calibre.gui2.store.amazon.amazon_plugin import AmazonKindleStore +from calibre.gui2.store.amazon_plugin import AmazonKindleStore +from calibre.gui2.store.gutenberg_plugin import GutenbergStore -plugins += [AmazonKindleStore] +plugins += [AmazonKindleStore, GutenbergStore] # }}} diff --git a/src/calibre/gui2/store/amazon/__init__.py b/src/calibre/gui2/store/amazon/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/calibre/gui2/store/amazon/web_control.py b/src/calibre/gui2/store/amazon/web_control.py deleted file mode 100644 index d7f95343d2..0000000000 --- a/src/calibre/gui2/store/amazon/web_control.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -__license__ = 'GPL 3' -__copyright__ = '2011, John Schember ' -__docformat__ = 'restructuredtext en' - -from PyQt4.Qt import QWebView, QWebPage - -class NPWebView(QWebView): - - def createWindow(self, type): - if type == QWebPage.WebBrowserWindow: - return self - else: - return None - - - - \ No newline at end of file diff --git a/src/calibre/gui2/store/amazon/amazon_plugin.py b/src/calibre/gui2/store/amazon_plugin.py similarity index 88% rename from src/calibre/gui2/store/amazon/amazon_plugin.py rename to src/calibre/gui2/store/amazon_plugin.py index 8c63bdafa5..7a3ba90ccf 100644 --- a/src/calibre/gui2/store/amazon/amazon_plugin.py +++ b/src/calibre/gui2/store/amazon_plugin.py @@ -18,9 +18,12 @@ class AmazonKindleStore(StorePlugin): name = 'Amazon Kindle' description = _('Buy Kindle books from Amazon') + ASTORE_URL = 'http://astore.amazon.com/josbl0e-20/' + def open(self, gui, parent=None, start_item=None): - from calibre.gui2.store.amazon.amazon_kindle_dialog import AmazonKindleDialog - d = AmazonKindleDialog(gui, parent, start_item) + from calibre.gui2.store.web_store_dialog import WebStoreDialog + d = WebStoreDialog(gui, self.ASTORE_URL, parent, start_item) + d.setWindowTitle('Amazon Kindle Store') d = d.exec_() def search(self, query, max_results=10, timeout=60): @@ -58,4 +61,4 @@ class AmazonKindleStore(StorePlugin): continue counter -= 1 - yield ('', title.strip(), author.strip(), price.strip(), asin.strip()) + yield ('', title.strip(), author.strip(), price.strip(), '/detail/'+asin.strip()) diff --git a/src/calibre/gui2/store/gutenberg_plugin.py b/src/calibre/gui2/store/gutenberg_plugin.py new file mode 100644 index 0000000000..c97e2c9ce3 --- /dev/null +++ b/src/calibre/gui2/store/gutenberg_plugin.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- + +__license__ = 'GPL 3' +__copyright__ = '2011, John Schember ' +__docformat__ = 'restructuredtext en' + +import urllib2 +from contextlib import closing + +from lxml import html + +from calibre import browser +from calibre.customize import StorePlugin + +class GutenbergStore(StorePlugin): + + name = 'Project Gutenberg' + description = _('The first producer of free ebooks.') + + + def open(self, gui, parent=None, start_item=None): + from calibre.gui2.store.web_store_dialog import WebStoreDialog + d = WebStoreDialog(gui, 'http://m.gutenberg.org/', parent, start_item) + d.setWindowTitle('Free eBooks by Project Gutenberg') + d = d.exec_() + + def search(self, query, max_results=10, timeout=60): + url = 'http://www.google.com/xhtml?q=site:gutenberg.org+' + urllib2.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('//div[@class="edewpi"]//div[@class="r ld"]'): + if counter <= 0: + break + + heading = ''.join(data.xpath('div[@class="jd"]/a//text()')) + title, _, author = heading.partition('by') + author = author.split('-')[0] + price = '$0.00' + + url = ''.join(data.xpath('span[@class="c"]/text()')) + id = url.split('/')[-1] + + counter -= 1 + yield ('', title.strip(), author.strip(), price.strip(), '/ebooks/' + id.strip()) + + diff --git a/src/calibre/gui2/store/web_control.py b/src/calibre/gui2/store/web_control.py new file mode 100644 index 0000000000..f31b750e52 --- /dev/null +++ b/src/calibre/gui2/store/web_control.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- + +__license__ = 'GPL 3' +__copyright__ = '2011, John Schember ' +__docformat__ = 'restructuredtext en' + +from PyQt4.Qt import QWebView, QWebPage, QNetworkCookieJar, QNetworkRequest + +class NPWebView(QWebView): + + def __init__(self, *args): + QWebView.__init__(self, *args) + self.gui = None + + #self.setPage(NPWebPage()) + self.page().networkAccessManager().setCookieJar(QNetworkCookieJar()) + self.page().setForwardUnsupportedContent(True) + self.page().unsupportedContent.connect(self.start_download) + self.page().downloadRequested.connect(self.start_download) + self.page().networkAccessManager().sslErrors.connect(self.ignore_ssl_errors) + #self.page().networkAccessManager().finished.connect(self.fin) + + def createWindow(self, type): + if type == QWebPage.WebBrowserWindow: + return self + else: + return None + + def set_gui(self, gui): + self.gui = gui + + def start_download(self, request): + if not self.gui: + print 'no gui' + return + + url = unicode(request.url().toString()) + self.gui.download_from_store(url) + + def ignore_ssl_errors(self, reply, errors): + reply.ignoreSslErrors(errors) + + def fin(self, reply): + if reply.error(): + print 'error' + print reply.error() + #print reply.attribute(QNetworkRequest.HttpStatusCodeAttribute).toInt() + + +class NPWebPage(QWebPage): + + def userAgentForUrl(self, url): + return 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.102 Safari/534.13' diff --git a/src/calibre/gui2/store/amazon/amazon_kindle_dialog.py b/src/calibre/gui2/store/web_store_dialog.py similarity index 62% rename from src/calibre/gui2/store/amazon/amazon_kindle_dialog.py rename to src/calibre/gui2/store/web_store_dialog.py index 108e1cfc40..467991e863 100644 --- a/src/calibre/gui2/store/amazon/amazon_kindle_dialog.py +++ b/src/calibre/gui2/store/web_store_dialog.py @@ -8,39 +8,41 @@ import urllib from PyQt4.Qt import QDialog, QUrl -from calibre.gui2.store.amazon.amazon_kindle_dialog_ui import Ui_Dialog +from calibre.gui2.store.web_store_dialog_ui import Ui_Dialog -class AmazonKindleDialog(QDialog, Ui_Dialog): +class WebStoreDialog(QDialog, Ui_Dialog): - ASTORE_URL = 'http://astore.amazon.com/josbl0e-20/' - - def __init__(self, gui, parent=None, start_item=None): + def __init__(self, gui, base_url, parent=None, detail_item=None): QDialog.__init__(self, parent=parent) self.setupUi(self) self.gui = gui + self.base_url = base_url + self.view.set_gui(self.gui) self.view.loadStarted.connect(self.load_started) self.view.loadProgress.connect(self.load_progress) self.view.loadFinished.connect(self.load_finished) self.home.clicked.connect(self.go_home) self.reload.clicked.connect(self.go_reload) - self.go_home(start_item=start_item) - + self.go_home(detail_item=detail_item) + def load_started(self): self.progress.setValue(0) def load_progress(self, val): self.progress.setValue(val) - def load_finished(self): + def load_finished(self, ok=True): self.progress.setValue(100) + #if not ok: + # print 'Error' - def go_home(self, checked=False, start_item=None): - url = self.ASTORE_URL - if start_item: - url += 'detail/' + urllib.quote(start_item) + def go_home(self, checked=False, detail_item=None): + url = self.base_url + if detail_item: + url += '/' + urllib.quote(detail_item) self.view.load(QUrl(url)) def go_reload(self, checked=False): diff --git a/src/calibre/gui2/store/amazon/amazon_kindle_dialog.ui b/src/calibre/gui2/store/web_store_dialog.ui similarity index 98% rename from src/calibre/gui2/store/amazon/amazon_kindle_dialog.ui rename to src/calibre/gui2/store/web_store_dialog.ui index fb4692fc5c..a6cce24d33 100644 --- a/src/calibre/gui2/store/amazon/amazon_kindle_dialog.ui +++ b/src/calibre/gui2/store/web_store_dialog.ui @@ -11,7 +11,7 @@ - Amazon Kindle Store + true diff --git a/src/calibre/gui2/store_download.py b/src/calibre/gui2/store_download.py index 241ff2f10a..fe99ae6f14 100644 --- a/src/calibre/gui2/store_download.py +++ b/src/calibre/gui2/store_download.py @@ -93,7 +93,6 @@ class StoreDownloader(Thread): self._download(job) self._add(job) self._save_as(job) - break except Exception, e: if not self._run: return @@ -125,13 +124,13 @@ class StoreDownloader(Thread): br = browser() - basename = br.geturl(url).split('/')[-1] + basename = br.open(url).geturl().split('/')[-1] ext = os.path.splitext(basename)[1][1:].lower() if ext not in BOOK_EXTENSIONS: raise Exception(_('Not a valid ebook format.')) tf = PersistentTemporaryFile(suffix=basename) - with closing(br.urlopen(url)) as f: + with closing(br.open(url)) as f: tf.write(f.read()) tf.close() job.tmp_file_name = tf.name @@ -141,7 +140,7 @@ class StoreDownloader(Thread): if not add_to_lib and job.tmp_file_name: return - ext = os.path.splitext(job.tmp_file_name)[1:] + ext = os.path.splitext(job.tmp_file_name)[1][1:] from calibre.ebooks.metadata.meta import get_metadata with open(job.tmp_file_name) as f: @@ -151,14 +150,14 @@ class StoreDownloader(Thread): def _save_as(self, job): url, save_loc, add_to_lib = job.args - if not save_loc and job.tmp_fie_name: + if not save_loc and job.tmp_file_name: return shutil.copy(job.tmp_fie_name, save_loc) def download_from_store(self, callback, db, url='', save_as_loc='', add_to_lib=True): description = _('Downloading %s') % url - job = StoreDownloadJob(callback, description, job_manager, db, url, save_as_loc, add_to_lib) + job = StoreDownloadJob(callback, description, self.job_manager, db, url, save_as_loc, add_to_lib) self.job_manager.add_job(job) self.jobs.put(job) diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index 85f58be218..aa36279c85 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -166,6 +166,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{ LayoutMixin.__init__(self) EmailMixin.__init__(self) + StoreDownloadMixin.__init__(self) DeviceMixin.__init__(self) self.progress_indicator = ProgressIndicator(self)