This commit is contained in:
GRiker 2010-11-11 04:17:38 -07:00
commit f1be0f9c16
20 changed files with 366 additions and 111 deletions

View File

@ -44,6 +44,7 @@
tickets: [7356]
- title: "News download: Workaround lack of thread safety in python mechanize, causing corrupted network packets (degrading network performance) on Ubuntu Maverick 64bit kernels"
tickets: [7321]
- title: "Convert comments to HTML for book details panel in separate thread to make scrolling through the book list faster when large comments are present"

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,51 @@
from calibre.web.feeds.news import BasicNewsRecipe
class EuropeanVoice(BasicNewsRecipe):
title = u'European Voice'
__author__ = 'malfi'
oldest_article = 14
max_articles_per_feed = 100
no_stylesheets = True
cover_url = 'http://www.europeanvoice.com/Css/images/logo.gif'
language = 'en'
keep_only_tags = [dict(name='div', attrs={'id':'articleLeftColumn'})]
remove_tags = [dict(name='div', attrs={'id':'BreadCrump'})]
feeds = [
(u'Whole site ',u'http://www.europeanvoice.com/Rss/2.xml'),
(u'News and analysis',u'http://www.europeanvoice.com/Rss/6.xml'),
(u'Comment',u'http://www.europeanvoice.com/Rss/7.xml'),
(u'Special reports',u'http://www.europeanvoice.com/Rss/5.xml'),
(u'People',u'http://www.europeanvoice.com/Rss/8.xml'),
(u'Career',u'http://www.europeanvoice.com/Rss/11.xml'),
(u'Policies',u'http://www.europeanvoice.com/Rss/4.xml'),
(u'EVents',u'http://www.europeanvoice.com/Rss/10.xml'),
(u'Policies - Economics',u'http://www.europeanvoice.com/Rss/31.xml'),
(u'Policies - Business',u'http://www.europeanvoice.com/Rss/19.xml'),
(u'Policies - Trade',u'http://www.europeanvoice.com/Rss/25.xml'),
(u'Policies - Information society',u'http://www.europeanvoice.com/Rss/20.xml'),
(u'Policies - Energy',u'http://www.europeanvoice.com/Rss/15.xml'),
(u'Policies - Transport',u'http://www.europeanvoice.com/Rss/18.xml'),
(u'Policies - Climate change',u'http://www.europeanvoice.com/Rss/16.xml'),
(u'Policies - Environment',u'http://www.europeanvoice.com/Rss/17.xml'),
(u'Policies - Farming & food',u'http://www.europeanvoice.com/Rss/23.xml'),
(u'Policies - Health & society',u'http://www.europeanvoice.com/Rss/24.xml'),
(u'Policies - Justice',u'http://www.europeanvoice.com/Rss/29.xml'),
(u'Policies - Foreign affairs',u'http://www.europeanvoice.com/Rss/27.xml')
]
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;}
p{font-family:Arial,Helvetica,sans-serif;font-size:small;}
body{font-family:Helvetica,Arial,sans-serif;font-size:small;}
'''
def print_version(self, url):
return url + '?bPrint=1'
def preprocess_html(self, soup):
denied = soup.findAll(True,text='Subscribers')
if denied:
raise Exception('Article skipped, because content can only be seen with subscription')
return soup

View File

@ -33,13 +33,14 @@ class IrishTimes(BasicNewsRecipe):
('Letters', 'http://www.irishtimes.com/feeds/rss/newspaper/letters.rss'),
]
def print_version(self, url):
if url.count('rss.feedsportal.com'):
u = url.replace('0Bhtml/story01.htm','_pf0Bhtml/story01.htm')
else:
u = url.replace('.html','_pf.html')
return u
if url.count('rss.feedsportal.com'):
u = 'http://www.irishtimes.com' + \
(((url[69:].replace('0C','/')).replace('0A','0'))).replace('0Bhtml/story01..htm','_pf.html')
else:
u = url.replace('.html','_pf.html')
return u
def get_article_url(self, article):
return article.link

View File

@ -21,8 +21,16 @@ class Pagina12(BasicNewsRecipe):
use_embedded_content = False
language = 'es'
remove_empty_feeds = True
publication_type = 'newspaper'
masthead_url = 'http://www.pagina12.com.ar/commons/imgs/logo-home.gif'
extra_css = ' body{font-family: Arial,Helvetica,sans-serif } img{margin-bottom: 0.4em} #autor{font-weight: bold} #fecha,#epigrafe{font-size: 0.9em; margin: 5px} #imagen{border: 1px solid black; margin: 0 0 1.25em 1.25em; width: 232px } '
extra_css = """
body{font-family: Arial,Helvetica,sans-serif }
img{margin-bottom: 0.4em; display:block}
#autor{font-weight: bold}
#fecha,#epigrafe{font-size: 0.9em; margin: 5px}
#imagen{border: 1px solid black; margin: 0 0 1.25em 1.25em; width: 232px }
.fgprincipal{font-size: large; font-weight: bold}
"""
conversion_options = {
'comment' : description
@ -31,7 +39,11 @@ class Pagina12(BasicNewsRecipe):
, 'language' : language
}
remove_tags = [dict(name='div', attrs={'id':['volver','logo','logo_suple','fin','permalink']})]
remove_tags = [
dict(name=['meta','link'])
,dict(name='div', attrs={'id':['volver','logo','logo_suple','fin','permalink']})
]
remove_attributes=['lang']
feeds = [
@ -65,4 +77,13 @@ class Pagina12(BasicNewsRecipe):
def preprocess_html(self, soup):
for item in soup.findAll(style=True):
del item['style']
for item in soup.findAll('span', attrs={'id':'seccion'}):
it = item.a
it.name='span'
del it['href']
del it['title']
for item in soup.findAll('p'):
it = item.find('h3')
if it:
it.name='span'
return soup

View File

@ -0,0 +1,69 @@
__license__ = 'GPL v3'
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
'''
rollingstone.com
'''
import re
from calibre.web.feeds.news import BasicNewsRecipe
class RollingStone(BasicNewsRecipe):
title = 'Rolling Stone Magazine - free content'
__author__ = 'Darko Miletic'
description = 'Rolling Stone Magazine features music, album and artist news, movie reviews, political, economic and pop culture commentary, videos, photos, and more.'
publisher = 'Werner Media inc.'
category = 'news, music, USA, world'
oldest_article = 15
max_articles_per_feed = 200
no_stylesheets = True
encoding = 'utf8'
use_embedded_content = False
language = 'en'
remove_empty_feeds = True
publication_type = 'magazine'
masthead_url = 'http://www.rollingstone.com/templates/rolling-stone-templates/theme/rstheme/images/rsLogo.png'
extra_css = """
body{font-family: Georgia,Times,serif }
img{margin-bottom: 0.4em; display:block}
"""
conversion_options = {
'comment' : description
, 'tags' : category
, 'publisher' : publisher
, 'language' : language
}
preprocess_regexps = [
(re.compile(r'xml:lang="en">.*?<head>', re.DOTALL|re.IGNORECASE),lambda match: 'xml:lang="en">\n<head>\n')
,(re.compile(r'</title>.*?</head>' , re.DOTALL|re.IGNORECASE),lambda match: '</title>\n</head>\n' )
]
keep_only_tags=[
dict(attrs={'class':['headerImgHolder','headerContent']})
,dict(name='div',attrs={'id':['teaser','storyTextContainer']})
,dict(name='div',attrs={'class':'blogDetailModule clearfix'})
]
remove_tags = [
dict(name=['meta','iframe','object','embed'])
,dict(attrs={'id':'mpStoryHeader'})
,dict(attrs={'class':'relatedTopics'})
]
remove_attributes=['lang','onclick','width','height','name']
remove_tags_before=dict(attrs={'class':'bloggerInfo'})
remove_tags_after=dict(attrs={'class':'relatedTopics'})
feeds = [
(u'All News' , u'http://www.rollingstone.com/siteServices/rss/allNews' )
,(u'All Blogs' , u'http://www.rollingstone.com/siteServices/rss/allBlogs' )
,(u'Movie Reviews' , u'http://www.rollingstone.com/siteServices/rss/movieReviews' )
,(u'Album Reviews' , u'http://www.rollingstone.com/siteServices/rss/albumReviews' )
,(u'Song Reviews' , u'http://www.rollingstone.com/siteServices/rss/songReviews' )
]
def preprocess_html(self, soup):
for item in soup.findAll(style=True):
del item['style']
return soup

View File

@ -348,8 +348,12 @@ class Build(Command):
VERSION = 1.0.0
CONFIG += %s
''')%(ext.name, ' '.join(ext.headers), ' '.join(ext.sources), archs)
pro = pro.replace('\\', '\\\\')
open(ext.name+'.pro', 'wb').write(pro)
subprocess.check_call([QMAKE, '-o', 'Makefile', ext.name+'.pro'])
qmc = [QMAKE, '-o', 'Makefile']
if iswindows:
qmc += ['-spec', 'win32-msvc2008']
subprocess.check_call(qmc + [ext.name+'.pro'])
subprocess.check_call([make, '-f', 'Makefile'])
objects = glob.glob(obj_pat)
return list(map(self.a, objects))

