merge from trunk

This commit is contained in:
Lee 2011-04-19 02:08:17 +08:00
commit d03d831149
9 changed files with 178 additions and 58 deletions

View File

@ -6,12 +6,13 @@ __copyright__ = 'Copyright 2010 Starson17'
www.arcamax.com
'''
from calibre.web.feeds.news import BasicNewsRecipe
from calibre.ebooks.BeautifulSoup import Tag
class Arcamax(BasicNewsRecipe):
title = 'Arcamax'
__author__ = 'Starson17'
__version__ = '1.03'
__date__ = '25 November 2010'
__version__ = '1.04'
__date__ = '18 April 2011'
description = u'Family Friendly Comics - Customize for more days/comics: Defaults to 7 days, 25 comics - 20 general, 5 editorial.'
category = 'news, comics'
language = 'en'
@ -30,8 +31,15 @@ class Arcamax(BasicNewsRecipe):
, 'language' : language
}
keep_only_tags = [dict(name='div', attrs={'class':['toon']}),
]
keep_only_tags = [dict(name='div', attrs={'class':['comics-header']}),
dict(name='b', attrs={'class':['current']}),
dict(name='article', attrs={'class':['comic']}),
]
remove_tags = [dict(name='div', attrs={'id':['comicfull' ]}),
dict(name='div', attrs={'class':['calendar' ]}),
dict(name='nav', attrs={'class':['calendar-nav' ]}),
]
def parse_index(self):
feeds = []
@ -71,7 +79,6 @@ class Arcamax(BasicNewsRecipe):
#(u"Rugrats", u"http://www.arcamax.com/rugrats"),
(u"Speed Bump", u"http://www.arcamax.com/speedbump"),
(u"Wizard of Id", u"http://www.arcamax.com/wizardofid"),
(u"Dilbert", u"http://www.arcamax.com/dilbert"),
(u"Zits", u"http://www.arcamax.com/zits"),
]:
articles = self.make_links(url)
@ -86,24 +93,37 @@ class Arcamax(BasicNewsRecipe):
for page in pages:
page_soup = self.index_to_soup(url)
if page_soup:
title = page_soup.find(name='div', attrs={'class':'toon'}).p.img['alt']
title = page_soup.find(name='div', attrs={'class':'comics-header'}).h1.contents[0]
page_url = url
prev_page_url = 'http://www.arcamax.com' + page_soup.find('a', attrs={'class':'next'}, text='Previous').parent['href']
current_articles.append({'title': title, 'url': page_url, 'description':'', 'date':''})
# orig prev_page_url = 'http://www.arcamax.com' + page_soup.find('a', attrs={'class':'prev'}, text='Previous').parent['href']
prev_page_url = 'http://www.arcamax.com' + page_soup.find('span', text='Previous').parent.parent['href']
date = self.tag_to_string(page_soup.find(name='b', attrs={'class':['current']}))
current_articles.append({'title': title, 'url': page_url, 'description':'', 'date': date})
url = prev_page_url
current_articles.reverse()
return current_articles
def preprocess_html(self, soup):
main_comic = soup.find('p',attrs={'class':'m0'})
if main_comic.a['target'] == '_blank':
main_comic.a.img['id'] = 'main_comic'
for img_tag in soup.findAll('img'):
parent_tag = img_tag.parent
if parent_tag.name == 'a':
new_tag = Tag(soup,'p')
new_tag.insert(0,img_tag)
parent_tag.replaceWith(new_tag)
elif parent_tag.name == 'p':
if not self.tag_to_string(parent_tag) == '':
new_div = Tag(soup,'div')
new_tag = Tag(soup,'p')
new_tag.insert(0,img_tag)
parent_tag.replaceWith(new_div)
new_div.insert(0,new_tag)
new_div.insert(1,parent_tag)
return soup
extra_css = '''
h1{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:large;}
h2{font-family:Arial,Helvetica,sans-serif; font-weight:normal;font-size:small;}
img#main_comic {max-width:100%; min-width:100%;}
img {max-width:100%; min-width:100%;}
p{font-family:Arial,Helvetica,sans-serif;font-size:small;}
body{font-family:Helvetica,Arial,sans-serif;font-size:small;}
'''

View File

@ -67,6 +67,23 @@ def authors_test(authors):
return test
def series_test(series, series_index):
series = series.lower()
def test(mi):
ms = mi.series.lower() if mi.series else ''
if (ms == series) and (series_index == mi.series_index):
return True
if mi.series:
prints('Series test failed. Expected: \'%s [%d]\' found \'%s[%d]\''% \
(series, series_index, ms, mi.series_index))
else:
prints('Series test failed. Expected: \'%s [%d]\' found no series'% \
(series, series_index))
return False
return test
def init_test(tdir_name):
tdir = tempfile.gettempdir()
lf = os.path.join(tdir, tdir_name.replace(' ', '')+'_identify_test.txt')

View File

@ -37,8 +37,6 @@ class EditMetadataAction(InterfaceAction):
md.addSeparator()
if test_eight_code:
dall = self.download_metadata
dident = partial(self.download_metadata, covers=False)
dcovers = partial(self.download_metadata, identify=False)
else:
dall = partial(self.download_metadata_old, False, covers=True)
dident = partial(self.download_metadata_old, False, covers=False)
@ -47,9 +45,9 @@ class EditMetadataAction(InterfaceAction):
md.addAction(_('Download metadata and covers'), dall,
Qt.ControlModifier+Qt.Key_D)
md.addAction(_('Download only metadata'), dident)
md.addAction(_('Download only covers'), dcovers)
if not test_eight_code:
md.addAction(_('Download only metadata'), dident)
md.addAction(_('Download only covers'), dcovers)
md.addAction(_('Download only social metadata'),
partial(self.download_metadata_old, False, covers=False,
set_metadata=False, set_social_metadata=True))
@ -80,7 +78,7 @@ class EditMetadataAction(InterfaceAction):
self.qaction.setEnabled(enabled)
self.action_merge.setEnabled(enabled)
def download_metadata(self, identify=True, covers=True, ids=None):
def download_metadata(self, ids=None):
if ids is None:
rows = self.gui.library_view.selectionModel().selectedRows()
if not rows or len(rows) == 0:
@ -90,7 +88,7 @@ class EditMetadataAction(InterfaceAction):
ids = [db.id(row.row()) for row in rows]
from calibre.gui2.metadata.bulk_download2 import start_download
start_download(self.gui, ids,
Dispatcher(self.bulk_metadata_downloaded), identify, covers)
Dispatcher(self.bulk_metadata_downloaded))
def bulk_metadata_downloaded(self, job):
if job.failed:

View File

@ -289,6 +289,7 @@ class Series(Base):
values = self.all_values = list(self.db.all_custom(num=self.col_id))
values.sort(key=sort_key)
w = MultiCompleteComboBox(parent)
w.set_separator(None)
w.setSizeAdjustPolicy(w.AdjustToMinimumContentsLengthWithIcon)
w.setMinimumContentsLength(25)
self.name_widget = w

View File

@ -12,7 +12,7 @@ from zipfile import ZipFile, ZIP_DEFLATED, ZIP_STORED
from PyQt4.Qt import QDialog
from calibre.constants import isosx, iswindows
from calibre.constants import isosx
from calibre.gui2 import open_local_file
from calibre.gui2.dialogs.tweak_epub_ui import Ui_Dialog
from calibre.libunzip import extract as zipextract

View File

@ -278,11 +278,13 @@ class AuthorSortEdit(EnLineEdit):
def copy_to_authors(self):
aus = self.current_val
meth = tweaks['author_sort_copy_method']
if aus:
ln, _, rest = aus.partition(',')
if rest:
au = rest.strip() + ' ' + ln.strip()
self.authors_edit.current_val = [au]
if meth in ('invert', 'nocomma', 'comma'):
aus = rest.strip() + ' ' + ln.strip()
self.authors_edit.current_val = [aus]
def auto_generate(self, *args):
au = unicode(self.authors_edit.text())
@ -465,16 +467,22 @@ class FormatsManager(QWidget): # {{{
self.metadata_from_format_button = QToolButton(self)
self.metadata_from_format_button.setIcon(QIcon(I('edit_input.png')))
self.metadata_from_format_button.setIconSize(QSize(32, 32))
self.metadata_from_format_button.setToolTip(
_('Set metadata for the book from the selected format'))
self.add_format_button = QToolButton(self)
self.add_format_button.setIcon(QIcon(I('add_book.png')))
self.add_format_button.setIconSize(QSize(32, 32))
self.add_format_button.clicked.connect(self.add_format)
self.add_format_button.setToolTip(
_('Add a format to this book'))
self.remove_format_button = QToolButton(self)
self.remove_format_button.setIcon(QIcon(I('trash.png')))
self.remove_format_button.setIconSize(QSize(32, 32))
self.remove_format_button.clicked.connect(self.remove_format)
self.remove_format_button.setToolTip(
_('Remove the selected format from this book'))
self.formats = FormatList(self)
self.formats.setAcceptDrops(True)
@ -939,7 +947,13 @@ class IdentifiersEdit(QLineEdit): # {{{
def fset(self, val):
if not val:
val = {}
txt = ', '.join(['%s:%s'%(k, v) for k, v in val.iteritems()])
def keygen(x):
x = x[0]
if x == 'isbn':
x = '00isbn'
return x
ids = sorted(val.iteritems(), key=keygen)
txt = ', '.join(['%s:%s'%(k, v) for k, v in ids])
self.setText(txt.strip())
self.setCursorPosition(0)
return property(fget=fget, fset=fset)
@ -959,7 +973,7 @@ class IdentifiersEdit(QLineEdit): # {{{
tt = self.BASE_TT
extra = ''
if not isbn:
col = 'rgba(0,255,0,0%)'
col = 'none'
elif check_isbn(isbn) is not None:
col = 'rgba(0,255,0,20%)'
extra = '\n\n'+_('This ISBN number is valid')

View File

@ -12,7 +12,8 @@ from functools import partial
from itertools import izip
from PyQt4.Qt import (QIcon, QDialog, QVBoxLayout, QTextBrowser, QSize,
QDialogButtonBox, QApplication, QTimer, QLabel, QProgressBar)
QDialogButtonBox, QApplication, QTimer, QLabel, QProgressBar,
QGridLayout, QPixmap, Qt)
from calibre.gui2.dialogs.message_box import MessageBox
from calibre.gui2.threaded_jobs import ThreadedJob
@ -25,37 +26,86 @@ from calibre.ebooks.metadata.book.base import Metadata
from calibre.customize.ui import metadata_plugins
from calibre.ptempfile import PersistentTemporaryFile
# Start download {{{
def show_config(gui, parent):
from calibre.gui2.preferences import show_config_widget
show_config_widget('Sharing', 'Metadata download', parent=parent,
gui=gui, never_shutdown=True)
def start_download(gui, ids, callback, identify, covers):
q = MessageBox(MessageBox.QUESTION, _('Schedule download?'),
class ConfirmDialog(QDialog):
def __init__(self, ids, parent):
QDialog.__init__(self, parent)
self.setWindowTitle(_('Schedule download?'))
self.setWindowIcon(QIcon(I('dialog_question.png')))
l = self.l = QGridLayout()
self.setLayout(l)
i = QLabel(self)
i.setPixmap(QPixmap(I('dialog_question.png')))
l.addWidget(i, 0, 0)
t = QLabel(
'<p>'+_('The download of metadata for the <b>%d selected book(s)</b> will'
' run in the background. Proceed?')%len(ids) +
'<p>'+_('You can monitor the progress of the download '
'by clicking the rotating spinner in the bottom right '
'corner.') +
'<p>'+_('When the download completes you will be asked for'
' confirmation before calibre applies the downloaded metadata.'),
show_copy_button=False, parent=gui)
b = q.bb.addButton(_('Configure download'), q.bb.ActionRole)
b.setIcon(QIcon(I('config.png')))
b.clicked.connect(partial(show_config, gui, q))
q.det_msg_toggle.setVisible(False)
' confirmation before calibre applies the downloaded metadata.')
)
t.setWordWrap(True)
l.addWidget(t, 0, 1)
l.setColumnStretch(0, 1)
l.setColumnStretch(1, 100)
ret = q.exec_()
b.clicked.disconnect()
if ret != q.Accepted:
self.identify = self.covers = True
self.bb = QDialogButtonBox(QDialogButtonBox.Cancel)
self.bb.rejected.connect(self.reject)
b = self.bb.addButton(_('Download only &metadata'),
self.bb.AcceptRole)
b.clicked.connect(self.only_metadata)
b.setIcon(QIcon(I('edit_input.png')))
b = self.bb.addButton(_('Download only &covers'),
self.bb.AcceptRole)
b.clicked.connect(self.only_covers)
b.setIcon(QIcon(I('default_cover.png')))
b = self.b = self.bb.addButton(_('&Configure download'), self.bb.ActionRole)
b.setIcon(QIcon(I('config.png')))
b.clicked.connect(partial(show_config, parent, self))
l.addWidget(self.bb, 1, 0, 1, 2)
b = self.bb.addButton(_('Download &both'),
self.bb.AcceptRole)
b.clicked.connect(self.accept)
b.setDefault(True)
b.setAutoDefault(True)
b.setIcon(QIcon(I('ok.png')))
self.resize(self.sizeHint())
b.setFocus(Qt.OtherFocusReason)
def only_metadata(self):
self.covers = False
self.accept()
def only_covers(self):
self.identify = False
self.accept()
def start_download(gui, ids, callback):
d = ConfirmDialog(ids, gui)
ret = d.exec_()
d.b.clicked.disconnect()
if ret != d.Accepted:
return
job = ThreadedJob('metadata bulk download',
_('Download metadata for %d books')%len(ids),
download, (ids, gui.current_db, identify, covers), {}, callback)
download, (ids, gui.current_db, d.identify, d.covers), {}, callback)
gui.job_manager.run_threaded_job(job)
gui.status_bar.show_message(_('Metadata download started'), 3000)
# }}}
class ViewLog(QDialog): # {{{
@ -93,9 +143,10 @@ def view_log(job, parent):
# }}}
# Apply downloaded metadata {{{
class ApplyDialog(QDialog):
def __init__(self, id_map, gui):
def __init__(self, gui):
QDialog.__init__(self, gui)
self.l = l = QVBoxLayout()
@ -104,27 +155,33 @@ class ApplyDialog(QDialog):
self.pb = QProgressBar(self)
l.addWidget(self.pb)
self.pb.setMinimum(0)
self.pb.setMaximum(len(id_map))
self.bb = QDialogButtonBox(QDialogButtonBox.Cancel)
self.bb.rejected.connect(self.reject)
self.bb.accepted.connect(self.accept)
l.addWidget(self.bb)
self.gui = gui
self.timer = QTimer(self)
self.timer.timeout.connect(self.do_one)
def start(self, id_map):
self.id_map = list(id_map.iteritems())
self.current_idx = 0
self.failures = []
self.ids = []
self.canceled = False
QTimer.singleShot(20, self.do_one)
self.pb.setMinimum(0)
self.pb.setMaximum(len(id_map))
self.timer.start(50)
def do_one(self):
if self.canceled:
return
if self.current_idx >= len(self.id_map):
self.timer.stop()
self.finalize()
return
i, mi = self.id_map[self.current_idx]
db = self.gui.current_db
try:
@ -144,15 +201,11 @@ class ApplyDialog(QDialog):
pass
self.pb.setValue(self.pb.value()+1)
if self.current_idx >= len(self.id_map) - 1:
self.finalize()
else:
self.current_idx += 1
QTimer.singleShot(20, self.do_one)
self.current_idx += 1
def reject(self):
self.canceled = True
self.timer.stop()
QDialog.reject(self)
def finalize(self):
@ -169,17 +222,18 @@ class ApplyDialog(QDialog):
title += ' - ' + authors_to_string(authors)
msg.append(title+'\n\n'+tb+'\n'+('*'*80))
error_dialog(self, _('Some failures'),
parent = self if self.isVisible() else self.parent()
error_dialog(parent, _('Some failures'),
_('Failed to apply updated metadata for some books'
' in your library. Click "Show Details" to see '
'details.'), det_msg='\n\n'.join(msg), show=True)
self.accept()
if self.ids:
cr = self.gui.library_view.currentIndex().row()
self.gui.library_view.model().refresh_ids(
self.ids, cr)
if self.gui.cover_flow:
self.gui.cover_flow.dataChanged()
self.accept()
_amd = None
def apply_metadata(job, gui, q, result):
@ -217,8 +271,11 @@ def apply_metadata(job, gui, q, result):
'Do you want to proceed?'), det_msg='\n'.join(modified)):
return
_amd = ApplyDialog(id_map, gui)
_amd.exec_()
if _amd is None:
_amd = ApplyDialog(gui)
_amd.start(id_map)
if len(id_map) > 3:
_amd.exec_()
def proceed(gui, job):
gui.status_bar.show_message(_('Metadata download completed'), 3000)
@ -248,6 +305,8 @@ def proceed(gui, job):
q.show()
q.finished.connect(partial(apply_metadata, job, gui, q))
# }}}
def merge_result(oldmi, newmi):
dummy = Metadata(_('Unknown'))
for f in msprefs['ignore_fields']:

View File

@ -156,6 +156,9 @@ class MetadataSingleDialogBase(ResizableDialog):
self.identifiers = IdentifiersEdit(self)
self.basic_metadata_widgets.append(self.identifiers)
self.clear_identifiers_button = QToolButton(self)
self.clear_identifiers_button.setIcon(QIcon(I('trash.png')))
self.clear_identifiers_button.clicked.connect(self.identifiers.clear)
self.publisher = PublisherEdit(self)
self.basic_metadata_widgets.append(self.publisher)
@ -541,8 +544,8 @@ class MetadataSingleDialog(MetadataSingleDialogBase): # {{{
sto(self.rating, self.tags)
create_row2(2, self.tags, self.tags_editor_button)
sto(self.tags_editor_button, self.identifiers)
create_row2(3, self.identifiers)
sto(self.identifiers, self.timestamp)
create_row2(3, self.identifiers, self.clear_identifiers_button)
sto(self.clear_identifiers_button, self.timestamp)
create_row2(4, self.timestamp, self.timestamp.clear_button)
sto(self.timestamp.clear_button, self.pubdate)
create_row2(5, self.pubdate, self.pubdate.clear_button)
@ -657,7 +660,8 @@ class MetadataSingleDialogAlt1(MetadataSingleDialogBase): # {{{
create_row(9, self.publisher, self.timestamp)
create_row(10, self.timestamp, self.identifiers,
button=self.timestamp.clear_button, icon='trash.png')
create_row(11, self.identifiers, self.comments)
create_row(11, self.identifiers, self.comments,
button=self.clear_identifiers_button, icon='trash.png')
tl.addItem(QSpacerItem(1, 1, QSizePolicy.Fixed, QSizePolicy.Expanding),
12, 1, 1 ,1)

View File

@ -30,6 +30,7 @@ from calibre.ebooks.metadata.book.base import Metadata
from calibre.gui2 import error_dialog, NONE
from calibre.utils.date import utcnow, fromordinal, format_date
from calibre.library.comments import comments_to_html
from calibre.constants import islinux
from calibre import force_unicode
# }}}
@ -116,6 +117,12 @@ class CoverDelegate(QStyledItemDelegate): # {{{
def paint(self, painter, option, index):
QStyledItemDelegate.paint(self, painter, option, index)
if islinux:
# On linux for some reason the selected color is drawn on top of
# the decoration
style = QApplication.style()
style.drawItemPixmap(painter, option.rect, Qt.AlignTop|Qt.AlignHCenter,
QPixmap(index.data(Qt.DecorationRole)))
if self.timer.isActive() and index.data(Qt.UserRole).toBool():
rect = QRect(0, 0, self.spinner_width, self.spinner_width)
rect.moveCenter(option.rect.center())
@ -945,7 +952,7 @@ class CoverFetch(QDialog): # {{{
# }}}
if __name__ == '__main__':
#DEBUG_DIALOG = True
DEBUG_DIALOG = True
app = QApplication([])
d = FullFetch()
d.start(title='great gatsby', authors=['fitzgerald'])