Untested store download job.

This commit is contained in:
John Schember 2011-02-24 18:45:05 -05:00
parent 7ed397ca4d
commit deea9f48bc
7 changed files with 198 additions and 9 deletions

View File

@ -588,7 +588,7 @@ class StorePlugin(Plugin): # {{{
author = 'John Schember'
type = _('Stores')
def open(self, parent=None, start_item=None):
def open(self, gui, parent=None, start_item=None):
'''
Open a dialog for displaying the store.
start_item is a refernce unique to the store

View File

@ -27,8 +27,8 @@ class StoreAction(InterfaceAction):
def search(self):
from calibre.gui2.store.search import SearchDialog
sd = SearchDialog(self.gui)
sd = SearchDialog(self.gui, self.gui)
sd.exec_()
def open_store(self, store_plugin):
store_plugin.open(self.gui)
store_plugin.open(self.gui, self.gui)

View File

@ -14,10 +14,12 @@ class AmazonKindleDialog(QDialog, Ui_Dialog):
ASTORE_URL = 'http://astore.amazon.com/josbl0e-20/'
def __init__(self, parent=None, start_item=None):
def __init__(self, gui, parent=None, start_item=None):
QDialog.__init__(self, parent=parent)
self.setupUi(self)
self.gui = gui
self.view.loadStarted.connect(self.load_started)
self.view.loadProgress.connect(self.load_progress)
self.view.loadFinished.connect(self.load_finished)

View File

@ -18,9 +18,9 @@ class AmazonKindleStore(StorePlugin):
name = 'Amazon Kindle'
description = _('Buy Kindle books from Amazon')
def open(self, parent=None, start_item=None):
def open(self, gui, parent=None, start_item=None):
from calibre.gui2.store.amazon.amazon_kindle_dialog import AmazonKindleDialog
d = AmazonKindleDialog(parent, start_item)
d = AmazonKindleDialog(gui, parent, start_item)
d = d.exec_()
def search(self, query, max_results=10, timeout=60):

View File

@ -21,9 +21,11 @@ class SearchDialog(QDialog, Ui_Dialog):
HANG_TIME = 75000 # milliseconds seconds
TIMEOUT = 75 # seconds
def __init__(self, *args):
def __init__(self, gui, *args):
QDialog.__init__(self, *args)
self.setupUi(self)
self.gui = gui
self.store_plugins = {}
self.running_threads = []
@ -96,7 +98,7 @@ class SearchDialog(QDialog, Ui_Dialog):
def open_store(self, index):
result = self.results_view.model().get_result(index)
self.store_plugins[result.store].open(self, result.item_data)
self.store_plugins[result.store].open(self.gui, self, result.item_data)
class SearchThread(Thread):

View File

@ -0,0 +1,183 @@
# -*- coding: utf-8 -*-
__license__ = 'GPL 3'
__copyright__ = '2011, John Schember <john@nachtimwald.com>'
__docformat__ = 'restructuredtext en'
import cStringIO
import os
import shutil
import time
from contextlib import closing
from threading import Thread
from Queue import Queue
from calibre import browser
from calibre.ebooks import BOOK_EXTENSIONS
from calibre.gui2 import Dispatcher
from calibre.ptempfile import PersistentTemporaryFile
from calibre.utils.ipc.job import BaseJob
class StoreDownloadJob(BaseJob):
def __init__(self, callback, description, job_manager, db, url='', save_as_loc='', add_to_lib=True):
BaseJob.__init__(self, description)
self.exception = None
self.job_manager = job_manager
self.db = db
self.args = (url, save_as_loc, add_to_lib)
self.tmp_file_name = ''
self.callback = callback
self.log_path = None
self._log_file = cStringIO.StringIO()
self._log_file.write(self.description.encode('utf-8') + '\n')
@property
def log_file(self):
if self.log_path is not None:
return open(self.log_path, 'rb')
return cStringIO.StringIO(self._log_file.getvalue())
def start_work(self):
self.start_time = time.time()
self.job_manager.changed_queue.put(self)
def job_done(self):
self.duration = time.time() - self.start_time
self.percent = 1
# Dump log onto disk
lf = PersistentTemporaryFile('store_log')
lf.write(self._log_file.getvalue())
lf.close()
self.log_path = lf.name
self._log_file.close()
self._log_file = None
self.job_manager.changed_queue.put(self)
def log_write(self, what):
self._log_file.write(what)
class StoreDownloader(Thread):
def __init__(self, job_manager):
Thread.__init__(self)
self.daemon = True
self.jobs = Queue()
self.job_manager = job_manager
self._run = True
def stop(self):
self._run = False
self.jobs.put(None)
def run(self):
while self._run:
try:
job = self.jobs.get()
except:
break
if job is None or not self._run:
break
failed, exc = False, None
job.start_work()
if job.kill_on_start:
job.log_write('Aborted\n')
job.failed = failed
job.killed = True
job.job_done()
continue
try:
self._download(job)
self._add(job)
self._save_as(job)
break
except Exception, e:
if not self._run:
return
import traceback
failed = True
exc = e
job.log_write('\nSending failed...\n')
job.log_write(traceback.format_exc())
if not self._run:
break
job.failed = failed
job.exception = exc
job.job_done()
try:
job.callback(job)
except:
import traceback
traceback.print_exc()
def _download(self, job):
url, save_loc, add_to_lib = job.args
if not url:
raise Exception(_('No file specified to download.'))
if not save_loc and not add_to_lib:
# Nothing to do.
return
br = browser()
basename = br.geturl(url).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:
tf.write(f.read())
tf.close()
job.tmp_file_name = tf.name
def _add(self, job):
url, save_loc, add_to_lib = job.args
if not add_to_lib and job.tmp_file_name:
return
ext = os.path.splitext(job.tmp_file_name)[1:]
from calibre.ebooks.metadata.meta import get_metadata
with open(job.tmp_file_name) as f:
mi = get_metadata(f, ext)
job.db.add_books([job.tmp_file_name], [ext], [mi])
def _save_as(self, job):
url, save_loc, add_to_lib = job.args
if not save_loc and job.tmp_fie_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)
self.job_manager.add_job(job)
self.jobs.put(job)
class StoreDownloadMixin(object):
def __init__(self):
self.store_downloader = StoreDownloader(self.job_manager)
self.store_downloader.start()
def download_from_store(self, url='', save_as_loc='', add_to_lib=True):
self.store_downloader.download_from_store(Dispatcher(self.downloaded_from_store), self.library_view.model().db, url, save_as_loc, add_to_lib)
self.status_bar.show_message(_('Downloading') + ' ' + url, 3000)
def downloaded_from_store(self, job):
if job.failed:
self.job_exception(job, dialog_title=_('Failed to download book'))
return
self.status_bar.show_message(job.description + ' ' + _('finished'), 5000)

View File

@ -33,6 +33,7 @@ from calibre.gui2.main_window import MainWindow
from calibre.gui2.layout import MainWindowMixin
from calibre.gui2.device import DeviceMixin
from calibre.gui2.email import EmailMixin
from calibre.gui2.store_download import StoreDownloadMixin
from calibre.gui2.jobs import JobManager, JobsDialog, JobsButton
from calibre.gui2.init import LibraryViewMixin, LayoutMixin
from calibre.gui2.search_box import SearchBoxMixin, SavedSearchBoxMixin
@ -89,7 +90,8 @@ class SystemTrayIcon(QSystemTrayIcon): # {{{
class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
TagBrowserMixin, CoverFlowMixin, LibraryViewMixin, SearchBoxMixin,
SavedSearchBoxMixin, SearchRestrictionMixin, LayoutMixin, UpdateMixin
SavedSearchBoxMixin, SearchRestrictionMixin, LayoutMixin, UpdateMixin,
StoreDownloadMixin
):
'The main GUI'