Customizable, dropdown Reject Reasons. Plugin only.

This commit is contained in:
Jim Miller 2012-11-19 15:59:26 -06:00
parent 2e331c8d78
commit 85d40e0399
3 changed files with 128 additions and 58 deletions

View file

@ -10,8 +10,10 @@ __docformat__ = 'restructuredtext en'
import traceback, copy, threading
from collections import OrderedDict
from PyQt4.Qt import (QDialog, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QFont, QWidget,
QTextEdit, QComboBox, QCheckBox, QPushButton, QTabWidget, QVariant, QScrollArea)
from PyQt4.Qt import (QDialog, QWidget, QVBoxLayout, QHBoxLayout, QLabel,
QLineEdit, QFont, QWidget, QTextEdit, QComboBox,
QCheckBox, QPushButton, QTabWidget, QVariant, QScrollArea,
QDialogButtonBox )
from calibre.gui2 import dynamic, info_dialog
from calibre.utils.config import JSONConfig
@ -35,6 +37,9 @@ PREFS_KEY_SETTINGS = 'settings'
default_prefs = {}
default_prefs['personal.ini'] = get_resources('plugin-example.ini')
default_prefs['rejecturls'] = ''
default_prefs['rejectreasons'] = '''Sucked
Boring
Dup from another site'''
default_prefs['updatemeta'] = True
default_prefs['updatecover'] = False
@ -199,6 +204,9 @@ class RejectURLList:
def get_list(self):
return copy.deepcopy(self._get_listcache())
def get_reject_reasons(self):
return self.prefs['rejectreasons'].splitlines()
rejecturllist = RejectURLList(prefs)
class ConfigWidget(QWidget):
@ -462,10 +470,19 @@ class BasicTab(QWidget):
self.l.addSpacing(10)
self.rejectlist = QPushButton('View Reject URL List', self)
self.rejectlist.setToolTip("View list of URLs FFDL will automatically Reject.")
horz = QHBoxLayout()
self.rejectlist = QPushButton('Edit Reject URL List', self)
self.rejectlist.setToolTip("Edit list of URLs FFDL will automatically Reject.")
self.rejectlist.clicked.connect(self.show_rejectlist)
self.l.addWidget(self.rejectlist)
horz.addWidget(self.rejectlist)
self.reject_reasons = QPushButton('Edit Reject Reasons List', self)
self.reject_reasons.setToolTip("Customize the Reasons presented when Rejecting URLs")
self.reject_reasons.clicked.connect(self.show_reject_reasons)
horz.addWidget(self.reject_reasons)
self.l.addLayout(horz)
self.l.insertStretch(-1)
@ -486,10 +503,11 @@ class BasicTab(QWidget):
def show_rejectlist(self):
rejectlist = []
for (url,note) in rejecturllist.get_list().items():
rejectlist.append((None,url,note))
rejectlist.append((None,url,note,note))
d = RejectListDialog(self,
rejectlist,
rejectreasons=rejecturllist.get_reject_reasons(),
header="Edit Reject URLs List",
show_delete=False)
d.exec_()
@ -503,6 +521,40 @@ class BasicTab(QWidget):
rejecturllist.add(rejectlist,clear=True)
def show_reject_reasons(self):
print("rejectreasons:%s"%prefs['rejectreasons'])
d = RejectReasonsDialog(self.windowIcon(),prefs['rejectreasons'],self)
d.exec_()
if d.result() == d.Accepted:
prefs['rejectreasons'] = unicode(d.reasons.toPlainText())
print("rejectreasons:%s"%prefs['rejectreasons'])
class RejectReasonsDialog(QDialog):
def __init__(self, icon, text, parent=None):
QDialog.__init__(self, parent)
self.resize(600, 500)
self.l = QVBoxLayout()
self.setLayout(self.l)
self.label = QLabel("Customize Reject List Reasons")
tooltip="Customize the Reasons presented when Rejecting URLs"
self.label.setToolTip(tooltip)
self.setWindowTitle(_('Reject Reasons'))
self.setWindowIcon(icon)
self.l.addWidget(self.label)
self.reasons = QTextEdit(self)
self.reasons.setToolTip(tooltip)
self.reasons.setLineWrapMode(QTextEdit.NoWrap)
self.reasons.setText(text)
self.l.addWidget(self.reasons)
button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
button_box.accepted.connect(self.accept)
button_box.rejected.connect(self.reject)
self.l.addWidget(button_box)
class PersonalIniTab(QWidget):
def __init__(self, parent_dialog, plugin_action):
@ -542,34 +594,6 @@ class PersonalIniTab(QWidget):
def show_defaults(self):
text = get_resources('plugin-defaults.ini')
ShowDefaultsIniDialog(self.windowIcon(),text,self).exec_()
# class RejectUrlsTab(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("List of story URLs you've previously rejected followed by an optional note. FFDL will stop and ask you if try to download a story on your reject list. The system will put title, author and why you rejected it when added from the FFDL 'Reject Story' option.")
# label.setWordWrap(True)
# self.l.addWidget(label)
# self.l.addSpacing(5)
# self.label = QLabel('Rejected URLs: (URL,Notes)')
# self.l.addWidget(self.label)
# self.rejecturls = QTextEdit(self)
# try:
# self.rejecturls.setFont(QFont("Courier",
# self.plugin_action.gui.font().pointSize()+1));
# except Exception as e:
# print("Couldn't get font: %s"%e)
# self.rejecturls.setLineWrapMode(QTextEdit.NoWrap)
# self.rejecturls.setText(prefs['rejecturls'])
# self.l.addWidget(self.rejecturls)
class ShowDefaultsIniDialog(QDialog):

