mirror of
https://github.com/wassname/FanFicFare.git
synced 2026-09-11 11:52:07 +08:00
Refactoring and cleaning up.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user