Refactoring and cleaning up.

This commit is contained in:
Jim Miller
2011-12-19 18:04:47 -06:00
parent cbc8cadd91
commit b75c9d4946
6 changed files with 143 additions and 146 deletions
+4 -6
View File
@@ -5,7 +5,7 @@ from __future__ import (unicode_literals, division, absolute_import,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2011, Fanficdownloader team'
__copyright__ = '2011, Jim Miller'
__docformat__ = 'restructuredtext en'
# The class that all Interface Action plugin wrappers must inherit from
@@ -22,7 +22,7 @@ class InterfacePluginDemo(InterfaceActionBase):
calibre utilities to run without needing to load the GUI libraries.
'''
name = 'aa FanFictionDownLoader Plugin'
description = 'UI plugin to download and maintain FanFiction from various sites.'
description = 'UI plugin to download FanFiction stories from various sites.'
supported_platforms = ['windows', 'osx', 'linux']
author = 'Jim Miller'
version = (1, 0, 0)
@@ -31,7 +31,7 @@ class InterfacePluginDemo(InterfaceActionBase):
#: This field defines the GUI plugin class that contains all the code
#: that actually does something. Its format is module_path:class_name
#: The specified class must be defined in the specified module.
actual_plugin = 'calibre_plugins.fanfictiondownloader_plugin.ui:InterfacePlugin'
actual_plugin = 'calibre_plugins.fanfictiondownloader_plugin.ui:FanFictionDownLoaderPlugin'
def is_customizable(self):
'''
@@ -78,11 +78,9 @@ class InterfacePluginDemo(InterfaceActionBase):
if ac is not None:
ac.apply_settings()
# For testing, run from command line with this:
# calibre-debug -e __init__.py
#
if __name__ == '__main__':
from PyQt4.Qt import QApplication
from calibre.gui2.preferences import test_widget
+4 -2
View File
@@ -1,9 +1,11 @@
FanFictionDownLoader Plugin Demo
FanFictionDownLoader Plugin
===========================
http://code.google.com/p/fanficdownloader/
Created by Jim Miller, borrowing heavily from Kovid Goyal's 'The InterfacePlugin Demo'
Created by Jim Miller, borrowing heavily from
Kovid Goyal's 'The InterfacePlugin Demo' and
Grant Drake's 'Count Pages' plugins.
Requires calibre >= 0.7.53
+1 -1
View File
@@ -4,7 +4,7 @@ from __future__ import (unicode_literals, division, absolute_import,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2011, Fanficdownloader team'
__copyright__ = '2011, Jim Miller'
__docformat__ = 'restructuredtext en'
from PyQt4.Qt import QWidget, QVBoxLayout, QLabel, QLineEdit, QTextEdit
-72
View File
@@ -1,72 +0,0 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
from __future__ import (unicode_literals, division, absolute_import,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2011, Jim Miller'
__docformat__ = 'restructuredtext en'
import os, traceback, time
import ConfigParser
from calibre.ebooks import DRMError
from calibre.ptempfile import PersistentTemporaryFile
from calibre.ebooks.metadata import MetaInformation
from calibre_plugins.fanfictiondownloader_plugin.fanficdownloader import adapters,writers,exceptions
def do_story_downloads(adaptertuple_list, fileform, db,
abort=None, log=None, notifications=[]): # lambda x,y:x lambda makes small anonymous function.
'''
Master job, to launch child jobs to download this list of stories
'''
print("do_story_downloads")
notifications.put((0.01, 'Start Downloading Stories'))
count = 0
total = len(adaptertuple_list)
# Queue all the jobs
for (url,adapter) in adaptertuple_list:
do_story_download(adapter,fileform,db)
count = count + 1
notifications.put((float(count)/total, 'Downloading Stories'))
# return the map as the job result
# return book_pages_map, book_words_map
return {},{}
def do_story_download(adapter,fileform,db):
print("do_story_download")
# ffdlconfig = ConfigParser.SafeConfigParser()
# adapter = adapters.getAdapter(ffdlconfig,url)
story = adapter.getStoryMetadataOnly()
mi = MetaInformation(story.getMetadata("title"),
(story.getMetadata("author"),)) # author is a list.
writer = writers.getWriter(fileform,adapter.config,adapter)
tmp = PersistentTemporaryFile("."+fileform)
print("tmp: "+tmp.name)
writer.writeStory(tmp)
print("post write tmp: "+tmp.name)
mi.set_identifiers({'url':story.getMetadata("storyUrl")})
mi.publisher = story.getMetadata("site")
mi.tags = writer.getTags()
mi.languages = ['en']
mi.pubdate = story.getMetadataRaw('datePublished').strftime("%Y-%m-%d")
mi.timestamp = story.getMetadataRaw('dateCreated').strftime("%Y-%m-%d")
mi.comments = story.getMetadata("description")
(notadded,addedcount)=db.add_books([tmp],[fileform],[mi], add_duplicates=True)
# Otherwise list of books doesn't update right away.
#self.gui.library_view.model().books_added(addedcount)
del adapter
del writer
+44 -35
View File
@@ -4,11 +4,13 @@ from __future__ import (unicode_literals, division,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2011, Fanficdownloader team'
__copyright__ = '2011, Jim Miller'
__docformat__ = 'restructuredtext en'
from PyQt4.Qt import (QDialog, QMessageBox, QVBoxLayout, QGridLayout, QPushButton, QProgressDialog, QString,
QLabel, QLineEdit, QInputDialog, QComboBox, QProgressDialog, QTimer )
from PyQt4.Qt import (QDialog, QMessageBox, QVBoxLayout, QGridLayout,
QPushButton, QProgressDialog, QString, QLabel,
QTextEdit, QLineEdit, QInputDialog, QComboBox,
QProgressDialog, QTimer )
from calibre.gui2 import error_dialog, warning_dialog, question_dialog
@@ -16,22 +18,28 @@ from calibre_plugins.fanfictiondownloader_plugin.fanficdownloader import adapter
class DownloadDialog(QDialog):
def __init__(self, gui, icon, do_user_config, pluginaction):
def __init__(self, gui, icon, do_user_config, start_downloads):
QDialog.__init__(self, gui)
self.gui = gui
self.do_user_config = do_user_config
self.pluginaction = pluginaction
self.start_downloads = start_downloads
self.setMinimumWidth(300)
self.l = QVBoxLayout()
self.setLayout(self.l)
self.setWindowTitle('FanFictionDownLoader')
self.setWindowIcon(icon)
self.l.addWidget(QLabel('Story URL:'))
self.url = QLineEdit(self)
self.l.addWidget(QLabel('Story URL(s), one per line:'))
self.url = QTextEdit(self)
self.url.setLineWrapMode(QTextEdit.NoWrap)
self.url.setText('http://test1.com?sid=12345')
self.l.addWidget(self.url)
# self.url = QLineEdit(self)
# self.url.setText('http://test1.com?sid=12345')
# self.l.addWidget(self.url)
self.l.addWidget(QLabel('Output Format:'))
self.fileform = QComboBox(self)
@@ -42,7 +50,7 @@ class DownloadDialog(QDialog):
self.l.addWidget(self.fileform)
self.ffdl_button = QPushButton(
'Download Story', self)
'Download Stories', self)
self.ffdl_button.clicked.connect(self.ffdl)
self.l.addWidget(self.ffdl_button)
@@ -68,21 +76,22 @@ class DownloadDialog(QDialog):
# get_resources will return a dictionary mapping names to bytes. Names that
# are not found in the zip file will not be in the returned dictionary.
text = get_resources('about.txt')
QMessageBox.about(self, 'About the Interface Plugin Demo',
QMessageBox.about(self, 'About the FanFictionDownLoader Plugin',
text.decode('utf-8'))
def ffdl(self):
self.pluginaction.start_downloads(unicode(self.url.text()),
unicode(self.fileform.currentText()))
self.start_downloads(unicode(self.url.toPlainText()),
unicode(self.fileform.currentText()))
self.hide()
def config(self):
self.do_user_config(parent=self)
# Apply the changes
#self.label.setText(prefs['hello_world_msg'])
class UserPassDialog(QDialog):
'''
Need to collect User/Pass for some sites.
'''
def __init__(self, gui, site):
QDialog.__init__(self, gui)
self.gui = gui
@@ -120,9 +129,11 @@ class UserPassDialog(QDialog):
self.status=False
self.hide()
class QueueProgressDialog(QProgressDialog):
def __init__(self, gui, title, loop_list, fileform, loop_function, enqueue_function, db):
class MetadataProgressDialog(QProgressDialog):
'''
ProgressDialog displayed while fetching metadata for each story.
'''
def __init__(self, gui, title, loop_list, fileform, getadapter_function, download_list_function, db):
QProgressDialog.__init__(self, title, QString(), 0, len(loop_list), gui)
self.setWindowTitle(title)
self.setMinimumWidth(500)
@@ -130,41 +141,39 @@ class QueueProgressDialog(QProgressDialog):
self.db = db
self.loop_list = loop_list
self.fileform = fileform
self.loop_function = loop_function
self.enqueue_function = enqueue_function
# self.book_ids, self.tdir, self.format_order, self.queue, self.db = \
# book_ids, tdir, format_order, queue, db
# self.pages_algorithm, self.pages_custom_column = pages_algorithm, pages_col
# self.words_algorithm, self.words_custom_column = words_algorithm, words_col
self.getadapter_function = getadapter_function
self.download_list_function = download_list_function
self.i, self.loop_bad, self.loop_good = 0, [], []
self.setValue(0)
self.setLabelText("Fetching metadata for %d of %d"%(0,len(self.loop_list)))
QTimer.singleShot(0, self.do_loop)
self.exec_()
def bump(self):
self.i += 1
self.setValue(self.i)
self.setLabelText("Fetching metadata for %d of %d"%(0,len(self.loop_list)))
def do_loop(self):
current = self.loop_list[self.i]
self.i += 1
self.bump()
try:
retval = self.loop_function(current,self.fileform)
retval = self.getadapter_function(current,self.fileform)
self.loop_good.append((current,retval))
except Exception as e:
self.loop_bad.append(current)
self.loop_bad.append((current,e))
self.setValue(self.i)
self.setLabelText("Fetching metadata for %d of %d"%(self.i,len(self.loop_list)))
if self.i >= len(self.loop_list):
return self.do_queue()
return self.do_when_finished()
else:
QTimer.singleShot(0, self.do_loop)
def do_queue(self):
def do_when_finished(self):
self.hide()
if self.loop_bad != []:
res = []
for current in self.loop_bad:
res.append('%s'%current)
for j in self.loop_bad:
res.append('%s : %s'%j)
msg = '%s' % '\n'.join(res)
warning_dialog(self.gui, _('Could not get metadata for some stories'),
_('Could not get metadata for %d of %d stories.') %
@@ -172,4 +181,4 @@ class QueueProgressDialog(QProgressDialog):
msg).exec_()
self.gui = None
# Queue a job to process these ePub/Mobi books
self.enqueue_function(self.loop_good,self.fileform)
self.download_list_function(self.loop_good,self.fileform)
+90 -30
View File
@@ -4,28 +4,26 @@ from __future__ import (unicode_literals, division, absolute_import,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2011, Fanficdownloader team'
__copyright__ = '2011, Jim Miller'
__docformat__ = 'restructuredtext en'
from StringIO import StringIO
import ConfigParser
from PyQt4.Qt import (QMessageBox)
# The class that all interface action plugins must inherit from
from calibre.gui2.actions import InterfaceAction
from calibre.ptempfile import PersistentTemporaryFile
from calibre.ebooks.metadata import MetaInformation
from calibre.gui2 import error_dialog, warning_dialog, question_dialog, info_dialog
from calibre.gui2.threaded_jobs import ThreadedJobServer, ThreadedJob
from calibre_plugins.fanfictiondownloader_plugin.fanficdownloader import adapters,writers,exceptions
from calibre.gui2.actions import InterfaceAction
from calibre.gui2.threaded_jobs import ThreadedJob
from calibre_plugins.fanfictiondownloader_plugin.fanficdownloader import adapters, writers, exceptions
from calibre_plugins.fanfictiondownloader_plugin.config import prefs
from calibre_plugins.fanfictiondownloader_plugin.plugin import (DownloadDialog, QueueProgressDialog,UserPassDialog)
from calibre_plugins.fanfictiondownloader_plugin.plugin import DownloadDialog, MetadataProgressDialog, UserPassDialog
from calibre_plugins.fanfictiondownloader_plugin.jobs import do_story_downloads
#from calibre_plugins.fanfictiondownloader_plugin.jobs import do_story_downloads
class InterfacePlugin(InterfaceAction):
class FanFictionDownLoaderPlugin(InterfaceAction):
name = 'FanFictionDownLoader'
@@ -33,8 +31,10 @@ class InterfacePlugin(InterfaceAction):
# The keyboard shortcut can be None if you dont want to use a keyboard
# shortcut. Remember that currently calibre has no central management for
# keyboard shortcuts, so try to use an unusual/unused shortcut.
# (text, icon_path, tooltip, keyboard shortcut)
# icon_path isn't in the zip--icon loaded below.
action_spec = ('FanFictionDownLoader', None,
'Download FanFiction stories from various web sites', None)
'Download FanFiction stories from various web sites', None)
action_type = 'current'
@@ -56,6 +56,7 @@ class InterfacePlugin(InterfaceAction):
# The qaction is automatically created from the action_spec defined
# above
self.qaction.setIcon(icon)
# Call function when plugin triggered.
self.qaction.triggered.connect(self.show_dialog)
def show_dialog(self):
@@ -76,45 +77,49 @@ class InterfacePlugin(InterfaceAction):
# self.gui is the main calibre GUI. It acts as the gateway to access
# all the elements of the calibre user interface, it should also be the
# parent of the dialog
d = DownloadDialog(self.gui, self.qaction.icon(), do_user_config, self)
# DownloadDialog just collects URLs, format and presents buttons.
d = DownloadDialog(self.gui,
self.qaction.icon(),
do_user_config, # method for config button
self.start_downloads, # method to start downloads
)
d.show()
def apply_settings(self):
# In an actual non trivial plugin, you would probably need to
# do something based on the settings in prefs
# No need to do anything with perfs here, but we could.
prefs
def start_downloads(self,url,fileform):
def start_downloads(self,urls,fileform):
self.ffdlconfig = ConfigParser.SafeConfigParser()
self.ffdlconfig.readfp(StringIO(get_resources("defaults.ini")))
self.ffdlconfig.readfp(StringIO(prefs['personal.ini']))
## XXX including code for Things to Come, namely, a list of
## URLs rather than just one.
url_list = [url,
#"http://test1.com?sid=6700",
#"http://test1.com?sid=6701",
# "http://test1.com?sid=6702",
# "http://test1.com?sid=6703",
# "http://test1.com?sid=6704",
# "http://test1.com?sid=6705",
# "http://test1.com?sid=6706"
]
url_list = urls.splitlines()
'''
http://test1.com?sid=6700
http://test1.com?sid=6701
http://test1.com?sid=6702
http://test1.com?sid=6703
http://test1.com?sid=6704
http://test1.com?sid=6705
http://test1.com?sid=6706
'''
self.fetchmeta_qpd = \
QueueProgressDialog(self.gui,
MetadataProgressDialog(self.gui,
"Getting Metadata for Stories",
url_list,
fileform,
self.get_adapter_for_story,
self.enqueue_story_list_for_download,
self.download_list,
self.db)
def get_adapter_for_story(self,url,fileform):
'''
Returns adapter object for story at URL. To be called from
QueueProgressDialog 'loop' to build up list of adapters. Also
MetadataProgressDialog 'loop' to build up list of adapters. Also
pops dialogs for is adult, user/pass, duplicate
'''
@@ -162,9 +167,9 @@ class InterfacePlugin(InterfaceAction):
else:
return None
def enqueue_story_list_for_download(self,adaptertuple_list,fileform):
def download_list(self,adaptertuple_list,fileform):
'''
Called by QueueProgressDialog to enqueue story downloads for BG processing.
Called by MetadataProgressDialog to enqueue story downloads for BG processing.
adapter_list is a list of tuples of (url,adapter)
'''
print("enqueue_story_list_for_download")
@@ -219,3 +224,58 @@ class InterfacePlugin(InterfaceAction):
# show_copy_button=False, parent=self.gui)
# p.show()
#info_dialog(self.gui,'FFDL Complete','It worked?')
def do_story_downloads(adaptertuple_list, fileform, db,
abort=None, log=None, notifications=[]): # lambda x,y:x lambda makes small anonymous function.
'''
Master job, to launch child jobs to download this list of stories
'''
print("do_story_downloads")
notifications.put((0.01, 'Start Downloading Stories'))
count = 0
total = len(adaptertuple_list)
# Queue all the jobs
for (url,adapter) in adaptertuple_list:
do_story_download(adapter,fileform,db)
count = count + 1
notifications.put((float(count)/total, 'Downloading Stories'))
# return the map as the job result
# return book_pages_map, book_words_map
return {},{}
def do_story_download(adapter,fileform,db):
print("do_story_download")
# ffdlconfig = ConfigParser.SafeConfigParser()
# adapter = adapters.getAdapter(ffdlconfig,url)
story = adapter.getStoryMetadataOnly()
mi = MetaInformation(story.getMetadata("title"),
(story.getMetadata("author"),)) # author is a list.
writer = writers.getWriter(fileform,adapter.config,adapter)
tmp = PersistentTemporaryFile("."+fileform)
print("tmp: "+tmp.name)
writer.writeStory(tmp)
print("post write tmp: "+tmp.name)
mi.set_identifiers({'url':story.getMetadata("storyUrl")})
mi.publisher = story.getMetadata("site")
mi.tags = writer.getTags()
mi.languages = ['en']
mi.pubdate = story.getMetadataRaw('datePublished').strftime("%Y-%m-%d")
mi.timestamp = story.getMetadataRaw('dateCreated').strftime("%Y-%m-%d")
mi.comments = story.getMetadata("description")
(notadded,addedcount)=db.add_books([tmp],[fileform],[mi], add_duplicates=True)
# Otherwise list of books doesn't update right away.
#self.gui.library_view.model().books_added(addedcount)
del adapter
del writer