View File

@ -13,7 +13,7 @@ from setup import Command, modules, functions, basenames, __version__, \
from setup.build_environment import msvc, MT, RC
from setup.installer.windows.wix import WixMixIn
QT_DIR = 'C:\\Qt\\4.6.3'
QT_DIR = 'Q:\\Qt\\4.7.1'
QT_DLLS = ['Core', 'Gui', 'Network', 'Svg', 'WebKit', 'Xml', 'XmlPatterns']
LIBUSB_DIR = 'C:\\libusb'
LIBUNRAR = 'C:\\Program Files\\UnrarDLL\\unrar.dll'

View File

@ -37,8 +37,7 @@ Qt
Extract Qt sourcecode to C:\Qt\4.x.x. Run configure and make::
configure -opensource -qt-zlib -qt-gif -qt-libmng -qt-libpng -qt-libtiff -qt-libjpeg -release -platform win32-msvc -no-qt3support -webkit -xmlpatterns -no-phonon
nmake
configure -opensource -release -qt-zlib -qt-gif -qt-libmng -qt-libpng -qt-libtiff -qt-libjpeg -release -platform win32-msvc2008 -no-qt3support -webkit -xmlpatterns -no-phonon -no-style-plastique -no-style-cleanlooks -no-style-motif -no-style-cde -no-declarative -no-scripttools -no-audio-backend -no-multimedia -no-dbus -no-openvg -no-opengl -no-qt3support -confirm-license && nmake
SIP
-----

