Sync to trunk.

This commit is contained in:
John Schember 2011-05-08 16:02:36 -04:00
commit e7c8ccdf8c
17 changed files with 153 additions and 44 deletions

View File

@ -30,3 +30,4 @@ nbproject/
.project
.pydevproject
.settings/
*.DS_Store

View File

@ -21,14 +21,19 @@ class Fronda(BasicNewsRecipe):
feeds = [(u'Infformacje', u'http://fronda.pl/news/feed')]
keep_only_tags = [dict(name='h1', attrs={'class':'big'}),
dict(name='ul', attrs={'class':'about clear'}),
dict(name='div', attrs={'class':'content'})]
keep_only_tags = [dict(name='h2', attrs={'class':'news_title'}),
dict(name='div', attrs={'class':'naglowek_tresc'}),
dict(name='div', attrs={'id':'czytaj'}) ]
remove_tags = [dict(name='a', attrs={'class':'print'})]
preprocess_regexps = [
(re.compile(i[0], re.IGNORECASE | re.DOTALL), i[1]) for i in
[ (r'<a href="#" class="print">Drukuj</a>', lambda match: ''),
(r'<p><a href="http://fronda.pl/sklepy">.*</a></p>', lambda match: ''),
[ (r'<p><a href="http://fronda.pl/sklepy">.*</a></p>', lambda match: ''),
(r'<p><a href="http://fronda.pl/pasaz">.*</a></p>', lambda match: ''),
(r'<h3><strong>W.* lektury.*</a></p></div>', lambda match: '</div>'),
(r'<h3>Zobacz t.*?</div>', lambda match: '</div>') ]
(r'<h3>Zobacz t.*?</div>', lambda match: '</div>'),
(r'<p[^>]*>&nbsp;</p>', lambda match: ''),
(r'<p><span style=".*?"><br /></span></p> ', lambda match: ''),
(r'<a style=\'float:right;margin-top:3px;\' href="http://www.facebook.com/share.php?.*?</a>', lambda match: '')]
]

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,36 @@
__license__ = 'GPL v3'
__copyright__ = '2011, Seongkyoun Yoo <Seongkyoun.yoo at gmail.com>'
'''
Profile to download KoreaHerald
'''
from calibre.web.feeds.news import BasicNewsRecipe
class KoreaHerald(BasicNewsRecipe):
title = u'KoreaHerald'
language = 'en'
description = u'Korea Herald News articles'
__author__ = 'Seongkyoun Yoo'
oldest_article = 10
recursions = 3
max_articles_per_feed = 10
no_stylesheets = True
keep_only_tags = [
dict(id=['contentLeft', '_article'])
]
remove_tags = [
dict(name='iframe'),
dict(name='div', attrs={'class':['left','htit2', 'navigation','banner_txt','banner_img']}),
dict(name='ul', attrs={'class':['link_icon', 'flow_icon','detailTextAD110113']}),
]
feeds = [
('All News','http://www.koreaherald.com/rss/020000000000.xml'),
('National','http://www.koreaherald.com/rss/020100000000.xml'),
('Business','http://www.koreaherald.com/rss/020200000000.xml'),
('Life&Style','http://www.koreaherald.com/rss/020300000000.xml'),
('Entertainment','http://www.koreaherald.com/rss/020400000000.xml'),
('Sports','http://www.koreaherald.com/rss/020500000000.xml'),
('Opinion','http://www.koreaherald.com/rss/020600000000.xml'),
('English Cafe','http://www.koreaherald.com/rss/021000000000.xml'),
]

View File

@ -2,7 +2,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
class RzeczpospolitaRecipe(BasicNewsRecipe):
__license__ = 'GPL v3'
__author__ = 'kwetal'
__author__ = u'kwetal and Tomasz Dlugosz'
language = 'pl'
version = 1
@ -38,6 +38,8 @@ class RzeczpospolitaRecipe(BasicNewsRecipe):
remove_tags.append(dict(name = 'div', attrs = {'class' : 'clr'}))
remove_tags.append(dict(name = 'div', attrs = {'id' : 'share_bottom'}))
remove_tags.append(dict(name = 'div', attrs = {'id' : 'copyright_law'}))
remove_tags.append(dict(name = 'div', attrs = {'class' : 'more'}))
remove_tags.append(dict(name = 'div', attrs = {'class' : 'editorPicks'}))
extra_css = '''
body {font-family: verdana, arial, helvetica, geneva, sans-serif ;}
@ -48,6 +50,13 @@ class RzeczpospolitaRecipe(BasicNewsRecipe):
.fot{font-size: x-small; color: #666666;}
'''
def skip_ad_pages(self, soup):
if ('advertisement' in soup.find('title').string.lower()):
href = soup.find('a').get('href')
return self.index_to_soup(href, raw=True)
else:
return None
def print_version(self, url):
start, sep, rest = url.rpartition('/')
forget, sep, index = rest.rpartition(',')

