sync with Kovid's branch

This commit is contained in:
Tomasz Długosz 2012-10-27 23:36:58 +02:00
commit 9fa0715276
14 changed files with 204 additions and 141 deletions

View File

@ -19,6 +19,54 @@
# new recipes: # new recipes:
# - title: # - title:
- version: 0.9.4
date: 2012-10-26
new features:
- title: "Conversion: Add an option to embed a font family into the book."
description: "The embedded font is used as the base font for all text that does not specify its own font family in the input document. Works only with output formats that support font embedding, principally EPUB/AZW3. Option is found under Look & Feel in the conversion dialog. You can ensure that the font is used for all text, regardless of the input document's styles by filtering out font family styles via the Filter Style Information option in the Conversion dialog."
type: major
- title: "When changing the title/author of a book, use hard links instead of copying the books' files, for a large speedup. Only works on filesystems that support hardlinks."
- title: "Linux installer: Resume interrupted downloads and verify the SHA-512 signature of the downloaded file before installing it."
bug fixes:
- title: "Windows: Check if any of the files of a book are in use before changing the title/author, this prevents the creation of duplicate files if one of the files is open in another program"
- title: "Kobo driver: Fix the ondevice status for some books getting lost."
tickets: [1069403]
- title: "Catalogs: Fix regression that broke use of prefix rules."
tickets: [1070086]
- title: "Tag Browser: Fix sorting incorrect for accented letters"
tickets: [1069835]
- title: "Make the bundled Liberation fonts available on all platforms for embedding"
- title: "Use mimetype for fonts from the EPUB 3 specification"
- title: "Get Books: Handle website change that broke the SONY Store plugin"
- title: "Generate cover: If the default font cannot render characters in the metadata (for example for east asian languages) try to automatically find a font on the system that is capable of rendering the characters"
- title: "Fix regression that broke certain types of CSS selectors."
tickets: [1068937]
- title: "Use font-weight:bold instead of font-weight:bolder for the <b> and <strong> tags as ADE cant handle bolder when embedded fonts are used"
improved recipes:
- New York Post
- PC World
- TIME Magazine
- Associated Press
new recipes:
- title: Yazihane
author: A Erdogan
- version: 0.9.3 - version: 0.9.3
date: 2012-10-19 date: 2012-10-19

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

BIN
manual/images/sg_pref.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

View File

@ -65,7 +65,7 @@ You create the custom column in the usual way, using Preferences -> Add your own
Then after restarting |app|, you must tell |app| that the column is to be treated as a hierarchy. Go to Preferences -> Look and Feel -> Tag Browser and enter the lookup name "#genre" into the "Categories with hierarchical items" box. Press Apply, and you are done with setting up. Then after restarting |app|, you must tell |app| that the column is to be treated as a hierarchy. Go to Preferences -> Look and Feel -> Tag Browser and enter the lookup name "#genre" into the "Categories with hierarchical items" box. Press Apply, and you are done with setting up.
.. image:: images/sg_pref.jpg .. image:: images/sg_pref.png
:align: center :align: center
At the point there are no genres in the column. We are left with the last step: how to apply a genre to a book. A genre does not exist in |app| until it appears on at least one book. To learn how to apply a genre for the first time, we must go into some detail about what a genre looks like in the metadata for a book. At the point there are no genres in the column. We are left with the last step: how to apply a genre to a book. A genre does not exist in |app| until it appears on at least one book. To learn how to apply a genre for the first time, we must go into some detail about what a genre looks like in the metadata for a book.

View File