View File

@ -221,7 +221,10 @@ class MetadataHeader(BookHeader):
else:
end = self.section_offset(number + 1)
self.stream.seek(start)
return self.stream.read(end - start)
try:
return self.stream.read(end - start)
except OverflowError:
return self.stream.read(os.stat(self.stream.name).st_size - start)
class MobiReader(object):
@ -398,6 +401,8 @@ class MobiReader(object):
elem.getparent().remove(elem)
fname = self.name.encode('ascii', 'replace')
fname = re.sub(r'[\x08\x15\0]+', '', fname)
if not fname:
fname = 'dummy'
htmlfile = os.path.join(output_dir,
ascii_filename(fname) + '.html')
try:

View File

@ -9,7 +9,8 @@ __docformat__ = 'restructuredtext en'
from lxml import html
from lxml.html import soupparser
from PyQt4.Qt import QApplication, QFontInfo, QPalette
from PyQt4.Qt import QApplication, QFontInfo, QPalette, QSize, QWidget, \
QToolBar, QVBoxLayout, QAction, QIcon
from PyQt4.QtWebKit import QWebView
from calibre.ebooks.chardet import xml_to_unicode
@ -17,6 +18,22 @@ from calibre import xml_replace_entities
class EditorWidget(QWebView):
def __init__(self, parent=None):
QWebView.__init__(self, parent)
for name, icon, text, checkable in [
('bold', 'format-text-bold', _('Bold'), True),
('italic', 'format-text-italic', _('Italic'), True),
('underline', 'format-text-underline', _('Underline'), True),
('strikethrough', 'format-text-underline', _('Underline'), True),
]:
ac = QAction(QIcon(I(icon+'.png')), text, self)
ac.setCheckable(checkable)
setattr(self, 'action_'+name, ac)
def sizeHint(self):
return QSize(150, 150)
@dynamic_property
def html(self):
@ -63,9 +80,31 @@ class EditorWidget(QWebView):
return property(fget=fget, fset=fset)
class Editor(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.toolbar = QToolBar(self)
self.editor = EditorWidget(self)
self._layout = QVBoxLayout(self)
self.setLayout(self._layout)
self._layout.setContentsMargins(0, 0, 0, 0)
self._layout.addWidget(self.toolbar)
self._layout.addWidget(self.editor)
@dynamic_property
def html(self):
def fset(self, v):
self.editor.html = v
return property(fget=lambda self:self.editor.html, fset=fset)
if __name__ == '__main__':
app = QApplication([])
w = EditorWidget()
w = Editor()
w.resize(800, 600)
w.show()
# testing {{{
@ -101,4 +140,4 @@ if __name__ == '__main__':
#print w.html.encode('utf-8')
# }}}
print w.html
#print w.html

View File

@ -1014,7 +1014,13 @@ class DeviceMixin(object): # {{{
self.status_bar.show_message(_('Sent by email:') + ', '.join(good),
5000)
if remove:
self.library_view.model().delete_books_by_id(remove)
try:
self.library_view.model().delete_books_by_id(remove)
except:
# Probably the user deleted the files, in any case, failing
# to delete the book is not catastrophic
traceback.print_exc()
def cover_to_thumbnail(self, data):
ht = self.device_manager.device.THUMBNAIL_HEIGHT \

View File

@ -101,9 +101,9 @@ class Category(QWidget): # {{{
ac.setStatusTip(p.description)
self.actions.append(ac)
w = self.bar.widgetForAction(ac)
w.setStyleSheet('QToolButton { margin-right: 20px; min-width: 100px }')
w.setCursor(Qt.PointingHandCursor)
w.setAutoRaise(True)
w.setMinimumWidth(100)
def triggered(self, plugin, *args):
self.plugin_activated.emit(plugin)

View File

@ -625,7 +625,11 @@ class ResultCache(SearchQueryParser): # {{{
# }}}
def remove(self, id):
self._data[id] = None
try:
self._data[id] = None
except IndexError:
# id is out of bounds, no point setting it to None anyway
pass
try:
self._map.remove(id)
except ValueError:

View File

@ -235,7 +235,7 @@ class MobileServer(object):
no_tag_count=True)
book['title'] = record[FM['title']]
for x in ('timestamp', 'pubdate'):
book[x] = strftime('%b, %Y', record[FM[x]])
book[x] = strftime('%d %b, %Y', record[FM[x]])
book['id'] = record[FM['id']]
books.append(book)
for key in CKEYS:

