mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
sync with Kovid's branch
This commit is contained in:
commit
9fa0715276
@ -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
BIN
manual/images/sg_pref.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 70 KiB |
@ -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.
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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=')
|
||||||
|
@ -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 '-->' 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
|
|
||||||
|
@ -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>"
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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 &originals, if available</string>
|
<string>Restore pre conversion &originals, if available</string>
|
||||||
|
@ -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)
|
||||||
|
@ -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:
|
||||||
|
@ -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 ""
|
||||||
|
|
||||||
|
@ -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():
|
||||||
|
Loading…
x
Reference in New Issue
Block a user