@ -38,8 +38,10 @@ class TheAtlantic(BasicNewsRecipe):
self.timefmt = ' [%s]'%ds self.timefmt = ' [%s]'%ds
cover = soup.find('img', src=True, attrs={'class':'cover'}) cover = soup.find('img', src=True, attrs={'class':'cover'})
if cover is not None: if cover is not None:
self.cover_url = cover['src'].replace(' ', '%20') self.cover_url = re.sub('\s','%20',re.sub('jpg.*','jpg',cover['src']))
self.log(self.cover_url)
feeds = [] feeds = []
seen_titles = set([]) seen_titles = set([])
@ -47,18 +49,16 @@ class TheAtlantic(BasicNewsRecipe):
section_title = self.tag_to_string(section.find('h2')) section_title = self.tag_to_string(section.find('h2'))
self.log('Found section:', section_title) self.log('Found section:', section_title)
articles = [] articles = []
for post in section.findAll('div', attrs={'class':lambda x : x and for post in section.findAll('h3', attrs={'class':'headline'}):
'post' in x}): a = post.find('a', href=True)
h = post.find(['h3', 'h4']) title = self.tag_to_string(a)
title = self.tag_to_string(h)
if title in seen_titles: if title in seen_titles:
continue continue
seen_titles.add(title) seen_titles.add(title)
a = post.find('a', href=True)
url = a['href'] url = a['href']
if url.startswith('/'): if url.startswith('/'):
url = 'http://www.theatlantic.com'+url url = 'http://www.theatlantic.com'+url
p = post.find('p', attrs={'class':'dek'}) p = post.parent.find('p', attrs={'class':'dek'})
desc = None desc = None
self.log('\tFound article:', title, 'at', url) self.log('\tFound article:', title, 'at', url)
if p is not None: if p is not None:
@ -69,19 +69,29 @@ class TheAtlantic(BasicNewsRecipe):
if articles: if articles:
feeds.append((section_title, articles)) feeds.append((section_title, articles))
poems = [] rightContent=soup.find('div', attrs = {'class':'rightContent'})
self.log('Found section: Poems') for module in rightContent.findAll('div', attrs={'class':'module'}):
pd = soup.find('h2', text='Poetry').parent.parent section_title = self.tag_to_string(module.find('h2'))
for poem in pd.findAll('h4'): articles = []
title = self.tag_to_string(poem) for post in module.findAll('div', attrs={'class':'post'}):
url = poem.find('a')['href'] a = post.find('a', href=True)
if url.startswith('/'): title = self.tag_to_string(a)
url = 'http://www.theatlantic.com' + url if title in seen_titles:
self.log('\tFound article:', title, 'at', url) continue
poems.append({'title':title, 'url':url, 'description':'', seen_titles.add(title)
'date':''}) url = a['href']
if poems: if url.startswith('/'):
feeds.append(('Poems', poems)) url = 'http://www.theatlantic.com'+url
p = post.parent.find('p', attrs={'class':'dek'})
desc = None
self.log('\tFound article:', title, 'at', url)
if p is not None:
desc = self.tag_to_string(p)
self.log('\t\t', desc)
articles.append({'title':title, 'url':url, 'description':desc, 'date':''})
if articles:
feeds.append((section_title, articles))
return feeds return feeds
@ -100,4 +110,3 @@ class TheAtlantic(BasicNewsRecipe):
table.replaceWith(div) table.replaceWith(div)
return soup return soup

View File