View File

@ -449,7 +449,7 @@ class CatalogPlugin(Plugin): # {{{
['author_sort','authors','comments','cover','formats',
'id','isbn','ondevice','pubdate','publisher','rating',
'series_index','series','size','tags','timestamp',
'title','uuid'])
'title_sort','title','uuid'])
all_custom_fields = set(db.custom_field_keys())
all_fields = all_std_fields.union(all_custom_fields)

View File

@ -68,9 +68,9 @@ class USER_DEFINED(USBMS):
'is prepended to any send_to_device template') + '</p>',
]
EXTRA_CUSTOMIZATION_DEFAULT = [
'0x0000',
'0x0000',
'0x0000',
'0xffff',
'0xffff',
'0xffff',
None,
'',
'',

View File

@ -68,7 +68,8 @@ def check_command_line_options(parser, args, log):
raise SystemExit(1)
output = args[2]
if output.startswith('.') and output != '.':
if output.startswith('.') and (output != '.' and not
output.startswith('..')):
output = os.path.splitext(os.path.basename(input))[0]+output
output = os.path.abspath(output)

View File

@ -212,6 +212,9 @@ class Source(Plugin):
def is_customizable(self):
return True
def customization_help(self):
return 'This plugin can only be customized using the GUI'
def config_widget(self):
from calibre.gui2.metadata.config import ConfigWidget
return ConfigWidget(self)

View File

@ -403,7 +403,7 @@ def identify(log, abort, # {{{
result.identify_plugin = plugin
if msprefs['txt_comments']:
if plugin.has_html_comments and result.comments:
result.comments = html2text(r.comments)
result.comments = html2text(result.comments)
log('The identify phase took %.2f seconds'%(time.time() - start_time))
log('The longest time (%f) was taken by:'%longest, lp)

View File

@ -20,6 +20,9 @@ class GenerateCatalogAction(InterfaceAction):
action_spec = (_('Create a catalog of the books in your calibre library'), 'catalog.png', 'Catalog builder', None)
dont_add_to = frozenset(['menubar-device', 'toolbar-device', 'context-menu-device'])
def genesis(self):
self.qaction.triggered.connect(self.generate_catalog)
def generate_catalog(self):
rows = self.gui.library_view.selectionModel().selectedRows()
if not rows or len(rows) < 2:

View File

@ -439,6 +439,7 @@ def populate_metadata_page(layout, db, book_id, bulk=False, two_column=False, pa
w = widget_factory(dt, col)
ans.append(w)
for c in range(0, len(w.widgets), 2):
w.widgets[c].setWordWrap(True)
w.widgets[c].setBuddy(w.widgets[c+1])
layout.addWidget(w.widgets[c], row, column)
layout.addWidget(w.widgets[c+1], row, column+1)

View File

@ -10,7 +10,7 @@ __docformat__ = 'restructuredtext en'
import textwrap, re, os
from PyQt4.Qt import (Qt, QDateEdit, QDate, pyqtSignal, QMessageBox,
QIcon, QToolButton, QWidget, QLabel, QGridLayout,
QIcon, QToolButton, QWidget, QLabel, QGridLayout, QApplication,
QDoubleSpinBox, QListWidgetItem, QSize, QPixmap,
QPushButton, QSpinBox, QLineEdit, QSizePolicy)
@ -1037,6 +1037,13 @@ class IdentifiersEdit(QLineEdit): # {{{
self.setToolTip(tt+extra)
self.setStyleSheet('QLineEdit { background-color: %s }'%col)
def paste_isbn(self):
text = unicode(QApplication.clipboard().text()).strip()
if text:
vals = self.current_val
vals['isbn'] = text
self.current_val = vals
# }}}
class PublisherEdit(MultiCompleteComboBox): # {{{

View File

@ -69,7 +69,9 @@ class MetadataSingleDialogBase(ResizableDialog):
self.setLayout(self.l)
self.l.setMargin(0)
self.l.addWidget(self.scroll_area)
self.l.addWidget(self.button_box)
ll = self.button_box_layout = QHBoxLayout()
self.l.addLayout(ll)
ll.addWidget(self.button_box)
self.setWindowIcon(QIcon(I('edit_input.png')))
self.setWindowTitle(_('Edit Metadata'))
@ -125,6 +127,13 @@ class MetadataSingleDialogBase(ResizableDialog):
'Swap the author and title'))
self.swap_title_author_button.clicked.connect(self.swap_title_author)
self.manage_authors_button = QToolButton(self)
self.manage_authors_button.setIcon(QIcon(I('user_profile.png')))
self.manage_authors_button.setToolTip('<p>' + _(
'Manage authors. Use to rename authors and correct '
'individual author\'s sort values') + '</p>')
self.manage_authors_button.clicked.connect(self.authors.manage_authors)
self.series = SeriesEdit(self)
self.remove_unused_series_button = QToolButton(self)
self.remove_unused_series_button.setToolTip(
@ -161,6 +170,12 @@ class MetadataSingleDialogBase(ResizableDialog):
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.paste_isbn_button = QToolButton(self)
self.paste_isbn_button.setToolTip('<p>' +
_('Paste the contents of the clipboard into the '
'identifiers box prefixed with isbn:') + '</p>')
self.paste_isbn_button.setIcon(QIcon(I('edit-paste.png')))
self.paste_isbn_button.clicked.connect(self.identifiers.paste_isbn)
self.publisher = PublisherEdit(self)
self.basic_metadata_widgets.append(self.publisher)
@ -499,7 +514,8 @@ class MetadataSingleDialog(MetadataSingleDialogBase): # {{{
sto(one, two)
sto(two, three)
tl.addWidget(self.swap_title_author_button, 0, 0, 2, 1)
tl.addWidget(self.swap_title_author_button, 0, 0, 1, 1)
tl.addWidget(self.manage_authors_button, 1, 0, 1, 1)
create_row(0, self.title, self.deduce_title_sort_button, self.title_sort)
sto(self.title_sort, self.authors)
@ -508,6 +524,7 @@ class MetadataSingleDialog(MetadataSingleDialogBase): # {{{
create_row(2, self.series, self.remove_unused_series_button,
self.series_index, icon='trash.png')
sto(self.series_index, self.swap_title_author_button)
sto(self.swap_title_author_button, self.manage_authors_button)
tl.addWidget(self.formats_manager, 0, 6, 3, 1)
@ -518,7 +535,7 @@ class MetadataSingleDialog(MetadataSingleDialogBase): # {{{
self.tabs[0].gb = gb = QGroupBox(_('Change cover'), self)
gb.l = l = QGridLayout()
gb.setLayout(l)
sto(self.swap_title_author_button, self.cover.buttons[0])
sto(self.manage_authors_button, self.cover.buttons[0])
for i, b in enumerate(self.cover.buttons[:3]):
l.addWidget(b, 0, i, 1, 1)
sto(b, self.cover.buttons[i+1])
@ -532,10 +549,16 @@ class MetadataSingleDialog(MetadataSingleDialogBase): # {{{
w.setLayout(w.l)
l.setMargin(0)
self.splitter.addWidget(w)
def create_row2(row, widget, button=None):
def create_row2(row, widget, button=None, front_button=None):
row += 1
ql = BuddyLabel(widget)
l.addWidget(ql, row, 0, 1, 1)
if front_button:
ltl = QHBoxLayout()
ltl.addWidget(front_button)
ltl.addWidget(ql)
l.addLayout(ltl, row, 0, 1, 1)
else:
l.addWidget(ql, row, 0, 1, 1)
l.addWidget(widget, row, 1, 1, 2 if button is None else 1)
if button is not None:
l.addWidget(button, row, 2, 1, 1)
@ -550,8 +573,10 @@ class MetadataSingleDialog(MetadataSingleDialogBase): # {{{
create_row2(1, self.rating)
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, self.clear_identifiers_button)
sto(self.tags_editor_button, self.paste_isbn_button)
sto(self.paste_isbn_button, self.identifiers)
create_row2(3, self.identifiers, self.clear_identifiers_button,
front_button=self.paste_isbn_button)
sto(self.clear_identifiers_button, self.timestamp)
create_row2(4, self.timestamp, self.timestamp.clear_button)
sto(self.timestamp.clear_button, self.pubdate)
@ -624,13 +649,13 @@ class MetadataSingleDialogAlt1(MetadataSingleDialogBase): # {{{
self.tabs[0].l.addWidget(gb, 0, 0, 1, 1)
gb.setLayout(tl)
self.button_box.addButton(self.fetch_metadata_button,
QDialogButtonBox.ActionRole)
self.button_box_layout.insertWidget(0, self.fetch_metadata_button)
self.config_metadata_button.setToolButtonStyle(Qt.ToolButtonTextOnly)
self.config_metadata_button.setText(_('Configure metadata downloading'))
self.button_box.addButton(self.config_metadata_button,
QDialogButtonBox.ActionRole)
sto(self.button_box, self.title)
self.button_box_layout.insertWidget(1, self.config_metadata_button)
sto(self.button_box, self.fetch_metadata_button)
sto(self.fetch_metadata_button, self.config_metadata_button)
sto(self.config_metadata_button, self.title)
def create_row(row, widget, tab_to, button=None, icon=None, span=1):
ql = BuddyLabel(widget)
@ -648,6 +673,8 @@ class MetadataSingleDialogAlt1(MetadataSingleDialogBase): # {{{
sto(widget, tab_to)
tl.addWidget(self.swap_title_author_button, 0, 0, 2, 1)
tl.addWidget(self.manage_authors_button, 2, 0, 1, 1)
tl.addWidget(self.paste_isbn_button, 11, 0, 1, 1)
create_row(0, self.title, self.title_sort,
button=self.deduce_title_sort_button, span=2,
@ -669,6 +696,9 @@ class MetadataSingleDialogAlt1(MetadataSingleDialogBase): # {{{
button=self.timestamp.clear_button, icon='trash.png')
create_row(11, self.identifiers, self.comments,
button=self.clear_identifiers_button, icon='trash.png')
sto(self.clear_identifiers_button, self.swap_title_author_button)
sto(self.swap_title_author_button, self.manage_authors_button)
sto(self.manage_authors_button, self.paste_isbn_button)
tl.addItem(QSpacerItem(1, 1, QSizePolicy.Fixed, QSizePolicy.Expanding),
12, 1, 1 ,1)
@ -708,7 +738,6 @@ class MetadataSingleDialogAlt1(MetadataSingleDialogBase): # {{{
gb = QGroupBox(_('Change cover'), tab1)
l = QGridLayout()
gb.setLayout(l)
sto(self.swap_title_author_button, self.cover.buttons[0])
for i, b in enumerate(self.cover.buttons[:3]):
l.addWidget(b, 0, i, 1, 1)
sto(b, self.cover.buttons[i+1])
@ -756,13 +785,13 @@ class MetadataSingleDialogAlt2(MetadataSingleDialogBase): # {{{
l.addWidget(gb, 0, 0, 1, 1)
gb.setLayout(tl)
self.button_box.addButton(self.fetch_metadata_button,
QDialogButtonBox.ActionRole)
self.button_box_layout.insertWidget(0, self.fetch_metadata_button)
self.config_metadata_button.setToolButtonStyle(Qt.ToolButtonTextOnly)
self.config_metadata_button.setText(_('Configure metadata downloading'))
self.button_box.addButton(self.config_metadata_button,
QDialogButtonBox.ActionRole)
sto(self.button_box, self.title)
self.button_box_layout.insertWidget(1, self.config_metadata_button)
sto(self.button_box, self.fetch_metadata_button)
sto(self.fetch_metadata_button, self.config_metadata_button)
sto(self.config_metadata_button, self.title)
def create_row(row, widget, tab_to, button=None, icon=None, span=1):
ql = BuddyLabel(widget)
@ -780,6 +809,8 @@ class MetadataSingleDialogAlt2(MetadataSingleDialogBase): # {{{
sto(widget, tab_to)
tl.addWidget(self.swap_title_author_button, 0, 0, 2, 1)
tl.addWidget(self.manage_authors_button, 2, 0, 2, 1)
tl.addWidget(self.paste_isbn_button, 11, 0, 1, 1)
create_row(0, self.title, self.title_sort,
button=self.deduce_title_sort_button, span=2,
@ -801,6 +832,9 @@ class MetadataSingleDialogAlt2(MetadataSingleDialogBase): # {{{
button=self.timestamp.clear_button, icon='trash.png')
create_row(11, self.identifiers, self.comments,
button=self.clear_identifiers_button, icon='trash.png')
sto(self.clear_identifiers_button, self.swap_title_author_button)
sto(self.swap_title_author_button, self.manage_authors_button)
sto(self.manage_authors_button, self.paste_isbn_button)
tl.addItem(QSpacerItem(1, 1, QSizePolicy.Fixed, QSizePolicy.Expanding),
12, 1, 1 ,1)
@ -820,7 +854,7 @@ class MetadataSingleDialogAlt2(MetadataSingleDialogBase): # {{{
l.addWidget(gb, 0, 1, 1, 1)
sp = QSizePolicy()
sp.setVerticalStretch(10)
sp.setHorizontalPolicy(QSizePolicy.Fixed)
sp.setHorizontalPolicy(QSizePolicy.Minimum)
sp.setVerticalPolicy(QSizePolicy.Expanding)
gb.setSizePolicy(sp)
self.set_custom_metadata_tab_order()
@ -842,7 +876,7 @@ class MetadataSingleDialogAlt2(MetadataSingleDialogBase): # {{{
lb = QGridLayout()
gb.setLayout(lb)
lb.addWidget(self.cover, 0, 0, 1, 3, alignment=Qt.AlignCenter)
sto(self.clear_identifiers_button, self.cover.buttons[0])
sto(self.manage_authors_button, self.cover.buttons[0])
for i, b in enumerate(self.cover.buttons[:3]):
lb.addWidget(b, 1, i, 1, 1)
sto(b, self.cover.buttons[i+1])

View File

@ -27,7 +27,7 @@ from calibre.utils.logging import default_log as log
from calibre.utils.magick.draw import thumbnail
from calibre.utils.zipfile import ZipFile, ZipInfo
FIELDS = ['all', 'title', 'author_sort', 'authors', 'comments',
FIELDS = ['all', 'title', 'title_sort', 'author_sort', 'authors', 'comments',
'cover', 'formats','id', 'isbn', 'ondevice', 'pubdate', 'publisher',
'rating', 'series_index', 'series', 'size', 'tags', 'timestamp', 'uuid']
@ -66,7 +66,7 @@ class CSV_XML(CatalogPlugin): # {{{
dest = 'sort_by',
action = None,
help = _('Output field to sort on.\n'
'Available fields: author_sort, id, rating, size, timestamp, title.\n'
'Available fields: author_sort, id, rating, size, timestamp, title_sort\n'
"Default: '%default'\n"
"Applies to: CSV, XML output formats"))]
@ -76,7 +76,7 @@ class CSV_XML(CatalogPlugin): # {{{
if opts.verbose:
opts_dict = vars(opts)
log("%s(): Generating %s" % (self.name,self.fmt))
log("%s(): Generating %s" % (self.name,self.fmt.upper()))
if opts.connected_device['is_device_connected']:
log(" connected_device: %s" % opts.connected_device['name'])
if opts_dict['search_text']:
@ -126,8 +126,11 @@ class CSV_XML(CatalogPlugin): # {{{
for field in fields:
if field.startswith('#'):
item = db.get_field(entry['id'],field,index_is_id=True)
elif field == 'title_sort':
item = entry['sort']
else:
item = entry[field]
if item is None:
outstr.append('""')
continue
@ -167,7 +170,7 @@ class CSV_XML(CatalogPlugin): # {{{
item = getattr(E, field.replace('#','_'))(val)
record.append(item)
for field in ('id', 'uuid', 'title', 'publisher', 'rating', 'size',
for field in ('id', 'uuid', 'publisher', 'rating', 'size',
'isbn','ondevice'):
if field in fields:
val = r[field]
@ -178,6 +181,10 @@ class CSV_XML(CatalogPlugin): # {{{
item = getattr(E, field)(val)
record.append(item)
if 'title' in fields:
title = E.title(r['title'], sort=r['sort'])
record.append(title)
if 'authors' in fields:
aus = E.authors(sort=r['author_sort'])
for au in r['authors']:

View File

@ -3056,7 +3056,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
'''
if prefix is None:
prefix = self.library_path
FIELDS = set(['title', 'authors', 'author_sort', 'publisher', 'rating',
FIELDS = set(['title', 'sort', 'authors', 'author_sort', 'publisher', 'rating',
'timestamp', 'size', 'tags', 'comments', 'series', 'series_index',
'uuid', 'pubdate', 'last_modified', 'identifiers'])
for x in self.custom_column_num_map:

View File

@ -10,6 +10,7 @@ License: http://www.opensource.org/licenses/mit-license.php
import re
from calibre.utils.icu import capitalize
from calibre.utils.config import prefs
__all__ = ['titlecase']
__version__ = '0.5'
@ -67,11 +68,12 @@ def titlecase(text):
line.append(icu_lower(word))
continue
match = MAC_MC.match(word)
if match and not match.group(2)[:3] in ('hin', 'ht'):
line.append("%s%s" % (capitalize(match.group(1)),
capitalize(match.group(2))))
continue
if prefs['language'].lower().startswith('en'):
match = MAC_MC.match(word)
if match and not match.group(2)[:3] in ('hin', 'ht'):
line.append("%s%s" % (capitalize(match.group(1)),
capitalize(match.group(2))))
continue
hyphenated = []
for item in word.split('-'):