Compare commits

..
Author SHA1 Message Date
Jim Miller e26a05491d Plugin-Don't disable menus when nothing selected--breaks keyboard shortcuts.
More verbiage on config dialogs, make FanFictionDownLoader itself shortcutable.
2012-01-27 15:56:52 -06:00
Jim Miller d1680a74dc Plugin-Update custom columns from metadata, allow skip update confirm, progress
bar for updating books after download.
2012-01-26 23:12:50 -06:00
Jim Miller 9b17e0c396 Plugin-Improved drag and drop of URLs onto 'Add New' dialog. 2012-01-24 21:48:25 -06:00
Jim Miller e73284d3cd Added tag calibre-plugin-1.2.3 for changeset 0e783c6c7f5e 2012-01-22 22:00:30 -06:00
5 changed files with 386 additions and 117 deletions
+1 -1
View File
@@ -27,7 +27,7 @@ class FanFictionDownLoaderBase(InterfaceActionBase):
description = 'UI plugin to download FanFiction stories from various sites.'
supported_platforms = ['windows', 'osx', 'linux']
author = 'Jim Miller'
version = (1, 2, 3)
version = (1, 3, 0)
minimum_calibre_version = (0, 8, 30)
#: This field defines the GUI plugin class that contains all the code
+145 -5
View File
@@ -10,7 +10,7 @@ __docformat__ = 'restructuredtext en'
import traceback, copy
from PyQt4.Qt import (QDialog, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit,
QTextEdit, QComboBox, QCheckBox, QPushButton, QTabWidget)
QTextEdit, QComboBox, QCheckBox, QPushButton, QTabWidget, QVariant)
from calibre.gui2 import dynamic, info_dialog
from calibre.utils.config import JSONConfig
@@ -47,6 +47,7 @@ all_prefs.defaults['read_lists'] = ''
all_prefs.defaults['addtolists'] = False
all_prefs.defaults['addtoreadlists'] = False
all_prefs.defaults['addtolistsonread'] = False
all_prefs.defaults['custom_cols'] = {}
# The list of settings to copy from all_prefs or the previous library
# when config is called for the first time on a library.
@@ -132,10 +133,14 @@ class ConfigWidget(QWidget):
tab_widget.addTab(self.list_tab, 'Reading Lists')
if 'Reading List' not in plugin_action.gui.iactions:
self.list_tab.setEnabled(False)
self.columns_tab = ColumnsTab(self, plugin_action)
tab_widget.addTab(self.columns_tab, 'Custom Columns')
self.other_tab = OtherTab(self, plugin_action)
tab_widget.addTab(self.other_tab, 'Other')
def save_settings(self):
# basic
@@ -164,6 +169,15 @@ class ConfigWidget(QWidget):
else:
# if they've removed everything, reset to default.
prefs['personal.ini'] = get_resources('plugin-example.ini')
# Custom Columns tab
colsmap = {}
for (col,combo) in self.columns_tab.custcol_dropdowns.iteritems():
val = unicode(combo.itemData(combo.currentIndex()).toString())
if val != 'none':
colsmap[col] = val
#print("colsmap[%s]:%s"%(col,colsmap[col]))
prefs['custom_cols'] = colsmap
def edit_shortcuts(self):
self.save_settings()
@@ -183,6 +197,11 @@ class BasicTab(QWidget):
self.l = QVBoxLayout()
self.setLayout(self.l)
label = QLabel('These settings control the basic features of the plugin--downloading FanFiction.')
label.setWordWrap(True)
self.l.addWidget(label)
self.l.addSpacing(5)
horz = QHBoxLayout()
label = QLabel('Default Output &Format:')
horz.addWidget(label)
@@ -214,7 +233,7 @@ class BasicTab(QWidget):
self.l.addLayout(horz)
self.updatemeta = QCheckBox('Default Update Calibre &Metadata?',self)
self.updatemeta.setToolTip('Update title, author, URL, tags, etc for story in Calibre from web site.')
self.updatemeta.setToolTip('Update title, author, URL, tags, custom columns, etc for story in Calibre from web site.')
self.updatemeta.setChecked(prefs['updatemeta'])
self.l.addWidget(self.updatemeta)
@@ -265,6 +284,11 @@ class PersonalIniTab(QWidget):
self.l = QVBoxLayout()
self.setLayout(self.l)
label = QLabel('These settings provide more detailed control over what metadata will be displayed inside the ebook as well as let you set is_adult and user/password for different sites.')
label.setWordWrap(True)
self.l.addWidget(label)
self.l.addSpacing(5)
self.label = QLabel('personal.ini:')
self.l.addWidget(self.label)
@@ -293,13 +317,13 @@ class ShowDefaultsIniDialog(QDialog):
self.l = QVBoxLayout()
self.setLayout(self.l)
self.label = QLabel("Plugin Defaults (Read-Only)")
self.label.setToolTip("These all of the plugin's configurable settings\nand their default settings.")
self.label.setToolTip("These are all of the plugin's configurable options\nand their default settings.")
self.setWindowTitle(_('Plugin Defaults'))
self.setWindowIcon(icon)
self.l.addWidget(self.label)
self.ini = QTextEdit(self)
self.ini.setToolTip("These all of the plugin's configurable settings\nand their default settings.")
self.ini.setToolTip("These are all of the plugin's configurable options\nand their default settings.")
self.ini.setLineWrapMode(QTextEdit.NoWrap)
self.ini.setText(text)
self.ini.setReadOnly(True)
@@ -379,6 +403,11 @@ class OtherTab(QWidget):
self.l = QVBoxLayout()
self.setLayout(self.l)
label = QLabel("These controls aren't plugin settings as such, but convenience buttons for setting Keyboard shortcuts and getting all the FanFictionDownLoader confirmation dialogs back again.")
label.setWordWrap(True)
self.l.addWidget(label)
self.l.addSpacing(5)
keyboard_shortcuts_button = QPushButton('Keyboard shortcuts...', self)
keyboard_shortcuts_button.setToolTip(_(
'Edit the keyboard shortcuts associated with this plugin'))
@@ -401,3 +430,114 @@ class OtherTab(QWidget):
info_dialog(self, _('Done'),
_('Confirmation dialogs have all been reset'), show=True)
permitted_values = {
'int' : ['numWords','numChapters'],
'float' : ['numWords','numChapters'],
'bool' : ['status-C','status-I'],
'datetime' : ['datePublished', 'dateUpdated', 'dateCreated'],
'enumeration' : ['category',
'genre',
'characters',
'status',
'datePublished',
'dateUpdated',
'dateCreated',
'rating',
'warnings',
'numChapters',
'numWords',
'site',
'storyId',
'authorId',
'extratags',
'title',
'storyUrl',
'description',
'author',
'authorUrl',
'formatname'
#,'formatext' # not useful information.
#,'siteabbrev'
#,'version'
]
}
# no point copying the whole list.
permitted_values['text'] = permitted_values['enumeration']
permitted_values['comments'] = permitted_values['enumeration']
titleLabels = {
'category':'Category',
'genre':'Genre',
'status':'Status',
'status-C':'Status:Completed',
'status-I':'Status:In-Progress',
'characters':'Characters',
'datePublished':'Published',
'dateUpdated':'Updated',
'dateCreated':'Packaged',
'rating':'Rating',
'warnings':'Warnings',
'numChapters':'Chapters',
'numWords':'Words',
'site':'Site',
'storyId':'Story ID',
'authorId':'Author ID',
'extratags':'Extra Tags',
'title':'Title',
'storyUrl':'Story URL',
'description':'Summary',
'author':'Author',
'authorUrl':'Author URL',
'formatname':'File Format',
'formatext':'File Extension',
'siteabbrev':'Site Abbrev',
'version':'FFD Version'
}
class ColumnsTab(QWidget):
def __init__(self, parent_dialog, plugin_action):
self.parent_dialog = parent_dialog
self.plugin_action = plugin_action
QWidget.__init__(self)
self.l = QVBoxLayout()
self.setLayout(self.l)
label = QLabel("If you have custom columns defined, they will be listed below. Choose a metadata value type to fill your columns automatically.")
label.setWordWrap(True)
self.l.addWidget(label)
self.l.addSpacing(5)
self.custcol_dropdowns = {}
custom_columns = self.plugin_action.gui.library_view.model().custom_columns
for key, column in custom_columns.iteritems():
if column['datatype'] in permitted_values:
# print("\n============== %s ===========\n"%key)
# for (k,v) in column.iteritems():
# print("column['%s'] => %s"%(k,v))
horz = QHBoxLayout()
label = QLabel('%s(%s)'%(column['name'],key))
label.setToolTip("Update this %s column with..."%column['datatype'])
horz.addWidget(label)
dropdown = QComboBox(self)
dropdown.addItem('',QVariant('none'))
for md in permitted_values[column['datatype']]:
dropdown.addItem(titleLabels[md],QVariant(md))
self.custcol_dropdowns[key] = dropdown
if key in prefs['custom_cols']:
dropdown.setCurrentIndex(dropdown.findData(QVariant(prefs['custom_cols'][key])))
if column['datatype'] == 'enumeration':
dropdown.setToolTip("Metadata values valid for this type of column.\nValues that aren't valid for this enumeration column will be ignored.")
else:
dropdown.setToolTip("Metadata values valid for this type of column.")
horz.addWidget(dropdown)
self.l.addLayout(horz)
self.l.insertStretch(-1)
#print("prefs['custom_cols'] %s"%prefs['custom_cols'])
+78 -21
View File
@@ -11,13 +11,16 @@ import traceback
from PyQt4 import QtGui
from PyQt4.Qt import (QDialog, QTableWidget, QMessageBox, QVBoxLayout, QHBoxLayout, QGridLayout,
QPushButton, QProgressDialog, QString, QLabel, QCheckBox, QIcon,
QPushButton, QProgressDialog, QString, QLabel, QCheckBox, QIcon, QTextCursor,
QTextEdit, QLineEdit, QInputDialog, QComboBox, QClipboard, QVariant,
QProgressDialog, QTimer, QDialogButtonBox, QPixmap, Qt,QAbstractItemView )
from calibre.gui2 import error_dialog, warning_dialog, question_dialog, info_dialog
from calibre.gui2.dialogs.confirm_delete import confirm
from calibre import confirm_config_name
from calibre.gui2 import dynamic
from calibre_plugins.fanfictiondownloader_plugin.fanficdownloader import adapters,writers,exceptions
from calibre_plugins.fanfictiondownloader_plugin.common_utils \
import (ReadOnlyTableWidgetItem, ReadOnlyTextIconWidgetItem, SizePersistedDialog,
@@ -45,7 +48,24 @@ class NotGoingToDownload(Exception):
def __str__(self):
return self.error
class DroppableQTextEdit(QTextEdit):
def __init__(self,parent):
QTextEdit.__init__(self,parent)
def canInsertFromMimeData(self, source):
if source.hasUrls():
return True;
else:
return QTextEdit.canInsertFromMimeData(self,source)
def insertFromMimeData(self, source):
if source.hasUrls():
for u in source.urls():
self.append(u.toString())
else:
return QTextEdit.insertFromMimeData(self, source)
class AddNewDialog(SizePersistedDialog):
def __init__(self, gui, prefs, icon, url_list_text):
@@ -60,7 +80,7 @@ class AddNewDialog(SizePersistedDialog):
self.setWindowIcon(icon)
self.l.addWidget(QLabel('Story URL(s), one per line:'))
self.url = QTextEdit(self)
self.url = DroppableQTextEdit(self)
self.url.setToolTip('URLs for stories, one per line.\nWill take URLs from clipboard, but only valid URLs.')
self.url.setLineWrapMode(QTextEdit.NoWrap)
self.url.setText(url_list_text)
@@ -180,25 +200,27 @@ class UserPassDialog(QDialog):
self.status=False
self.hide()
class MetadataProgressDialog(QProgressDialog):
class LoopProgressDialog(QProgressDialog):
'''
ProgressDialog displayed while fetching metadata for each story.
'''
def __init__(self, gui,
book_list,
options,
metadata_function,
startdownload_function):
foreach_function,
finish_function,
init_label="Fetching metadata for stories...",
win_title="Downloading metadata for stories",
status_prefix="Fetched metadata for"):
QProgressDialog.__init__(self,
"Fetching metadata for stories...",
init_label,
QString(), 0, len(book_list), gui)
self.setWindowTitle("Downloading metadata for stories")
self.setWindowTitle(win_title)
self.setMinimumWidth(500)
self.gui = gui
self.book_list = book_list
self.options = options
self.metadata_function = metadata_function
self.startdownload_function = startdownload_function
self.foreach_function = foreach_function
self.finish_function = finish_function
self.status_prefix = status_prefix
self.i = 0
## self.do_loop does QTimer.singleShot on self.do_loop also.
@@ -207,7 +229,7 @@ class MetadataProgressDialog(QProgressDialog):
self.exec_()
def updateStatus(self):
self.setLabelText("Fetched metadata for %d of %d"%(self.i+1,len(self.book_list)))
self.setLabelText("%s %d of %d"%(self.status_prefix,self.i+1,len(self.book_list)))
self.setValue(self.i+1)
print(self.labelText())
@@ -220,7 +242,7 @@ class MetadataProgressDialog(QProgressDialog):
try:
## collision spec passed into getadapter by partial from ffdl_plugin
## no retval only if it exists, but collision is SKIP
self.metadata_function(book)
self.foreach_function(book)
except NotGoingToDownload as d:
book['good']=False
@@ -245,7 +267,7 @@ class MetadataProgressDialog(QProgressDialog):
self.hide()
self.gui = None
# Queues a job to process these books in the background.
self.startdownload_function(self.book_list)
self.finish_function(self.book_list)
class AboutDialog(QDialog):
@@ -290,7 +312,7 @@ class AuthorTableWidgetItem(ReadOnlyTableWidgetItem):
class UpdateExistingDialog(SizePersistedDialog):
def __init__(self, gui, header, prefs, icon, books,
save_size_name='FanFictionDownLoader plugin:update list dialog'):
save_size_name='fanfictiondownloader_plugin:update list dialog'):
SizePersistedDialog.__init__(self, gui, save_size_name)
self.gui = gui
@@ -398,14 +420,35 @@ class UpdateExistingDialog(SizePersistedDialog):
'updatemeta': unicode(self.updatemeta.isChecked()),
}
def display_story_list(gui, header, prefs, icon, books,
label_text='',
save_size_name='fanfictiondownloader_plugin:display list dialog',
offer_skip=False):
all_good = True
for b in books:
if not b['good']:
all_good=False
break
##
if all_good and not dynamic.get(confirm_config_name(save_size_name), True):
return True
pass
## fake accept?
d = DisplayStoryListDialog(gui, header, prefs, icon, books,
label_text,
save_size_name,
offer_skip and all_good)
d.exec_()
return d.result() == d.Accepted
class DisplayStoryListDialog(SizePersistedDialog):
def __init__(self, gui, header, prefs, icon, books,
label_text='',
save_size_name='FanFictionDownLoader plugin:display list dialog'):
save_size_name='fanfictiondownloader_plugin:display list dialog',
offer_skip=False):
SizePersistedDialog.__init__(self, gui, save_size_name)
# UpdateExistingDialog.__init__(self, gui, header, prefs, icon, books,
# save_size_name='FanFictionDownLoader plugin:display list dialog')
self.name = save_size_name
self.gui = gui
self.setWindowTitle(header)
@@ -426,6 +469,15 @@ class DisplayStoryListDialog(SizePersistedDialog):
#self.label.setWordWrap(True)
options_layout.addWidget(self.label)
if offer_skip:
spacerItem1 = QtGui.QSpacerItem(2, 4, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
options_layout.addItem(spacerItem1)
self.again = QCheckBox('Show this again?',self)
self.again.setChecked(True)
self.again.stateChanged.connect(self.toggle)
self.again.setToolTip('Uncheck to skip review and update stories immediately when no problems.')
options_layout.addWidget(self.again)
button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
button_box.accepted.connect(self.accept)
button_box.rejected.connect(self.reject)
@@ -437,10 +489,15 @@ class DisplayStoryListDialog(SizePersistedDialog):
# Cause our dialog size to be restored from prefs or created on first usage
self.resize_dialog()
self.books_table.populate_table(books)
def get_books(self):
return self.books_table.get_books()
def toggle(self, *args):
dynamic[confirm_config_name(self.name)] = self.again.isChecked()
class StoryListTableWidget(QTableWidget):
def __init__(self, parent):
+159 -87
View File
@@ -33,10 +33,10 @@ from calibre_plugins.fanfictiondownloader_plugin.fanficdownloader import adapter
from calibre_plugins.fanfictiondownloader_plugin.epubmerge import doMerge
from calibre_plugins.fanfictiondownloader_plugin.dcsource import get_dcsource
from calibre_plugins.fanfictiondownloader_plugin.config import (prefs)
from calibre_plugins.fanfictiondownloader_plugin.config import (prefs, permitted_values)
from calibre_plugins.fanfictiondownloader_plugin.dialogs import (
AddNewDialog, UpdateExistingDialog, DisplayStoryListDialog,
MetadataProgressDialog, UserPassDialog, AboutDialog,
AddNewDialog, UpdateExistingDialog, display_story_list, DisplayStoryListDialog,
LoopProgressDialog, UserPassDialog, AboutDialog,
OVERWRITE, OVERWRITEALWAYS, UPDATE, UPDATEALWAYS, ADDNEW, SKIP, CALIBREONLY,
NotGoingToDownload )
@@ -66,7 +66,8 @@ class FanFictionDownLoaderPlugin(InterfaceAction):
# (text, icon_path, tooltip, keyboard shortcut)
# icon_path isn't in the zip--icon loaded below.
action_spec = (name, None,
'Download FanFiction stories from various web sites', None)
'Download FanFiction stories from various web sites', ())
# None for keyboard shortcut doesn't allow shortcut. () does, there just isn't one yet
action_type = 'global'
# make button menu drop down only
@@ -138,7 +139,6 @@ class FanFictionDownLoaderPlugin(InterfaceAction):
triggered=self.update_existing)
if 'Reading List' in self.gui.iactions and (prefs['addtolists'] or prefs['addtoreadlists']) :
## XXX mod and rebuild menu when lists selected/empty
self.menu.addSeparator()
addmenutxt, rmmenutxt = None, None
if prefs['addtolists'] and prefs['addtoreadlists'] :
@@ -165,14 +165,14 @@ class FanFictionDownLoaderPlugin(InterfaceAction):
shortcut_name=rmmenutxt,
triggered=partial(self.update_lists,add=False))
try:
self.add_send_action.setEnabled( len(self.gui.library_view.get_selected_ids()) > 0 )
except:
pass
try:
self.add_remove_action.setEnabled( len(self.gui.library_view.get_selected_ids()) > 0 )
except:
pass
# try:
# self.add_send_action.setEnabled( len(self.gui.library_view.get_selected_ids()) > 0 )
# except:
# pass
# try:
# self.add_remove_action.setEnabled( len(self.gui.library_view.get_selected_ids()) > 0 )
# except:
# pass
self.menu.addSeparator()
self.get_list_action = self.create_menu_item_ex(self.menu, 'Get URLs from Selected Books', image='bookmarks.png',
@@ -193,8 +193,8 @@ class FanFictionDownLoaderPlugin(InterfaceAction):
shortcut_name='About FanFictionDownLoader',
triggered=self.about)
self.update_action.setEnabled( len(self.gui.library_view.get_selected_ids()) > 0 )
self.get_list_action.setEnabled( len(self.gui.library_view.get_selected_ids()) > 0 )
# self.update_action.setEnabled( len(self.gui.library_view.get_selected_ids()) > 0 )
# self.get_list_action.setEnabled( len(self.gui.library_view.get_selected_ids()) > 0 )
# Before we finalize, make sure we delete any actions for menus that are no longer displayed
for menu_id, unique_name in self.old_actions_unique_map.iteritems():
@@ -287,6 +287,8 @@ class FanFictionDownLoaderPlugin(InterfaceAction):
self.start_downloads( options, add_books )
def update_existing(self):
if len(self.gui.library_view.get_selected_ids()) == 0:
return
#print("update_existing()")
previous = self.gui.library_view.currentIndex()
db = self.gui.current_db
@@ -337,14 +339,13 @@ class FanFictionDownLoaderPlugin(InterfaceAction):
self.gui.status_bar.show_message(_('Started fetching metadata for %s stories.'%len(books)), 3000)
MetadataProgressDialog(self.gui,
books,
options,
partial(self.get_metadata_for_book, options = options),
partial(self.start_download_list, options = options))
# MetadataProgressDialog calls get_metadata_for_book for each 'good' story,
LoopProgressDialog(self.gui,
books,
partial(self.get_metadata_for_book, options = options),
partial(self.start_download_list, options = options))
# LoopProgressDialog calls get_metadata_for_book for each 'good' story,
# get_metadata_for_book updates book for each,
# MetadataProgressDialog calls start_download_list at the end which goes
# LoopProgressDialog calls start_download_list at the end which goes
# into the BG, or shows list if no 'good' books.
def get_metadata_for_book(self,book,
@@ -353,7 +354,7 @@ class FanFictionDownLoaderPlugin(InterfaceAction):
'updatemeta':True}):
'''
Update passed in book dict with metadata from website and
necessary data. To be called from MetadataProgressDialog
necessary data. To be called from LoopProgressDialog
'loop'. Also pops dialogs for is adult, user/pass.
'''
@@ -407,6 +408,7 @@ class FanFictionDownLoaderPlugin(InterfaceAction):
story = adapter.getStoryMetadataOnly()
writer = writers.getWriter(options['fileform'],adapter.config,adapter)
book['all_metadata'] = story.getAllMetadata(removeallentities=True)
book['title'] = story.getMetadata("title", removeallentities=True)
book['author_sort'] = book['author'] = story.getMetadata("author", removeallentities=True)
book['publisher'] = story.getMetadata("site")
@@ -542,7 +544,7 @@ class FanFictionDownLoaderPlugin(InterfaceAction):
'collision':ADDNEW,
'updatemeta':True}):
'''
Called by MetadataProgressDialog to start story downloads BG processing.
Called by LoopProgressDialog to start story downloads BG processing.
adapter_list is a list of tuples of (url,adapter)
'''
#print("start_download_list:book_list:%s"%book_list)
@@ -557,18 +559,6 @@ class FanFictionDownLoaderPlugin(InterfaceAction):
self.download_list_completed(notjob,options=options)
return
# ## XXX show list before starting download.
# d = DisplayStoryListDialog(self.gui,
# 'Download List',
# prefs,
# self.qaction.icon(),
# book_list,
# label_text='Status of stories to be downloaded'
# )
# d.exec_()
# if d.result() != d.Accepted:
# return
for book in book_list:
if book['good']:
break
@@ -597,75 +587,125 @@ class FanFictionDownLoaderPlugin(InterfaceAction):
self.gui.status_bar.show_message('Starting %d FanFictionDownLoads'%len(book_list),3000)
def _update_book(self,book,db=None,
options={'fileform':'epub',
'collision':ADDNEW,
'updatemeta':True}):
print("add/update %s %s"%(book['title'],book['url']))
mi = self._make_mi_from_book(book)
if options['collision'] != CALIBREONLY:
self._add_or_update_book(book,options,prefs,mi)
if options['collision'] == CALIBREONLY or \
(options['updatemeta'] and book['good']) :
self._update_metadata(db, book['calibre_id'], book, mi)
def _update_books_completed(self, book_list, options={}):
add_list = filter(lambda x : x['good'] and x['added'], book_list)
update_list = filter(lambda x : x['good'] and not x['added'], book_list)
update_ids = [ x['calibre_id'] for x in update_list ]
if len(add_list):
## even shows up added to searchs. Nice.
self.gui.library_view.model().books_added(len(add_list))
if update_ids:
self.gui.library_view.model().refresh_ids(update_ids)
current = self.gui.library_view.currentIndex()
self.gui.library_view.model().current_changed(current, self.previous)
self.gui.tags_view.recount()
self.gui.status_bar.show_message(_('Finished Adding/Updating %d books.'%(len(update_list) + len(add_list))), 3000)
if len(update_list) + len(add_list) != len(book_list):
d = DisplayStoryListDialog(self.gui,
'Updates completed, final status',
prefs,
self.qaction.icon(),
book_list,
label_text='Stories have be added or updated in Calibre, some had additional problems.'
)
d.exec_()
print("all done, remove temp dir.")
remove_dir(options['tdir'])
def download_list_completed(self, job, options={}):
if job.failed:
self.gui.job_exception(job, dialog_title='Failed to Download Stories')
return
previous = self.gui.library_view.currentIndex()
self.previous = self.gui.library_view.currentIndex()
db = self.gui.current_db
# XXX Switch this to a calibre standard confirm that has a
# 'don't show this anymore' checkbox. (But only if all good?)
d = DisplayStoryListDialog(self.gui,
'Downloads finished, confirm to update Calibre',
prefs,
self.qaction.icon(),
job.result,
label_text='Stories will not be added or updated in Calibre without confirmation.'
)
d.exec_()
if d.result() == d.Accepted:
if display_story_list(self.gui,
'Downloads finished, confirm to update Calibre',
prefs,
self.qaction.icon(),
job.result,
label_text='Stories will not be added or updated in Calibre without confirmation.',
offer_skip=True):
## in case the user removed any from the list.
book_list = d.get_books()
book_list = job.result
good_list = filter(lambda x : x['good'], book_list)
total_good = len(good_list)
self.gui.status_bar.show_message(_('Adding/Updating %s books.'%total_good), 3000)
self.gui.status_bar.show_message(_('Adding/Updating %s books.'%total_good))
for book in good_list:
print("add/update %s %s"%(book['title'],book['url']))
mi = self._make_mi_from_book(book)
LoopProgressDialog(self.gui,
good_list,
partial(self._update_book, options=options, db=self.gui.current_db),
partial(self._update_books_completed, options=options),
init_label="Updating calibre for stories...",
win_title="Update calibre for stories",
status_prefix="Updated")
# for book in good_list:
# print("add/update %s %s"%(book['title'],book['url']))
# mi = self._make_mi_from_book(book)
if options['collision'] != CALIBREONLY:
self._add_or_update_book(book,options,prefs,mi)
# if options['collision'] != CALIBREONLY:
# self._add_or_update_book(book,options,prefs,mi)
if options['collision'] == CALIBREONLY or \
(options['updatemeta'] and book['good']) :
self._update_metadata(db, book['calibre_id'], book, mi)
add_list = filter(lambda x : x['good'] and x['added'], book_list)
update_list = filter(lambda x : x['good'] and not x['added'], book_list)
update_ids = [ x['calibre_id'] for x in update_list ]
if len(add_list):
## even shows up added to searchs. Nice.
self.gui.library_view.model().books_added(len(add_list))
# if options['collision'] == CALIBREONLY or \
# (options['updatemeta'] and book['good']) :
# self._update_metadata(db, book['calibre_id'], book, mi)
if update_ids:
self.gui.library_view.model().refresh_ids(update_ids)
current = self.gui.library_view.currentIndex()
self.gui.library_view.model().current_changed(current, previous)
self.gui.tags_view.recount()
##### split here.
self.gui.status_bar.show_message(_('Finished Adding/Updating %d books.'%(len(update_list) + len(add_list))), 3000)
# add_list = filter(lambda x : x['good'] and x['added'], book_list)
# update_list = filter(lambda x : x['good'] and not x['added'], book_list)
# update_ids = [ x['calibre_id'] for x in update_list ]
# if len(add_list):
# ## even shows up added to searchs. Nice.
# self.gui.library_view.model().books_added(len(add_list))
# if update_ids:
# self.gui.library_view.model().refresh_ids(update_ids)
# current = self.gui.library_view.currentIndex()
# self.gui.library_view.model().current_changed(current, previous)
# self.gui.tags_view.recount()
if len(update_list) + len(add_list) != total_good:
d = DisplayStoryListDialog(self.gui,
'Updates completed, final status',
prefs,
self.qaction.icon(),
book_list,
label_text='Stories have be added or updated in Calibre, some had additional problems.'
)
d.exec_()
# self.gui.status_bar.show_message(_('Finished Adding/Updating %d books.'%(len(update_list) + len(add_list))), 3000)
# if len(update_list) + len(add_list) != total_good:
# d = DisplayStoryListDialog(self.gui,
# 'Updates completed, final status',
# prefs,
# self.qaction.icon(),
# book_list,
# label_text='Stories have be added or updated in Calibre, some had additional problems.'
# )
# d.exec_()
print("all done, remove temp dir.")
remove_dir(options['tdir'])
# print("all done, remove temp dir.")
# remove_dir(options['tdir'])
def _add_or_update_book(self,book,options,prefs,mi=None):
db = self.gui.current_db
@@ -718,6 +758,38 @@ class FanFictionDownLoaderPlugin(InterfaceAction):
mi.languages=['eng']
db.set_metadata(book_id,mi)
# do configured column updates here.
#print("all_metadata: %s"%book['all_metadata'])
custom_columns = self.gui.library_view.model().custom_columns
#print("prefs['custom_cols'] %s"%prefs['custom_cols'])
for col, meta in prefs['custom_cols'].iteritems():
#print("setting %s to %s"%(col,meta))
if col not in custom_columns:
print("%s not an existing column, skipping."%col)
continue
coldef = custom_columns[col]
if not meta.startswith('status-') and meta not in book['all_metadata']:
print("No value for %s, skipping."%meta)
continue
if meta not in permitted_values[coldef['datatype']]:
print("%s not a valid column type for %s, skipping."%(col,meta))
continue
label = coldef['label']
if coldef['datatype'] in ('enumeration','text','comments','datetime'):
db.set_custom(book_id, book['all_metadata'][meta], label=label, commit=False)
elif coldef['datatype'] in ('int','float'):
num = unicode(book['all_metadata'][meta]).replace(",","")
db.set_custom(book_id, num, label=label, commit=False)
elif coldef['datatype'] == 'bool' and meta.startswith('status-'):
if meta == 'status-C':
val = book['all_metadata']['status'] == 'Completed'
if meta == 'status-I':
val = book['all_metadata']['status'] == 'In-Progress'
db.set_custom(book_id, val, label=label, commit=False)
db.commit()
def _get_clean_reading_lists(self,lists):
if lists == None or lists.strip() == "" :
return []
+3 -3
View File
@@ -56,15 +56,15 @@ class Story:
else:
return value
def getAllMetadata(self):
def getAllMetadata(self, removeallentities=False):
'''
All single value *and* list value metadata as strings.
'''
allmetadata = {}
for k in self.metadata.keys():
allmetadata[k] = self.getMetadata(k)
allmetadata[k] = self.getMetadata(k, removeallentities)
for l in self.listables.keys():
allmetadata[l] = self.getMetadata(l)
allmetadata[l] = self.getMetadata(l, removeallentities)
return allmetadata