@ -1,5 +1,5 @@
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2010-2012, Darko Miletic <darko.miletic at gmail.com>' __copyright__ = '2010-2011, Darko Miletic <darko.miletic at gmail.com>'
''' '''
www.ft.com/uk-edition www.ft.com/uk-edition
''' '''
@ -42,24 +42,18 @@ class FinancialTimes(BasicNewsRecipe):
def get_browser(self): def get_browser(self):
br = BasicNewsRecipe.get_browser() br = BasicNewsRecipe.get_browser()
br.open(self.INDEX) br.open(self.INDEX)
if self.username is not None and self.password is not None: br.open(self.LOGIN)
br.open(self.LOGIN2) br.select_form(name='loginForm')
br.select_form(name='loginForm') br['username'] = self.username
br['username'] = self.username br['password'] = self.password
br['password'] = self.password br.submit()
br.submit()
return br return br
keep_only_tags = [ keep_only_tags = [
dict(name='div' , attrs={'class':['fullstory fullstoryHeader', 'ft-story-header']}) dict(name='div', attrs={'class':['fullstory fullstoryHeader', 'ft-story-header']})
,dict(name='div' , attrs={'class':'standfirst'}) ,dict(name='div', attrs={'class':'standfirst'})
,dict(name='div' , attrs={'id' :'storyContent'}) ,dict(name='div', attrs={'id' :'storyContent'})
,dict(name='div' , attrs={'class':['ft-story-body','index-detail']}) ,dict(name='div', attrs={'class':['ft-story-body','index-detail']})
,dict(name='div' , attrs={'class':['ft-story-body','index-detail']})
,dict(name='h2' , attrs={'class':'entry-title'} )
,dict(name='span', attrs={'class':lambda x: x and 'posted-on' in x.split()} )
,dict(name='span', attrs={'class':'author_byline'} )
,dict(name='div' , attrs={'class':'entry-content'} )
] ]
remove_tags = [ remove_tags = [
dict(name='div', attrs={'id':'floating-con'}) dict(name='div', attrs={'id':'floating-con'})
@ -88,17 +82,21 @@ class FinancialTimes(BasicNewsRecipe):
if self.test and count > 2: if self.test and count > 2:
return articles return articles
rawlink = item['href'] rawlink = item['href']
url = rawlink if rawlink.startswith('http://'):
if not rawlink.startswith('http://'): url = rawlink
url = self.PREFIX + rawlink else:
urlverified = self.browser.open_novisit(url).geturl() # resolve redirect. url = self.PREFIX + rawlink
try:
urlverified = self.browser.open_novisit(url).geturl() # resolve redirect.
except:
continue
title = self.tag_to_string(item) title = self.tag_to_string(item)
date = strftime(self.timefmt) date = strftime(self.timefmt)
articles.append({ articles.append({
'title' :title 'title' :title
,'date' :date ,'date' :date
,'url' :urlverified ,'url' :urlverified
,'description':'' ,'description':''
}) })
return articles return articles
@ -110,20 +108,21 @@ class FinancialTimes(BasicNewsRecipe):
wide = soup.find('div',attrs={'class':'wide'}) wide = soup.find('div',attrs={'class':'wide'})
if not wide: if not wide:
return feeds return feeds
allsections = wide.findAll(attrs={'class':lambda x: x and 'footwell' in x.split()}) strest = wide.findAll('h3', attrs={'class':'section'})
if not allsections: if not strest:
return feeds return feeds
st = wide.findAll('h4',attrs={'class':'section-no-arrow'})
if st:
st.extend(strest)
count = 0 count = 0
for item in allsections: for item in st:
count = count + 1 count = count + 1
if self.test and count > 2: if self.test and count > 2:
return feeds return feeds
fitem = item.h3 ftitle = self.tag_to_string(item)
if not fitem:
fitem = item.h4
ftitle = self.tag_to_string(fitem)
self.report_progress(0, _('Fetching feed')+' %s...'%(ftitle)) self.report_progress(0, _('Fetching feed')+' %s...'%(ftitle))
feedarts = self.get_artlinks(item.ul) if item.parent.ul is not None:
feedarts = self.get_artlinks(item.parent.ul)
feeds.append((ftitle,feedarts)) feeds.append((ftitle,feedarts))
return feeds return feeds
@ -157,7 +156,7 @@ class FinancialTimes(BasicNewsRecipe):
def get_cover_url(self): def get_cover_url(self):
cdate = datetime.date.today() cdate = datetime.date.today()
if cdate.isoweekday() == 7: if cdate.isoweekday() == 7:
cdate -= datetime.timedelta(days=1) cdate -= datetime.timedelta(days=1)
return cdate.strftime('http://specials.ft.com/vtf_pdf/%d%m%y_FRONT1_LON.pdf') return cdate.strftime('http://specials.ft.com/vtf_pdf/%d%m%y_FRONT1_LON.pdf')
def get_obfuscated_article(self, url): def get_obfuscated_article(self, url):
@ -170,8 +169,10 @@ class FinancialTimes(BasicNewsRecipe):
except: except:
print "Retrying download..." print "Retrying download..."
count += 1 count += 1
tfile = PersistentTemporaryFile('_fa.html') self.temp_files.append(PersistentTemporaryFile('_fa.html'))
tfile.write(html) self.temp_files[-1].write(html)
tfile.close() self.temp_files[-1].close()
self.temp_files.append(tfile) return self.temp_files[-1].name
return tfile.name
def cleanup(self):
self.browser.open('https://registration.ft.com/registration/login/logout?location=')

View File

@ -1,5 +1,4 @@
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
from calibre.ebooks.BeautifulSoup import BeautifulSoup
class NewYorkTimesBookReview(BasicNewsRecipe): class NewYorkTimesBookReview(BasicNewsRecipe):
title = u'New York Times Book Review' title = u'New York Times Book Review'
@ -7,50 +6,16 @@ class NewYorkTimesBookReview(BasicNewsRecipe):
__author__ = 'Krittika Goyal' __author__ = 'Krittika Goyal'
oldest_article = 8 #days oldest_article = 8 #days
max_articles_per_feed = 1000 max_articles_per_feed = 1000
recursions = 2 #recursions = 2
#encoding = 'latin1' #encoding = 'latin1'
use_embedded_content = False
no_stylesheets = True
auto_cleanup = True
remove_stylesheets = True
#remove_tags_before = dict(name='h1', attrs={'class':'heading'})
remove_tags_after = dict(name='div', attrs={'id':'authorId'})
remove_tags = [
dict(name='iframe'),
dict(name=['div', 'a'], attrs={'class':['enlargeThis', 'jumpLink']}),
dict(name='div', attrs={'id':['sidebarArticles', 'toolsRight']}),
#dict(name='ul', attrs={'class':'article-tools'}),
#dict(name='ul', attrs={'class':'articleTools'}),
]
match_regexps = [
r'http://www.nytimes.com/.+pagewanted=[2-9]+'
]
feeds = [ feeds = [
('New York Times Sunday Book Review', ('New York Times Sunday Book Review',
'http://feeds.nytimes.com/nyt/rss/SundayBookReview'), 'http://feeds.nytimes.com/nyt/rss/SundayBookReview'),
] ]
def preprocess_html(self, soup):
story = soup.find(name='div', attrs={'id':'article'})
#td = heading.findParent(name='td')
#td.extract()
soup = BeautifulSoup('<html><head><title>t</title></head><body></body></html>')
body = soup.find(name='body')
body.insert(0, story)
#for x in soup.findAll(name='p', text=lambda x:x and '--&gt;' in x):
#p = x.findParent('p')
#if p is not None:
#p.extract()
return soup
def postprocess_html(self, soup, first):
for div in soup.findAll(id='pageLinks'):
div.extract()
if not first:
h1 = soup.find('h1')
if h1 is not None:
h1.extract()
t = soup.find(attrs={'class':'timestamp'})
if t is not None:
t.extract()
return soup

View File

@ -4,7 +4,7 @@ __license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net' __copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
__appname__ = u'calibre' __appname__ = u'calibre'
numeric_version = (0, 9, 3) numeric_version = (0, 9, 4)
__version__ = u'.'.join(map(unicode, numeric_version)) __version__ = u'.'.join(map(unicode, numeric_version))
__author__ = u"Kovid Goyal <kovid@kovidgoyal.net>" __author__ = u"Kovid Goyal <kovid@kovidgoyal.net>"

View File

@ -184,6 +184,11 @@ class CSSFlattener(object):
faces = fontconfig.fonts_for_family(family) faces = fontconfig.fonts_for_family(family)
if not faces or not u'normal' in faces: if not faces or not u'normal' in faces:
msg = (u'No embeddable fonts found for family: %r'%self.opts.embed_font_family) msg = (u'No embeddable fonts found for family: %r'%self.opts.embed_font_family)
if faces:
msg = (u'The selected font %s has no Regular typeface, only'
' %s faces, it cannot be used.')%(
self.opts.embed_font_family,
', '.join(faces.iterkeys()))
if failure_critical: if failure_critical:
raise ValueError(msg) raise ValueError(msg)
self.oeb.log.warn(msg) self.oeb.log.warn(msg)

View File

@ -504,7 +504,11 @@ from the value in the box</string>
<item> <item>
<widget class="QCheckBox" name="restore_original"> <widget class="QCheckBox" name="restore_original">
<property name="toolTip"> <property name="toolTip">
<string>When doing a same format to same format conversion, for e.g., EPUB to EPUB, calibre saves the original EPUB as ORIGINAL_EPUB. This option tells calibre to restore the EPUB from ORIGINAL_EPUB. Useful if you did a bulk conversion of a large number of books and something went wrong.</string> <string>When doing a same format to same format conversion,
for e.g., EPUB to EPUB, calibre saves the original EPUB
as ORIGINAL_EPUB. This option tells calibre to restore
the EPUB from ORIGINAL_EPUB. Useful if you did a bulk
conversion of a large number of books and something went wrong.</string>
</property> </property>
<property name="text"> <property name="text">
<string>Restore pre conversion &amp;originals, if available</string> <string>Restore pre conversion &amp;originals, if available</string>

View File

@ -13,6 +13,7 @@ from PyQt4.Qt import (QFontInfo, QFontMetrics, Qt, QFont, QFontDatabase, QPen,
QToolButton, QGridLayout, QListView, QWidget, QDialogButtonBox, QIcon, QToolButton, QGridLayout, QListView, QWidget, QDialogButtonBox, QIcon,
QHBoxLayout, QLabel, QModelIndex) QHBoxLayout, QLabel, QModelIndex)
from calibre.gui2 import error_dialog
from calibre.utils.icu import sort_key from calibre.utils.icu import sort_key
def writing_system_for_font(font): def writing_system_for_font(font):
@ -173,6 +174,20 @@ class FontFamilyDialog(QDialog):
if idx == 0: return None if idx == 0: return None
return self.families[idx] return self.families[idx]
def accept(self):
ff = self.font_family
if ff:
from calibre.utils.fonts import fontconfig
faces = fontconfig.fonts_for_family(ff) or {}
faces = frozenset(faces.iterkeys())
if 'normal' not in faces:
error_dialog(self, _('Not a useable font'),
_('The %s font family does not have a Regular typeface, so it'
' cannot be used. It has only the "%s" face(s).')%(
ff, ', '.join(faces)), show=True)
return
QDialog.accept(self)
class FontFamilyChooser(QWidget): class FontFamilyChooser(QWidget):
family_changed = pyqtSignal(object) family_changed = pyqtSignal(object)

View File

@ -646,12 +646,13 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
spath = os.path.join(self.library_path, *current_path.split('/')) spath = os.path.join(self.library_path, *current_path.split('/'))
tpath = os.path.join(self.library_path, *path.split('/')) tpath = os.path.join(self.library_path, *path.split('/'))
wam = WindowsAtomicFolderMove(spath) if iswindows and current_path else None source_ok = current_path and os.path.exists(spath)
wam = WindowsAtomicFolderMove(spath) if iswindows and source_ok else None
try: try:
if not os.path.exists(tpath): if not os.path.exists(tpath):
os.makedirs(tpath) os.makedirs(tpath)
if current_path and os.path.exists(spath): # Migrate existing files if source_ok: # Migrate existing files
self.copy_cover_to(id, os.path.join(tpath, 'cover.jpg'), self.copy_cover_to(id, os.path.join(tpath, 'cover.jpg'),
index_is_id=True, windows_atomic_move=wam, index_is_id=True, windows_atomic_move=wam,
use_hardlink=True) use_hardlink=True)
@ -669,7 +670,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
self.conn.commit() self.conn.commit()
self.data.set(id, self.FIELD_MAP['path'], path, row_is_id=True) self.data.set(id, self.FIELD_MAP['path'], path, row_is_id=True)
# Delete not needed directories # Delete not needed directories
if current_path and os.path.exists(spath): if source_ok:
if not samefile(spath, tpath): if not samefile(spath, tpath):
if wam is not None: if wam is not None:
wam.delete_originals() wam.delete_originals()
@ -1432,7 +1433,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
if use_hardlink: if use_hardlink:
try: try:
hardlink_file(path, dest) hardlink_file(path, dest)
return return True
except: except:
pass pass
with lopen(dest, 'wb') as d: with lopen(dest, 'wb') as d:

View File

@ -4,9 +4,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: calibre 0.9.3\n" "Project-Id-Version: calibre 0.9.4\n"
"POT-Creation-Date: 2012-10-24 09:36+IST\n" "POT-Creation-Date: 2012-10-26 09:57+IST\n"
"PO-Revision-Date: 2012-10-24 09:36+IST\n" "PO-Revision-Date: 2012-10-26 09:57+IST\n"
"Last-Translator: Automatically generated\n" "Last-Translator: Automatically generated\n"
"Language-Team: LANGUAGE\n" "Language-Team: LANGUAGE\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
@ -173,12 +173,12 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/library/database2.py:586 #: /home/kovid/work/calibre/src/calibre/library/database2.py:586
#: /home/kovid/work/calibre/src/calibre/library/database2.py:594 #: /home/kovid/work/calibre/src/calibre/library/database2.py:594
#: /home/kovid/work/calibre/src/calibre/library/database2.py:605 #: /home/kovid/work/calibre/src/calibre/library/database2.py:605
#: /home/kovid/work/calibre/src/calibre/library/database2.py:2273 #: /home/kovid/work/calibre/src/calibre/library/database2.py:2274
#: /home/kovid/work/calibre/src/calibre/library/database2.py:2427 #: /home/kovid/work/calibre/src/calibre/library/database2.py:2428
#: /home/kovid/work/calibre/src/calibre/library/database2.py:2857 #: /home/kovid/work/calibre/src/calibre/library/database2.py:2858
#: /home/kovid/work/calibre/src/calibre/library/database2.py:3504 #: /home/kovid/work/calibre/src/calibre/library/database2.py:3505
#: /home/kovid/work/calibre/src/calibre/library/database2.py:3506 #: /home/kovid/work/calibre/src/calibre/library/database2.py:3507
#: /home/kovid/work/calibre/src/calibre/library/database2.py:3643 #: /home/kovid/work/calibre/src/calibre/library/database2.py:3644
#: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250
#: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251
#: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247
@ -882,26 +882,26 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:666
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:67
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:668
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061 #: /home/kovid/work/calibre/src/calibre/library/database2.py:1062
#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:887
#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:910
msgid "Yes" msgid "Yes"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/db/fields.py:163 #: /home/kovid/work/calibre/src/calibre/db/fields.py:163
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216 #: /home/kovid/work/calibre/src/calibre/library/database2.py:1217
msgid "Main" msgid "Main"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/db/fields.py:165 #: /home/kovid/work/calibre/src/calibre/db/fields.py:165
#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:77
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1218 #: /home/kovid/work/calibre/src/calibre/library/database2.py:1219
msgid "Card A" msgid "Card A"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/db/fields.py:167 #: /home/kovid/work/calibre/src/calibre/db/fields.py:167
#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:79
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1220 #: /home/kovid/work/calibre/src/calibre/library/database2.py:1221
msgid "Card B" msgid "Card B"
msgstr "" msgstr ""
@ -1048,14 +1048,14 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199
#: /home/kovid/work/calibre/src/calibre/library/database2.py:371 #: /home/kovid/work/calibre/src/calibre/library/database2.py:371
#: /home/kovid/work/calibre/src/calibre/library/database2.py:384 #: /home/kovid/work/calibre/src/calibre/library/database2.py:384
#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 #: /home/kovid/work/calibre/src/calibre/library/database2.py:3362
#: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187
msgid "News" msgid "News"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770
#: /home/kovid/work/calibre/src/calibre/library/database2.py:3317 #: /home/kovid/work/calibre/src/calibre/library/database2.py:3318
#: /home/kovid/work/calibre/src/calibre/library/database2.py:3335 #: /home/kovid/work/calibre/src/calibre/library/database2.py:3336
msgid "Catalog" msgid "Catalog"
msgstr "" msgstr ""
@ -1099,10 +1099,10 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:128
#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:131
#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:348
#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1307
#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1311
#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1315
#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1635 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1319
#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1323
#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:1642
#: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:155
#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:144
#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:147
@ -11001,6 +11001,10 @@ msgstr ""
msgid "Choose &font family" msgid "Choose &font family"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/font_family_chooser.py:196
msgid "Clear the font family"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/init.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/init.py:108
#: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:296
msgid "Cover Browser" msgid "Cover Browser"
@ -12216,7 +12220,7 @@ msgstr ""
msgid "" msgid ""
"If set, this option will causes calibre to check if a file\n" "If set, this option will causes calibre to check if a file\n"
" being auto-added is already in the calibre library.\n" " being auto-added is already in the calibre library.\n"
" If it is, a meesage will pop up asking you whether\n" " If it is, a message will pop up asking you whether\n"
" you want to add it anyway." " you want to add it anyway."
msgstr "" msgstr ""
@ -15287,7 +15291,7 @@ msgid "Options to customize the ebook viewer"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config.py:30
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1106 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1107
msgid "Remember last used window size" msgid "Remember last used window size"
msgstr "" msgstr ""
@ -15854,35 +15858,35 @@ msgstr ""
msgid "Loading ebook..." msgid "Loading ebook..."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:977 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978
msgid "Could not open ebook" msgid "Could not open ebook"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:978 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:979
msgid "Unknown error" msgid "Unknown error"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1093 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1094
msgid "Options to control the ebook viewer" msgid "Options to control the ebook viewer"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1100 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1101
msgid "If specified, viewer window will try to come to the front when started." msgid "If specified, viewer window will try to come to the front when started."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1103 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1104
msgid "If specified, viewer window will try to open full screen when started." msgid "If specified, viewer window will try to open full screen when started."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1108 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1109
msgid "Print javascript alert and console messages to the console" msgid "Print javascript alert and console messages to the console"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1110 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1111
msgid "The position at which to open the specified book. The position is a location as displayed in the top left corner of the viewer." msgid "The position at which to open the specified book. The position is a location as displayed in the top left corner of the viewer."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1117 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1118
msgid "" msgid ""
"%prog [options] file\n" "%prog [options] file\n"
"\n" "\n"
@ -17358,17 +17362,17 @@ msgstr ""
msgid "creating custom column " msgid "creating custom column "
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/library/database2.py:3669 #: /home/kovid/work/calibre/src/calibre/library/database2.py:3670
#, python-format #, python-format
msgid "<p>Migrating old database to ebook library in %s<br><center>" msgid "<p>Migrating old database to ebook library in %s<br><center>"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/library/database2.py:3698 #: /home/kovid/work/calibre/src/calibre/library/database2.py:3699
#, python-format #, python-format
msgid "Copying <b>%s</b>" msgid "Copying <b>%s</b>"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/library/database2.py:3715 #: /home/kovid/work/calibre/src/calibre/library/database2.py:3716
msgid "Compacting database" msgid "Compacting database"
msgstr "" msgstr ""

View File

@ -314,6 +314,17 @@ class WindowsAtomicFolderMove(object):
break break
f.write(raw) f.write(raw)
def release_file(self, path):
key = None
for p, h in self.handle_map.iteritems():
if samefile_windows(path, p):
key = (p, h)
break
if key is not None:
import win32file
win32file.CloseHandle(key[1])
self.handle_map.pop(key[0])
def close_handles(self): def close_handles(self):
import win32file import win32file
for h in self.handle_map.itervalues(): for h in self.handle_map.itervalues():