View File

@ -5,8 +5,8 @@
msgid ""
msgstr ""
"Project-Id-Version: calibre 0.7.27\n"
"POT-Creation-Date: 2010-11-06 09:35+MDT\n"
"PO-Revision-Date: 2010-11-06 09:35+MDT\n"
"POT-Creation-Date: 2010-11-10 07:14+MST\n"
"PO-Revision-Date: 2010-11-10 07:14+MST\n"
"Last-Translator: Automatically generated\n"
"Language-Team: LANGUAGE\n"
"MIME-Version: 1.0\n"
@ -72,9 +72,9 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:78
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:119
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:153
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:611
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:817
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:819
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:616
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:822
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:824
#: /home/kovid/work/calibre/src/calibre/ebooks/odt/input.py:49
#: /home/kovid/work/calibre/src/calibre/ebooks/odt/input.py:51
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:911
@ -273,7 +273,7 @@ msgid "Change the way calibre behaves"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:734
#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:206
#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:208
msgid "Add your own columns"
msgstr ""
@ -1881,8 +1881,8 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:605
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/info.py:45
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:102
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:103
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:108
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:109
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/delete_matching_from_device.py:75
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:58
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:65
@ -1916,8 +1916,8 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:39
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:206
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:189
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:104
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:74
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:110
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:79
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:325
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1131
#: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:178
@ -2213,7 +2213,7 @@ msgstr ""
msgid "All articles"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:259
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:262
msgid "This is an Amazon Topaz book. It cannot be processed."
msgstr ""
@ -3140,7 +3140,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:391
#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:101
#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:739
#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:741
msgid "Not allowed"
msgstr ""
@ -3207,7 +3207,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/actions/copy_to_library.py:147
#: /home/kovid/work/calibre/src/calibre/gui2/device.py:720
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:683
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:685
#: /home/kovid/work/calibre/src/calibre/gui2/metadata.py:189
msgid "Failed"
msgstr ""
@ -3878,11 +3878,11 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:25
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:49
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:58
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:403
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:119
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:120
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:121
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:131
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:405
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:125
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:126
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:127
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:137
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/delete_matching_from_device.py:76
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:320
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1117
@ -3891,10 +3891,10 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:26
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:52
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:122
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:123
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:124
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:127
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:128
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:129
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:130
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:133
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:319
#: /home/kovid/work/calibre/src/calibre/gui2/preferences/emailp.py:24
#: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:117
@ -3925,7 +3925,7 @@ msgstr ""
msgid "None"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:402
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:404
msgid "Double-click to open Book Details window"
msgstr ""
@ -4146,6 +4146,19 @@ msgstr ""
msgid "Tab template for catalog.ui"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/comments_editor.py:25
msgid "Bold"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/comments_editor.py:26
msgid "Italic"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/comments_editor.py:27
#: /home/kovid/work/calibre/src/calibre/gui2/comments_editor.py:28
msgid "Underline"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/bulk.py:36
msgid "For settings that cannot be specified in this dialog, use the values saved in a previous conversion (if they exist) instead of using the defaults specified in the Preferences"
msgstr ""
@ -4613,6 +4626,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:185
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:353
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:393
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:214
msgid "&Series:"
msgstr ""
@ -4798,7 +4812,7 @@ msgid "Options specific to the input format."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/single_ui.py:117
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:71
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:76
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:96
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/progress_ui.py:53
msgid "Dialog"
@ -4988,8 +5002,8 @@ msgid "Force maximum line length"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/xexp_edit_ui.py:56
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:72
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:73
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:77
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:78
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_format_ui.py:46
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/confirm_delete_ui.py:54
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/password_ui.py:62
@ -5400,15 +5414,15 @@ msgstr ""
msgid "&Paste from clipboard"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:75
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:80
msgid "Fit &cover within view"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:76
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:81
msgid "&Previous"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:77
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:82
msgid "&Next"
msgstr ""
@ -5565,6 +5579,7 @@ msgid "Set options for converting %s"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:97
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:211
msgid "&Title:"
msgstr ""
@ -5813,40 +5828,40 @@ msgid "Book %d:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:274
msgid "<b>You can destroy your library using this feature.</b> Changes are permanent. There is no undo function. This feature is experimental, and there may be bugs. You are strongly encouraged to back up your library before proceeding.<p>Search and replace in text fields using character matching or regular expressions. "
msgid "<b>You can destroy your library using this feature.</b> Changes are permanent. There is no undo function. You are strongly encouraged to back up your library before proceeding.<p>Search and replace in text fields using character matching or regular expressions. "
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:283
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:282
msgid "In character mode, the field is searched for the entered search text. The text is replaced by the specified replacement text everywhere it is found in the specified field. After replacement is finished, the text can be changed to upper-case, lower-case, or title-case. If the case-sensitive check box is checked, the search text must match exactly. If it is unchecked, the search text will match both upper- and lower-case letters"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:294
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:293
msgid "In regular expression mode, the search text is an arbitrary python-compatible regular expression. The replacement text can contain backreferences to parenthesized expressions in the pattern. The search is not anchored, and can match and replace multiple times on the same string. The modification functions (lower-case etc) are applied to the matched text, not to the field as a whole. The destination box specifies the field where the result after matching and replacement is to be assigned. You can replace the text in the field, or prepend or append the matched text. See <a href=\"http://docs.python.org/library/re.html\"> this reference</a> for more information on python's regular expressions, and in particular the 'sub' function."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:436
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:438
msgid "You must specify a destination when source is a composite field"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:528
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:536
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:631
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:530
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:538
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:633
msgid "Search/replace invalid"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:529
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:531
msgid "Authors cannot be set to the empty string. Book title %s not processed"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:537
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:539
msgid "Title cannot be set to the empty string. Book title %s not processed"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:632
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:634
msgid "Search pattern is invalid: %s"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:669
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:671
msgid ""
"Applying changes to %d books.\n"
"Phase {0} {1}%%."
@ -6071,7 +6086,7 @@ msgid "Your test:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:401
msgid "&Search and replace (experimental)"
msgid "&Search and replace"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:91
@ -6570,56 +6585,92 @@ msgstr ""
msgid "Negate"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:118
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:198
msgid "Advanced Search"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:119
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:199
msgid "Find entries that have..."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:120
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:200
msgid "&All these words:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:121
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:201
msgid "This exact &phrase:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:122
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:202
msgid "&One or more of these words:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:123
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:203
msgid "But dont show entries that have..."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:124
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:204
msgid "Any of these &unwanted words:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:125
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:205
msgid "What kind of match to use:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:126
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:206
msgid "Contains: the word or phrase matches anywhere in the metadata"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:127
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:207
msgid "Equals: the word or phrase must match an entire metadata field"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:128
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:208
msgid "Regular expression: the expression must match anywhere in the metadata"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:129
msgid " "
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:209
msgid "See the <a href=\"http://calibre-ebook.com/user_manual/gui.html#the-search-interface\">User Manual</a> for more help"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:130
msgid "See the <a href=\"http://calibre-ebook.com/user_manual/gui.html#the-search-interface\">User Manual</a> for more help"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:210
msgid "A&dvanced Search"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:212
msgid "Enter the title."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:213
msgid "&Author:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:215
msgid "Ta&gs:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:216
msgid "Enter an author's name. Only one author can be used."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:217
msgid "Enter a series name, without an index. Only one series name can be used."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:218
msgid "Enter tags separated by spaces"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:219
msgid "&Clear"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:220
msgid "Search only in specific fields:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:221
msgid "Titl&e/Author/Series ..."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/select_formats.py:45
@ -7231,35 +7282,39 @@ msgstr ""
msgid "Books display will be restricted to those matching the selected saved search"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:172
#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:170
msgid "Shift+Ctrl+F"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:173
msgid "Advanced search"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:177
#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:178
msgid "<p>Search the list of books by title, author, publisher, tags, comments, etc.<br><br>Words separated by spaces are ANDed"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:180
#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:181
msgid "&Go!"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:186
#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:187
msgid "Do Quick Search (you can also press the Enter key)"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:192
#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:193
msgid "Reset Quick Search"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:204
#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:205
msgid "Copy current search text (instead of search name)"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:210
#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:211
msgid "Save current search under the name shown in the box"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:216
#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:217
msgid "Delete current saved search"
msgstr ""
@ -7316,47 +7371,47 @@ msgstr ""
msgid "Double click to <b>edit</b> me<br><br>"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:144
#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:146
msgid "Hide column %s"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:149
#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:151
msgid "Sort on %s"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:150
#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:152
msgid "Ascending"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:153
#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:155
msgid "Descending"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:165
#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:167
msgid "Change text alignment for %s"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:167
#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:169
msgid "Left"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:167
#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:169
msgid "Right"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:168
#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:170
msgid "Center"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:187
#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:189
msgid "Show column"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:199
#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:201
msgid "Restore default layout"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:740
#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:742
msgid "Dropping onto a device is not supported. First add the book to the calibre library."
msgstr ""
@ -9027,7 +9082,7 @@ msgid "Options to customize the ebook viewer"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/documentview.py:42
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:704
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:708
msgid "Remember last used window size"
msgstr ""
@ -9197,63 +9252,63 @@ msgstr ""
msgid "No matches found for: %s"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:481
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:485
msgid "Loading flow..."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:517
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:521
msgid "Laying out %s"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:548
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:552
msgid "Bookmark #%d"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:552
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:556
msgid "Add bookmark"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:553
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:557
msgid "Enter title for bookmark:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:563
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:567
msgid "Manage Bookmarks"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:600
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:604
msgid "Loading ebook..."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:608
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:612
msgid "DRM Error"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:609
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:613
msgid "<p>This book is protected by <a href=\"%s\">DRM</a>"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:613
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:617
msgid "Could not open ebook"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:691
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:695
msgid "Options to control the ebook viewer"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:698
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:702
msgid "If specified, viewer window will try to come to the front when started."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:701
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:705
msgid "If specified, viewer window will try to open full screen when started."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:706
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:710
msgid "Print javascript alert and console messages to the console"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:712
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:716
msgid ""
"%prog [options] file\n"
"\n"