mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-23 15:30:45 -04:00
0.9.20+ - fixed EPUB to PDF problem when rendering from catalog
This commit is contained in:
commit
72d0301a7c
@ -616,7 +616,10 @@ or a Remote Desktop solution.
|
|||||||
If you must share the actual library, use a file syncing tool like
|
If you must share the actual library, use a file syncing tool like
|
||||||
DropBox or rsync or Microsoft SkyDrive instead of a networked drive. Even with
|
DropBox or rsync or Microsoft SkyDrive instead of a networked drive. Even with
|
||||||
these tools there is danger of data corruption/loss, so only do this if you are
|
these tools there is danger of data corruption/loss, so only do this if you are
|
||||||
willing to live with that risk.
|
willing to live with that risk. In particular, be aware that **Google Drive**
|
||||||
|
is incompatible with |app|, if you put your |app| library in Google Drive, you
|
||||||
|
*will* suffer data loss. See
|
||||||
|
`this thread <http://www.mobileread.com/forums/showthread.php?t=205581>`_ for details.
|
||||||
|
|
||||||
Content From The Web
|
Content From The Web
|
||||||
---------------------
|
---------------------
|
||||||
|
27
recipes/democracy_journal.recipe
Normal file
27
recipes/democracy_journal.recipe
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
import re
|
||||||
|
|
||||||
|
class AdvancedUserRecipe1361743898(BasicNewsRecipe):
|
||||||
|
title = u'Democracy Journal'
|
||||||
|
description = '''A journal of ideas. Published quarterly.'''
|
||||||
|
__author__ = u'David Nye'
|
||||||
|
language = 'en'
|
||||||
|
oldest_article = 90
|
||||||
|
max_articles_per_feed = 30
|
||||||
|
no_stylesheets = True
|
||||||
|
auto_cleanup = True
|
||||||
|
|
||||||
|
def parse_index(self):
|
||||||
|
articles = []
|
||||||
|
feeds = []
|
||||||
|
soup = self.index_to_soup("http://www.democracyjournal.org")
|
||||||
|
for x in soup.findAll(href=re.compile("http://www\.democracyjournal\.org/\d*/.*php$")):
|
||||||
|
url = x.get('href')
|
||||||
|
title = self.tag_to_string(x)
|
||||||
|
articles.append({'title':title, 'url':url, 'description':'', 'date':''})
|
||||||
|
feeds.append(('Articles', articles))
|
||||||
|
return feeds
|
||||||
|
|
||||||
|
def print_version(self, url):
|
||||||
|
return url + '?page=all'
|
||||||
|
|
27
recipes/el_malpensante.recipe
Normal file
27
recipes/el_malpensante.recipe
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# coding=utf-8
|
||||||
|
# https://github.com/iemejia/calibrecolombia
|
||||||
|
|
||||||
|
'''
|
||||||
|
http://www.elmalpensante.com/
|
||||||
|
'''
|
||||||
|
|
||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
|
class ElMalpensante(BasicNewsRecipe):
|
||||||
|
title = u'El Malpensante'
|
||||||
|
language = 'es_CO'
|
||||||
|
__author__ = 'Ismael Mejia <iemejia@gmail.com>'
|
||||||
|
cover_url = 'http://elmalpensante.com/img/layout/logo.gif'
|
||||||
|
description = 'El Malpensante'
|
||||||
|
oldest_article = 30
|
||||||
|
simultaneous_downloads = 20
|
||||||
|
#tags = 'news, sport, blog'
|
||||||
|
use_embedded_content = True
|
||||||
|
remove_empty_feeds = True
|
||||||
|
max_articles_per_feed = 100
|
||||||
|
feeds = [(u'Artículos', u'http://www.elmalpensante.com/articulosRSS.php'),
|
||||||
|
(u'Malpensantías', u'http://www.elmalpensante.com/malpensantiasRSS.php'),
|
||||||
|
(u'Margaritas', u'http://www.elmalpensante.com/margaritasRSS.php'),
|
||||||
|
# This one is almost the same as articulos so we leave articles
|
||||||
|
# (u'Noticias', u'http://www.elmalpensante.com/noticiasRSS.php'),
|
||||||
|
]
|
12
recipes/geopolityka.recipe
Normal file
12
recipes/geopolityka.recipe
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
|
class BasicUserRecipe1361379046(BasicNewsRecipe):
|
||||||
|
title = u'Geopolityka.org'
|
||||||
|
language = 'pl'
|
||||||
|
__author__ = 'chemik111'
|
||||||
|
oldest_article = 15
|
||||||
|
max_articles_per_feed = 100
|
||||||
|
auto_cleanup = True
|
||||||
|
|
||||||
|
feeds = [(u'Rss', u'http://geopolityka.org/index.php?format=feed&type=rss')]
|
||||||
|
|
68
recipes/hnonline.recipe
Normal file
68
recipes/hnonline.recipe
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
import re
|
||||||
|
|
||||||
|
class HNonlineRecipe(BasicNewsRecipe):
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__author__ = 'lacike'
|
||||||
|
language = 'sk'
|
||||||
|
version = 1
|
||||||
|
|
||||||
|
title = u'HNonline'
|
||||||
|
publisher = u'HNonline'
|
||||||
|
category = u'News, Newspaper'
|
||||||
|
description = u'News from Slovakia'
|
||||||
|
cover_url = u'http://hnonline.sk/img/sk/_relaunch/logo2.png'
|
||||||
|
|
||||||
|
oldest_article = 1
|
||||||
|
max_articles_per_feed = 100
|
||||||
|
use_embedded_content = False
|
||||||
|
remove_empty_feeds = True
|
||||||
|
|
||||||
|
no_stylesheets = True
|
||||||
|
remove_javascript = True
|
||||||
|
|
||||||
|
# Feeds from: http://rss.hnonline.sk, for listing see http://rss.hnonline.sk/prehlad
|
||||||
|
feeds = []
|
||||||
|
feeds.append((u'HNonline|Ekonomika a firmy', u'http://rss.hnonline.sk/?p=kC1000'))
|
||||||
|
feeds.append((u'HNonline|Slovensko', u'http://rss.hnonline.sk/?p=kC2000'))
|
||||||
|
feeds.append((u'HNonline|Svet', u'http://rss.hnonline.sk/?p=kC3000'))
|
||||||
|
feeds.append((u'HNonline|\u0160port', u'http://rss.hnonline.sk/?p=kC4000'))
|
||||||
|
feeds.append((u'HNonline|Online rozhovor', u'http://rss.hnonline.sk/?p=kCR000'))
|
||||||
|
|
||||||
|
feeds.append((u'FinWeb|Spr\u00E1vy zo sveta financi\u00ED', u'http://rss.finweb.hnonline.sk/spravodajstvo'))
|
||||||
|
feeds.append((u'FinWeb|Koment\u00E1re a anal\u00FDzy', u'http://rss.finweb.hnonline.sk/?p=kPC200'))
|
||||||
|
feeds.append((u'FinWeb|Invest\u00EDcie', u'http://rss.finweb.hnonline.sk/?p=kPC300'))
|
||||||
|
feeds.append((u'FinWeb|Svet akci\u00ED', u'http://rss.finweb.hnonline.sk/?p=kPC400'))
|
||||||
|
feeds.append((u'FinWeb|Rozhovory', u'http://rss.finweb.hnonline.sk/?p=kPC500'))
|
||||||
|
feeds.append((u'FinWeb|T\u00E9ma t\u00FD\u017Ed\u0148a', u'http://rss.finweb.hnonline.sk/?p=kPC600'))
|
||||||
|
feeds.append((u'FinWeb|Rebr\u00ED\u010Dky', u'http://rss.finweb.hnonline.sk/?p=kPC700'))
|
||||||
|
|
||||||
|
feeds.append((u'HNstyle|Kult\u00FAra', u'http://style.hnonline.sk/?p=kTC100'))
|
||||||
|
feeds.append((u'HNstyle|Auto-moto', u'http://style.hnonline.sk/?p=kTC200'))
|
||||||
|
feeds.append((u'HNstyle|Digit\u00E1l', u'http://style.hnonline.sk/?p=kTC300'))
|
||||||
|
feeds.append((u'HNstyle|Veda', u'http://style.hnonline.sk/?p=kTCV00'))
|
||||||
|
feeds.append((u'HNstyle|Dizajn', u'http://style.hnonline.sk/?p=kTC400'))
|
||||||
|
feeds.append((u'HNstyle|Cestovanie', u'http://style.hnonline.sk/?p=kTCc00'))
|
||||||
|
feeds.append((u'HNstyle|V\u00EDkend', u'http://style.hnonline.sk/?p=kTC800'))
|
||||||
|
feeds.append((u'HNstyle|Gastro', u'http://style.hnonline.sk/?p=kTC600'))
|
||||||
|
feeds.append((u'HNstyle|M\u00F3da', u'http://style.hnonline.sk/?p=kTC700'))
|
||||||
|
feeds.append((u'HNstyle|Modern\u00E1 \u017Eena', u'http://style.hnonline.sk/?p=kTCA00'))
|
||||||
|
feeds.append((u'HNstyle|Pre\u010Do nie?!', u'http://style.hnonline.sk/?p=k7C000'))
|
||||||
|
|
||||||
|
keep_only_tags = []
|
||||||
|
keep_only_tags.append(dict(name = 'h1', attrs = {'class': 'detail-titulek'}))
|
||||||
|
keep_only_tags.append(dict(name = 'div', attrs = {'class': 'detail-podtitulek'}))
|
||||||
|
keep_only_tags.append(dict(name = 'div', attrs = {'class': 'detail-perex'}))
|
||||||
|
keep_only_tags.append(dict(name = 'div', attrs = {'class': 'detail-text'}))
|
||||||
|
|
||||||
|
remove_tags = []
|
||||||
|
#remove_tags.append(dict(name = 'div', attrs = {'id': re.compile('smeplayer.*')}))
|
||||||
|
|
||||||
|
remove_tags_after = []
|
||||||
|
#remove_tags_after = [dict(name = 'p', attrs = {'class': 'autor_line'})]
|
||||||
|
|
||||||
|
extra_css = '''
|
||||||
|
@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)}
|
||||||
|
@font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/LiberationSans.ttf)}
|
||||||
|
body {font-family: sans1, serif1;}
|
||||||
|
'''
|
BIN
recipes/icons/hnonline.png
Normal file
BIN
recipes/icons/hnonline.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.5 KiB |
BIN
recipes/icons/nezavisne_novine.png
Normal file
BIN
recipes/icons/nezavisne_novine.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 454 B |
59
recipes/nezavisne_novine.recipe
Normal file
59
recipes/nezavisne_novine.recipe
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2013, Darko Miletic <darko.miletic at gmail.com>'
|
||||||
|
'''
|
||||||
|
www.nezavisne.com
|
||||||
|
'''
|
||||||
|
from calibre import strftime
|
||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
|
class NezavisneNovine(BasicNewsRecipe):
|
||||||
|
title = 'Nezavisne novine'
|
||||||
|
__author__ = 'Darko Miletic'
|
||||||
|
description = 'Nezavisne novine - Najnovije vijesti iz BiH, Srbije, Hrvatske, Crne Gore i svijeta'
|
||||||
|
publisher = 'NIGP "DNN"'
|
||||||
|
category = 'news, politics, Bosnia, Balcans'
|
||||||
|
oldest_article = 2
|
||||||
|
max_articles_per_feed = 200
|
||||||
|
no_stylesheets = True
|
||||||
|
encoding = 'utf8'
|
||||||
|
use_embedded_content = False
|
||||||
|
language = 'sr'
|
||||||
|
remove_empty_feeds = True
|
||||||
|
publication_type = 'newspaper'
|
||||||
|
cover_url = strftime('http://pdf.nezavisne.com/slika/novina/nezavisne_novine.jpg?v=%Y%m%d')
|
||||||
|
masthead_url = 'http://www.nezavisne.com/slika/osnova/nezavisne-novine-logo.gif'
|
||||||
|
extra_css = """
|
||||||
|
body{font-family: Arial,Helvetica,sans-serif }
|
||||||
|
img{margin-bottom: 0.4em; display:block}
|
||||||
|
"""
|
||||||
|
|
||||||
|
conversion_options = {
|
||||||
|
'comment' : description
|
||||||
|
, 'tags' : category
|
||||||
|
, 'publisher' : publisher
|
||||||
|
, 'language' : language
|
||||||
|
}
|
||||||
|
keep_only_tags = [dict(name='div', attrs={'class':'vijest'})]
|
||||||
|
remove_tags_after = dict(name='div', attrs={'id':'wrap'})
|
||||||
|
remove_tags = [
|
||||||
|
dict(name=['meta','link','iframe','object'])
|
||||||
|
,dict(name='div', attrs={'id':'wrap'})
|
||||||
|
]
|
||||||
|
remove_attributes=['lang','xmlns:fb','xmlns:og']
|
||||||
|
|
||||||
|
|
||||||
|
feeds = [
|
||||||
|
(u'Novosti' , u'http://feeds.feedburner.com/Novosti-NezavisneNovine' )
|
||||||
|
,(u'Posao' , u'http://feeds.feedburner.com/Posao-NezavisneNovine' )
|
||||||
|
,(u'Sport' , u'http://feeds.feedburner.com/Sport-NezavisneNovine' )
|
||||||
|
,(u'Komentar' , u'http://feeds.feedburner.com/Komentari-NezavisneNovine' )
|
||||||
|
,(u'Umjetnost i zabava' , u'http://feeds.feedburner.com/UmjetnostIZabava-NezavisneNovine' )
|
||||||
|
,(u'Život i stil' , u'http://feeds.feedburner.com/ZivotIStil-NezavisneNovine' )
|
||||||
|
,(u'Auto' , u'http://feeds.feedburner.com/Auto-NezavisneNovine' )
|
||||||
|
,(u'Nauka i tehnologija', u'http://feeds.feedburner.com/NaukaITehnologija-NezavisneNovine')
|
||||||
|
]
|
||||||
|
|
||||||
|
def preprocess_html(self, soup):
|
||||||
|
for item in soup.findAll(style=True):
|
||||||
|
del item['style']
|
||||||
|
return soup
|
33
recipes/revista_cromos.recipe
Normal file
33
recipes/revista_cromos.recipe
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# coding=utf-8
|
||||||
|
# https://github.com/iemejia/calibrecolombia
|
||||||
|
|
||||||
|
'''
|
||||||
|
http://www.cromos.com.co/
|
||||||
|
'''
|
||||||
|
|
||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
|
class ElMalpensante(BasicNewsRecipe):
|
||||||
|
title = u'Revista Cromos'
|
||||||
|
language = 'es_CO'
|
||||||
|
__author__ = 'Ismael Mejia <iemejia@gmail.com>'
|
||||||
|
cover_url = 'http://www.cromos.com.co/sites/cromos.com.co/themes/cromos_theme/images/logo_morado.gif'
|
||||||
|
description = 'Revista Cromos'
|
||||||
|
oldest_article = 7
|
||||||
|
simultaneous_downloads = 20
|
||||||
|
#tags = 'news, sport, blog'
|
||||||
|
use_embedded_content = True
|
||||||
|
remove_empty_feeds = True
|
||||||
|
max_articles_per_feed = 100
|
||||||
|
feeds = [(u'Cromos', u'http://www.cromos.com.co/rss.xml'),
|
||||||
|
(u'Moda', u'http://www.cromos.com.co/moda/feed'),
|
||||||
|
(u'Estilo de Vida', u'http://www.cromos.com.co/estilo-de-vida/feed'),
|
||||||
|
(u'Cuidado Personal', u'http://www.cromos.com.co/estilo-de-vida/cuidado-personal/feed'),
|
||||||
|
(u'Salud y Alimentación', u'http://www.cromos.com.co/estilo-de-vida/salud-y-alimentacion/feed'),
|
||||||
|
(u'Personajes', u'http://www.cromos.com.co/personajes/feed'),
|
||||||
|
(u'Actualidad', u'http://www.cromos.com.co/personajes/actualidad/feed'),
|
||||||
|
(u'Espectáculo', u'http://www.cromos.com.co/personajes/espectaculo/feed'),
|
||||||
|
(u'Reportajes', u'http://www.cromos.com.co/reportajes/feed'),
|
||||||
|
(u'Eventos', u'http://www.cromos.com.co/eventos/feed'),
|
||||||
|
(u'Modelos', u'http://www.cromos.com.co/modelos/feed'),
|
||||||
|
]
|
@ -1,24 +1,38 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>'
|
|
||||||
'''
|
'''
|
||||||
sciencenews.org
|
sciencenews.org
|
||||||
'''
|
'''
|
||||||
from calibre.web.feeds.news import BasicNewsRecipe
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
class Sciencenews(BasicNewsRecipe):
|
class ScienceNewsIssue(BasicNewsRecipe):
|
||||||
title = u'ScienceNews'
|
title = u'Science News Recent Issues'
|
||||||
__author__ = u'Darko Miletic and Sujata Raman'
|
__author__ = u'Darko Miletic, Sujata Raman and Starson17'
|
||||||
description = u"Science News is an award-winning weekly newsmagazine covering the most important research in all fields of science. Its 16 pages each week are packed with short, accurate articles that appeal to both general readers and scientists. Published since 1922, the magazine now reaches about 150,000 subscribers and more than 1 million readers. These are the latest News Items from Science News."
|
description = u'''Science News is an award-winning weekly
|
||||||
|
newsmagazine covering the most important research in all fields of science.
|
||||||
|
Its 16 pages each week are packed with short, accurate articles that appeal
|
||||||
|
to both general readers and scientists. Published since 1922, the magazine
|
||||||
|
now reaches about 150,000 subscribers and more than 1 million readers.
|
||||||
|
These are the latest News Items from Science News. This recipe downloads
|
||||||
|
the last 30 days worth of articles.'''
|
||||||
|
category = u'Science, Technology, News'
|
||||||
|
publisher = u'Society for Science & the Public'
|
||||||
oldest_article = 30
|
oldest_article = 30
|
||||||
language = 'en'
|
language = 'en'
|
||||||
|
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
auto_cleanup = True
|
|
||||||
timefmt = ' [%A, %d %B, %Y]'
|
timefmt = ' [%A, %d %B, %Y]'
|
||||||
|
recursions = 1
|
||||||
|
remove_attributes = ['style']
|
||||||
|
|
||||||
|
conversion_options = {'linearize_tables' : True
|
||||||
|
, 'comment' : description
|
||||||
|
, 'tags' : category
|
||||||
|
, 'publisher' : publisher
|
||||||
|
, 'language' : language
|
||||||
|
}
|
||||||
|
|
||||||
extra_css = '''
|
extra_css = '''
|
||||||
.content_description{font-family:georgia ;font-size:x-large; color:#646464 ; font-weight:bold;}
|
.content_description{font-family:georgia ;font-size:x-large; color:#646464 ; font-weight:bold;}
|
||||||
@ -27,36 +41,33 @@ class Sciencenews(BasicNewsRecipe):
|
|||||||
.content_edition{font-family:helvetica,arial ;font-size: xx-small ;}
|
.content_edition{font-family:helvetica,arial ;font-size: xx-small ;}
|
||||||
.exclusive{color:#FF0000 ;}
|
.exclusive{color:#FF0000 ;}
|
||||||
.anonymous{color:#14487E ;}
|
.anonymous{color:#14487E ;}
|
||||||
.content_content{font-family:helvetica,arial ;font-size: x-small ; color:#000000;}
|
.content_content{font-family:helvetica,arial ;font-size: medium ; color:#000000;}
|
||||||
.description{color:#585858;font-family:helvetica,arial ;font-size: xx-small ;}
|
.description{color:#585858;font-family:helvetica,arial ;font-size: large ;}
|
||||||
.credit{color:#A6A6A6;font-family:helvetica,arial ;font-size: xx-small ;}
|
.credit{color:#A6A6A6;font-family:helvetica,arial ;font-size: xx-small ;}
|
||||||
'''
|
'''
|
||||||
|
|
||||||
#keep_only_tags = [ dict(name='div', attrs={'id':'column_action'}) ]
|
keep_only_tags = [ dict(name='div', attrs={'class':'content_content'}),
|
||||||
#remove_tags_after = dict(name='ul', attrs={'id':'content_functions_bottom'})
|
dict(name='ul', attrs={'id':'toc'})
|
||||||
#remove_tags = [
|
]
|
||||||
#dict(name='ul', attrs={'id':'content_functions_bottom'})
|
|
||||||
#,dict(name='div', attrs={'id':['content_functions_top','breadcrumb_content']})
|
|
||||||
#,dict(name='img', attrs={'class':'icon'})
|
|
||||||
#,dict(name='div', attrs={'class': 'embiggen'})
|
|
||||||
#]
|
|
||||||
|
|
||||||
feeds = [(u"Science News / News Items", u'http://sciencenews.org/index.php/feed/type/news/name/news.rss/view/feed/name/all.rss')]
|
feeds = [(u"Science News Current Issues", u'http://www.sciencenews.org/view/feed/type/edition/name/issues.rss')]
|
||||||
|
|
||||||
|
match_regexps = [
|
||||||
|
r'www.sciencenews.org/view/feature/id/',
|
||||||
|
r'www.sciencenews.org/view/generic/id'
|
||||||
|
]
|
||||||
|
|
||||||
def get_cover_url(self):
|
def get_cover_url(self):
|
||||||
cover_url = None
|
cover_url = None
|
||||||
index = 'http://www.sciencenews.org/view/home'
|
index = 'http://www.sciencenews.org/view/home'
|
||||||
soup = self.index_to_soup(index)
|
soup = self.index_to_soup(index)
|
||||||
link_item = soup.find(name = 'img',alt = "issue")
|
link_item = soup.find(name = 'img',alt = "issue")
|
||||||
print link_item
|
|
||||||
if link_item:
|
if link_item:
|
||||||
cover_url = 'http://www.sciencenews.org' + link_item['src'] + '.jpg'
|
cover_url = 'http://www.sciencenews.org' + link_item['src'] + '.jpg'
|
||||||
|
|
||||||
return cover_url
|
return cover_url
|
||||||
|
|
||||||
#def preprocess_html(self, soup):
|
def preprocess_html(self, soup):
|
||||||
|
for tag in soup.findAll(name=['span']):
|
||||||
#for tag in soup.findAll(name=['span']):
|
tag.name = 'div'
|
||||||
#tag.name = 'div'
|
return soup
|
||||||
|
|
||||||
#return soup
|
|
||||||
|
22
recipes/unperiodico.recipe
Normal file
22
recipes/unperiodico.recipe
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# https://github.com/iemejia/calibrecolombia
|
||||||
|
|
||||||
|
'''
|
||||||
|
http://www.unperiodico.unal.edu.co/
|
||||||
|
'''
|
||||||
|
|
||||||
|
from calibre import strftime
|
||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
|
class UNPeriodico(BasicNewsRecipe):
|
||||||
|
title = u'UN Periodico'
|
||||||
|
language = 'es_CO'
|
||||||
|
__author__ = 'Ismael Mejia <iemejia@gmail.com>'
|
||||||
|
cover_url = 'http://www.unperiodico.unal.edu.co/fileadmin/templates/periodico/img/logoperiodico.png'
|
||||||
|
description = 'UN Periodico'
|
||||||
|
oldest_article = 30
|
||||||
|
max_articles_per_feed = 100
|
||||||
|
publication_type = 'newspaper'
|
||||||
|
feeds = [
|
||||||
|
(u'UNPeriodico', u'http://www.unperiodico.unal.edu.co/rss/type/rss2/')
|
||||||
|
]
|
@ -55,20 +55,14 @@ class WallStreetJournal(BasicNewsRecipe):
|
|||||||
]
|
]
|
||||||
remove_tags_after = [dict(id="article_story_body"), {'class':"article story"},]
|
remove_tags_after = [dict(id="article_story_body"), {'class':"article story"},]
|
||||||
|
|
||||||
|
use_javascript_to_login = True
|
||||||
|
|
||||||
def get_browser(self):
|
def javascript_login(self, br, username, password):
|
||||||
br = BasicNewsRecipe.get_browser(self)
|
br.visit('https://id.wsj.com/access/pages/wsj/us/login_standalone.html?mg=com-wsj', timeout=120)
|
||||||
if self.username is not None and self.password is not None:
|
f = br.select_form(nr=0)
|
||||||
br.open('http://commerce.wsj.com/auth/login')
|
f['username'] = username
|
||||||
br.select_form(nr=1)
|
f['password'] = password
|
||||||
br['user'] = self.username
|
br.submit(timeout=120)
|
||||||
br['password'] = self.password
|
|
||||||
res = br.submit()
|
|
||||||
raw = res.read()
|
|
||||||
if 'Welcome,' not in raw and '>Logout<' not in raw and '>Log Out<' not in raw:
|
|
||||||
raise ValueError('Failed to log in to wsj.com, check your '
|
|
||||||
'username and password')
|
|
||||||
return br
|
|
||||||
|
|
||||||
def populate_article_metadata(self, article, soup, first):
|
def populate_article_metadata(self, article, soup, first):
|
||||||
if first and hasattr(self, 'add_toc_thumbnail'):
|
if first and hasattr(self, 'add_toc_thumbnail'):
|
||||||
|
@ -88,7 +88,7 @@ class ZeitEPUBAbo(BasicNewsRecipe):
|
|||||||
(re.compile(u' \u00AB'), lambda match: u'\u00AB '), # before closing quotation
|
(re.compile(u' \u00AB'), lambda match: u'\u00AB '), # before closing quotation
|
||||||
(re.compile(u'\u00BB '), lambda match: u' \u00BB'), # after opening quotation
|
(re.compile(u'\u00BB '), lambda match: u' \u00BB'), # after opening quotation
|
||||||
# filtering for spaces in large numbers for better readability
|
# filtering for spaces in large numbers for better readability
|
||||||
(re.compile(r'(?<=\d\d)(?=\d\d\d[ ,\.;\)<\?!-])'), lambda match: u'\u2008'), # end of the number with some character following
|
(re.compile(r'(?<=\d\d)(?=\d\d\d[ ,;\)<\?!-])'), lambda match: u'\u2008'), # end of the number with some character following
|
||||||
(re.compile(r'(?<=\d\d)(?=\d\d\d. )'), lambda match: u'\u2008'), # end of the number with full-stop following, then space is necessary (avoid file names)
|
(re.compile(r'(?<=\d\d)(?=\d\d\d. )'), lambda match: u'\u2008'), # end of the number with full-stop following, then space is necessary (avoid file names)
|
||||||
(re.compile(u'(?<=\d)(?=\d\d\d\u2008)'), lambda match: u'\u2008'), # next level
|
(re.compile(u'(?<=\d)(?=\d\d\d\u2008)'), lambda match: u'\u2008'), # next level
|
||||||
(re.compile(u'(?<=\d)(?=\d\d\d\u2008)'), lambda match: u'\u2008'), # next level
|
(re.compile(u'(?<=\d)(?=\d\d\d\u2008)'), lambda match: u'\u2008'), # next level
|
||||||
|
Binary file not shown.
@ -517,3 +517,10 @@ default_tweak_format = None
|
|||||||
# your library and your personal editing style.
|
# your library and your personal editing style.
|
||||||
preselect_first_completion = False
|
preselect_first_completion = False
|
||||||
|
|
||||||
|
#: Recognize numbers inside text when sorting
|
||||||
|
# This means that when sorting on text fields like title the text "Book 2"
|
||||||
|
# will sort before the text "Book 100". If you want this behavior, set
|
||||||
|
# numeric_collation = True note that doing so will cause problems with text
|
||||||
|
# that starts with numbers and is a little slower.
|
||||||
|
numeric_collation = False
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ from calibre.ptempfile import PersistentTemporaryFile
|
|||||||
from calibre.db.schema_upgrades import SchemaUpgrade
|
from calibre.db.schema_upgrades import SchemaUpgrade
|
||||||
from calibre.library.field_metadata import FieldMetadata
|
from calibre.library.field_metadata import FieldMetadata
|
||||||
from calibre.ebooks.metadata import title_sort, author_to_author_sort
|
from calibre.ebooks.metadata import title_sort, author_to_author_sort
|
||||||
from calibre.utils.icu import strcmp
|
from calibre.utils.icu import sort_key
|
||||||
from calibre.utils.config import to_json, from_json, prefs, tweaks
|
from calibre.utils.config import to_json, from_json, prefs, tweaks
|
||||||
from calibre.utils.date import utcfromtimestamp, parse_date
|
from calibre.utils.date import utcfromtimestamp, parse_date
|
||||||
from calibre.utils.filenames import (is_case_sensitive, samefile, hardlink_file)
|
from calibre.utils.filenames import (is_case_sensitive, samefile, hardlink_file)
|
||||||
@ -172,7 +172,9 @@ def _author_to_author_sort(x):
|
|||||||
return author_to_author_sort(x.replace('|', ','))
|
return author_to_author_sort(x.replace('|', ','))
|
||||||
|
|
||||||
def icu_collator(s1, s2):
|
def icu_collator(s1, s2):
|
||||||
return strcmp(force_unicode(s1, 'utf-8'), force_unicode(s2, 'utf-8'))
|
return cmp(sort_key(force_unicode(s1, 'utf-8')),
|
||||||
|
sort_key(force_unicode(s2, 'utf-8')))
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
# Unused aggregators {{{
|
# Unused aggregators {{{
|
||||||
|
@ -211,6 +211,12 @@ class Cache(object):
|
|||||||
self.fields['ondevice'] = create_field('ondevice',
|
self.fields['ondevice'] = create_field('ondevice',
|
||||||
VirtualTable('ondevice'))
|
VirtualTable('ondevice'))
|
||||||
|
|
||||||
|
for name, field in self.fields.iteritems():
|
||||||
|
if name[0] == '#' and name.endswith('_index'):
|
||||||
|
field.series_field = self.fields[name[:-len('_index')]]
|
||||||
|
elif name == 'series_index':
|
||||||
|
field.series_field = self.fields['series']
|
||||||
|
|
||||||
@read_api
|
@read_api
|
||||||
def field_for(self, name, book_id, default_value=None):
|
def field_for(self, name, book_id, default_value=None):
|
||||||
'''
|
'''
|
||||||
@ -609,11 +615,11 @@ class Cache(object):
|
|||||||
icon_map=icon_map)
|
icon_map=icon_map)
|
||||||
|
|
||||||
@write_api
|
@write_api
|
||||||
def set_field(self, name, book_id_to_val_map):
|
def set_field(self, name, book_id_to_val_map, allow_case_change=True):
|
||||||
# TODO: Specialize title/authors to also update path
|
# TODO: Specialize title/authors to also update path
|
||||||
# TODO: Handle updating caches used by composite fields
|
# TODO: Handle updating caches used by composite fields
|
||||||
dirtied = self.fields[name].writer.set_books(
|
dirtied = self.fields[name].writer.set_books(
|
||||||
book_id_to_val_map, self.backend)
|
book_id_to_val_map, self.backend, allow_case_change=allow_case_change)
|
||||||
return dirtied
|
return dirtied
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
@ -46,6 +46,7 @@ class Field(object):
|
|||||||
elif name == 'languages':
|
elif name == 'languages':
|
||||||
self.category_formatter = calibre_langcode_to_name
|
self.category_formatter = calibre_langcode_to_name
|
||||||
self.writer = Writer(self)
|
self.writer = Writer(self)
|
||||||
|
self.series_field = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def metadata(self):
|
def metadata(self):
|
||||||
|
@ -22,7 +22,11 @@ class WritingTest(BaseTest):
|
|||||||
|
|
||||||
def create_getter(self, name, getter=None):
|
def create_getter(self, name, getter=None):
|
||||||
if getter is None:
|
if getter is None:
|
||||||
ans = lambda db:partial(db.get_custom, label=name[1:],
|
if name.endswith('_index'):
|
||||||
|
ans = lambda db:partial(db.get_custom_extra, index_is_id=True,
|
||||||
|
label=name[1:].replace('_index', ''))
|
||||||
|
else:
|
||||||
|
ans = lambda db:partial(db.get_custom, label=name[1:],
|
||||||
index_is_id=True)
|
index_is_id=True)
|
||||||
else:
|
else:
|
||||||
ans = lambda db:partial(getattr(db, getter), index_is_id=True)
|
ans = lambda db:partial(getattr(db, getter), index_is_id=True)
|
||||||
@ -41,11 +45,11 @@ class WritingTest(BaseTest):
|
|||||||
self.create_setter(name, setter))
|
self.create_setter(name, setter))
|
||||||
|
|
||||||
def run_tests(self, tests):
|
def run_tests(self, tests):
|
||||||
cl = self.cloned_library
|
|
||||||
results = {}
|
results = {}
|
||||||
for test in tests:
|
for test in tests:
|
||||||
results[test] = []
|
results[test] = []
|
||||||
for val in test.vals:
|
for val in test.vals:
|
||||||
|
cl = self.cloned_library
|
||||||
cache = self.init_cache(cl)
|
cache = self.init_cache(cl)
|
||||||
cache.set_field(test.name, {1: val})
|
cache.set_field(test.name, {1: val})
|
||||||
cached_res = cache.field_for(test.name, 1)
|
cached_res = cache.field_for(test.name, 1)
|
||||||
@ -53,23 +57,35 @@ class WritingTest(BaseTest):
|
|||||||
db = self.init_old(cl)
|
db = self.init_old(cl)
|
||||||
getter = test.getter(db)
|
getter = test.getter(db)
|
||||||
sqlite_res = getter(1)
|
sqlite_res = getter(1)
|
||||||
test.setter(db)(1, val)
|
if test.name.endswith('_index'):
|
||||||
old_cached_res = getter(1)
|
val = float(val) if val is not None else 1.0
|
||||||
self.assertEqual(old_cached_res, cached_res,
|
self.assertEqual(sqlite_res, val,
|
||||||
'Failed setting for %s with value %r, cached value not the same. Old: %r != New: %r'%(
|
'Failed setting for %s with value %r, sqlite value not the same. val: %r != sqlite_val: %r'%(
|
||||||
test.name, val, old_cached_res, cached_res))
|
test.name, val, val, sqlite_res))
|
||||||
db.refresh()
|
else:
|
||||||
old_sqlite_res = getter(1)
|
test.setter(db)(1, val)
|
||||||
self.assertEqual(old_sqlite_res, sqlite_res,
|
old_cached_res = getter(1)
|
||||||
'Failed setting for %s, sqlite value not the same: %r != %r'%(
|
self.assertEqual(old_cached_res, cached_res,
|
||||||
test.name, old_sqlite_res, sqlite_res))
|
'Failed setting for %s with value %r, cached value not the same. Old: %r != New: %r'%(
|
||||||
|
test.name, val, old_cached_res, cached_res))
|
||||||
|
db.refresh()
|
||||||
|
old_sqlite_res = getter(1)
|
||||||
|
self.assertEqual(old_sqlite_res, sqlite_res,
|
||||||
|
'Failed setting for %s, sqlite value not the same: %r != %r'%(
|
||||||
|
test.name, old_sqlite_res, sqlite_res))
|
||||||
del db
|
del db
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def test_one_one(self):
|
def test_one_one(self):
|
||||||
'Test setting of values in one-one fields'
|
'Test setting of values in one-one fields'
|
||||||
tests = []
|
tests = [self.create_test('#yesno', (True, False, 'true', 'false', None))]
|
||||||
|
for name, getter, setter in (
|
||||||
|
('#series_index', None, None),
|
||||||
|
('series_index', 'series_index', 'set_series_index'),
|
||||||
|
('#float', None, None),
|
||||||
|
):
|
||||||
|
vals = ['1.5', None, 0, 1.0]
|
||||||
|
tests.append(self.create_test(name, tuple(vals), getter, setter))
|
||||||
|
|
||||||
for name, getter, setter in (
|
for name, getter, setter in (
|
||||||
('pubdate', 'pubdate', 'set_pubdate'),
|
('pubdate', 'pubdate', 'set_pubdate'),
|
||||||
('timestamp', 'timestamp', 'set_timestamp'),
|
('timestamp', 'timestamp', 'set_timestamp'),
|
||||||
@ -78,6 +94,25 @@ class WritingTest(BaseTest):
|
|||||||
tests.append(self.create_test(
|
tests.append(self.create_test(
|
||||||
name, ('2011-1-12', UNDEFINED_DATE, None), getter, setter))
|
name, ('2011-1-12', UNDEFINED_DATE, None), getter, setter))
|
||||||
|
|
||||||
|
for name, getter, setter in (
|
||||||
|
('title', 'title', 'set_title'),
|
||||||
|
('uuid', 'uuid', 'set_uuid'),
|
||||||
|
('author_sort', 'author_sort', 'set_author_sort'),
|
||||||
|
('sort', 'title_sort', 'set_title_sort'),
|
||||||
|
('#comments', None, None),
|
||||||
|
('comments', 'comments', 'set_comment'),
|
||||||
|
):
|
||||||
|
vals = ['something', None]
|
||||||
|
if name not in {'comments', '#comments'}:
|
||||||
|
# Setting text column to '' returns None in the new backend
|
||||||
|
# and '' in the old. I think None is more correct.
|
||||||
|
vals.append('')
|
||||||
|
if name == 'comments':
|
||||||
|
# Again new behavior of deleting comment rather than setting
|
||||||
|
# empty string is more correct.
|
||||||
|
vals.remove(None)
|
||||||
|
tests.append(self.create_test(name, tuple(vals), getter, setter))
|
||||||
|
|
||||||
self.run_tests(tests)
|
self.run_tests(tests)
|
||||||
|
|
||||||
def tests():
|
def tests():
|
||||||
|
@ -13,11 +13,13 @@ from datetime import datetime
|
|||||||
from calibre.constants import preferred_encoding, ispy3
|
from calibre.constants import preferred_encoding, ispy3
|
||||||
from calibre.utils.date import (parse_only_date, parse_date, UNDEFINED_DATE,
|
from calibre.utils.date import (parse_only_date, parse_date, UNDEFINED_DATE,
|
||||||
isoformat)
|
isoformat)
|
||||||
|
if ispy3:
|
||||||
|
unicode = str
|
||||||
|
|
||||||
# Convert data into values suitable for the db {{{
|
# Convert data into values suitable for the db {{{
|
||||||
|
|
||||||
if ispy3:
|
def sqlite_datetime(x):
|
||||||
unicode = str
|
return isoformat(x, sep=' ') if isinstance(x, datetime) else x
|
||||||
|
|
||||||
def single_text(x):
|
def single_text(x):
|
||||||
if x is None:
|
if x is None:
|
||||||
@ -98,17 +100,19 @@ def get_adapter(name, metadata):
|
|||||||
|
|
||||||
if name == 'title':
|
if name == 'title':
|
||||||
return lambda x: ans(x) or _('Unknown')
|
return lambda x: ans(x) or _('Unknown')
|
||||||
|
if name == 'author_sort':
|
||||||
|
return lambda x: ans(x) or ''
|
||||||
if name == 'authors':
|
if name == 'authors':
|
||||||
return lambda x: ans(x) or (_('Unknown'),)
|
return lambda x: ans(x) or (_('Unknown'),)
|
||||||
if name in {'timestamp', 'last_modified'}:
|
if name in {'timestamp', 'last_modified'}:
|
||||||
return lambda x: ans(x) or UNDEFINED_DATE
|
return lambda x: ans(x) or UNDEFINED_DATE
|
||||||
|
if name == 'series_index':
|
||||||
|
return lambda x: 1.0 if ans(x) is None else ans(x)
|
||||||
|
|
||||||
return ans
|
return ans
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
def sqlite_datetime(x):
|
# One-One fields {{{
|
||||||
return isoformat(x, sep=' ') if isinstance(x, datetime) else x
|
|
||||||
|
|
||||||
def one_one_in_books(book_id_val_map, db, field, *args):
|
def one_one_in_books(book_id_val_map, db, field, *args):
|
||||||
'Set a one-one field in the books table'
|
'Set a one-one field in the books table'
|
||||||
if book_id_val_map:
|
if book_id_val_map:
|
||||||
@ -134,6 +138,22 @@ def one_one_in_other(book_id_val_map, db, field, *args):
|
|||||||
field.table.book_col_map.update(updated)
|
field.table.book_col_map.update(updated)
|
||||||
return set(book_id_val_map)
|
return set(book_id_val_map)
|
||||||
|
|
||||||
|
def custom_series_index(book_id_val_map, db, field, *args):
|
||||||
|
series_field = field.series_field
|
||||||
|
sequence = []
|
||||||
|
for book_id, sidx in book_id_val_map.iteritems():
|
||||||
|
if sidx is None:
|
||||||
|
sidx = 1.0
|
||||||
|
ids = series_field.ids_for_book(book_id)
|
||||||
|
if ids:
|
||||||
|
sequence.append((sidx, book_id, ids[0]))
|
||||||
|
field.table.book_col_map[book_id] = sidx
|
||||||
|
if sequence:
|
||||||
|
db.conn.executemany('UPDATE %s SET %s=? WHERE book=? AND value=?'%(
|
||||||
|
field.metadata['table'], field.metadata['column']), sequence)
|
||||||
|
return {s[0] for s in sequence}
|
||||||
|
# }}}
|
||||||
|
|
||||||
def dummy(book_id_val_map, *args):
|
def dummy(book_id_val_map, *args):
|
||||||
return set()
|
return set()
|
||||||
|
|
||||||
@ -148,16 +168,19 @@ class Writer(object):
|
|||||||
if dt == 'composite' or field.name in {
|
if dt == 'composite' or field.name in {
|
||||||
'id', 'cover', 'size', 'path', 'formats', 'news'}:
|
'id', 'cover', 'size', 'path', 'formats', 'news'}:
|
||||||
self.set_books_func = dummy
|
self.set_books_func = dummy
|
||||||
|
elif self.name[0] == '#' and self.name.endswith('_index'):
|
||||||
|
self.set_books_func = custom_series_index
|
||||||
elif field.is_many:
|
elif field.is_many:
|
||||||
# TODO: Implement this
|
# TODO: Implement this
|
||||||
pass
|
pass
|
||||||
|
# TODO: Remember to change commas to | when writing authors to sqlite
|
||||||
else:
|
else:
|
||||||
self.set_books_func = (one_one_in_books if field.metadata['table']
|
self.set_books_func = (one_one_in_books if field.metadata['table']
|
||||||
== 'books' else one_one_in_other)
|
== 'books' else one_one_in_other)
|
||||||
if self.name in {'timestamp', 'uuid'}:
|
if self.name in {'timestamp', 'uuid', 'sort'}:
|
||||||
self.accept_vals = bool
|
self.accept_vals = bool
|
||||||
|
|
||||||
def set_books(self, book_id_val_map, db):
|
def set_books(self, book_id_val_map, db, allow_case_change=True):
|
||||||
book_id_val_map = {k:self.adapter(v) for k, v in
|
book_id_val_map = {k:self.adapter(v) for k, v in
|
||||||
book_id_val_map.iteritems() if self.accept_vals(v)}
|
book_id_val_map.iteritems() if self.accept_vals(v)}
|
||||||
if not book_id_val_map:
|
if not book_id_val_map:
|
||||||
|
@ -22,13 +22,14 @@ class IRIVER_STORY(USBMS):
|
|||||||
FORMATS = ['epub', 'fb2', 'pdf', 'djvu', 'txt']
|
FORMATS = ['epub', 'fb2', 'pdf', 'djvu', 'txt']
|
||||||
|
|
||||||
VENDOR_ID = [0x1006]
|
VENDOR_ID = [0x1006]
|
||||||
PRODUCT_ID = [0x4023, 0x4024, 0x4025, 0x4034]
|
PRODUCT_ID = [0x4023, 0x4024, 0x4025, 0x4034, 0x4037]
|
||||||
BCD = [0x0323, 0x0326]
|
BCD = [0x0323, 0x0326, 0x226]
|
||||||
|
|
||||||
VENDOR_NAME = 'IRIVER'
|
VENDOR_NAME = 'IRIVER'
|
||||||
WINDOWS_MAIN_MEM = ['STORY', 'STORY_EB05', 'STORY_WI-FI', 'STORY_EB07']
|
WINDOWS_MAIN_MEM = ['STORY', 'STORY_EB05', 'STORY_WI-FI', 'STORY_EB07',
|
||||||
|
'STORY_EB12']
|
||||||
WINDOWS_MAIN_MEM = re.compile(r'(%s)&'%('|'.join(WINDOWS_MAIN_MEM)))
|
WINDOWS_MAIN_MEM = re.compile(r'(%s)&'%('|'.join(WINDOWS_MAIN_MEM)))
|
||||||
WINDOWS_CARD_A_MEM = ['STORY', 'STORY_SD']
|
WINDOWS_CARD_A_MEM = ['STORY', 'STORY_SD', 'STORY_EB12_SD']
|
||||||
WINDOWS_CARD_A_MEM = re.compile(r'(%s)&'%('|'.join(WINDOWS_CARD_A_MEM)))
|
WINDOWS_CARD_A_MEM = re.compile(r'(%s)&'%('|'.join(WINDOWS_CARD_A_MEM)))
|
||||||
|
|
||||||
#OSX_MAIN_MEM = 'Kindle Internal Storage Media'
|
#OSX_MAIN_MEM = 'Kindle Internal Storage Media'
|
||||||
|
@ -6,7 +6,7 @@ import os, time, sys
|
|||||||
|
|
||||||
from calibre.constants import preferred_encoding, DEBUG
|
from calibre.constants import preferred_encoding, DEBUG
|
||||||
from calibre import isbytestring, force_unicode
|
from calibre import isbytestring, force_unicode
|
||||||
from calibre.utils.icu import strcmp
|
from calibre.utils.icu import sort_key
|
||||||
|
|
||||||
from calibre.devices.usbms.books import Book as Book_
|
from calibre.devices.usbms.books import Book as Book_
|
||||||
from calibre.devices.usbms.books import CollectionsBookList
|
from calibre.devices.usbms.books import CollectionsBookList
|
||||||
@ -239,9 +239,8 @@ class KTCollectionsBookList(CollectionsBookList):
|
|||||||
if y is None:
|
if y is None:
|
||||||
return -1
|
return -1
|
||||||
if isinstance(x, basestring) and isinstance(y, basestring):
|
if isinstance(x, basestring) and isinstance(y, basestring):
|
||||||
c = strcmp(force_unicode(x), force_unicode(y))
|
x, y = sort_key(force_unicode(x)), sort_key(force_unicode(y))
|
||||||
else:
|
c = cmp(x, y)
|
||||||
c = cmp(x, y)
|
|
||||||
if c != 0:
|
if c != 0:
|
||||||
return c
|
return c
|
||||||
# same as above -- no sort_key needed here
|
# same as above -- no sort_key needed here
|
||||||
|
@ -13,7 +13,7 @@ from calibre.devices.interface import BookList as _BookList
|
|||||||
from calibre.constants import preferred_encoding
|
from calibre.constants import preferred_encoding
|
||||||
from calibre import isbytestring, force_unicode
|
from calibre import isbytestring, force_unicode
|
||||||
from calibre.utils.config import device_prefs, tweaks
|
from calibre.utils.config import device_prefs, tweaks
|
||||||
from calibre.utils.icu import strcmp
|
from calibre.utils.icu import sort_key
|
||||||
from calibre.utils.formatter import EvalFormatter
|
from calibre.utils.formatter import EvalFormatter
|
||||||
|
|
||||||
class Book(Metadata):
|
class Book(Metadata):
|
||||||
@ -281,9 +281,8 @@ class CollectionsBookList(BookList):
|
|||||||
if y is None:
|
if y is None:
|
||||||
return -1
|
return -1
|
||||||
if isinstance(x, basestring) and isinstance(y, basestring):
|
if isinstance(x, basestring) and isinstance(y, basestring):
|
||||||
c = strcmp(force_unicode(x), force_unicode(y))
|
x, y = sort_key(force_unicode(x)), sort_key(force_unicode(y))
|
||||||
else:
|
c = cmp(x, y)
|
||||||
c = cmp(x, y)
|
|
||||||
if c != 0:
|
if c != 0:
|
||||||
return c
|
return c
|
||||||
# same as above -- no sort_key needed here
|
# same as above -- no sort_key needed here
|
||||||
|
@ -75,6 +75,13 @@ class PagedDisplay
|
|||||||
this.margin_side = margin_side
|
this.margin_side = margin_side
|
||||||
this.margin_bottom = margin_bottom
|
this.margin_bottom = margin_bottom
|
||||||
|
|
||||||
|
handle_rtl_body: (body_style) ->
|
||||||
|
if body_style.direction == "rtl"
|
||||||
|
for node in document.body.childNodes
|
||||||
|
if node.nodeType == node.ELEMENT_NODE and window.getComputedStyle(node).direction == "rtl"
|
||||||
|
node.style.setProperty("direction", "rtl")
|
||||||
|
document.body.style.direction = "ltr"
|
||||||
|
|
||||||
layout: (is_single_page=false) ->
|
layout: (is_single_page=false) ->
|
||||||
# start_time = new Date().getTime()
|
# start_time = new Date().getTime()
|
||||||
body_style = window.getComputedStyle(document.body)
|
body_style = window.getComputedStyle(document.body)
|
||||||
@ -84,6 +91,7 @@ class PagedDisplay
|
|||||||
# Check if the current document is a full screen layout like
|
# Check if the current document is a full screen layout like
|
||||||
# cover, if so we treat it specially.
|
# cover, if so we treat it specially.
|
||||||
single_screen = (document.body.scrollHeight < window.innerHeight + 75)
|
single_screen = (document.body.scrollHeight < window.innerHeight + 75)
|
||||||
|
this.handle_rtl_body(body_style)
|
||||||
first_layout = true
|
first_layout = true
|
||||||
|
|
||||||
ww = window.innerWidth
|
ww = window.innerWidth
|
||||||
|
@ -31,7 +31,7 @@ def self_closing_sub(match):
|
|||||||
return '<%s%s></%s>'%(match.group(1), match.group(2), match.group(1))
|
return '<%s%s></%s>'%(match.group(1), match.group(2), match.group(1))
|
||||||
|
|
||||||
def load_html(path, view, codec='utf-8', mime_type=None,
|
def load_html(path, view, codec='utf-8', mime_type=None,
|
||||||
pre_load_callback=lambda x:None, path_is_html=False,
|
pre_load_callback=lambda x:None, path_is_html=False,
|
||||||
force_as_html=False):
|
force_as_html=False):
|
||||||
from PyQt4.Qt import QUrl, QByteArray
|
from PyQt4.Qt import QUrl, QByteArray
|
||||||
if mime_type is None:
|
if mime_type is None:
|
||||||
@ -45,13 +45,13 @@ def load_html(path, view, codec='utf-8', mime_type=None,
|
|||||||
html = f.read().decode(codec, 'replace')
|
html = f.read().decode(codec, 'replace')
|
||||||
|
|
||||||
html = EntityDeclarationProcessor(html).processed_html
|
html = EntityDeclarationProcessor(html).processed_html
|
||||||
self_closing_pat = re.compile(r'<\s*([A-Za-z1-6]+)([^>]*)/\s*>')
|
self_closing_pat = re.compile(r'<\s*([:A-Za-z0-9-]+)([^>]*)/\s*>')
|
||||||
html = self_closing_pat.sub(self_closing_sub, html)
|
html = self_closing_pat.sub(self_closing_sub, html)
|
||||||
|
|
||||||
loading_url = QUrl.fromLocalFile(path)
|
loading_url = QUrl.fromLocalFile(path)
|
||||||
pre_load_callback(loading_url)
|
pre_load_callback(loading_url)
|
||||||
|
|
||||||
if force_as_html or re.search(r'<[:a-zA-Z]*svg', html) is None:
|
if force_as_html or re.search(r'<[:a-zA-Z0-9-]*svg', html) is None:
|
||||||
view.setHtml(html, loading_url)
|
view.setHtml(html, loading_url)
|
||||||
else:
|
else:
|
||||||
view.setContent(QByteArray(html.encode(codec)), mime_type,
|
view.setContent(QByteArray(html.encode(codec)), mime_type,
|
||||||
|
@ -174,6 +174,7 @@ def gui_polish(data):
|
|||||||
files = data.pop('files')
|
files = data.pop('files')
|
||||||
if not data.pop('metadata'):
|
if not data.pop('metadata'):
|
||||||
data.pop('opf')
|
data.pop('opf')
|
||||||
|
if not data.pop('do_cover'):
|
||||||
data.pop('cover')
|
data.pop('cover')
|
||||||
file_map = {x:x for x in files}
|
file_map = {x:x for x in files}
|
||||||
opts = ALL_OPTS.copy()
|
opts = ALL_OPTS.copy()
|
||||||
|
@ -9,10 +9,11 @@ __docformat__ = 'restructuredtext en'
|
|||||||
|
|
||||||
import os, sys
|
import os, sys
|
||||||
|
|
||||||
from calibre import prints
|
from calibre import prints, as_unicode
|
||||||
from calibre.ebooks.oeb.base import OEB_STYLES, OEB_DOCS, XPath
|
from calibre.ebooks.oeb.base import OEB_STYLES, OEB_DOCS, XPath
|
||||||
from calibre.ebooks.oeb.polish.container import OEB_FONTS
|
from calibre.ebooks.oeb.polish.container import OEB_FONTS
|
||||||
from calibre.utils.fonts.sfnt.subset import subset
|
from calibre.utils.fonts.sfnt.subset import subset
|
||||||
|
from calibre.utils.fonts.sfnt.errors import UnsupportedFont
|
||||||
from calibre.utils.fonts.utils import get_font_names
|
from calibre.utils.fonts.utils import get_font_names
|
||||||
|
|
||||||
def remove_font_face_rules(container, sheet, remove_names, base):
|
def remove_font_face_rules(container, sheet, remove_names, base):
|
||||||
@ -46,9 +47,16 @@ def subset_all_fonts(container, font_stats, report):
|
|||||||
raw = f.read()
|
raw = f.read()
|
||||||
font_name = get_font_names(raw)[-1]
|
font_name = get_font_names(raw)[-1]
|
||||||
warnings = []
|
warnings = []
|
||||||
container.log('Subsetting font: %s'%font_name)
|
container.log('Subsetting font: %s'%(font_name or name))
|
||||||
nraw, old_sizes, new_sizes = subset(raw, chars,
|
try:
|
||||||
|
nraw, old_sizes, new_sizes = subset(raw, chars,
|
||||||
warnings=warnings)
|
warnings=warnings)
|
||||||
|
except UnsupportedFont as e:
|
||||||
|
container.log.warning(
|
||||||
|
'Unsupported font: %s, ignoring. Error: %s'%(
|
||||||
|
name, as_unicode(e)))
|
||||||
|
continue
|
||||||
|
|
||||||
for w in warnings:
|
for w in warnings:
|
||||||
container.log.warn(w)
|
container.log.warn(w)
|
||||||
olen = sum(old_sizes.itervalues())
|
olen = sum(old_sizes.itervalues())
|
||||||
|
@ -363,7 +363,10 @@ class CSSFlattener(object):
|
|||||||
cssdict['font-weight'] = 'normal' # ADE chokes on font-weight medium
|
cssdict['font-weight'] = 'normal' # ADE chokes on font-weight medium
|
||||||
|
|
||||||
fsize = font_size
|
fsize = font_size
|
||||||
if not self.context.disable_font_rescaling:
|
is_drop_cap = (cssdict.get('float', None) == 'left' and 'font-size' in
|
||||||
|
cssdict and len(node) == 0 and node.text and
|
||||||
|
len(node.text) == 1)
|
||||||
|
if not self.context.disable_font_rescaling and not is_drop_cap:
|
||||||
_sbase = self.sbase if self.sbase is not None else \
|
_sbase = self.sbase if self.sbase is not None else \
|
||||||
self.context.source.fbase
|
self.context.source.fbase
|
||||||
dyn_rescale = dynamic_rescale_factor(node)
|
dyn_rescale = dynamic_rescale_factor(node)
|
||||||
@ -382,7 +385,7 @@ class CSSFlattener(object):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
minlh = self.context.minimum_line_height / 100.
|
minlh = self.context.minimum_line_height / 100.
|
||||||
if style['line-height'] < minlh * fsize:
|
if not is_drop_cap and style['line-height'] < minlh * fsize:
|
||||||
cssdict['line-height'] = str(minlh)
|
cssdict['line-height'] = str(minlh)
|
||||||
except:
|
except:
|
||||||
self.oeb.logger.exception('Failed to set minimum line-height')
|
self.oeb.logger.exception('Failed to set minimum line-height')
|
||||||
|
@ -13,9 +13,10 @@ from operator import itemgetter
|
|||||||
from collections import Counter, OrderedDict
|
from collections import Counter, OrderedDict
|
||||||
from future_builtins import map
|
from future_builtins import map
|
||||||
|
|
||||||
|
from calibre import as_unicode
|
||||||
from calibre.ebooks.pdf.render.common import (Array, String, Stream,
|
from calibre.ebooks.pdf.render.common import (Array, String, Stream,
|
||||||
Dictionary, Name)
|
Dictionary, Name)
|
||||||
from calibre.utils.fonts.sfnt.subset import pdf_subset
|
from calibre.utils.fonts.sfnt.subset import pdf_subset, UnsupportedFont
|
||||||
|
|
||||||
STANDARD_FONTS = {
|
STANDARD_FONTS = {
|
||||||
'Times-Roman', 'Helvetica', 'Courier', 'Symbol', 'Times-Bold',
|
'Times-Roman', 'Helvetica', 'Courier', 'Symbol', 'Times-Bold',
|
||||||
@ -150,12 +151,16 @@ class Font(object):
|
|||||||
|
|
||||||
self.used_glyphs = set()
|
self.used_glyphs = set()
|
||||||
|
|
||||||
def embed(self, objects):
|
def embed(self, objects, debug):
|
||||||
self.font_descriptor['FontFile'+('3' if self.is_otf else '2')
|
self.font_descriptor['FontFile'+('3' if self.is_otf else '2')
|
||||||
] = objects.add(self.font_stream)
|
] = objects.add(self.font_stream)
|
||||||
self.write_widths(objects)
|
self.write_widths(objects)
|
||||||
self.write_to_unicode(objects)
|
self.write_to_unicode(objects)
|
||||||
pdf_subset(self.metrics.sfnt, self.used_glyphs)
|
try:
|
||||||
|
pdf_subset(self.metrics.sfnt, self.used_glyphs)
|
||||||
|
except UnsupportedFont as e:
|
||||||
|
debug('Subsetting of %s not supported, embedding full font. Error: %s'%(
|
||||||
|
self.metrics.names.get('full_name', 'Unknown'), as_unicode(e)))
|
||||||
if self.is_otf:
|
if self.is_otf:
|
||||||
self.font_stream.write(self.metrics.sfnt['CFF '].raw)
|
self.font_stream.write(self.metrics.sfnt['CFF '].raw)
|
||||||
else:
|
else:
|
||||||
@ -221,7 +226,7 @@ class FontManager(object):
|
|||||||
}))
|
}))
|
||||||
return self.std_map[name]
|
return self.std_map[name]
|
||||||
|
|
||||||
def embed_fonts(self):
|
def embed_fonts(self, debug):
|
||||||
for font in self.fonts:
|
for font in self.fonts:
|
||||||
font.embed(self.objects)
|
font.embed(self.objects, debug)
|
||||||
|
|
||||||
|
@ -488,7 +488,7 @@ class PDFStream(object):
|
|||||||
def end(self):
|
def end(self):
|
||||||
if self.current_page.getvalue():
|
if self.current_page.getvalue():
|
||||||
self.end_page()
|
self.end_page()
|
||||||
self.font_manager.embed_fonts()
|
self.font_manager.embed_fonts(self.debug)
|
||||||
inforef = self.objects.add(self.info)
|
inforef = self.objects.add(self.info)
|
||||||
self.links.add_links()
|
self.links.add_links()
|
||||||
self.objects.pdf_serialize(self.stream)
|
self.objects.pdf_serialize(self.stream)
|
||||||
|
@ -44,13 +44,18 @@ class Polish(QDialog): # {{{
|
|||||||
_('<h3>Smarten punctuation</h3>%s')%HELP['smarten_punctuation'],
|
_('<h3>Smarten punctuation</h3>%s')%HELP['smarten_punctuation'],
|
||||||
|
|
||||||
'metadata':_('<h3>Updating metadata</h3>'
|
'metadata':_('<h3>Updating metadata</h3>'
|
||||||
'<p>This will update all metadata and covers in the'
|
'<p>This will update all metadata <i>except</i> the cover in the'
|
||||||
' ebook files to match the current metadata in the'
|
' ebook files to match the current metadata in the'
|
||||||
' calibre library.</p><p>If the ebook file does not have'
|
' calibre library.</p>'
|
||||||
' an identifiable cover, a new cover is inserted.</p>'
|
|
||||||
' <p>Note that most ebook'
|
' <p>Note that most ebook'
|
||||||
' formats are not capable of supporting all the'
|
' formats are not capable of supporting all the'
|
||||||
' metadata in calibre.</p>'),
|
' metadata in calibre.</p><p>There is a separate option to'
|
||||||
|
' update the cover.</p>'),
|
||||||
|
'do_cover': _('<p>Update the covers in the ebook files to match the'
|
||||||
|
' current cover in the calibre library.</p>'
|
||||||
|
'<p>If the ebook file does not have'
|
||||||
|
' an identifiable cover, a new cover is inserted.</p>'
|
||||||
|
),
|
||||||
'jacket':_('<h3>Book Jacket</h3>%s')%HELP['jacket'],
|
'jacket':_('<h3>Book Jacket</h3>%s')%HELP['jacket'],
|
||||||
'remove_jacket':_('<h3>Remove Book Jacket</h3>%s')%HELP['remove_jacket'],
|
'remove_jacket':_('<h3>Remove Book Jacket</h3>%s')%HELP['remove_jacket'],
|
||||||
}
|
}
|
||||||
@ -63,11 +68,12 @@ class Polish(QDialog): # {{{
|
|||||||
|
|
||||||
count = 0
|
count = 0
|
||||||
self.all_actions = OrderedDict([
|
self.all_actions = OrderedDict([
|
||||||
('subset', _('Subset all embedded fonts')),
|
('subset', _('&Subset all embedded fonts')),
|
||||||
('smarten_punctuation', _('Smarten punctuation')),
|
('smarten_punctuation', _('Smarten &punctuation')),
|
||||||
('metadata', _('Update metadata in book files')),
|
('metadata', _('Update &metadata in the book files')),
|
||||||
('jacket', _('Add metadata as a "book jacket" page')),
|
('do_cover', _('Update the &cover in the book files')),
|
||||||
('remove_jacket', _('Remove a previously inserted book jacket')),
|
('jacket', _('Add metadata as a "book &jacket" page')),
|
||||||
|
('remove_jacket', _('&Remove a previously inserted book jacket')),
|
||||||
])
|
])
|
||||||
prefs = gprefs.get('polishing_settings', {})
|
prefs = gprefs.get('polishing_settings', {})
|
||||||
for name, text in self.all_actions.iteritems():
|
for name, text in self.all_actions.iteritems():
|
||||||
@ -243,8 +249,10 @@ class Polish(QDialog): # {{{
|
|||||||
cover = os.path.join(base, 'cover.jpg')
|
cover = os.path.join(base, 'cover.jpg')
|
||||||
if db.copy_cover_to(book_id, cover, index_is_id=True):
|
if db.copy_cover_to(book_id, cover, index_is_id=True):
|
||||||
data['cover'] = cover
|
data['cover'] = cover
|
||||||
|
is_orig = {}
|
||||||
for fmt in formats:
|
for fmt in formats:
|
||||||
ext = fmt.replace('ORIGINAL_', '').lower()
|
ext = fmt.replace('ORIGINAL_', '').lower()
|
||||||
|
is_orig[ext.upper()] = 'ORIGINAL_' in fmt
|
||||||
with open(os.path.join(base, '%s.%s'%(book_id, ext)), 'wb') as f:
|
with open(os.path.join(base, '%s.%s'%(book_id, ext)), 'wb') as f:
|
||||||
db.copy_format_to(book_id, fmt, f, index_is_id=True)
|
db.copy_format_to(book_id, fmt, f, index_is_id=True)
|
||||||
data['files'].append(f.name)
|
data['files'].append(f.name)
|
||||||
@ -257,7 +265,7 @@ class Polish(QDialog): # {{{
|
|||||||
self.pd.set_msg(_('Queueing book %(nums)s of %(tot)s (%(title)s)')%dict(
|
self.pd.set_msg(_('Queueing book %(nums)s of %(tot)s (%(title)s)')%dict(
|
||||||
nums=num, tot=len(self.book_id_map), title=mi.title))
|
nums=num, tot=len(self.book_id_map), title=mi.title))
|
||||||
|
|
||||||
self.jobs.append((desc, data, book_id, base))
|
self.jobs.append((desc, data, book_id, base, is_orig))
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class Report(QDialog): # {{{
|
class Report(QDialog): # {{{
|
||||||
@ -404,11 +412,11 @@ class PolishAction(InterfaceAction):
|
|||||||
d = Polish(self.gui.library_view.model().db, book_id_map, parent=self.gui)
|
d = Polish(self.gui.library_view.model().db, book_id_map, parent=self.gui)
|
||||||
if d.exec_() == d.Accepted and d.jobs:
|
if d.exec_() == d.Accepted and d.jobs:
|
||||||
show_reports = bool(d.show_reports.isChecked())
|
show_reports = bool(d.show_reports.isChecked())
|
||||||
for desc, data, book_id, base in reversed(d.jobs):
|
for desc, data, book_id, base, is_orig in reversed(d.jobs):
|
||||||
job = self.gui.job_manager.run_job(
|
job = self.gui.job_manager.run_job(
|
||||||
Dispatcher(self.book_polished), 'gui_polish', args=(data,),
|
Dispatcher(self.book_polished), 'gui_polish', args=(data,),
|
||||||
description=desc)
|
description=desc)
|
||||||
job.polish_args = (book_id, base, data['files'], show_reports)
|
job.polish_args = (book_id, base, data['files'], show_reports, is_orig)
|
||||||
if d.jobs:
|
if d.jobs:
|
||||||
self.gui.jobs_pointer.start()
|
self.gui.jobs_pointer.start()
|
||||||
self.gui.status_bar.show_message(
|
self.gui.status_bar.show_message(
|
||||||
@ -419,11 +427,11 @@ class PolishAction(InterfaceAction):
|
|||||||
self.gui.job_exception(job)
|
self.gui.job_exception(job)
|
||||||
return
|
return
|
||||||
db = self.gui.current_db
|
db = self.gui.current_db
|
||||||
book_id, base, files, show_reports = job.polish_args
|
book_id, base, files, show_reports, is_orig = job.polish_args
|
||||||
fmts = set()
|
fmts = set()
|
||||||
for path in files:
|
for path in files:
|
||||||
fmt = path.rpartition('.')[-1].upper()
|
fmt = path.rpartition('.')[-1].upper()
|
||||||
if tweaks['save_original_format_when_polishing']:
|
if tweaks['save_original_format_when_polishing'] and not is_orig[fmt]:
|
||||||
fmts.add(fmt)
|
fmts.add(fmt)
|
||||||
db.save_original_format(book_id, fmt, notify=False)
|
db.save_original_format(book_id, fmt, notify=False)
|
||||||
with open(path, 'rb') as f:
|
with open(path, 'rb') as f:
|
||||||
|
@ -327,6 +327,13 @@ class EditorWidget(QWebView): # {{{
|
|||||||
else:
|
else:
|
||||||
return QWebView.keyReleaseEvent(self, ev)
|
return QWebView.keyReleaseEvent(self, ev)
|
||||||
|
|
||||||
|
def contextMenuEvent(self, ev):
|
||||||
|
menu = self.page().createStandardContextMenu()
|
||||||
|
paste = self.pageAction(QWebPage.Paste)
|
||||||
|
for action in menu.actions():
|
||||||
|
if action == paste:
|
||||||
|
menu.insertAction(action, self.pageAction(QWebPage.PasteAndMatchStyle))
|
||||||
|
menu.exec_(ev.globalPos())
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
@ -622,8 +622,7 @@ class BulkBase(Base):
|
|||||||
return
|
return
|
||||||
val = self.gui_val
|
val = self.gui_val
|
||||||
val = self.normalize_ui_val(val)
|
val = self.normalize_ui_val(val)
|
||||||
if val != self.initial_val:
|
self.db.set_custom_bulk(book_ids, val, num=self.col_id, notify=notify)
|
||||||
self.db.set_custom_bulk(book_ids, val, num=self.col_id, notify=notify)
|
|
||||||
|
|
||||||
def make_widgets(self, parent, main_widget_class, extra_label_text=''):
|
def make_widgets(self, parent, main_widget_class, extra_label_text=''):
|
||||||
w = QWidget(parent)
|
w = QWidget(parent)
|
||||||
@ -1030,8 +1029,7 @@ class BulkText(BulkBase):
|
|||||||
else:
|
else:
|
||||||
val = self.gui_val
|
val = self.gui_val
|
||||||
val = self.normalize_ui_val(val)
|
val = self.normalize_ui_val(val)
|
||||||
if val != self.initial_val:
|
self.db.set_custom_bulk(book_ids, val, num=self.col_id, notify=notify)
|
||||||
self.db.set_custom_bulk(book_ids, val, num=self.col_id, notify=notify)
|
|
||||||
|
|
||||||
def getter(self):
|
def getter(self):
|
||||||
if self.col_metadata['is_multiple']:
|
if self.col_metadata['is_multiple']:
|
||||||
|
@ -369,7 +369,7 @@ def build_pipe(print_error=True):
|
|||||||
t.start()
|
t.start()
|
||||||
t.join(3.0)
|
t.join(3.0)
|
||||||
if t.is_alive():
|
if t.is_alive():
|
||||||
if iswindows():
|
if iswindows:
|
||||||
cant_start()
|
cant_start()
|
||||||
else:
|
else:
|
||||||
f = os.path.expanduser('~/.calibre_calibre GUI.lock')
|
f = os.path.expanduser('~/.calibre_calibre GUI.lock')
|
||||||
|
@ -790,8 +790,7 @@ class DocumentView(QWebView): # {{{
|
|||||||
self.manager.load_started()
|
self.manager.load_started()
|
||||||
|
|
||||||
load_html(path, self, codec=getattr(path, 'encoding', 'utf-8'), mime_type=getattr(path,
|
load_html(path, self, codec=getattr(path, 'encoding', 'utf-8'), mime_type=getattr(path,
|
||||||
'mime_type', 'text/html'), pre_load_callback=callback,
|
'mime_type', 'text/html'), pre_load_callback=callback)
|
||||||
force_as_html=True)
|
|
||||||
entries = set()
|
entries = set()
|
||||||
for ie in getattr(path, 'index_entries', []):
|
for ie in getattr(path, 'index_entries', []):
|
||||||
if ie.start_anchor:
|
if ie.start_anchor:
|
||||||
|
@ -725,13 +725,15 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
|||||||
self.view.shrink_fonts()
|
self.view.shrink_fonts()
|
||||||
|
|
||||||
def magnification_changed(self, val):
|
def magnification_changed(self, val):
|
||||||
tt = _('%(which)s font size [%(sc)s]\nCurrent magnification: %(mag).1f')
|
tt = '%(action)s [%(sc)s]\n'+_('Current magnification: %(mag).1f')
|
||||||
sc = unicode(self.action_font_size_larger.shortcut().toString())
|
sc = unicode(self.action_font_size_larger.shortcut().toString())
|
||||||
self.action_font_size_larger.setToolTip(
|
self.action_font_size_larger.setToolTip(
|
||||||
tt %dict(which=_('Increase'), mag=val, sc=sc))
|
tt %dict(action=unicode(self.action_font_size_larger.text()),
|
||||||
|
mag=val, sc=sc))
|
||||||
sc = unicode(self.action_font_size_smaller.shortcut().toString())
|
sc = unicode(self.action_font_size_smaller.shortcut().toString())
|
||||||
self.action_font_size_smaller.setToolTip(
|
self.action_font_size_smaller.setToolTip(
|
||||||
tt %dict(which=_('Decrease'), mag=val, sc=sc))
|
tt %dict(action=unicode(self.action_font_size_smaller.text()),
|
||||||
|
mag=val, sc=sc))
|
||||||
self.action_font_size_larger.setEnabled(self.view.multiplier < 3)
|
self.action_font_size_larger.setEnabled(self.view.multiplier < 3)
|
||||||
self.action_font_size_smaller.setEnabled(self.view.multiplier > 0.2)
|
self.action_font_size_smaller.setEnabled(self.view.multiplier > 0.2)
|
||||||
|
|
||||||
|
@ -955,8 +955,8 @@ class LayoutButton(QToolButton):
|
|||||||
|
|
||||||
def set_state_to_hide(self, *args):
|
def set_state_to_hide(self, *args):
|
||||||
self.setChecked(True)
|
self.setChecked(True)
|
||||||
label = _('Hide')
|
self.setText(_('Hide %(label)s %(shortcut)s'%dict(
|
||||||
self.setText(label + ' ' + self.label+ u' (%s)'%self.shortcut)
|
label=self.label, shortcut=self.shortcut)))
|
||||||
self.setToolTip(self.text())
|
self.setToolTip(self.text())
|
||||||
self.setStatusTip(self.text())
|
self.setStatusTip(self.text())
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ from calibre.ebooks.metadata import title_sort, author_to_author_sort
|
|||||||
from calibre.utils.date import parse_date, isoformat, local_tz, UNDEFINED_DATE
|
from calibre.utils.date import parse_date, isoformat, local_tz, UNDEFINED_DATE
|
||||||
from calibre import isbytestring, force_unicode
|
from calibre import isbytestring, force_unicode
|
||||||
from calibre.constants import iswindows, DEBUG, plugins
|
from calibre.constants import iswindows, DEBUG, plugins
|
||||||
from calibre.utils.icu import strcmp
|
from calibre.utils.icu import sort_key
|
||||||
from calibre import prints
|
from calibre import prints
|
||||||
|
|
||||||
from dateutil.tz import tzoffset
|
from dateutil.tz import tzoffset
|
||||||
@ -189,7 +189,8 @@ def pynocase(one, two, encoding='utf-8'):
|
|||||||
return cmp(one.lower(), two.lower())
|
return cmp(one.lower(), two.lower())
|
||||||
|
|
||||||
def icu_collator(s1, s2):
|
def icu_collator(s1, s2):
|
||||||
return strcmp(force_unicode(s1, 'utf-8'), force_unicode(s2, 'utf-8'))
|
return cmp(sort_key(force_unicode(s1, 'utf-8')),
|
||||||
|
sort_key(force_unicode(s2, 'utf-8')))
|
||||||
|
|
||||||
def load_c_extensions(conn, debug=DEBUG):
|
def load_c_extensions(conn, debug=DEBUG):
|
||||||
try:
|
try:
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: calibre 0.9.20\n"
|
"Project-Id-Version: calibre 0.9.20\n"
|
||||||
"POT-Creation-Date: 2013-02-22 10:18+IST\n"
|
"POT-Creation-Date: 2013-02-24 10:08+IST\n"
|
||||||
"PO-Revision-Date: 2013-02-22 10:18+IST\n"
|
"PO-Revision-Date: 2013-02-24 10:08+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"
|
||||||
@ -24,8 +24,8 @@ msgstr ""
|
|||||||
#: /home/kovid/work/calibre/src/calibre/db/cache.py:124
|
#: /home/kovid/work/calibre/src/calibre/db/cache.py:124
|
||||||
#: /home/kovid/work/calibre/src/calibre/db/cache.py:127
|
#: /home/kovid/work/calibre/src/calibre/db/cache.py:127
|
||||||
#: /home/kovid/work/calibre/src/calibre/db/cache.py:138
|
#: /home/kovid/work/calibre/src/calibre/db/cache.py:138
|
||||||
#: /home/kovid/work/calibre/src/calibre/db/write.py:100
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/db/write.py:102
|
#: /home/kovid/work/calibre/src/calibre/db/write.py:102
|
||||||
|
#: /home/kovid/work/calibre/src/calibre/db/write.py:106
|
||||||
#: /home/kovid/work/calibre/src/calibre/devices/android/driver.py:383
|
#: /home/kovid/work/calibre/src/calibre/devices/android/driver.py:383
|
||||||
#: /home/kovid/work/calibre/src/calibre/devices/android/driver.py:384
|
#: /home/kovid/work/calibre/src/calibre/devices/android/driver.py:384
|
||||||
#: /home/kovid/work/calibre/src/calibre/devices/hanvon/driver.py:114
|
#: /home/kovid/work/calibre/src/calibre/devices/hanvon/driver.py:114
|
||||||
@ -882,8 +882,8 @@ msgstr ""
|
|||||||
msgid "Disable the named plugin"
|
msgid "Disable the named plugin"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/db/backend.py:321
|
#: /home/kovid/work/calibre/src/calibre/db/backend.py:323
|
||||||
#: /home/kovid/work/calibre/src/calibre/db/backend.py:330
|
#: /home/kovid/work/calibre/src/calibre/db/backend.py:332
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:322
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:322
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_library.py:98
|
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_library.py:98
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:749
|
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:749
|
||||||
@ -896,7 +896,7 @@ msgstr ""
|
|||||||
#: /home/kovid/work/calibre/src/calibre/db/cache.py:152
|
#: /home/kovid/work/calibre/src/calibre/db/cache.py:152
|
||||||
#: /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:678
|
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:677
|
||||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1030
|
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1030
|
||||||
#: /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
|
||||||
@ -908,25 +908,25 @@ msgstr ""
|
|||||||
msgid "%(tt)sAverage rating is %(rating)3.1f"
|
msgid "%(tt)sAverage rating is %(rating)3.1f"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/db/fields.py:232
|
#: /home/kovid/work/calibre/src/calibre/db/fields.py:233
|
||||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1187
|
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1187
|
||||||
msgid "Main"
|
msgid "Main"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/db/fields.py:234
|
#: /home/kovid/work/calibre/src/calibre/db/fields.py:235
|
||||||
#: /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:1189
|
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1189
|
||||||
msgid "Card A"
|
msgid "Card A"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/db/fields.py:236
|
#: /home/kovid/work/calibre/src/calibre/db/fields.py:237
|
||||||
#: /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:1191
|
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1191
|
||||||
msgid "Card B"
|
msgid "Card B"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/db/fields.py:471
|
#: /home/kovid/work/calibre/src/calibre/db/fields.py:472
|
||||||
#: /home/kovid/work/calibre/src/calibre/db/fields.py:486
|
#: /home/kovid/work/calibre/src/calibre/db/fields.py:487
|
||||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2822
|
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2822
|
||||||
#: /home/kovid/work/calibre/src/calibre/devices/nook/driver.py:106
|
#: /home/kovid/work/calibre/src/calibre/devices/nook/driver.py:106
|
||||||
#: /home/kovid/work/calibre/src/calibre/devices/prs505/sony_cache.py:448
|
#: /home/kovid/work/calibre/src/calibre/devices/prs505/sony_cache.py:448
|
||||||
@ -3479,7 +3479,7 @@ 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:678
|
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:677
|
||||||
msgid "No"
|
msgid "No"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3928,7 +3928,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/polish/main.py:48
|
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/polish/main.py:48
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:392
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:400
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel.py:197
|
#: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel.py:197
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:132
|
#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:132
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:223
|
#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:223
|
||||||
@ -4034,27 +4034,27 @@ msgstr ""
|
|||||||
msgid "Polishing took: %.1f seconds"
|
msgid "Polishing took: %.1f seconds"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/polish/main.py:201
|
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/polish/main.py:202
|
||||||
msgid "Path to a cover image. Changes the cover specified in the ebook. If no cover is present, or the cover is not properly identified, inserts a new cover."
|
msgid "Path to a cover image. Changes the cover specified in the ebook. If no cover is present, or the cover is not properly identified, inserts a new cover."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/polish/main.py:204
|
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/polish/main.py:205
|
||||||
msgid "Path to an OPF file. The metadata in the book is updated from the OPF file."
|
msgid "Path to an OPF file. The metadata in the book is updated from the OPF file."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/polish/main.py:209
|
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/polish/main.py:210
|
||||||
msgid "Produce more verbose output, useful for debugging."
|
msgid "Produce more verbose output, useful for debugging."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/polish/main.py:219
|
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/polish/main.py:220
|
||||||
msgid "You must provide the input file to polish"
|
msgid "You must provide the input file to polish"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/polish/main.py:223
|
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/polish/main.py:224
|
||||||
msgid "Unknown extra arguments"
|
msgid "Unknown extra arguments"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/polish/main.py:241
|
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/polish/main.py:242
|
||||||
msgid "You must specify at least one action to perform"
|
msgid "You must specify at least one action to perform"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4385,7 +4385,7 @@ msgstr ""
|
|||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:192
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:192
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:256
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:256
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:293
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:293
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:377
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:385
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:82
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:82
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:271
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:271
|
||||||
msgid "No books selected"
|
msgid "No books selected"
|
||||||
@ -5393,165 +5393,175 @@ msgid "<h3>Smarten punctuation</h3>%s"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:46
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:46
|
||||||
msgid "<h3>Updating metadata</h3><p>This will update all metadata and covers in the ebook files to match the current metadata in the calibre library.</p><p>If the ebook file does not have an identifiable cover, a new cover is inserted.</p> <p>Note that most ebook formats are not capable of supporting all the metadata in calibre.</p>"
|
msgid "<h3>Updating metadata</h3><p>This will update all metadata <i>except</i> the cover in the ebook files to match the current metadata in the calibre library.</p> <p>Note that most ebook formats are not capable of supporting all the metadata in calibre.</p><p>There is a separate option to update the cover.</p>"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:54
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:54
|
||||||
|
msgid "<p>Update the covers in the ebook files to match the current cover in the calibre library.</p><p>If the ebook file does not have an identifiable cover, a new cover is inserted.</p>"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:59
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "<h3>Book Jacket</h3>%s"
|
msgid "<h3>Book Jacket</h3>%s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:55
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:60
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "<h3>Remove Book Jacket</h3>%s"
|
msgid "<h3>Remove Book Jacket</h3>%s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:61
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:66
|
||||||
msgid "Select actions to perform:"
|
msgid "Select actions to perform:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:66
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:71
|
||||||
msgid "Subset all embedded fonts"
|
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:249
|
||||||
|
msgid "&Subset all embedded fonts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:67
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:72
|
||||||
msgid "Smarten punctuation"
|
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:240
|
||||||
|
msgid "Smarten &punctuation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:68
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:73
|
||||||
msgid "Update metadata in book files"
|
msgid "Update &metadata in the book files"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:69
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:74
|
||||||
msgid "Add metadata as a \"book jacket\" page"
|
msgid "Update the &cover in the book files"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:70
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:75
|
||||||
msgid "Remove a previously inserted book jacket"
|
msgid "Add metadata as a \"book &jacket\" page"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:80
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:76
|
||||||
|
msgid "&Remove a previously inserted book jacket"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:86
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:99
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:105
|
||||||
msgid "Show &report"
|
msgid "Show &report"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:101
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:107
|
||||||
msgid "Show a report of all the actions performed after polishing is completed"
|
msgid "Show a report of all the actions performed after polishing is completed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:107
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:113
|
||||||
msgid "&Save Settings"
|
msgid "&Save Settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:109
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:115
|
||||||
msgid "&Load Settings"
|
msgid "&Load Settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:112
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:118
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/duplicates.py:47
|
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/duplicates.py:47
|
||||||
msgid "Select &all"
|
msgid "Select &all"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:114
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:120
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/duplicates.py:49
|
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/duplicates.py:49
|
||||||
msgid "Select &none"
|
msgid "Select &none"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:130
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:136
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:195
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:201
|
||||||
msgid "No actions selected"
|
msgid "No actions selected"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:131
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:137
|
||||||
msgid "You must select at least one action before saving"
|
msgid "You must select at least one action before saving"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:133
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:139
|
||||||
msgid "Choose name"
|
msgid "Choose name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:134
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:140
|
||||||
msgid "Choose a name for these settings"
|
msgid "Choose a name for these settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:154
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:160
|
||||||
msgid "Remove saved settings"
|
msgid "Remove saved settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:196
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:202
|
||||||
msgid "You must select at least one action, or click Cancel."
|
msgid "You must select at least one action, or click Cancel."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:210
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:216
|
||||||
msgid "Queueing books for polishing"
|
msgid "Queueing books for polishing"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:252
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:260
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Polish %s"
|
msgid "Polish %s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:253
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:261
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Polish book %(nums)s of %(tot)s (%(title)s)"
|
msgid "Polish book %(nums)s of %(tot)s (%(title)s)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:257
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:265
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Queueing book %(nums)s of %(tot)s (%(title)s)"
|
msgid "Queueing book %(nums)s of %(tot)s (%(title)s)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:283
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:291
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Ignore remaining %d reports"
|
msgid "Ignore remaining %d reports"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:290
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:298
|
||||||
msgid "View full &log"
|
msgid "View full &log"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:313
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:321
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Polishing of %s"
|
msgid "Polishing of %s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:319
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:327
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The original file has been saved as %s."
|
msgid "The original file has been saved as %s."
|
||||||
msgid_plural "The original files have been saved as %s."
|
msgid_plural "The original files have been saved as %s."
|
||||||
msgstr[0] ""
|
msgstr[0] ""
|
||||||
msgstr[1] ""
|
msgstr[1] ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:321
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:329
|
||||||
msgid " and "
|
msgid " and "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:324
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:332
|
||||||
msgid "If you polish again, the polishing will run on the originals."
|
msgid "If you polish again, the polishing will run on the originals."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:359
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:367
|
||||||
msgid "P"
|
msgid "P"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:359
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:367
|
||||||
msgid "Polish books"
|
msgid "Polish books"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:376
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:384
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:389
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:397
|
||||||
msgid "Cannot polish"
|
msgid "Cannot polish"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:390
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:398
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Polishing is only supported for books in the %s formats. Convert to one of those formats before polishing."
|
msgid "Polishing is only supported for books in the %s formats. Convert to one of those formats before polishing."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:415
|
#: /home/kovid/work/calibre/src/calibre/gui2/actions/polish.py:423
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Start polishing of %d book(s)"
|
msgid "Start polishing of %d book(s)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -7317,10 +7327,6 @@ msgstr ""
|
|||||||
msgid "Text &justification:"
|
msgid "Text &justification:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:240
|
|
||||||
msgid "Smarten &punctuation"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:241
|
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:241
|
||||||
msgid "&Transliterate unicode characters to ASCII"
|
msgid "&Transliterate unicode characters to ASCII"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -7353,10 +7359,6 @@ msgstr ""
|
|||||||
msgid "&Disable font size rescaling"
|
msgid "&Disable font size rescaling"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:249
|
|
||||||
msgid "&Subset all embedded fonts"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/lrf_output.py:16
|
#: /home/kovid/work/calibre/src/calibre/gui2/convert/lrf_output.py:16
|
||||||
msgid "LRF Output"
|
msgid "LRF Output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -8263,10 +8265,10 @@ msgstr ""
|
|||||||
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:116
|
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:116
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:153
|
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:153
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:187
|
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:187
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:682
|
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:681
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:723
|
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:722
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:746
|
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:745
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:797
|
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:796
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:348
|
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:348
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:356
|
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:356
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:83
|
#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:83
|
||||||
@ -8279,23 +8281,23 @@ msgid "Undefined"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:130
|
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:130
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:754
|
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:753
|
||||||
msgid "star(s)"
|
msgid "star(s)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:131
|
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:131
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:755
|
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:754
|
||||||
msgid "Unrated"
|
msgid "Unrated"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:174
|
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:174
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:784
|
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:783
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Set '%s' to today"
|
msgid "Set '%s' to today"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:176
|
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:176
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:786
|
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:785
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Clear '%s'"
|
msgid "Clear '%s'"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -8320,35 +8322,35 @@ msgstr ""
|
|||||||
msgid "The enumeration \"{0}\" contains an invalid value that will be set to the default"
|
msgid "The enumeration \"{0}\" contains an invalid value that will be set to the default"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:637
|
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:636
|
||||||
msgid "Apply changes"
|
msgid "Apply changes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:830
|
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:829
|
||||||
msgid "Remove series"
|
msgid "Remove series"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:833
|
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:832
|
||||||
msgid "Automatically number books"
|
msgid "Automatically number books"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:836
|
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:835
|
||||||
msgid "Force numbers to start with "
|
msgid "Force numbers to start with "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:906
|
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:905
|
||||||
msgid "The enumeration \"{0}\" contains invalid values that will not appear in the list"
|
msgid "The enumeration \"{0}\" contains invalid values that will not appear in the list"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:950
|
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:949
|
||||||
msgid "Remove all tags"
|
msgid "Remove all tags"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:970
|
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:969
|
||||||
msgid "tags to add"
|
msgid "tags to add"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:977
|
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:976
|
||||||
msgid "tags to remove"
|
msgid "tags to remove"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -9343,7 +9345,7 @@ msgstr ""
|
|||||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/edit_authors_dialog.py:122
|
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/edit_authors_dialog.py:122
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/lrf_renderer/main.py:160
|
#: /home/kovid/work/calibre/src/calibre/gui2/lrf_renderer/main.py:160
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:543
|
#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:543
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:751
|
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:753
|
||||||
msgid "No matches found"
|
msgid "No matches found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -16154,7 +16156,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:1146
|
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1148
|
||||||
msgid "Remember last used window size"
|
msgid "Remember last used window size"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -16724,83 +16726,73 @@ msgstr ""
|
|||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:728
|
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:728
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid "Current magnification: %(mag).1f"
|
||||||
"%(which)s font size [%(sc)s]\n"
|
|
||||||
"Current magnification: %(mag).1f"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:731
|
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:754
|
||||||
msgid "Increase"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:734
|
|
||||||
msgid "Decrease"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:752
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "No matches found for: %s"
|
msgid "No matches found for: %s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:801
|
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:803
|
||||||
msgid "Loading flow..."
|
msgid "Loading flow..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:879
|
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:881
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Laying out %s"
|
msgid "Laying out %s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:946
|
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:948
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Bookmark #%d"
|
msgid "Bookmark #%d"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:950
|
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:952
|
||||||
msgid "Add bookmark"
|
msgid "Add bookmark"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:951
|
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:953
|
||||||
msgid "Enter title for bookmark:"
|
msgid "Enter title for bookmark:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:962
|
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:964
|
||||||
msgid "Manage Bookmarks"
|
msgid "Manage Bookmarks"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1004
|
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1006
|
||||||
msgid "Loading ebook..."
|
msgid "Loading ebook..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1017
|
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1019
|
||||||
msgid "Could not open ebook"
|
msgid "Could not open ebook"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1018
|
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1020
|
||||||
msgid "Unknown error"
|
msgid "Unknown error"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1133
|
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1135
|
||||||
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:1140
|
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1142
|
||||||
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:1143
|
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1145
|
||||||
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:1148
|
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1150
|
||||||
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:1150
|
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1152
|
||||||
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:1157
|
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:1159
|
||||||
msgid ""
|
msgid ""
|
||||||
"%prog [options] file\n"
|
"%prog [options] file\n"
|
||||||
"\n"
|
"\n"
|
||||||
@ -16914,7 +16906,8 @@ msgid "Show"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:958
|
#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:958
|
||||||
msgid "Hide"
|
#, python-format
|
||||||
|
msgid "Hide %(label)s %(shortcut)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:995
|
#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:995
|
||||||
@ -19363,6 +19356,18 @@ msgstr ""
|
|||||||
msgid "pm"
|
msgid "pm"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: /home/kovid/work/calibre/src/calibre/utils/localization.py:204
|
||||||
|
msgid "&Copy"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: /home/kovid/work/calibre/src/calibre/utils/localization.py:205
|
||||||
|
msgid "Select All"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: /home/kovid/work/calibre/src/calibre/utils/localization.py:206
|
||||||
|
msgid "Copy &Link location"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/utils/pyconsole/console.py:56
|
#: /home/kovid/work/calibre/src/calibre/utils/pyconsole/console.py:56
|
||||||
msgid "Choose theme (needs restart)"
|
msgid "Choose theme (needs restart)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -19988,3 +19993,11 @@ msgstr ""
|
|||||||
#: /home/kovid/work/calibre/resources/default_tweaks.py:512
|
#: /home/kovid/work/calibre/resources/default_tweaks.py:512
|
||||||
msgid "This means that you can make changes and press Enter and your changes will\nnot be overwritten by a matching completion. However, if you wish to use the\ncompletions you will now have to press Tab to select one before pressing\nEnter. Which technique you prefer will depend on the state of metadata in\nyour library and your personal editing style."
|
msgid "This means that you can make changes and press Enter and your changes will\nnot be overwritten by a matching completion. However, if you wish to use the\ncompletions you will now have to press Tab to select one before pressing\nEnter. Which technique you prefer will depend on the state of metadata in\nyour library and your personal editing style."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: /home/kovid/work/calibre/resources/default_tweaks.py:519
|
||||||
|
msgid "Recognize numbers inside text when sorting"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: /home/kovid/work/calibre/resources/default_tweaks.py:520
|
||||||
|
msgid "This means that when sorting on text fields like title the text \"Book 2\"\nwill sort before the text \"Book 100\". If you want this behavior, set\nnumeric_collation = True note that doing so will cause problems with text\nthat starts with numbers and is a little slower."
|
||||||
|
msgstr ""
|
||||||
|
@ -110,6 +110,21 @@ icu_Collator_set_strength(icu_Collator *self, PyObject *val, void *closure) {
|
|||||||
}
|
}
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
|
// Collator.numeric {{{
|
||||||
|
static PyObject *
|
||||||
|
icu_Collator_get_numeric(icu_Collator *self, void *closure) {
|
||||||
|
UErrorCode status = U_ZERO_ERROR;
|
||||||
|
return Py_BuildValue("O", (ucol_getAttribute(self->collator, UCOL_NUMERIC_COLLATION, &status) == UCOL_ON) ? Py_True : Py_False);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
icu_Collator_set_numeric(icu_Collator *self, PyObject *val, void *closure) {
|
||||||
|
UErrorCode status = U_ZERO_ERROR;
|
||||||
|
ucol_setAttribute(self->collator, UCOL_NUMERIC_COLLATION, (PyObject_IsTrue(val)) ? UCOL_ON : UCOL_OFF, &status);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// }}}
|
||||||
|
|
||||||
// Collator.actual_locale {{{
|
// Collator.actual_locale {{{
|
||||||
static PyObject *
|
static PyObject *
|
||||||
icu_Collator_actual_locale(icu_Collator *self, void *closure) {
|
icu_Collator_actual_locale(icu_Collator *self, void *closure) {
|
||||||
@ -415,6 +430,10 @@ static PyGetSetDef icu_Collator_getsetters[] = {
|
|||||||
(char *)"The strength of this collator.",
|
(char *)"The strength of this collator.",
|
||||||
NULL},
|
NULL},
|
||||||
|
|
||||||
|
{(char *)"numeric",
|
||||||
|
(getter)icu_Collator_get_numeric, (setter)icu_Collator_set_numeric,
|
||||||
|
(char *)"If True the collator sorts contiguous digits as numbers rather than strings, so 2 will sort before 10.",
|
||||||
|
NULL},
|
||||||
|
|
||||||
{NULL} /* Sentinel */
|
{NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
@ -12,7 +12,7 @@ from functools import partial
|
|||||||
from calibre.constants import plugins
|
from calibre.constants import plugins
|
||||||
from calibre.utils.config_base import tweaks
|
from calibre.utils.config_base import tweaks
|
||||||
|
|
||||||
_icu = _collator = _primary_collator = _secondary_collator = None
|
_icu = _collator = _primary_collator = _sort_collator = None
|
||||||
_locale = None
|
_locale = None
|
||||||
|
|
||||||
_none = u''
|
_none = u''
|
||||||
@ -41,6 +41,7 @@ def load_icu():
|
|||||||
return _icu
|
return _icu
|
||||||
|
|
||||||
def load_collator():
|
def load_collator():
|
||||||
|
'The default collator for most locales takes both case and accented letters into account'
|
||||||
global _collator
|
global _collator
|
||||||
if _collator is None:
|
if _collator is None:
|
||||||
icu = load_icu()
|
icu = load_icu()
|
||||||
@ -49,18 +50,25 @@ def load_collator():
|
|||||||
return _collator
|
return _collator
|
||||||
|
|
||||||
def primary_collator():
|
def primary_collator():
|
||||||
|
'Ignores case differences and accented characters'
|
||||||
global _primary_collator
|
global _primary_collator
|
||||||
if _primary_collator is None:
|
if _primary_collator is None:
|
||||||
_primary_collator = _collator.clone()
|
_primary_collator = _collator.clone()
|
||||||
_primary_collator.strength = _icu.UCOL_PRIMARY
|
_primary_collator.strength = _icu.UCOL_PRIMARY
|
||||||
return _primary_collator
|
return _primary_collator
|
||||||
|
|
||||||
def secondary_collator():
|
def sort_collator():
|
||||||
global _secondary_collator
|
'Ignores case differences and recognizes numbers in strings'
|
||||||
if _secondary_collator is None:
|
global _sort_collator
|
||||||
_secondary_collator = _collator.clone()
|
if _sort_collator is None:
|
||||||
_secondary_collator.strength = _icu.UCOL_SECONDARY
|
_sort_collator = _collator.clone()
|
||||||
return _secondary_collator
|
_sort_collator.strength = _icu.UCOL_SECONDARY
|
||||||
|
if tweaks['numeric_collation']:
|
||||||
|
try:
|
||||||
|
_sort_collator.numeric = True
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
return _sort_collator
|
||||||
|
|
||||||
def py_sort_key(obj):
|
def py_sort_key(obj):
|
||||||
if not obj:
|
if not obj:
|
||||||
@ -72,15 +80,15 @@ def icu_sort_key(collator, obj):
|
|||||||
return _none2
|
return _none2
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
return _secondary_collator.sort_key(obj)
|
return _sort_collator.sort_key(obj)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return secondary_collator().sort_key(obj)
|
return sort_collator().sort_key(obj)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
if isinstance(obj, unicode):
|
if isinstance(obj, unicode):
|
||||||
obj = obj.replace(u'\0', u'')
|
obj = obj.replace(u'\0', u'')
|
||||||
else:
|
else:
|
||||||
obj = obj.replace(b'\0', b'')
|
obj = obj.replace(b'\0', b'')
|
||||||
return _secondary_collator.sort_key(obj)
|
return _sort_collator.sort_key(obj)
|
||||||
|
|
||||||
def icu_change_case(upper, locale, obj):
|
def icu_change_case(upper, locale, obj):
|
||||||
func = _icu.upper if upper else _icu.lower
|
func = _icu.upper if upper else _icu.lower
|
||||||
@ -233,9 +241,9 @@ def collation_order(a):
|
|||||||
if _icu_not_ok:
|
if _icu_not_ok:
|
||||||
return (ord(a[0]), 1) if a else (0, 0)
|
return (ord(a[0]), 1) if a else (0, 0)
|
||||||
try:
|
try:
|
||||||
return icu_collation_order(_secondary_collator, a)
|
return icu_collation_order(_sort_collator, a)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return icu_collation_order(secondary_collator(), a)
|
return icu_collation_order(sort_collator(), a)
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
@ -333,6 +341,7 @@ pêché'''
|
|||||||
|
|
||||||
german = create(german)
|
german = create(german)
|
||||||
c = _icu.Collator('de')
|
c = _icu.Collator('de')
|
||||||
|
c.numeric = True
|
||||||
gs = list(sorted(german, key=c.sort_key))
|
gs = list(sorted(german, key=c.sort_key))
|
||||||
if gs != create(german_good):
|
if gs != create(german_good):
|
||||||
print 'German sorting failed'
|
print 'German sorting failed'
|
||||||
@ -340,6 +349,7 @@ pêché'''
|
|||||||
print
|
print
|
||||||
french = create(french)
|
french = create(french)
|
||||||
c = _icu.Collator('fr')
|
c = _icu.Collator('fr')
|
||||||
|
c.numeric = True
|
||||||
fs = list(sorted(french, key=c.sort_key))
|
fs = list(sorted(french, key=c.sort_key))
|
||||||
if fs != create(french_good):
|
if fs != create(french_good):
|
||||||
print 'French sorting failed (note that French fails with icu < 4.6)'
|
print 'French sorting failed (note that French fails with icu < 4.6)'
|
||||||
@ -388,6 +398,25 @@ pêché'''
|
|||||||
print 'startswith() failed'
|
print 'startswith() failed'
|
||||||
return
|
return
|
||||||
|
|
||||||
|
print '\nTesting collation_order()'
|
||||||
|
for group in [
|
||||||
|
('Šaa', 'Smith', 'Solženicyn', 'Štepánek'),
|
||||||
|
('calibre', 'Charon', 'Collins'),
|
||||||
|
('01', '1'),
|
||||||
|
('1', '11', '13'),
|
||||||
|
]:
|
||||||
|
last = None
|
||||||
|
for x in group:
|
||||||
|
val = icu_collation_order(sort_collator(), x)
|
||||||
|
if val[1] != 1:
|
||||||
|
prints('collation_order() returned incorrect length for', x)
|
||||||
|
if last is None:
|
||||||
|
last = val
|
||||||
|
else:
|
||||||
|
if val != last:
|
||||||
|
prints('collation_order() returned incorrect value for', x)
|
||||||
|
last = val
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
@ -201,6 +201,9 @@ if False:
|
|||||||
_('am')
|
_('am')
|
||||||
# NOTE: Post Meridian (i.e. like 10:00 pm)
|
# NOTE: Post Meridian (i.e. like 10:00 pm)
|
||||||
_('pm')
|
_('pm')
|
||||||
|
_('&Copy')
|
||||||
|
_('Select All')
|
||||||
|
_('Copy &Link location')
|
||||||
|
|
||||||
_lcase_map = {}
|
_lcase_map = {}
|
||||||
for k in _extra_lang_codes:
|
for k in _extra_lang_codes:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user