View file

@ -8,6 +8,7 @@ __copyright__ = '2011, Jim Miller'
__docformat__ = 'restructuredtext en'
import traceback
from functools import partial
from PyQt4 import QtGui
from PyQt4.Qt import (QDialog, QTableWidget, QMessageBox, QVBoxLayout, QHBoxLayout,
@ -19,6 +20,7 @@ from PyQt4.Qt import (QDialog, QTableWidget, QMessageBox, QVBoxLayout, QHBoxLayo
from calibre.gui2 import error_dialog, warning_dialog, question_dialog, info_dialog
from calibre.gui2.dialogs.confirm_delete import confirm
from calibre.gui2.complete2 import EditWithComplete
from calibre import confirm_config_name
from calibre.gui2 import dynamic
@ -717,9 +719,10 @@ class StoryListTableWidget(QTableWidget):
class RejectListTableWidget(QTableWidget):
def __init__(self, parent):
def __init__(self, parent,rejectreasons=[]):
QTableWidget.__init__(self, parent)
self.setSelectionBehavior(QAbstractItemView.SelectRows)
self.rejectreasons = rejectreasons
def on_headersection_clicked(self):
self.setSortingEnabled(True)
@ -755,22 +758,58 @@ class RejectListTableWidget(QTableWidget):
def populate_table_row(self, row, rejectrow):
(bookid,url,note) = rejectrow
(bookid,url,titleauth,oldrejnote) = rejectrow
if oldrejnote:
noteprefix = note = oldrejnote
# incase the existing note ends with one of the known reasons.
for reason in self.rejectreasons:
if noteprefix.endswith(' - '+reason):
noteprefix = noteprefix[:-len(' - '+reason)]
break
else:
noteprefix = note = titleauth
url_cell = ReadOnlyTableWidgetItem(url)
url_cell.setData(Qt.UserRole, QVariant(bookid))
url_cell.setToolTip('URL to add to the Reject List.')
self.setItem(row, 0, url_cell)
note_cell = QTableWidgetItem(note)
note_cell.setToolTip('Double-click to edit note.')
self.setItem(row, 1, note_cell)
note_cell = EditWithComplete(self)
# This is a more than slightly kludgey way to get
# EditWithComplete to *not* alpha-order the reasons, but leave
# them in the order entered. If
# calibre.gui2.complete2.CompleteModel.set_items ever changes,
# this function will need to also.
def complete_model_set_items_kludge(self, items):
items = [unicode(x.strip()) for x in items]
items = [x for x in items if x]
items = tuple(items)
self.all_items = self.current_items = items
self.current_prefix = ''
self.reset()
note_cell.lineEdit().mcompleter.model().set_items = \
partial(complete_model_set_items_kludge,
note_cell.lineEdit().mcompleter.model())
items = [note]+[ noteprefix+" - "+x for x in self.rejectreasons ]
note_cell.update_items_cache(items)
note_cell.show_initial_value(note)
note_cell.set_separator(None)
note_cell.setToolTip('Select or Edit Reject Note.')
self.setCellWidget(row, 1, note_cell)
# note_cell = QTableWidgetItem(note)
# note_cell.setToolTip('Double-click to edit note.')
# self.setItem(row, 1, note_cell)
def get_reject_list(self):
rejectrows = []
for row in range(self.rowCount()):
bookid = self.item(row, 0).data(Qt.UserRole).toPyObject()
url = unicode(self.item(row, 0).text())
note = unicode(self.item(row, 1).text())
note = unicode(self.cellWidget(row, 1).currentText()).strip()
rejectrows.append((bookid,url,note))
return rejectrows
@ -849,6 +888,7 @@ class RejectListTableWidget(QTableWidget):
class RejectListDialog(SizePersistedDialog):
def __init__(self, gui, reject_list,
rejectreasons=[],
header="List of Books to Reject",
icon='rotate-right.png',
show_delete=True,
@ -867,7 +907,7 @@ class RejectListDialog(SizePersistedDialog):
rejects_layout = QHBoxLayout()
layout.addLayout(rejects_layout)
self.rejects_table = RejectListTableWidget(self)
self.rejects_table = RejectListTableWidget(self,rejectreasons=rejectreasons)
rejects_layout.addWidget(self.rejects_table)
button_layout = QVBoxLayout()
@ -919,4 +959,3 @@ class RejectListDialog(SizePersistedDialog):
def get_deletebooks(self):
return self.deletebooks.isChecked()

View file

@ -347,10 +347,6 @@ class FanFictionDownLoaderPlugin(InterfaceAction):
show_copy_button=False)
def reject_list_urls(self):
if self.gui.current_view().selectionModel().selectedRows() == 0 :
self.gui.status_bar.show_message(_('No Selected Books to Get URLs From'), 3000)
return
if self.is_library_view():
book_list = map( partial(self._convert_id_to_book, good=False),
self.gui.library_view.get_selected_ids() )
@ -361,6 +357,10 @@ class FanFictionDownLoaderPlugin(InterfaceAction):
#paths = view.model().paths(rows)
book_list = map( partial(self._convert_row_to_book, good=False), rows )
if len(book_list) == 0 :
self.gui.status_bar.show_message(_('No Selected Books have URLs to Reject'), 3000)
return
LoopProgressDialog(self.gui,
book_list,
partial(self._reject_story_url_for_list, db=self.gui.current_db),
@ -375,21 +375,27 @@ class FanFictionDownLoaderPlugin(InterfaceAction):
self._populate_book_from_calibre_id(book,db)
book['url'] = self._get_story_url(db,book_id=book['calibre_id'])
elif book['path']:
book['url'] = self._get_story_url(db,path=book['path'])
if book['url'] == None:
book['good']=False
else:
book['good']=True
# get existing note, if there is one.
book['oldrejnote']=rejecturllist.check(book['url'])
def _finish_reject_list_urls(self, book_list):
# construct reject list of (calibre_id, url, note) tuples.
reject_list = [ (x['calibre_id'],x['url'],
"%s by %s"%(x['title'],
', '.join(x['author']))) for x in book_list if x['good'] ]
# construct reject list of tuples:
# (calibre_id, url, "title, authors", old reject note).
reject_list = [ ( x['calibre_id'],x['url'],
"%s by %s"%(x['title'],
', '.join(x['author'])),
x['oldrejnote'])
for x in book_list if x['good'] ]
if reject_list:
d = RejectListDialog(self.gui,reject_list)
d = RejectListDialog(self.gui,reject_list,
rejectreasons=rejecturllist.get_reject_reasons())
d.exec_()
if d.result() != d.Accepted:
@ -400,6 +406,7 @@ class FanFictionDownLoaderPlugin(InterfaceAction):
for (bookid,url,note) in d.get_reject_list():
bookids.append(bookid)
rejectlist.append((url,note))
print("Adding (%s) to Reject List: %s"%(url,note))
rejecturllist.add(rejectlist)
@ -1369,11 +1376,11 @@ make_firstimage_cover:true
identifiers = db.get_identifiers(book_id,index_is_id=True)
if 'url' in identifiers:
# identifiers have :->| in url.
print("url from ident url:"+identifiers['url'].replace('|',':'))
# print("url from ident url:%s"%identifiers['url'].replace('|',':'))
return identifiers['url'].replace('|',':')
elif 'uri' in identifiers:
# identifiers have :->| in uri.
print("uri from ident uri:"+identifiers['uri'].replace('|',':'))
# print("uri from ident uri:%s"%identifiers['uri'].replace('|',':'))
return identifiers['uri'].replace('|',':')
else:
existingepub = None
@ -1382,7 +1389,7 @@ make_firstimage_cover:true
mi = get_metadata(existingepub,'EPUB')
identifiers = mi.get_identifiers()
if 'url' in identifiers:
print("url from get_metadata:"+identifiers['url'].replace('|',':'))
# print("url from get_metadata:%s"%identifiers['url'].replace('|',':'))
return identifiers['url'].replace('|',':')
elif path.lower().endswith('.epub'):
existingepub = path
@ -1392,11 +1399,11 @@ make_firstimage_cover:true
# look for dc:source first, then scan HTML if lookforurlinhtml
link = get_dcsource(existingepub)
if link:
print("url from get_dcsource:"+link)
# print("url from get_dcsource:%s"%link)
return link
elif prefs['lookforurlinhtml']:
link = get_story_url_from_html(existingepub,self._is_good_downloader_url)
print("url from get_story_url_from_html:"+link)
# print("url from get_story_url_from_html:%s"%link)
return link
return None