Sync to trunk.

This commit is contained in:
John Schember 2010-05-24 17:48:46 -04:00
commit 28730f61a7
101 changed files with 50992 additions and 25721 deletions

View File

@ -4,6 +4,70 @@
# for important features/bug fixes.
# Also, each release can have new and improved recipes.
- version: 0.6.54
date: 2010-05-21
new features:
- title: "EPUB Output: Add option to toggle preserving the aspect ratio of the cover."
type: major
description: >
"By default calibre creates an SVG based cover that scales with the screen size of the reader used to view it. Previosuly this scaling
was limited to preserve the aspect ratio of the image. This would often result in white borders at the sides or top and bottom of the image.
No, by default, calibre will setup the cover to not preserve aspect ratio, doing away with the white borders. The downside is that if the
aspect ratio of the cover is very different from the reader, it will look distorted. The old behavior can be restored via
Preferences->Conversion->EPUB Output."
- title: "Conversion pipeline: calibre will now automatically replace all ligatures in the input document."
type: major
description: >
"Conversion pipeline: calibre will now automatically replace all ligatures in the input document with the normal character
sequence they are meant to represent. This is because most readers lack the font support to display ligatures.
This can be turned off via an option under Look & Feel, in the Conversion settings."
- title: "Support for the iPapyrus and Newsmy readers and the Sony Ericsson XPERIA X10"
- title: "PDF Output: Set the first page to the cover."
tickets: [5581]
bug fixes:
- title: "Conversion pipeline: Handle input documents with no text. Allows conversion of MOBI files tha are only a sequence of images."
tickets: [5554]
- title: "Fix text justification control not working with translated version of calibre"
tickets: [5551]
- title: "HTML Input: Encoding detection fixed for <meta> tags that have newlines in their content attributes"
tickets: [5567]
- title: "EPUB Input: Handle malformed UUID in EPUB with obfuscated fonts."
tickets: [5552]
- title: "Don't resort when editing columns in the main GUI"
- title: "Fix regression in Kobo driver that caused it to only detect books in the root directory of the device"
new recipes:
- title: La Stampa and Libero
author: Gabriele Marini
- title: Der Tagesspiegel
author: ipaschke
- title: EMG and Agro Gerilla
author: Darko Miletic
- title: American Prospect, FactCheck and PolitiFact
author: Michael Heinz
improved recipes:
- Times Online
- The Atlantic
- Il Messagero
- Leggo
- Instapaper
- New York Review of Books
- NIN Online
- version: 0.6.53
date: 2010-05-15
@ -157,7 +221,7 @@
new features:
- title: "Add merge book feature"
type: major
desc: >
description: >
"You can now merge multiple books into a single book, by clicking the arrow next to the edit meta information button.
Meta information from the books will be merged as well as individual book files in different formats"

Binary file not shown.

After

Width:  |  Height:  |  Size: 705 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 682 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 682 B

View File

@ -0,0 +1,40 @@
__license__ = 'GPL v3'
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
'''
boljevac.blogspot.com
'''
import re
from calibre.web.feeds.news import BasicNewsRecipe
class AgroGerila(BasicNewsRecipe):
title = 'Agro Gerila'
__author__ = 'Darko Miletic'
description = 'Politicki nekorektan blog.'
oldest_article = 45
max_articles_per_feed = 100
language = 'sr'
encoding = 'utf-8'
no_stylesheets = True
use_embedded_content = True
publication_type = 'blog'
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/tt0003m_.ttf)} body{font-family: "Trebuchet MS",Trebuchet,Verdana,sans1,sans-serif} .article_description{font-family: sans1, sans-serif} img{margin-bottom: 0.8em; border: 1px solid #333333; padding: 4px } '
conversion_options = {
'comment' : description
, 'tags' : 'film, blog, srbija'
, 'publisher': 'Dry-Na-Nord'
, 'language' : language
}
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
feeds = [(u'Posts', u'http://boljevac.blogspot.com/feeds/posts/default')]
def preprocess_html(self, soup):
for item in soup.findAll(style=True):
del item['style']
return self.adeify_images(soup)

View File

@ -0,0 +1,43 @@
__license__ = 'GPL v3'
__copyright__ = '2010, Walt Anthony <workshop.northpole at gmail.com>'
'''
www.americanthinker.com
'''
from calibre.web.feeds.news import BasicNewsRecipe
class AmericanThinker(BasicNewsRecipe):
title = u'American Thinker'
description = "American Thinker is a daily internet publication devoted to the thoughtful exploration of issues of importance to Americans."
__author__ = 'Walt Anthony'
publisher = 'Thomas Lifson'
category = 'news, politics, USA'
oldest_article = 7 #days
max_articles_per_feed = 50
summary_length = 150
language = 'en'
remove_javascript = True
no_stylesheets = True
conversion_options = {
'comment' : description
, 'tags' : category
, 'publisher' : publisher
, 'language' : language
, 'linearize_tables' : True
}
remove_tags = [
dict(name=['table', 'iframe', 'embed', 'object'])
]
remove_tags_after = dict(name='div', attrs={'class':'article_body'})
feeds = [(u'http://feeds.feedburner.com/americanthinker'),
(u'http://feeds.feedburner.com/AmericanThinkerBlog')
]
def print_version(self, url):
return 'http://www.americanthinker.com/printpage/?url=' + url

View File

@ -0,0 +1,26 @@
import re
from calibre.web.feeds.news import BasicNewsRecipe
class AmericanProspect(BasicNewsRecipe):
title = u'American Prospect'
__author__ = u'Michael Heinz'
oldest_article = 30
language = 'en'
max_articles_per_feed = 100
recursions = 0
no_stylesheets = True
remove_javascript = True
preprocess_regexps = [
(re.compile(r'<body.*?<div class="pad_10L10R">', re.DOTALL|re.IGNORECASE), lambda match: '<body><div>'),
(re.compile(r'</div>.*</body>', re.DOTALL|re.IGNORECASE), lambda match: '</div></body>'),
(re.compile('\r'),lambda match: ''),
(re.compile(r'<!-- .+? -->', re.DOTALL|re.IGNORECASE), lambda match: ''),
(re.compile(r'<link .+?>', re.DOTALL|re.IGNORECASE), lambda match: ''),
(re.compile(r'<script.*?</script>', re.DOTALL|re.IGNORECASE), lambda match: ''),
(re.compile(r'<noscript.*?</noscript>', re.DOTALL|re.IGNORECASE), lambda match: ''),
(re.compile(r'<meta .*?/>', re.DOTALL|re.IGNORECASE), lambda match: ''),
]
feeds = [(u'Articles', u'feed://www.prospect.org/articles_rss.jsp')]

View File

@ -5,7 +5,7 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
'''
theatlantic.com
'''
import string
import string, re
from calibre.web.feeds.news import BasicNewsRecipe
from calibre.ebooks.BeautifulSoup import Tag, NavigableString
@ -23,6 +23,8 @@ class TheAtlantic(BasicNewsRecipe):
remove_tags = [dict(id=['header', 'printAds', 'pageControls'])]
no_stylesheets = True
preprocess_regexps = [(re.compile(r'<!--.*?-->', re.DOTALL), lambda m: '')]
def print_version(self, url):
return url.replace('/archive/', '/print/')

View File

@ -9,6 +9,7 @@ class BillOReilly(BasicNewsRecipe):
title = u"Bill O'Reilly"
__author__ = 'Rob Lammert - rob.lammert[at]gmail.com'
description = u"Articles from Bill O'Reilly's website and his Fox New's website"
language = 'en'
oldest_article = 7.0
max_articles_per_feed = 100
recursions = 0

View File

@ -31,7 +31,7 @@ class DigitalSpyUK(BasicNewsRecipe):
remove_tags = [dict(name=['link'])]
remove_attributes = ['height','width']
keep_only_tags = [dict(name='div',attrs={'id':'article'})]
keep_only_tags = [dict(name='div',attrs={'id':'content'})]
feeds = [
(u'News' , u'http://www.digitalspy.co.uk/rss/zones/gb/all.xml' )

View File

@ -22,7 +22,7 @@ class Economist(BasicNewsRecipe):
' Needs a subscription from ')+INDEX
oldest_article = 7.0
cover_url = 'http://www.economist.com/images/covers/currentcovereu_large.jpg'
cover_url = 'http://www.economist.com/images/covers/currentcoverus_large.jpg'
remove_tags = [dict(name=['script', 'noscript', 'title', 'iframe', 'cf_floatingcontent']),
dict(attrs={'class':['dblClkTrk']})]
remove_tags_before = dict(name=lambda tag: tag.name=='title' and tag.parent.name=='body')

View File

@ -15,7 +15,7 @@ class Economist(BasicNewsRecipe):
' Much slower than the subscription based version.')
oldest_article = 7.0
cover_url = 'http://www.economist.com/images/covers/currentcovereu_large.jpg'
cover_url = 'http://www.economist.com/images/covers/currentcoverus_large.jpg'
remove_tags = [dict(name=['script', 'noscript', 'title', 'iframe', 'cf_floatingcontent']),
dict(attrs={'class':['dblClkTrk']})]
remove_tags_before = dict(name=lambda tag: tag.name=='title' and tag.parent.name=='body')

View File

@ -0,0 +1,45 @@
__license__ = 'GPL v3'
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
'''
emg.rs/en/news
'''
from calibre.web.feeds.news import BasicNewsRecipe
class emportal_en(BasicNewsRecipe):
title = 'Ekonom:east News'
__author__ = 'Darko Miletic'
description = 'Daily business news from Serbia.'
publisher = 'Ekonom:east Media Group'
category = 'Business, SEE, Serbia, Belgrade, news, Ekonomist, EMportal'
oldest_article = 2
max_articles_per_feed = 200
no_stylesheets = True
encoding = 'utf8'
use_embedded_content = False
language = 'en'
remove_empty_feeds = True
masthead_url = 'http://www.emg.rs/img/emportal-rss.png'
extra_css = ' body{font-family: Arial,Helvetica,sans-serif } '
conversion_options = {
'comment' : description
, 'tags' : category
, 'publisher' : publisher
, 'language' : language
}
remove_tags = [dict(attrs={'class':['text-share']})]
keep_only_tags = [dict(attrs={'class':'text'})]
remove_tags_after = dict(attrs={'class':'text-share'})
remove_attributes = ['width','height']
feeds = [(u'Serbia' , u'http://www.emg.rs/en/news/serbia/rss.xml')]
def print_version(self, url):
return url.replace('.html','.print.html')
def preprocess_html(self, soup):
for item in soup.findAll(style=True):
del item['style']
return soup

View File

@ -0,0 +1,51 @@
__license__ = 'GPL v3'
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
'''
emg.rs/vesti
'''
import re
from calibre.web.feeds.news import BasicNewsRecipe
class emportal_rs(BasicNewsRecipe):
title = 'Ekonom:east Vesti'
__author__ = 'Darko Miletic'
description = 'Vasa dnevna doza poslovnih informacija iz Srbije, regiona i sveta. Vesti, Berze, Dogadaji, Casopisi.'
publisher = 'Ekonom:east Media Group'
category = 'Ekonom:east Media Group, Ekonomist, Budelar, Bankar, EMportal, Preduzeca, Moja Posla, EU praktikum, ekonomija, Srbija, Beograd, investicije, finansije, energetika, berza'
oldest_article = 2
max_articles_per_feed = 200
no_stylesheets = True
encoding = 'utf8'
use_embedded_content = False
language = 'sr'
remove_empty_feeds = True
masthead_url = 'http://www.emg.rs/img/emportal-rss.png'
extra_css = ' @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{font-family: Arial,Helvetica,sans1,sans-serif } .article_description{font-family: sans1, sans-serif} '
conversion_options = {
'comment' : description
, 'tags' : category
, 'publisher' : publisher
, 'language' : language
}
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
remove_tags = [dict(attrs={'class':['text-share']})]
keep_only_tags = [dict(attrs={'class':'text'})]
remove_tags_after = dict(attrs={'class':'text-share'})
remove_attributes = ['width','height']
feeds = [
(u'Srbija' , u'http://www.emg.rs/vesti/srbija/rss.xml')
,(u'Region' , u'http://www.emg.rs/vesti/region/rss.xml')
,(u'Svet' , u'http://www.emg.rs/vesti/svet/rss.xml' )
]
def print_version(self, url):
return url.replace('.html','.print.html')
def preprocess_html(self, soup):
for item in soup.findAll(style=True):
del item['style']
return soup

View File

@ -0,0 +1,19 @@
from calibre.web.feeds.news import BasicNewsRecipe
class FactCheckOrg(BasicNewsRecipe):
title = u'Factcheck'
__author__ = u'Michael Heinz'
language = 'en'
oldest_article = 7
max_articles_per_feed = 100
recursion = 0
publication_type = 'magazine'
masthead_url = 'http://factcheck.org/wp-content/themes/Streamline/images/headernew.jpg'
cover_url = 'http://factcheck.org/wp-content/themes/Streamline/images/headernew.jpg'
remove_tags = [ dict({'id':['footer','footerabout','sidebar']}) ]
feeds = [(u'Factcheck', u'feed://www.factcheck.org/feed/')]

View File

@ -9,14 +9,20 @@ class Freakonomics(BasicNewsRecipe):
title = 'Freakonomics Blog'
description = 'The Hidden side of everything'
__author__ = 'Kovid Goyal'
__author__ = 'Starson17'
language = 'en'
cover_url = 'http://ilkerugur.files.wordpress.com/2009/04/freakonomics.jpg'
feeds = [('Blog', 'http://feeds.feedburner.com/freakonomicsblog')]
feeds = [('Blog', 'http://freakonomics.blogs.nytimes.com/feed/atom/')]
def get_article_url(self, article):
return article.get('feedburner_origlink', None)
def print_version(self, url):
return url + '?pagemode=print'
keep_only_tags = [dict(name='div', attrs={'id':'header'}),
dict(name='h1'),
dict(name='h2'),
dict(name='div', attrs={'class':'entry-content'}),
]
extra_css = '''
h1{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:large;}
h2{font-family:Arial,Helvetica,sans-serif; font-weight:normal;font-size:small;}
p{font-family:Arial,Helvetica,sans-serif;font-size:small;}
body{font-family:Helvetica,Arial,sans-serif;font-size:small;}
'''

View File

@ -7,14 +7,14 @@ description = 'Italian daily newspaper - v1.01 (04, January 2010)'
'''
http://www.messaggero.it/
'''
import time
from calibre.web.feeds.news import BasicNewsRecipe
class IlMessaggero(BasicNewsRecipe):
__author__ = 'Gabriele Marini'
description = 'Italian News'
cover_url = 'http://www.ilmessaggero.it/img_tst/logomsgr.gif'
# cover_url = 'http://www.ilmessaggero.it/img_tst/logomsgr.gif'
title = u'Il Messaggero'
publisher = 'Caltagirone Editore'
category = 'News, politics, culture, economy, general interest'
@ -34,6 +34,21 @@ class IlMessaggero(BasicNewsRecipe):
dict(name='h2', attrs={'class':'sottotitLettura'}),
dict(name='span', attrs={'class':'testoArticoloG'})
]
def get_cover_url(self):
cover = None
st = time.localtime()
year = str(st.tm_year)
month = "%.2d" % st.tm_mon
day = "%.2d" % st.tm_mday
cover='http://carta.ilmessaggero.it/' + year + month + day + '/jpeg/MSGR_20_CITTA_1.jpg'
br = BasicNewsRecipe.get_browser()
try:
br.open(cover)
except:
self.log("\nCover unavailable")
cover = 'http://www.ilmessaggero.it/img_tst/logomsgr.gif'
return cover

View File

@ -0,0 +1,57 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__author__ = 'Gabriele Marini, based on Darko Miletic'
__copyright__ = '2009-2010, Darko Miletic <darko.miletic at gmail.com>'
description = 'On Line Motor News - 01-05-2010'
'''
http://www.infomotori.it/
'''
from calibre.ebooks.BeautifulSoup import BeautifulSoup
from calibre.web.feeds.news import BasicNewsRecipe
class infomotori(BasicNewsRecipe):
author = 'Gabriele Marini'
title = u'Infomotori'
cover = 'http://www.infomotori.com/content/files/anniversario_01.gif'
oldest_article = 31
max_articles_per_feed = 100
recursion = 100
use_embedded_content = False
language = 'it'
use_embedded_content = False
remove_javascript = True
no_stylesheets = True
language = 'it'
timefmt = '[%a, %d %b, %Y]'
def print_version(self, url):
raw = self.browser.open(url).read()
soup = BeautifulSoup(raw.decode('utf8', 'replace'))
print_link = soup.find('a', {'class':'printarticle'})
'''if print_link is None:
keep_only_tags = [ dict(name='div', attrs={'class':['article main-column-article photogallery-column','category-header','article-body']})
]
remove_tags = [ dict(name='div', attrs={'class':['thumbnails-article','infoflash-footer','imushortarticle']}),
dict(name='div', attrs={'id':['linkinviastampa','linkspazioblu','altriarticoli','articoliconcorrenti','articolicorrelati','boxbrand']}),
dict(name='table', attrs={'class':'article-page'})
]
remove_tags_after = [ dict(name='div', attrs={'id':'articlebody'})
]
return url
'''
return print_link['href']
feeds = [(u'Ultime Novit\xe0', u'http://feeds.infomotori.com/ultimenovita'),
(u'Auto: Ultime Novit\xe0 ', u'http://feeds.infomotori.com/autonovita'),
(u'Moto: Ultime Novit\xe0 Moto', u'http://feeds.infomotori.com/motonovita'),
(u'Notizie Flash', u'http://feeds.infomotori.com/infoflashmotori'),
(u'Veicoli Ecologici e Mobilit\xe0 Sostenibile', u'http://feeds.infomotori.com/ecomotori'),
(u'4x4 Fuoristrada, Crossover e Suv', u'http://feeds.infomotori.com/fuoristrada'),
(u'Shopping Motori', u'http://feeds.infomotori.com/shoppingmotori')
]

View File

@ -1,11 +1,10 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__copyright__ = '2009, Darko Miletic <darko.miletic at gmail.com>'
__copyright__ = '2009-2010, Darko Miletic <darko.miletic at gmail.com>'
'''
www.instapaper.com
'''
import urllib
from calibre import strftime
from calibre.web.feeds.news import BasicNewsRecipe
@ -22,18 +21,15 @@ class Instapaper(BasicNewsRecipe):
max_articles_per_feed = 100
no_stylesheets = True
use_embedded_content = False
remove_javascript = True
needs_subscription = True
INDEX = u'http://www.instapaper.com'
LOGIN = INDEX + u'/user/login'
html2lrf_options = [
'--comment', description
, '--category', category
, '--publisher', publisher
]
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\noverride_css=" p {text-indent: 0em; margin-top: 0em; margin-bottom: 0.5em} img {margin-top: 0em; margin-bottom: 0.4em}"'
conversion_options = {
'comment' : description
, 'tags' : category
, 'publisher' : publisher
}
feeds = [
(u'Unread articles' , INDEX + u'/u' )
@ -63,7 +59,7 @@ class Instapaper(BasicNewsRecipe):
description = self.tag_to_string(item.div)
atag = item.a
if atag and atag.has_key('href'):
url = self.INDEX + atag['href'] + '/text'
url = atag['href']
title = self.tag_to_string(atag)
date = strftime(self.timefmt)
articles.append({
@ -75,3 +71,6 @@ class Instapaper(BasicNewsRecipe):
totalfeeds.append((feedtitle, articles))
return totalfeeds
def print_version(self, url):
return self.INDEX + '/text?u=' + urllib.quote(url)

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__author__ = 'Lorenzo Vigentini'
__author__ = 'Lorenzo Vigentini, Gabriele Marini'
__copyright__ = '2009, Lorenzo Vigentini <l.vigentini at gmail.com>'
__version__ = 'v1.02'
__date__ = '10, January 2010'
@ -10,17 +10,17 @@ __description__ = 'Italian weekly magazine'
from calibre.web.feeds.news import BasicNewsRecipe
class laGazzetta(BasicNewsRecipe):
__author__ = 'Lorenzo Vigentini'
class Espresso(BasicNewsRecipe):
__author__ = 'Lorenzo Vigentini, Gabriele Marini'
description = 'Italian weekly magazine'
cover_url = 'http://espresso.repubblica.it/images/logo_espresso.gif'
title = 'l Espresso '
publisher = 'Gruppo editoriale lEspresso'
title = 'L\'Espresso '
publisher = 'Gruppo editoriale L\'Espresso'
category = 'News, politics, culture, economy, general interest'
language = 'it'
encoding = 'cp1252'
# encoding = 'cp1252'
timefmt = '[%a, %d %b, %Y]'
oldest_article = 16
@ -33,35 +33,45 @@ class laGazzetta(BasicNewsRecipe):
feeds = [
(u'Espresso Homepage', u'http://kpm.data.kataweb.it/kpm3eolx/rss/home'),
(u'Espresso Local', u'http://kpm.data.kataweb.it/kpm3eolx/rss/local'),
(u'Espresso Style & Design', u'http://kpm.data.kataweb.it/kpm3eolx/rss/style_design'),
(u'Espresso Opinioni', u'http://kpm.data.kataweb.it/kpm3eolx/rss/opinioni'),
(u'Espresso Rubriche', u'http://kpm.data.kataweb.it/kpm3eolx/rss/rubriche'),
(u'Espresso Limes', u'http://temi.repubblica.it/limes/feed/')
(u'Homepage', u'http://kpm.data.kataweb.it/kpm3eolx/rss/home'),
(u'Local', u'http://kpm.data.kataweb.it/kpm3eolx/rss/local'),
(u'Style & Design', u'http://kpm.data.kataweb.it/kpm3eolx/rss/style_design'),
(u'Opinioni', u'http://kpm.data.kataweb.it/kpm3eolx/rss/opinioni'),
(u'Rubriche', u'http://kpm.data.kataweb.it/kpm3eolx/rss/rubriche'),
(u'Limes', u'http://temi.repubblica.it/limes/feed/'),
(u'Chiesa: HomePage', u'http://data.kataweb.it/rss/chiesa/homepage/it'),
(u'Chiesa: Speciali e Focus', u'http://data.kataweb.it/rss/chiesa/speciali_e_focus/it')
]
def print_version(self,url):
print url[7:25]
if url[7:25] == 'temi.repubblica.it':
return url + '/?printpage=undefined'
elif url[7:25] == 'www.chiesa.espress':
return url
return url + '/&print=true'
keep_only_tags = [
dict(name='div', attrs={'class':['testo','copertina','occhiello','firma','didascalia','content-second-right','detail-articles','titolo-local','generic-articles']}),
dict(name='div', attrs={'class':['generic-articles','summary','detail-articles']}),
dict(name='div', attrs={'id':'content-second-right'})
dict(name='div', attrs={'id':['content-second-right','content2']})
]
remove_tags = [
dict(name='div',attrs={'class':['servizi','aggiungi','label-web','bottom-mobile','box-abbonamenti','box-cerca','big','little','stampaweb']}),
dict(name='div',attrs={'id':['topheader','header','navigation-new','navigation','content-second-left']}),
dict(name='div',attrs={'id':['topheader','header','navigation-new','navigation','content-second-left','menutext']}),
dict(name='ul',attrs={'id':'user-utility'}),
dict(name=['script','noscript','iframe'])
]
extra_css = '''
h1 {font-family:"Trebuchet MS",Arial,Helvetica,sans-serif; font-size:20px; font-size-adjust:none; font-stretch:normal; font-style:normal; font-variant:normal; font-weight:bold; line-height:18px;}
h2 {font-family:"Trebuchet MS",Arial,Helvetica,sans-serif; font-size:18px; font-size-adjust:none; font-stretch:normal; font-style:normal; font-variant:normal; font-weight:bold; line-height:16px; }
h3 {color:#333333;font-family:"Trebuchet MS",Arial,Helvetica,sans-serif; font-size:16px; font-size-adjust:none; font-stretch:normal; font-style:normal; font-variant:normal; font-weight:bold; line-height:14px;}
h4 {color:#333333; font-family:"Trebuchet MS",Arial,Helvetica,sans-serif;font-size:16px; font-size-adjust:none; font-stretch:normal; font-style:normal; font-variant:normal; font-weight:bold; line-height:14px; }
h5 {color:#333333; font-family:"Trebuchet MS",Arial,Helvetica,sans-serif; font-size:12px; font-size-adjust:none; font-stretch:normal; font-style:normal; font-variant:normal; font-weight:bold; line-height:14px; text-transform:uppercase;}
.firma {color:#333333;font-family:"Trebuchet MS",Arial,Helvetica,sans-serif;font-size:12px; font-size-adjust:none; font-stretch:normal; font-style:italic; font-variant:normal; font-weight:bold; line-height:15px; text-decoration:none;}
.testo {font-family:"Trebuchet MS",Arial,Helvetica,sans-serif; font-size:10px;}
'''
# extra_css = '''
# h1 {font-family:Times New Roman,"Trebuchet MS",Arial,Helvetica,sans-serif; font-size:24px; font-size-adjust:none; font-stretch:normal; font-style:normal; font-variant:normal; font-weight:bold; line-height:18px;}
# h2 {font-family:Times New Roman, "Trebuchet MS",Arial,Helvetica,sans-serif; font-size:18px; font-size-adjust:none; font-stretch:normal; font-style:normal; font-variant:normal; font-weight:bold; line-height:16px; }
# h3 {color:#333333;font-family:Times New Roman, "Trebuchet MS",Arial,Helvetica,sans-serif; font-size:16px; font-size-adjust:none; font-stretch:normal; font-style:normal; font-variant:normal; font-weight:bold; line-height:14px;}
# h4 {color:#333333; font-family:Times New Roman, "Trebuchet MS",Arial,Helvetica,sans-serif;font-size:16px; font-size-adjust:none; font-stretch:normal; font-style:normal; font-variant:normal; font-weight:bold; line-height:14px; }
# h5 {color:#333333; font-family:Times New Roman, "Trebuchet MS",Arial,Helvetica,sans-serif; font-size:12px; font-size-adjust:none; font-stretch:normal; font-style:normal; font-variant:normal; font-weight:bold; line-height:14px; text-transform:uppercase;}
# .firma {color:#333333;font-family:Times New Roman, "Trebuchet MS",Arial,Helvetica,sans-serif;font-size:12px; font-size-adjust:none; font-stretch:normal; font-style:italic; font-variant:normal; font-weight:bold; line-height:15px; text-decoration:none;}
# .testo {font-family:Times New Roman, "Trebuchet MS",Arial,Helvetica,sans-serif; font-size:10px;}
# '''

View File

@ -1,8 +1,8 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__author__ = 'Lorenzo Vigentini, based on Darko Miletic'
__author__ = 'Lorenzo Vigentini, based on Darko Miletic, Gabriele Marini'
__copyright__ = '2009, Darko Miletic <darko.miletic at gmail.com>, Lorenzo Vigentini <l.vigentini at gmail.com>'
description = 'Italian daily newspaper - v1.01 (04, January 2010)'
description = 'Italian daily newspaper - v1.01 (04, January 2010); 16.05.2010 new version'
'''
http://www.repubblica.it/
@ -11,7 +11,7 @@ http://www.repubblica.it/
from calibre.web.feeds.news import BasicNewsRecipe
class LaRepubblica(BasicNewsRecipe):
author = 'Lorenzo Vigentini, based on Darko Miletic'
__author__ = 'Lorenzo Vigentini, Gabriele Marini'
description = 'Italian daily newspaper'
cover_url = 'http://www.repubblica.it/images/homepage/la_repubblica_logo.gif'
@ -36,7 +36,8 @@ class LaRepubblica(BasicNewsRecipe):
keep_only_tags = [dict(name='div', attrs={'class':'articolo'}),
dict(name='div', attrs={'class':'body-text'}),
dict(name='div', attrs={'class':'page-content'}),
# dict(name='div', attrs={'class':'page-content'}),
dict(name='p', attrs={'class':'disclaimer clearfix'}),
dict(name='div', attrs={'id':'contA'})
]
@ -47,10 +48,8 @@ class LaRepubblica(BasicNewsRecipe):
dict(name='div', attrs={'class':'bottom-mobile'}),
dict(name='div', attrs={'id':['rssdiv','blocco']}),
dict(name='div', attrs={'class':'utility'}),
dict(name='div', attrs={'class':'generalbox'})
]
remove_tags_after = [
dict(name='div',attrs={'id':'ugc_linkUpload'})
dict(name='div', attrs={'class':'generalbox'}),
dict(name='ul', attrs={'id':'hystory'})
]
feeds = [

View File

@ -0,0 +1,67 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__author__ = 'Gabriele Marini, based on Darko Miletic'
__copyright__ = '2009, Darko Miletic <darko.miletic at gmail.com>'
__description__ = 'La Stampa 05/05/2010'
'''
http://www.lastampa.it/
'''
from calibre.web.feeds.news import BasicNewsRecipe
class LaStampa(BasicNewsRecipe):
title = u'La Stampa'
language = 'it'
__author__ = 'Gabriele Marini'
oldest_article = 15
max_articles_per_feed = 50
recursion = 100
cover_url = 'http://www.lastampa.it/edicola/PDF/1.pdf'
use_embedded_content = False
remove_javascript = True
no_stylesheets = True
conversion_options = {'linearize_tables':True}
remove_attributes = ['colspan']
extra_css = ' .boxocchiello2{font-size: small} .catenaccio{font-style: italic} .titoloRub{font-size: xx-large; font-weight: bold } .titologir{font-size: xx-large; font-weight: bold } .sezione{font-weight: bold} '
def get_article_url(self, article):
link = article.get('links')
if link:
return link[0]['href']
keep_only_tags = [dict(attrs={'class':['boxocchiello2','titoloRub','titologir','catenaccio','sezione','articologirata']}),
dict(name='div', attrs={'id':'corpoarticolo'})
]
remove_tags = [dict(name='div', attrs={'id':'menutop'}),
dict(name='div', attrs={'id':'fwnetblocco'}),
dict(name='table', attrs={'id':'strumenti'}),
dict(name='table', attrs={'id':'imgesterna'}),
dict(name='a', attrs={'class':'linkblu'}),
dict(name='a', attrs={'class':'link'}),
dict(name='span', attrs={'class':['boxocchiello','boxocchiello2','sezione']})
]
feeds = [
(u'Home', u'http://www.lastampa.it/redazione/rss_home.xml'),
(u'Editoriali', u'http://www.lastampa.it/cmstp/rubriche/oggetti/rss.asp?ID_blog=25'),
(u'Politica', u'http://www.lastampa.it/redazione/cmssezioni/politica/rss_politica.xml'),
(u'ArciItaliana', u'http://www.lastampa.it/cmstp/rubriche/oggetti/rss.asp?ID_blog=14'),
(u'Cronache', u'http://www.lastampa.it/redazione/cmssezioni/cronache/rss_cronache.xml'),
(u'Esteri', u'http://www.lastampa.it/redazione/cmssezioni/esteri/rss_esteri.xml'),
(u'Danni Collaterali', u'http://www.lastampa.it/cmstp/rubriche/oggetti/rss.asp?ID_blog=90'),
(u'Economia', u'http://www.lastampa.it/redazione/cmssezioni/economia/rss_economia.xml'),
(u'Tecnologia ', u'http://www.lastampa.it/cmstp/rubriche/oggetti/rss.asp?ID_blog=30'),
(u'Spettacoli', u'http://www.lastampa.it/redazione/cmssezioni/spettacoli/rss_spettacoli.xml'),
(u'Sport', u'http://www.lastampa.it/sport/rss_home.xml'),
(u'Torino', u'http://rss.feedsportal.com/c/32418/f/466938/index.rss'),
(u'Motori', u'http://www.lastampa.it/cmstp/rubriche/oggetti/rss.asp?ID_blog=57'),
(u'Scienza', u'http://www.lastampa.it/cmstp/rubriche/oggetti/rss.asp?ID_blog=38'),
(u'Fotografia', u'http://rss.feedsportal.com/c/32418/f/478449/index.rss'),
(u'Scuola', u'http://www.lastampa.it/cmstp/rubriche/oggetti/rss.asp?ID_blog=60'),
(u'Tempo Libero', u'http://www.lastampa.it/tempolibero/rss_home.xml')
]

View File

@ -7,14 +7,14 @@ description = 'Italian daily newspaper - v1.00 05-05-2010'
'''
http://www.leggo.it
'''
import time
from calibre.web.feeds.news import BasicNewsRecipe
class LeggoIT(BasicNewsRecipe):
__author__ = 'Gabriele Marini'
description = 'Italian Free daily newspaper'
cover_url = 'http://www.leggo.it/img/logo-leggo2.gif'
# cover_url = 'http://www.leggo.it/img/logo-leggo2.gif'
title = u'Leggo.it'
publisher = 'Ced Caltagirone Editore S.p.A.'
category = 'News, politics, culture, economy, general interest'
@ -46,4 +46,20 @@ class LeggoIT(BasicNewsRecipe):
(u'Salute', u'http://www.leggo.it/rss/salute.xml'),
(u'Scienza', u'http://www.leggo.it/rss/scienza.xml')
]
def get_cover_url(self):
cover = None
st = time.localtime()
year = str(st.tm_year)
month = "%.2d" % st.tm_mon
day = "%.2d" % st.tm_mday
cover='http://www.leggo.it/'+ year + month + day + '/jpeg/LEGGO_ROMA_1.jpg'
br = BasicNewsRecipe.get_browser()
try:
br.open(cover)
except:
self.log("\nCover unavailable")
cover = 'http://www.leggo.it/img/logo-leggo2.gif'
return cover

View File

@ -4,7 +4,7 @@ __author__ = 'Lorenzo Vigentini'
__copyright__ = '2009, Lorenzo Vigentini <l.vigentini at gmail.com>'
__version__ = 'v1.01'
__date__ = '10, January 2010'
__description__ = 'Monthly Italian edition of Scientific American'
__description__ = 'Monthly Italian edition of Scientific American, 16.05.2010 new version'
'''
http://lescienze.espresso.repubblica.it/
@ -13,22 +13,22 @@ http://lescienze.espresso.repubblica.it/
from calibre.web.feeds.news import BasicNewsRecipe
class leScienze(BasicNewsRecipe):
author = 'Lorenzo Vigentini'
__author__ = 'Lorenzo Vigentini, Gabriele Marini'
description = 'Monthly Italian edition of Scientific American'
cover_url = 'http://lescienze.espresso.repubblica.it/images/logo_lescienze.gif'
title = 'le Scienze'
publisher = 'Gruppo editoriale lEspresso'
publisher = 'Gruppo editoriale L\'Espresso'
category = 'Science, general interest'
language = 'it'
encoding = 'cp1252'
# encoding = 'cp1252'
timefmt = '[%a, %d %b, %Y]'
oldest_article = 31
max_articles_per_feed = 20
oldest_article = 100
max_articles_per_feed = 100
use_embedded_content = False
recursion = 10
recursion = 20
remove_javascript = True
no_stylesheets = True
@ -46,6 +46,8 @@ class leScienze(BasicNewsRecipe):
remove_tags_after = [dict(name='div',attrs={'class':'box-commenti'})]
feeds = [
(u'Home', u'http://data.kataweb.it/rss/scienze'),
(u'Antropologia', u'http://data.kataweb.it/rss/scienze/antropologia'),
(u'Archeologia', u'http://data.kataweb.it/rss/scienze/archeologia'),
(u'Arte e Musica', u'http://data.kataweb.it/rss/scienze/arte_e_musica'),
@ -72,18 +74,3 @@ class leScienze(BasicNewsRecipe):
(u'Storia della scienza', u'http://data.kataweb.it/rss/scienze/storia_della_scienza')
]
extra_css = '''
h1 {font-family:"Trebuchet MS",Arial,Helvetica,sans-serif; font-size:20px; font-size-adjust:none; font-stretch:normal; font-style:normal; font-variant:normal; font-weight:bold; line-height:18px;}
h2 {font-family:"Trebuchet MS",Arial,Helvetica,sans-serif; font-size:18px; font-size-adjust:none; font-stretch:normal; font-style:normal; font-variant:normal; font-weight:bold; line-height:16px; }
h3 {color:#333333;font-family:"Trebuchet MS",Arial,Helvetica,sans-serif; font-size:16px; font-size-adjust:none; font-stretch:normal; font-style:normal; font-variant:normal; font-weight:bold; line-height:14px;}
h4 {color:#333333; font-family:"Trebuchet MS",Arial,Helvetica,sans-serif;font-size:16px; font-size-adjust:none; font-stretch:normal; font-style:normal; font-variant:normal; font-weight:bold; line-height:14px; }
h5 {color:#333333; font-family:"Trebuchet MS",Arial,Helvetica,sans-serif; font-size:12px; font-size-adjust:none; font-stretch:normal; font-style:normal; font-variant:normal; font-weight:bold; line-height:14px; text-transform:uppercase;}
.occhiello {color:#666666;display:block;font-family:"Trebuchet MS",Arial,Helvetica,sans-serif;font-size:13px;font-size-adjust:none;font-stretch:normal;font-style:normal;font-variant:normal;font-weight:bold;line-height:15px;}
.titolo {font-weight:bold;}
.label {font-family:"Trebuchet MS",Arial,Helvetica,sans-serif;font-size:12px;font-size-adjust:none;font-stretch:normal;font-style:normal;font-variant:normal;font-weight:bold;height:15px;line-height:15px;text-transform:uppercase;}
.firma {color:#333333;font-family:"Trebuchet MS",Arial,Helvetica,sans-serif;font-size:12px; font-size-adjust:none; font-stretch:normal; font-style:italic; font-variant:normal; font-weight:bold; line-height:15px; text-decoration:none;}
.testo {font-family:"Trebuchet MS",Arial,Helvetica,sans-serif; font-size:10px;}
'''

View File

@ -0,0 +1,56 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__author__ = 'Gabriele Marini, based on Darko Miletic'
__copyright__ = '2009-2010, Darko Miletic <darko.miletic at gmail.com>'
description = 'Italian daily newspaper - 13-05-2010'
'''
http://www.libero-news.it/
'''
from calibre.web.feeds.news import BasicNewsRecipe
class LiberoNews(BasicNewsRecipe):
__author__ = 'Marini Gabriele'
description = 'Italian daily newspaper'
cover_url = 'http://www.ilgiornale.it/img_v1/logo.gif'
title = u'Libero'
publisher = 'EDITORIALE LIBERO s.r.l 2006'
category = 'News, politics, culture, economy, general interest'
language = 'it'
timefmt = '[%a, %d %b, %Y]'
oldest_article = 7
max_articles_per_feed = 50
use_embedded_content = False
recursion = 100
no_stylesheets = True
conversion_options = {'linearize_tables':True}
remove_javascript = True
keep_only_tags = [
dict(name='div', attrs={'class':'Articolo'})
]
remove_tags = [
dict(name='div', attrs={'class':['CommentaFoto','Priva2']}),
dict(name='div', attrs={'id':['commentigenerale']})
]
feeds = [
(u'Politica', u'http://www.libero-news.it/rss.jsp?sezione=14'),
(u'Italia', u'http://www.libero-news.it/rss.jsp?sezione=15'),
(u'Esteri', u'http://www.libero-news.it/rss.jsp?sezione=16'),
(u'Economia', u'http://www.libero-news.it/rss.jsp?sezione=17'),
(u'Cultura', u'http://www.libero-news.it/rss.jsp?sezione=18'),
(u'Scienze', u'http://www.libero-news.it/rss.jsp?sezione=19'),
(u'Tecnologia', u'http://www.libero-news.it/rss.jsp?sezione=20'),
(u'LifeStyle', u'http://www.libero-news.it/rss.jsp?sezione=22'),
(u'Sport', u'http://www.libero-news.it/rss.jsp?sezione=23'),
(u'Costume e Societ\xc3\xa0', u' http://www.libero-news.it/rss.jsp?sezione=24'),
(u'Milano', u'http://www.libero-news.it/rss.jsp?sezione=26'),
(u'Roma', u'http://www.libero-news.it/rss.jsp?sezione=27'),
(u'Alimentazione', u'http://www.libero-news.it/rss.jsp?sezione=29')
]

View File

@ -23,7 +23,7 @@ class NewYorkReviewOfBooks(BasicNewsRecipe):
no_javascript = True
needs_subscription = True
keep_only_tags = [dict(id='article-body')]
keep_only_tags = [dict(id=['article-body','page-title'])]
remove_tags = [dict(attrs={'class':['article-tools', 'article-links',
'center advertisement']})]

View File

@ -21,7 +21,7 @@ class NewYorkReviewOfBooks(BasicNewsRecipe):
no_stylesheets = True
no_javascript = True
keep_only_tags = [dict(id='article-body')]
keep_only_tags = [dict(id=['article-body', 'page-title'])]
remove_tags = [dict(attrs={'class':['article-tools', 'article-links',
'center advertisement']})]

View File

@ -50,6 +50,7 @@ class Newsweek(BasicNewsRecipe):
'articlecontent','photoBox', 'article columnist first']}, ]
recursions = 1
match_regexps = [r'http://www.newsweek.com/id/\S+/page/\d+']
preprocess_regexps = [(re.compile(r'<!--.*?-->', re.DOTALL), lambda m: '')]
def find_title(self, section):
d = {'scope':'Scope', 'thetake':'The Take', 'features':'Features',

View File

@ -5,7 +5,7 @@ __copyright__ = '2008-2010, Darko Miletic <darko.miletic at gmail.com>'
www.nin.co.rs
'''
import re, urllib
import re
from calibre import strftime
from calibre.web.feeds.news import BasicNewsRecipe
@ -16,13 +16,13 @@ class Nin(BasicNewsRecipe):
publisher = 'NIN d.o.o.'
category = 'news, politics, Serbia'
no_stylesheets = True
delay = 1
oldest_article = 15
encoding = 'utf-8'
needs_subscription = True
remove_empty_feeds = True
PREFIX = 'http://www.nin.co.rs'
INDEX = PREFIX + '/?change_lang=ls'
LOGIN = PREFIX + '/?logout=true'
use_embedded_content = False
language = 'sr'
publication_type = 'magazine'
@ -41,14 +41,12 @@ class Nin(BasicNewsRecipe):
def get_browser(self):
br = BasicNewsRecipe.get_browser()
br.open(self.INDEX)
if self.username is not None and self.password is not None:
data = urllib.urlencode({ 'login_name':self.username
,'login_password':self.password
,'imageField.x':'32'
,'imageField.y':'15'
})
br.open(self.LOGIN,data)
br.open(self.INDEX)
br.select_form(name='form1')
br['login_name' ] = self.username
br['login_password'] = self.password
br.submit()
return br
keep_only_tags =[dict(name='td', attrs={'width':'520'})]

View File

@ -0,0 +1,148 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
__docformat__ = 'restructuredtext en'
'''
http://www.guardian.co.uk/theobserver
'''
from calibre import strftime
from calibre.web.feeds.news import BasicNewsRecipe
class Guardian(BasicNewsRecipe):
title = u'The Observer'
__author__ = 'jbambridge'
language = 'en_GB'
simultaneous_downloads = 5
oldest_article = 7
max_articles_per_feed = 100
remove_javascript = True
timefmt = ' [%a, %d %b %Y]'
filter_regexps = [r'r\.kelkoo\.com']
keep_only_tags = [
dict(name='div', attrs={'id':["content","article_header","main-article-info",]}),
]
remove_tags = [
dict(name='div', attrs={'class':["video-content","videos-third-column"]}),
dict(name='div', attrs={'id':["article-toolbox","subscribe-feeds",]}),
dict(name='div', attrs={'class':["promo-component bookshop-books-promo bookshop-books"]}),
dict(name='ul', attrs={'class':["pagination"]}),
dict(name='ul', attrs={'id':["content-actions"]}),
dict(name='li', attrs={'id':["product-image"]}),
]
use_embedded_content = False
no_stylesheets = True
extra_css = '''
.article-attributes{font-size: x-small; font-family:Arial,Helvetica,sans-serif;}
.h1{font-size: large ;font-family:georgia,serif; font-weight:bold;}
.stand-first-alone{color:#666666; font-size:small; font-family:Arial,Helvetica,sans-serif;}
.caption{color:#666666; font-size:x-small; font-family:Arial,Helvetica,sans-serif;}
#article-wrapper{font-size:small; font-family:Arial,Helvetica,sans-serif;font-weight:normal;}
.main-article-info{font-family:Arial,Helvetica,sans-serif;}
#full-contents{font-size:small; font-family:Arial,Helvetica,sans-serif;font-weight:normal;}
#match-stats-summary{font-size:small; font-family:Arial,Helvetica,sans-serif;font-weight:normal;}
'''
feeds = [
(u'Main Section', u'feed://www.guardian.co.uk/theobserver/news/uknews/rss'),
(u'News', u'feed://www.guardian.co.uk/theobserver/news/rss'),
(u'World News', u'feed://www.guardian.co.uk/theobserver/news/worldnews/rss'),
(u'In Focus', u'feed://www.guardian.co.uk/theobserver/news/focus/rss'),
(u'7 Days', u'feed://www.guardian.co.uk/theobserver/news/7days/rss'),
(u'Seven Days', u'feed://www.guardian.co.uk/theobserver/news/seven-days/rss'),
(u'Media', u'feed://www.guardian.co.uk/theobserver/news/media/rss'),
(u'Business', u'feed://www.guardian.co.uk/theobserver/businessandmedia/rss'),
(u'Cash', u'feed://www.guardian.co.uk/theobserver/news/cash/rss'),
(u'Money', u'feed://feeds.guardian.co.uk/theguardian/money/rss'),
(u'Comment', u'feed://www.guardian.co.uk/theobserver/news/comment/rss'),
(u'Travel', u'feed://www.guardian.co.uk/theobserver/escape/rss'),
(u'Culture', u'feed://www.guardian.co.uk/theobserver/review/rss'),
(u'Money', u'feed://feeds.guardian.co.uk/theguardian/money/rss'),
(u'TV & Radio', u'feed://www.guardian.co.uk/tv-and-radio/rss'),
(u'New Review', u'feed://www.guardian.co.uk/theobserver/new-review/rss'),
(u'Agenda', u'feed://www.guardian.co.uk/theobserver/new-review/agenda/rss'),
(u'Critics', u'feed://www.guardian.co.uk/theobserver/new-review/critics/rss'),
(u'Features', u'feed://www.guardian.co.uk/theobserver/new-review/features/rss'),
(u'Discover', u'feed://www.guardian.co.uk/theobserver/new-review/discover/rss'),
(u'Books', u'feed://www.guardian.co.uk/theobserver/new-review/books/rss'),
(u'Magazine', u'feed://www.guardian.co.uk/theobserver/magazine/rss'),
(u'Regulars', u'feed://www.guardian.co.uk/theobserver/magazine/regulars/rss'),
(u'Life & Style', u'feed://www.guardian.co.uk/theobserver/magazine/life-and-style/rss'),
(u'Mag Features', u'feed://www.guardian.co.uk/theobserver/magazine/features2/rss'),
(u'Sport', u'feed://www.guardian.co.uk/theobserver/sport/rss')
]
def get_article_url(self, article):
url = article.get('guid', None)
if '/video/' in url or '/flyer/' in url or '/quiz/' in url or \
'/gallery/' in url or 'ivebeenthere' in url or \
'pickthescore' in url or 'audioslideshow' in url :
url = None
return url
def preprocess_html(self, soup):
for item in soup.findAll(style=True):
del item['style']
for item in soup.findAll(face=True):
del item['face']
for tag in soup.findAll(name=['ul','li']):
tag.name = 'div'
return soup
def find_sections(self):
soup = self.index_to_soup('http://www.guardian.co.uk/theobserver')
# find cover pic
img = soup.find( 'img',attrs ={'alt':'Guardian digital edition'})
if img is not None:
self.cover_url = img['src']
# end find cover pic
idx = soup.find('div', id='book-index')
for s in idx.findAll('strong', attrs={'class':'book'}):
a = s.find('a', href=True)
yield (self.tag_to_string(a), a['href'])
def find_articles(self, url):
soup = self.index_to_soup(url)
div = soup.find('div', attrs={'class':'book-index'})
for ul in div.findAll('ul', attrs={'class':'trailblock'}):
for li in ul.findAll('li'):
a = li.find(href=True)
if not a:
continue
title = self.tag_to_string(a)
url = a['href']
if not title or not url:
continue
tt = li.find('div', attrs={'class':'trailtext'})
if tt is not None:
for da in tt.findAll('a'): da.extract()
desc = self.tag_to_string(tt).strip()
yield {
'title': title, 'url':url, 'description':desc,
'date' : strftime('%a, %d %b'),
}
def parse_index(self):
try:
feeds = []
for title, href in self.find_sections():
feeds.append((title, list(self.find_articles(href))))
return feeds
except:
raise NotImplementedError
def postprocess_html(self,soup,first):
return soup.findAll('html')[0]

View File

@ -0,0 +1,30 @@
from calibre.web.feeds.news import BasicNewsRecipe
class PolitiFactCom(BasicNewsRecipe):
title = u'Politifact'
__author__ = u'Michael Heinz'
oldest_article = 21
max_articles_per_feed = 100
recursion = 0
language = 'en'
no_stylesheets = True
publication_type = 'magazine'
masthead_url = 'http://static.politifact.com.s3.amazonaws.com/images/politifactdotcom-flag-fff_01.png'
cover_url = 'http://static.politifact.com.s3.amazonaws.com/images/politifactdotcom-flag-fff_01.png'
remove_tags = [
dict(name='div', attrs={'class':'pfstoryarchive'}),
dict(name='div', attrs={'class':'pfhead'}),
dict(name='div', attrs={'class':'boxmid'}),
]
keep_only_tags = [dict(name='div', attrs={'class':'pfcontentleft'})]
feeds = [
(u'Articles', u'http://www.politifact.com/feeds/articles/truth-o-meter/'),
(u'Obamameter', u'http://politifact.com/feeds/updates/'),
(u'Statements', u'http://www.politifact.com/feeds/statements/truth-o-meter/')
]

View File

@ -8,6 +8,7 @@ class SeanHannity(BasicNewsRecipe):
__author__ = 'Rob Lammert - rob.lammert[at]gmail.com'
description = u"Articles from Sean Hannity's website, www.hannity.com"
oldest_article = 7.0
language = 'en'
max_articles_per_feed = 100
recursions = 0
encoding = 'utf8'

View File

@ -0,0 +1,86 @@
__license__ = 'GPL v3'
__copyright__ = '2010 Ingo Paschke <ipaschke@gmail.com>'
'''
Fetch Tagesspiegel.
'''
import string, re
from calibre import strftime
from calibre.web.feeds.news import BasicNewsRecipe
class TagesspiegelRSS(BasicNewsRecipe):
title = u'Der Tagesspiegel'
__author__ = 'ipaschke'
language = 'de'
oldest_article = 7
max_articles_per_feed = 100
extra_css = '''
.hcf-overline{color:#990000; font-family:Arial,Helvetica,sans-serif;font-size:xx-small;display:block}
.hcf-teaser{font-family:Verdana,Arial,Helvetica;font-size:x-small;margin-top:0}
h1{font-family:Arial,Helvetica,sans-serif;font-size:large;clear:right;}
.hcf-caption{color:#666666; font-family:Arial,Helvetica,sans-serif;font-size:xx-small;}
.hcf-copyright{color:#666666; font-family:Arial,Helvetica,sans-serif;font-size:xx-small;}
.hcf-article{font-family:Arial,Helvetica;font-size:x-small}
.quote{font-family:Georgia,Palatino,Palatino Linotype,FreeSerif,serif;font-size:x-small}
.quote .cite{font-family:Georgia,Palatino,Palatino Linotype,FreeSerif,serif;font-size:xx-small}
.hcf-inline-left{float:left;margin-right:15px;position:relative;}
.hcf-inline-right{float:right;margin-right:15px;position:relative;}
.hcf-smart-box{font-family: Arial, Helvetica, sans-serif; font-size: xx-small; margin: 0px 15px 8px 0px; width: 300px;}
'''
no_stylesheets = True
no_javascript = True
remove_empty_feeds = True
encoding = 'utf-8'
keep_only_tags = dict(name='div', attrs={'class':["hcf-article"]})
remove_tags = [
dict(name='link'), dict(name='iframe'),dict(name='style'),dict(name='meta'),dict(name='button'),
dict(name='div', attrs={'class':["hcf-jump-to-comments","hcf-clear","hcf-magnify hcf-media-control"] }),
dict(name='span', attrs={'class':["hcf-mainsearch",] }),
dict(name='ul', attrs={'class':["hcf-tools"] }),
]
def parse_index(self):
soup = self.index_to_soup('http://www.tagesspiegel.de/zeitung/')
def feed_title(div):
return ''.join(div.findAll(text=True, recursive=False)).strip()
articles = {}
key = None
ans = []
for div in soup.findAll(True, attrs={'class':['hcf-teaser', 'hcf-header', 'story headline']}):
if div['class'] == 'hcf-header':
key = string.capwords(feed_title(div.em.a))
articles[key] = []
ans.append(key)
elif div['class'] == 'hcf-teaser' and getattr(div.contents[0],'name','') == 'h2':
a = div.find('a', href=True)
if not a:
continue
url = 'http://www.tagesspiegel.de' + a['href']
title = self.tag_to_string(a, use_alt=True).strip()
description = ''
pubdate = strftime('%a, %d %b')
summary = div.find('p', attrs={'class':'hcf-teaser'})
if summary:
description = self.tag_to_string(summary, use_alt=False)
feed = key if key is not None else 'Uncategorized'
if not articles.has_key(feed):
articles[feed] = []
if not 'podcasts' in url:
articles[feed].append(
dict(title=title, url=url, date=pubdate,
description=re.sub('mehr$', '', description),
content=''))
ans = [(key, articles[key]) for key in ans if articles.has_key(key)]
return ans

View File

@ -5,6 +5,7 @@ __copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
'''
timesonline.co.uk
'''
import re
from calibre.web.feeds.news import BasicNewsRecipe
from calibre.ebooks.BeautifulSoup import Tag
@ -26,6 +27,8 @@ class Timesonline(BasicNewsRecipe):
recursions = 9
match_regexps = [r'http://www.timesonline.co.uk/.*page=[2-9]']
preprocess_regexps = [(re.compile(r'<!--.*?-->', re.DOTALL), lambda m: '')]
keep_only_tags = [
dict(name='div', attrs= {'id':['region-column1and2-layout2']}),
{'class' : ['subheading']},
@ -76,8 +79,7 @@ class Timesonline(BasicNewsRecipe):
soup = self.index_to_soup(index)
link_item = soup.find(name = 'div',attrs ={'class': "float-left margin-right-15"})
if link_item:
cover_url = 'http://www.timesonline.co.uk' + link_item.img['src']
print cover_url
cover_url = link_item.img['src']
return cover_url
def get_article_url(self, article):
@ -85,9 +87,9 @@ class Timesonline(BasicNewsRecipe):
def preprocess_html(self, soup):
soup.html['xml:lang'] = self.lang
soup.html['lang'] = self.lang
mlang = Tag(soup,'meta',[("http-equiv","Content-Language"),("content",self.lang)])
soup.html['xml:lang'] = self.language
soup.html['lang'] = self.language
mlang = Tag(soup,'meta',[("http-equiv","Content-Language"),("content",self.language)])
mcharset = Tag(soup,'meta',[("http-equiv","Content-Type"),("content","text/html; charset=ISO-8859-1")])
soup.head.insert(0,mlang)
soup.head.insert(1,mcharset)

View File

@ -2,7 +2,7 @@ __license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
__docformat__ = 'restructuredtext en'
__appname__ = 'calibre'
__version__ = '0.6.53'
__version__ = '0.6.54'
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
import re

View File

@ -450,9 +450,9 @@ from calibre.devices.eslick.driver import ESLICK
from calibre.devices.nuut2.driver import NUUT2
from calibre.devices.iriver.driver import IRIVER_STORY
from calibre.devices.binatone.driver import README
from calibre.devices.hanvon.driver import N516, EB511, ALEX, AZBOOKA
from calibre.devices.hanvon.driver import N516, EB511, ALEX, AZBOOKA, THEBOOK
from calibre.devices.edge.driver import EDGE
from calibre.devices.teclast.driver import TECLAST_K3
from calibre.devices.teclast.driver import TECLAST_K3, NEWSMY, IPAPYRUS
from calibre.devices.sne.driver import SNE
from calibre.devices.misc import PALMPRE, KOBO, AVANT
@ -530,9 +530,12 @@ plugins += [
EB600,
README,
N516,
THEBOOK,
EB511,
ELONEX,
TECLAST_K3,
NEWSMY,
IPAPYRUS,
EDGE,
SNE,
ALEX,

View File

@ -245,6 +245,8 @@ class iPadOutput(OutputProfile):
name = 'iPad'
short_name = 'ipad'
description = _('Intended for the iPad and similar devices with a '
'resolution of 768x1024')
screen_size = (768, 1024)
comic_screen_size = (768, 1024)
dpi = 132.0

View File

@ -24,6 +24,9 @@ class ANDROID(USBMS):
# Motorola
0x22b8 : { 0x41d9 : [0x216], 0x2d67 : [0x100], 0x41db : [0x216]},
# Sony Ericsson
0xfce : { 0xd12e : [0x0100]},
0x18d1 : { 0x4e11 : [0x0100, 0x226], 0x4e12: [0x0100, 0x226]},
# Samsung

View File

@ -24,7 +24,7 @@ class N516(USBMS):
VENDOR_ID = [0x0525]
PRODUCT_ID = [0xa4a5]
BCD = [0x323, 0x326, 0x399]
BCD = [0x323, 0x326]
VENDOR_NAME = 'INGENIC'
WINDOWS_MAIN_MEM = '_FILE-STOR_GADGE'
@ -34,6 +34,16 @@ class N516(USBMS):
EBOOK_DIR_MAIN = 'e_book'
SUPPORTS_SUB_DIRS = True
class THEBOOK(N516):
name = 'The Book driver'
gui_name = 'The Book'
description = _('Communicate with The Book reader.')
author = 'Kovid Goyal'
BCD = [0x399]
MAIN_MEMORY_VOLUME_LABEL = 'The Book Main Memory'
EBOOK_DIR_MAIN = 'My books'
class ALEX(N516):
name = 'Alex driver'

View File

@ -34,6 +34,6 @@ class Worker(threading.Thread):
def run(self):
'''Thread loops taking jobs from the queue as they become available'''
while True:
job = self.jobs.get(True, None)
self.jobs.get(True, None)
# Do job
self.jobs.task_done()

View File

@ -17,10 +17,10 @@ class PALMPRE(USBMS):
supported_platforms = ['windows', 'osx', 'linux']
# Ordered list of supported formats
FORMATS = ['mobi', 'prc', 'pdb', 'txt']
FORMATS = ['epub', 'mobi', 'prc', 'pdb', 'txt']
VENDOR_ID = [0x0830]
PRODUCT_ID = [0x8004, 0x8002]
PRODUCT_ID = [0x8004, 0x8002, 0x0101]
BCD = [0x0316]
VENDOR_NAME = 'PALM'
@ -48,6 +48,7 @@ class KOBO(USBMS):
WINDOWS_MAIN_MEM = '.KOBOEREADER'
EBOOK_DIR_MAIN = ''
SUPPORTS_SUB_DIRS = True
class AVANT(USBMS):
name = 'Booq Avant Device Interface'

View File

@ -39,4 +39,28 @@ class TECLAST_K3(USBMS):
return drives
class NEWSMY(TECLAST_K3):
name = 'Newsmy device interface'
gui_name = 'Newsmy'
description = _('Communicate with the Newsmy reader.')
FORMATS = ['epub', 'fb2', 'pdb', 'html', 'pdf', 'txt', 'skt']
VENDOR_NAME = ''
WINDOWS_MAIN_MEM = 'NEWSMY'
WINDOWS_CARD_A_MEM = 'USBDISK____SD'
def windows_sort_drives(self, drives):
return drives
class IPAPYRUS(TECLAST_K3):
name = 'iPapyrus device interface'
gui_name = 'iPapyrus'
description = _('Communicate with the iPapyrus reader.')
FORMATS = ['epub', 'pdf', 'txt']
VENDOR_NAME = 'E_READER'
WINDOWS_MAIN_MEM = ''

View File

@ -32,7 +32,7 @@ def detect(aBuf):
ENCODING_PATS = [
re.compile(r'<\?[^<>]+encoding=[\'"](.*?)[\'"][^<>]*>',
re.IGNORECASE),
re.compile(r'<meta.*?content=[\'"].*?charset=([^\s\'"]+).*?[\'"].*?>',
re.compile(r'''<meta\s+?[^<>]+?content=['"][^'"]*?charset=([-a-z0-9]+)[^'"]*?['"][^<>]*>''',
re.IGNORECASE)
]
ENTITY_PATTERN = re.compile(r'&(\S+?);')

View File

@ -15,6 +15,7 @@ from calibre.ptempfile import PersistentTemporaryDirectory
from calibre.utils.date import parse_date
from calibre.utils.zipfile import ZipFile
from calibre import extract, walk
from calibre.constants import __version__
DEBUG_README=u'''
This debug directory contains snapshots of the e-book as it passes through the
@ -410,6 +411,18 @@ OptionRecommendation(name='asciiize',
)
),
OptionRecommendation(name='keep_ligatures',
recommended_value=False, level=OptionRecommendation.LOW,
help=_('Preserve ligatures present in the input document. '
'A ligature is a special rendering of a pair of '
'characters like ff, fi, fl et cetera. '
'Most readers do not have support for '
'ligatures in their default fonts, so they are '
'unlikely to render correctly. By default, calibre '
'will turn a ligature into the corresponding pair of normal '
'characters. This option will preserve them instead.')
),
OptionRecommendation(name='title',
recommended_value=None, level=OptionRecommendation.LOW,
help=_('Set the title.')),
@ -711,6 +724,7 @@ OptionRecommendation(name='timestamp',
if self.opts.verbose > 1:
self.log.debug('Resolved conversion options')
try:
self.log.debug('calibre version:', __version__)
self.log.debug(pprint.pformat(self.opts.__dict__))
except:
self.log.exception('Failed to get resolved conversion options')

View File

@ -18,6 +18,24 @@ convert_entities = functools.partial(entity_to_unicode, exceptions=['quot',
'apos', 'lt', 'gt', 'amp', '#60', '#62'])
_span_pat = re.compile('<span.*?</span>', re.DOTALL|re.IGNORECASE)
LIGATURES = {
u'\u00c6': u'AE',
u'\u00e6': u'ae',
u'\u0152': u'OE',
u'\u0153': u'oe',
u'\u0132': u'IJ',
u'\u0133': u'ij',
u'\u1D6B': u'ue',
u'\uFB00': u'ff',
u'\uFB01': u'fi',
u'\uFB02': u'fl',
u'\uFB03': u'ffi',
u'\uFB04': u'ffl',
u'\uFB05': u'ft',
u'\uFB06': u'st',
}
_ligpat = re.compile(u'|'.join(LIGATURES))
def sanitize_head(match):
x = match.group(1)
@ -228,6 +246,9 @@ class HTMLPreProcessor(object):
else:
rules = []
if not self.extra_opts.keep_ligatures:
html = _ligpat.sub(lambda m:LIGATURES[m.group()], html)
end_rules = []
if getattr(self.extra_opts, 'remove_header', None):
try:

View File

@ -37,8 +37,13 @@ class EPUBInput(InputFormatPlugin):
scheme = item.get(xkey)
if (scheme and scheme.lower() == 'uuid') or \
(item.text and item.text.startswith('urn:uuid:')):
try:
key = str(item.text).rpartition(':')[-1]
key = list(map(ord, uuid.UUID(key).bytes))
except:
import traceback
traceback.print_exc()
key = None
try:
root = etree.parse(encfile)
@ -49,7 +54,7 @@ class EPUBInput(InputFormatPlugin):
cr = em.getparent().xpath('descendant::*[contains(name(), "CipherReference")]')[0]
uri = cr.get('URI')
path = os.path.abspath(os.path.join(os.path.dirname(encfile), '..', *uri.split('/')))
if os.path.exists(path):
if key is not None and os.path.exists(path):
self._encrypted_font_uris.append(uri)
self.decrypt_font(key, path)
return True

View File

@ -7,12 +7,10 @@ __copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import os, shutil, re
from urllib import unquote
from calibre.customize.conversion import OutputFormatPlugin
from calibre.ptempfile import TemporaryDirectory
from calibre.constants import __appname__, __version__
from calibre import guess_type, CurrentDir
from calibre import CurrentDir
from calibre.customize.conversion import OptionRecommendation
from calibre.constants import filesystem_encoding
@ -92,51 +90,21 @@ class EPUBOutput(OutputFormatPlugin):
'as a blank page.')
),
OptionRecommendation(name='preserve_cover_aspect_ratio',
recommended_value=False, help=_(
'When using an SVG cover, this option will cause the cover to scale '
'to cover the available screen area, but still preserve its aspect ratio '
'(ratio of width to height). That means there may be white borders '
'at the sides or top and bottom of the image, but the image will '
'never be distorted. Without this option the image may be slightly '
'distorted, but there will be no borders.'
)
),
])
recommendations = set([('pretty_print', True, OptionRecommendation.HIGH)])
NONSVG_TITLEPAGE_COVER = '''\
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="calibre:cover" content="true" />
<title>Cover</title>
<style type="text/css" title="override_css">
@page {padding: 0pt; margin:0pt}
body { text-align: center; padding:0pt; margin: 0pt; }
div { padding:0pt; margin: 0pt; }
</style>
</head>
<body>
<div>
<img src="%s" alt="cover" style="height: 100%%" />
</div>
</body>
</html>
'''
TITLEPAGE_COVER = '''\
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="calibre:cover" content="true" />
<title>Cover</title>
<style type="text/css" title="override_css">
@page {padding: 0pt; margin:0pt}
body { text-align: center; padding:0pt; margin: 0pt; }
</style>
</head>
<body>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="100%%" height="100%%" viewBox="0 0 600 800"
preserveAspectRatio="xMidYMid meet">
<image width="600" height="800" xlink:href="%s"/>
</svg>
</body>
</html>
'''
def workaround_webkit_quirks(self):
from calibre.ebooks.oeb.base import XPath
@ -167,7 +135,12 @@ class EPUBOutput(OutputFormatPlugin):
)
split(self.oeb, self.opts)
self.insert_cover()
from calibre.ebooks.oeb.transforms.cover import CoverManager
cm = CoverManager(
no_default_cover=self.opts.no_default_epub_cover,
no_svg_cover=self.opts.no_svg_cover,
preserve_aspect_ratio=self.opts.preserve_cover_aspect_ratio)
cm(self.oeb, self.opts, self.log)
self.workaround_sony_quirks()
@ -259,97 +232,6 @@ class EPUBOutput(OutputFormatPlugin):
ans += '\n</encryption>'
return ans
def default_cover(self):
'''
Create a generic cover for books that dont have a cover
'''
from calibre.utils.pil_draw import draw_centered_text
from calibre.ebooks.metadata import authors_to_string
if self.opts.no_default_epub_cover:
return None
self.log('Generating default cover')
m = self.oeb.metadata
title = unicode(m.title[0])
authors = [unicode(x) for x in m.creator if x.role == 'aut']
import cStringIO
cover_file = cStringIO.StringIO()
try:
try:
from PIL import Image, ImageDraw, ImageFont
Image, ImageDraw, ImageFont
except ImportError:
import Image, ImageDraw, ImageFont
font_path = P('fonts/liberation/LiberationSerif-Bold.ttf')
app = '['+__appname__ +' '+__version__+']'
COVER_WIDTH, COVER_HEIGHT = 590, 750
img = Image.new('RGB', (COVER_WIDTH, COVER_HEIGHT), 'white')
draw = ImageDraw.Draw(img)
# Title
font = ImageFont.truetype(font_path, 44)
bottom = draw_centered_text(img, draw, font, title, 15, ysep=9)
# Authors
bottom += 14
font = ImageFont.truetype(font_path, 32)
authors = authors_to_string(authors)
bottom = draw_centered_text(img, draw, font, authors, bottom, ysep=7)
# Vanity
font = ImageFont.truetype(font_path, 28)
width, height = draw.textsize(app, font=font)
left = max(int((COVER_WIDTH - width)/2.), 0)
top = COVER_HEIGHT - height - 15
draw.text((left, top), app, fill=(0,0,0), font=font)
# Logo
logo = Image.open(I('library.png'), 'r')
width, height = logo.size
left = max(int((COVER_WIDTH - width)/2.), 0)
top = max(int((COVER_HEIGHT - height)/2.), 0)
img.paste(logo, (left, max(bottom, top)))
img = img.convert('RGB').convert('P', palette=Image.ADAPTIVE)
img.convert('RGB').save(cover_file, 'JPEG')
cover_file.flush()
id, href = self.oeb.manifest.generate('cover_image', 'cover_image.jpg')
item = self.oeb.manifest.add(id, href, guess_type('t.jpg')[0],
data=cover_file.getvalue())
m.clear('cover')
m.add('cover', item.id)
return item.href
except:
self.log.exception('Failed to generate default cover')
return None
def insert_cover(self):
from calibre.ebooks.oeb.base import urldefrag
from calibre import guess_type
g, m = self.oeb.guide, self.oeb.manifest
item = None
if 'titlepage' not in g:
if 'cover' in g:
href = g['cover'].href
else:
href = self.default_cover()
if href is not None:
templ = self.NONSVG_TITLEPAGE_COVER if self.opts.no_svg_cover \
else self.TITLEPAGE_COVER
tp = templ%unquote(href)
id, href = m.generate('titlepage', 'titlepage.xhtml')
item = m.add(id, href, guess_type('t.xhtml')[0],
data=etree.fromstring(tp))
else:
item = self.oeb.manifest.hrefs[
urldefrag(self.oeb.guide['titlepage'].href)[0]]
if item is not None:
self.oeb.spine.insert(0, item, True)
if 'cover' not in self.oeb.guide.refs:
self.oeb.guide.add('cover', 'Title Page', 'a')
self.oeb.guide.refs['cover'].href = item.href
if 'titlepage' in self.oeb.guide.refs:
self.oeb.guide.refs['titlepage'].href = item.href
def condense_ncx(self, ncx_path):
if not self.opts.pretty_print:
tree = etree.parse(ncx_path)

View File

@ -669,10 +669,19 @@ class OPF(object):
remove = list(self.authors_path(self.metadata))
for elem in remove:
elem.getparent().remove(elem)
elems = []
for author in val:
attrib = {'{%s}role'%self.NAMESPACES['opf']: 'aut'}
elem = self.create_metadata_element('creator', attrib=attrib)
self.set_text(elem, author.strip())
# Ensure new author element is at the top of the list
# for broken implementations that always use the first
# <dc:creator> element with no attention to the role
elems.append(elem)
for elem in reversed(elems):
parent = elem.getparent()
parent.remove(elem)
parent.insert(0, elem)
return property(fget=fget, fset=fset)

View File

@ -18,10 +18,10 @@ from calibre.ebooks.chardet import xml_to_unicode
from calibre.utils.zipfile import safe_replace, ZipFile
from calibre.utils.config import DynamicConfig
from calibre.utils.logging import Log
from calibre.ebooks.epub.output import EPUBOutput
from calibre import guess_type, prints
from calibre.ebooks.oeb.transforms.cover import CoverManager
TITLEPAGE = EPUBOutput.TITLEPAGE_COVER.decode('utf-8')
TITLEPAGE = CoverManager.SVG_TEMPLATE.decode('utf-8').replace('__ar__', 'none')
def character_count(html):
'''

View File

@ -0,0 +1,173 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
__license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import textwrap
from urllib import unquote
from lxml import etree
from calibre import __appname__, __version__, guess_type
class CoverManager(object):
SVG_TEMPLATE = textwrap.dedent('''\
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="calibre:cover" content="true" />
<title>Cover</title>
<style type="text/css" title="override_css">
@page {padding: 0pt; margin:0pt}
body { text-align: center; padding:0pt; margin: 0pt; }
</style>
</head>
<body>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="100%%" height="100%%" viewBox="0 0 600 800"
preserveAspectRatio="__ar__">
<image width="600" height="800" xlink:href="%s"/>
</svg>
</body>
</html>
''')
NONSVG_TEMPLATE = textwrap.dedent('''\
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="calibre:cover" content="true" />
<title>Cover</title>
<style type="text/css" title="override_css">
@page {padding: 0pt; margin:0pt}
body { text-align: center; padding:0pt; margin: 0pt }
div { padding:0pt; margin: 0pt }
img { padding:0pt; margin: 0pt }
</style>
</head>
<body>
<div>
<img src="%s" alt="cover" __style__ />
</div>
</body>
</html>
''')
def __init__(self, no_default_cover=False, no_svg_cover=False,
preserve_aspect_ratio=False, fixed_size=None):
self.no_default_cover = no_default_cover
self.no_svg_cover = no_svg_cover
self.preserve_aspect_ratio = preserve_aspect_ratio
ar = 'xMidYMid meet' if preserve_aspect_ratio else 'none'
self.svg_template = self.SVG_TEMPLATE.replace('__ar__', ar)
if fixed_size is None:
style = 'style="height: 100%%"'
else:
width, height = fixed_size
style = 'style="height: %s; width: %s"'%(width, height)
self.non_svg_template = self.NONSVG_TEMPLATE.replace('__style__',
style)
def __call__(self, oeb, opts, log):
self.oeb = oeb
self.log = log
self.insert_cover()
def default_cover(self):
'''
Create a generic cover for books that dont have a cover
'''
from calibre.utils.pil_draw import draw_centered_text
from calibre.ebooks.metadata import authors_to_string
if self.no_default_cover:
return None
self.log('Generating default cover')
m = self.oeb.metadata
title = unicode(m.title[0])
authors = [unicode(x) for x in m.creator if x.role == 'aut']
import cStringIO
cover_file = cStringIO.StringIO()
try:
try:
from PIL import Image, ImageDraw, ImageFont
Image, ImageDraw, ImageFont
except ImportError:
import Image, ImageDraw, ImageFont
font_path = P('fonts/liberation/LiberationSerif-Bold.ttf')
app = '['+__appname__ +' '+__version__+']'
COVER_WIDTH, COVER_HEIGHT = 590, 750
img = Image.new('RGB', (COVER_WIDTH, COVER_HEIGHT), 'white')
draw = ImageDraw.Draw(img)
# Title
font = ImageFont.truetype(font_path, 44)
bottom = draw_centered_text(img, draw, font, title, 15, ysep=9)
# Authors
bottom += 14
font = ImageFont.truetype(font_path, 32)
authors = authors_to_string(authors)
bottom = draw_centered_text(img, draw, font, authors, bottom, ysep=7)
# Vanity
font = ImageFont.truetype(font_path, 28)
width, height = draw.textsize(app, font=font)
left = max(int((COVER_WIDTH - width)/2.), 0)
top = COVER_HEIGHT - height - 15
draw.text((left, top), app, fill=(0,0,0), font=font)
# Logo
logo = Image.open(I('library.png'), 'r')
width, height = logo.size
left = max(int((COVER_WIDTH - width)/2.), 0)
top = max(int((COVER_HEIGHT - height)/2.), 0)
img.paste(logo, (left, max(bottom, top)))
img = img.convert('RGB').convert('P', palette=Image.ADAPTIVE)
img.convert('RGB').save(cover_file, 'JPEG')
cover_file.flush()
id, href = self.oeb.manifest.generate('cover_image', 'cover_image.jpg')
item = self.oeb.manifest.add(id, href, guess_type('t.jpg')[0],
data=cover_file.getvalue())
m.clear('cover')
m.add('cover', item.id)
return item.href
except:
self.log.exception('Failed to generate default cover')
return None
def insert_cover(self):
from calibre.ebooks.oeb.base import urldefrag
g, m = self.oeb.guide, self.oeb.manifest
item = None
if 'titlepage' not in g:
if 'cover' in g:
href = g['cover'].href
else:
href = self.default_cover()
if href is not None:
templ = self.non_svg_template if self.no_svg_cover \
else self.svg_template
tp = templ%unquote(href)
id, href = m.generate('titlepage', 'titlepage.xhtml')
item = m.add(id, href, guess_type('t.xhtml')[0],
data=etree.fromstring(tp))
else:
item = self.oeb.manifest.hrefs[
urldefrag(self.oeb.guide['titlepage'].href)[0]]
if item is not None:
self.oeb.spine.insert(0, item, True)
if 'cover' not in self.oeb.guide.refs:
self.oeb.guide.add('cover', 'Title Page', 'a')
self.oeb.guide.refs['cover'].href = item.href
if 'titlepage' in self.oeb.guide.refs:
self.oeb.guide.refs['titlepage'].href = item.href

View File

@ -164,7 +164,10 @@ class CSSFlattener(object):
body = html.find(XHTML('body'))
fsize = self.context.source.fbase
self.baseline_node(body, stylizer, sizes, fsize)
try:
sbase = max(sizes.items(), key=operator.itemgetter(1))[0]
except:
sbase = 12.0
self.oeb.logger.info(
"Source base font size is %0.05fpt" % sbase)
return sbase

View File

@ -22,7 +22,7 @@ from calibre.ebooks.pdf.pageoptions import UNITS, PAPER_SIZES, \
class PDFOutput(OutputFormatPlugin):
name = 'PDF Output'
author = 'John Schember'
author = 'John Schember and Kovid Goyal'
file_type = 'pdf'
options = set([
@ -44,12 +44,20 @@ class PDFOutput(OutputFormatPlugin):
level=OptionRecommendation.LOW, choices=ORIENTATIONS.keys(),
help=_('The orientation of the page. Default is portrait. Choices '
'are %s') % ORIENTATIONS.keys()),
OptionRecommendation(name='preserve_cover_aspect_ratio',
recommended_value=False,
help=_('Preserve the aspect ratio of the cover, instead'
' of stretching it to fill the ull first page of the'
' generated pdf.')
),
])
def convert(self, oeb_book, output_path, input_plugin, opts, log):
self.oeb = oeb_book
self.input_plugin, self.opts, self.log = input_plugin, opts, log
self.output_path = output_path
self.metadata = oeb_book.metadata
self.cover_data = None
if input_plugin.is_image_collection:
log.debug('Converting input as an image collection...')
@ -61,8 +69,20 @@ class PDFOutput(OutputFormatPlugin):
def convert_images(self, images):
self.write(ImagePDFWriter, images)
def get_cover_data(self):
g, m = self.oeb.guide, self.oeb.manifest
if 'titlepage' not in g:
if 'cover' in g:
href = g['cover'].href
from calibre.ebooks.oeb.base import urlnormalize
for item in m:
if item.href == urlnormalize(href):
self.cover_data = item.data
def convert_text(self, oeb_book):
self.log.debug('Serializing oeb input to disk for processing...')
self.get_cover_data()
with TemporaryDirectory('_pdf_out') as oeb_dir:
from calibre.customize.ui import plugin_for_output_format
oeb_output = plugin_for_output_format('oeb')
@ -74,7 +94,7 @@ class PDFOutput(OutputFormatPlugin):
self.write(PDFWriter, [s.path for s in opf.spine])
def write(self, Writer, items):
writer = Writer(self.opts, self.log)
writer = Writer(self.opts, self.log, cover_data=self.cover_data)
close = False
if not hasattr(self.output_path, 'write'):

View File

@ -15,14 +15,83 @@ from calibre.ptempfile import PersistentTemporaryDirectory
from calibre.ebooks.pdf.pageoptions import unit, paper_size, \
orientation
from calibre.ebooks.metadata import authors_to_string
from calibre.ptempfile import PersistentTemporaryFile
from calibre import __appname__, __version__, fit_image
from PyQt4 import QtCore
from PyQt4.Qt import QUrl, QEventLoop, SIGNAL, QObject, \
QPrinter, QMetaObject, QSizeF, Qt
from PyQt4.Qt import QUrl, QEventLoop, QObject, \
QPrinter, QMetaObject, QSizeF, Qt, QPainter, QPixmap
from PyQt4.QtWebKit import QWebView
from pyPdf import PdfFileWriter, PdfFileReader
def get_pdf_printer():
return QPrinter(QPrinter.HighResolution)
def get_custom_size(opts):
custom_size = None
if opts.custom_size != None:
width, sep, height = opts.custom_size.partition('x')
if height != '':
try:
width = int(width)
height = int(height)
custom_size = (width, height)
except:
custom_size = None
return custom_size
def setup_printer(opts, for_comic=False):
from calibre.gui2 import is_ok_to_use_qt
if not is_ok_to_use_qt():
raise Exception('Not OK to use Qt')
printer = get_pdf_printer()
custom_size = get_custom_size(opts)
if opts.output_profile.short_name == 'default':
if custom_size is None:
printer.setPaperSize(paper_size(opts.paper_size))
else:
printer.setPaperSize(QSizeF(custom_size[0], custom_size[1]), unit(opts.unit))
else:
w = opts.output_profile.comic_screen_size[0] if for_comic else \
opts.output_profile.width
h = opts.output_profile.comic_screen_size[1] if for_comic else \
opts.output_profile.height
dpi = opts.output_profile.dpi
printer.setPaperSize(QSizeF(float(w) / dpi, float(h)/dpi), QPrinter.Inch)
printer.setPageMargins(0, 0, 0, 0, QPrinter.Point)
printer.setOrientation(orientation(opts.orientation))
printer.setOutputFormat(QPrinter.PdfFormat)
return printer
def get_printer_page_size(opts, for_comic=False):
printer = setup_printer(opts, for_comic=for_comic)
size = printer.paperSize(QPrinter.Millimeter)
return size.width() / 10., size.height() / 10.
def draw_image_page(printer, painter, p, preserve_aspect_ratio=True):
page_rect = printer.pageRect()
if preserve_aspect_ratio:
aspect_ratio = float(p.width())/p.height()
nw, nh = page_rect.width(), page_rect.height()
if aspect_ratio > 1:
nh = int(page_rect.width()/aspect_ratio)
else: # Width is smaller than height
nw = page_rect.height()*aspect_ratio
__, nnw, nnh = fit_image(nw, nh, page_rect.width(),
page_rect.height())
dx = int((page_rect.width() - nnw)/2.)
dy = int((page_rect.height() - nnh)/2.)
page_rect.moveTo(dx, dy)
page_rect.setHeight(nnh)
page_rect.setWidth(nnw)
painter.drawPixmap(page_rect, p, p.rect())
class PDFMetadata(object):
def __init__(self, oeb_metadata=None):
self.title = _('Unknown')
@ -35,8 +104,9 @@ class PDFMetadata(object):
self.author = authors_to_string([x.value for x in oeb_metadata.creator])
class PDFWriter(QObject):
def __init__(self, opts, log):
class PDFWriter(QObject): # {{{
def __init__(self, opts, log, cover_data=None):
from calibre.gui2 import is_ok_to_use_qt
if not is_ok_to_use_qt():
raise Exception('Not OK to use Qt')
@ -46,25 +116,16 @@ class PDFWriter(QObject):
self.loop = QEventLoop()
self.view = QWebView()
self.connect(self.view, SIGNAL('loadFinished(bool)'), self._render_html)
self.view.setRenderHints(QPainter.Antialiasing|QPainter.TextAntialiasing|QPainter.SmoothPixmapTransform)
self.view.loadFinished.connect(self._render_html,
type=Qt.QueuedConnection)
self.render_queue = []
self.combine_queue = []
self.tmp_path = PersistentTemporaryDirectory('_pdf_output_parts')
self.custom_size = None
if opts.custom_size != None:
width, sep, height = opts.custom_size.partition('x')
if height != '':
try:
width = int(width)
height = int(height)
self.custom_size = (width, height)
except:
self.custom_size = None
self.opts = opts
self.size = self._size()
self.size = get_printer_page_size(opts)
self.cover_data = cover_data
def dump(self, items, out_stream, pdf_metadata):
self.metadata = pdf_metadata
@ -77,27 +138,6 @@ class PDFWriter(QObject):
QMetaObject.invokeMethod(self, "_render_book", Qt.QueuedConnection)
self.loop.exec_()
def _size(self):
'''
The size of a pdf page in cm.
'''
printer = QPrinter(QPrinter.HighResolution)
if self.opts.output_profile.short_name == 'default':
if self.custom_size == None:
printer.setPaperSize(paper_size(self.opts.paper_size))
else:
printer.setPaperSize(QSizeF(self.custom_size[0], self.custom_size[1]), unit(self.opts.unit))
else:
printer.setPaperSize(QSizeF(self.opts.output_profile.width / self.opts.output_profile.dpi, self.opts.output_profile.height / self.opts.output_profile.dpi), QPrinter.Inch)
printer.setPageMargins(0, 0, 0, 0, QPrinter.Point)
printer.setOrientation(orientation(self.opts.orientation))
printer.setOutputFormat(QPrinter.PdfFormat)
size = printer.paperSize(QPrinter.Millimeter)
return size.width() / 10, size.height() / 10
@QtCore.pyqtSignature('_render_book()')
def _render_book(self):
@ -114,17 +154,20 @@ class PDFWriter(QObject):
self.view.load(QUrl.fromLocalFile(item))
def _render_html(self, ok):
if ok:
item_path = os.path.join(self.tmp_path, '%i.pdf' % len(self.combine_queue))
self.logger.debug('\tRendering item %s as %i' % (os.path.basename(str(self.view.url().toLocalFile())), len(self.combine_queue)))
printer = QPrinter(QPrinter.HighResolution)
def get_printer(self):
printer = get_pdf_printer()
printer.setPaperSize(QSizeF(self.size[0] * 10, self.size[1] * 10), QPrinter.Millimeter)
printer.setPageMargins(0, 0, 0, 0, QPrinter.Point)
printer.setOrientation(orientation(self.opts.orientation))
printer.setOutputFormat(QPrinter.PdfFormat)
printer.setFullPage(True)
return printer
def _render_html(self, ok):
if ok:
item_path = os.path.join(self.tmp_path, '%i.pdf' % len(self.combine_queue))
self.logger.debug('\tRendering item %s as %i' % (os.path.basename(str(self.view.url().toLocalFile())), len(self.combine_queue)))
printer = self.get_printer()
printer.setOutputFileName(item_path)
self.view.print_(printer)
self._render_book()
@ -134,9 +177,27 @@ class PDFWriter(QObject):
shutil.rmtree(self.tmp_path, True)
self.tmp_path = PersistentTemporaryDirectory('_pdf_output_parts')
def insert_cover(self):
if self.cover_data is None:
return
item_path = os.path.join(self.tmp_path, 'cover.pdf')
printer = self.get_printer()
printer.setOutputFileName(item_path)
self.combine_queue.insert(0, item_path)
p = QPixmap()
p.loadFromData(self.cover_data)
if not p.isNull():
painter = QPainter(printer)
draw_image_page(printer, painter, p,
preserve_aspect_ratio=self.opts.preserve_cover_aspect_ratio)
painter.end()
def _write(self):
self.logger.debug('Combining individual PDF parts...')
self.insert_cover()
try:
outPDF = PdfFileWriter(title=self.metadata.title, author=self.metadata.author)
for item in self.combine_queue:
@ -148,37 +209,50 @@ class PDFWriter(QObject):
self._delete_tmpdir()
self.loop.exit(0)
# }}}
class ImagePDFWriter(PDFWriter):
class ImagePDFWriter(object):
def _render_next(self):
item = str(self.render_queue.pop(0))
self.combine_queue.append(os.path.join(self.tmp_path, '%i.pdf' % (len(self.combine_queue) + 1)))
def __init__(self, opts, log, cover_data=None):
self.opts = opts
self.log = log
self.size = get_printer_page_size(opts, for_comic=True)
self.logger.debug('Processing %s...' % item)
height = 'height: %fcm;' % (self.size[1] * 1.3)
html = '<html><body style="margin: 0;"><img src="%s" style="%s display: block; margin-left: auto; margin-right: auto; padding: 0px;" /></body></html>' % (item, height)
self.view.setHtml(html)
def _size(self):
printer = QPrinter(QPrinter.HighResolution)
if self.opts.output_profile.short_name == 'default':
if self.custom_size == None:
printer.setPaperSize(paper_size(self.opts.paper_size))
else:
printer.setPaperSize(QSizeF(self.custom_size[0], self.custom_size[1]), unit(self.opts.unit))
else:
printer.setPaperSize(QSizeF(self.opts.output_profile.comic_screen_size[0] / self.opts.output_profile.dpi, self.opts.output_profile.comic_screen_size[1] / self.opts.output_profile.dpi), QPrinter.Inch)
def dump(self, items, out_stream, pdf_metadata):
f = PersistentTemporaryFile('_comic2pdf.pdf')
f.close()
try:
self.render_images(f.name, pdf_metadata, items)
with open(f.name, 'rb') as x:
shutil.copyfileobj(x, out_stream)
finally:
os.remove(f.name)
def render_images(self, outpath, mi, items):
printer = get_pdf_printer()
printer.setPaperSize(QSizeF(self.size[0] * 10, self.size[1] * 10), QPrinter.Millimeter)
printer.setPageMargins(0, 0, 0, 0, QPrinter.Point)
printer.setOrientation(orientation(self.opts.orientation))
printer.setOutputFormat(QPrinter.PdfFormat)
printer.setOutputFileName(outpath)
printer.setDocName(mi.title)
printer.setCreator(u'%s [%s]'%(__appname__, __version__))
# Seems to be no way to set author
printer.setFullPage(True)
size = printer.paperSize(QPrinter.Millimeter)
painter = QPainter(printer)
painter.setRenderHints(QPainter.Antialiasing|QPainter.SmoothPixmapTransform)
for i, imgpath in enumerate(items):
self.log('Rendering image:', i)
p = QPixmap()
p.load(imgpath)
if not p.isNull():
if i > 0:
printer.newPage()
draw_image_page(printer, painter, p)
else:
self.log.warn('Failed to load image', i)
painter.end()
return size.width() / 10, size.height() / 10

View File

@ -354,7 +354,6 @@ if another paragraph_def is found, the state changes to collect_tokens.
def __tab_stop_func(self, line):
"""
"""
type = 'tabs-%s' % self.__tab_type
self.__att_val_dict['tabs'] += '%s:' % self.__tab_type
self.__att_val_dict['tabs'] += '%s;' % line[20:-1]
self.__tab_type = 'left'
@ -373,7 +372,6 @@ if another paragraph_def is found, the state changes to collect_tokens.
"""
leader = self.__tab_type_dict.get(self.__token_info)
if leader != None:
type = 'tabs-%s' % self.__tab_type
self.__att_val_dict['tabs'] += '%s^' % leader
else:
if self.__run_level > 3:

View File

@ -318,7 +318,6 @@ class Styles:
Try to add the number to dictionary entry tabs-left, or tabs-right, etc.
If the dictionary entry doesn't exist, create one.
"""
type = 'tabs-%s' % self.__tab_type
try:
if self.__leader_found:
self.__styles_dict['par'][self.__styles_num]['tabs']\
@ -362,7 +361,6 @@ class Styles:
leader = self.__tab_type_dict.get(self.__token_info)
if leader != None:
leader += '^'
type = 'tabs-%s' % self.__tab_type
try:
self.__styles_dict['par'][self.__styles_num]['tabs'] += ':%s;' % leader
except KeyError:

View File

@ -18,8 +18,11 @@ class PluginWidget(Widget, Ui_Form):
def __init__(self, parent, get_option, get_help, db=None, book_id=None):
Widget.__init__(self, parent, 'epub_output',
['dont_split_on_page_breaks', 'flow_size',
'no_default_epub_cover', 'no_svg_cover']
'no_default_epub_cover', 'no_svg_cover',
'preserve_cover_aspect_ratio',]
)
for i in range(2):
self.opt_no_svg_cover.toggle()
self.db, self.book_id = db, book_id
self.initialize_options(get_option, get_help, db, book_id)

View File

@ -14,13 +14,34 @@
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<item row="0" column="0">
<widget class="QCheckBox" name="opt_dont_split_on_page_breaks">
<property name="text">
<string>Do not &amp;split on page breaks</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="opt_no_default_epub_cover">
<property name="text">
<string>No default &amp;cover</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="opt_no_svg_cover">
<property name="text">
<string>No &amp;SVG cover</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="opt_preserve_cover_aspect_ratio">
<property name="text">
<string>Preserve cover &amp;aspect ratio</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label">
<property name="text">
@ -60,22 +81,25 @@
</property>
</spacer>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="opt_no_default_epub_cover">
<property name="text">
<string>No default &amp;cover</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="opt_no_svg_cover">
<property name="text">
<string>No &amp;SVG cover</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
<connections>
<connection>
<sender>opt_no_svg_cover</sender>
<signal>toggled(bool)</signal>
<receiver>opt_preserve_cover_aspect_ratio</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>81</x>
<y>73</y>
</hint>
<hint type="destinationlabel">
<x>237</x>
<y>68</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -6,7 +6,7 @@ __license__ = 'GPL v3'
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
from PyQt4.Qt import SIGNAL
from PyQt4.Qt import SIGNAL, QVariant
from calibre.gui2.convert.look_and_feel_ui import Ui_Form
from calibre.gui2.convert import Widget
@ -24,8 +24,14 @@ class LookAndFeelWidget(Widget, Ui_Form):
'linearize_tables',
'disable_font_rescaling', 'insert_blank_line',
'remove_paragraph_spacing', 'remove_paragraph_spacing_indent_size','input_encoding',
'asciiize']
'asciiize', 'keep_ligatures']
)
for val, text in [
('original', _('Original')),
('left', _('Left align')),
('justify', _('Justify text'))
]:
self.opt_change_justification.addItem(text, QVariant(val))
self.db, self.book_id = db, book_id
self.initialize_options(get_option, get_help, db, book_id)
self.opt_disable_font_rescaling.toggle()
@ -35,6 +41,21 @@ class LookAndFeelWidget(Widget, Ui_Form):
self.opt_remove_paragraph_spacing.toggle()
self.opt_remove_paragraph_spacing.toggle()
def get_value_handler(self, g):
if g is self.opt_change_justification:
ans = unicode(g.itemData(g.currentIndex()).toString())
return ans
return Widget.get_value_handler(self, g)
def set_value_handler(self, g, val):
if g is self.opt_change_justification:
for i in range(g.count()):
c = unicode(g.itemData(i).toString())
if val == c:
g.setCurrentIndex(i)
break
return True
def font_key_wizard(self):
from calibre.gui2.convert.font_key import FontKeyChooser
d = FontKeyChooser(self, self.opt_base_font_size.value(),

View File

@ -31,7 +31,7 @@
</property>
</widget>
</item>
<item row="1" column="2">
<item row="1" column="1" colspan="2">
<widget class="QDoubleSpinBox" name="opt_base_font_size">
<property name="suffix">
<string> pt</string>
@ -63,7 +63,7 @@
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<item row="2" column="1" colspan="3">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLineEdit" name="opt_font_size_mapping">
@ -84,7 +84,7 @@
<string>...</string>
</property>
<property name="icon">
<iconset>
<iconset resource="../../../../resources/images.qrc">
<normaloff>:/images/wizard.svg</normaloff>:/images/wizard.svg</iconset>
</property>
<property name="iconSize">
@ -107,7 +107,7 @@
</property>
</widget>
</item>
<item row="3" column="2">
<item row="3" column="1" colspan="2">
<widget class="QDoubleSpinBox" name="opt_line_height">
<property name="suffix">
<string> pt</string>
@ -127,32 +127,17 @@
</property>
</widget>
</item>
<item row="4" column="1" colspan="2">
<item row="4" column="1" colspan="3">
<widget class="QLineEdit" name="opt_input_encoding"/>
</item>
<item row="5" column="0" colspan="3">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<item row="5" column="0" colspan="2">
<widget class="QCheckBox" name="opt_remove_paragraph_spacing">
<property name="text">
<string>Remove &amp;spacing between paragraphs</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<item row="5" column="2" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_4">
@ -179,7 +164,12 @@
</item>
</layout>
</item>
</layout>
<item row="6" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Text justification:</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QCheckBox" name="opt_linearize_tables">
@ -188,14 +178,7 @@
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QCheckBox" name="opt_asciiize">
<property name="text">
<string>&amp;Transliterate unicode characters to ASCII.</string>
</property>
</widget>
</item>
<item row="10" column="0" colspan="3">
<item row="9" column="0" colspan="4">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Extra &amp;CSS</string>
@ -207,6 +190,16 @@
</layout>
</widget>
</item>
<item row="6" column="2" colspan="2">
<widget class="QComboBox" name="opt_change_justification"/>
</item>
<item row="7" column="1" colspan="3">
<widget class="QCheckBox" name="opt_asciiize">
<property name="text">
<string>&amp;Transliterate unicode characters to ASCII</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QCheckBox" name="opt_insert_blank_line">
<property name="text">
@ -214,35 +207,13 @@
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_5">
<item row="8" column="1" colspan="2">
<widget class="QCheckBox" name="opt_keep_ligatures">
<property name="text">
<string>Text justification:</string>
<string>Keep &amp;ligatures</string>
</property>
</widget>
</item>
<item row="6" column="2">
<widget class="QComboBox" name="opt_change_justification">
<property name="currentIndex">
<number>2</number>
</property>
<item>
<property name="text">
<string>justify</string>
</property>
</item>
<item>
<property name="text">
<string>left</string>
</property>
</item>
<item>
<property name="text">
<string>original</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
<resources>

View File

@ -18,7 +18,8 @@ class PluginWidget(Widget, Ui_Form):
HELP = _('Options specific to')+' PDF '+_('output')
def __init__(self, parent, get_option, get_help, db=None, book_id=None):
Widget.__init__(self, parent, 'pdf_output', ['paper_size', 'orientation'])
Widget.__init__(self, parent, 'pdf_output', ['paper_size',
'orientation', 'preserve_cover_aspect_ratio'])
self.db, self.book_id = db, book_id
self.initialize_options(get_option, get_help, db, book_id)

View File

@ -40,7 +40,7 @@
<item row="1" column="1">
<widget class="QComboBox" name="opt_orientation"/>
</item>
<item row="2" column="0">
<item row="3" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
@ -53,6 +53,13 @@
</property>
</spacer>
</item>
<item row="2" column="0" colspan="2">
<widget class="QCheckBox" name="opt_preserve_cover_aspect_ratio">
<property name="text">
<string>Preserve &amp;aspect ratio of cover</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>

View File

@ -695,8 +695,8 @@ class BooksModel(QAbstractTableModel):
self.db.set(row, column, val)
self.emit(SIGNAL("dataChanged(QModelIndex, QModelIndex)"), \
index, index)
if column == self.sorted_on[0]:
self.resort()
#if column == self.sorted_on[0]:
# self.resort()
return True

View File

@ -601,7 +601,7 @@
<normaloff>:/images/merge_books.svg</normaloff>:/images/merge_books.svg</iconset>
</property>
<property name="text">
<string>Merge books</string>
<string>Merge book records</string>
</property>
<property name="shortcut">
<string>M</string>

View File

@ -106,6 +106,13 @@ class Booq(Device):
output_format = 'EPUB'
id = 'booq'
class TheBook(Device):
name = 'The Book'
manufacturer = 'Augen'
output_profile = 'prs505'
output_format = 'EPUB'
id = 'thebook'
class Avant(Booq):
name = 'Booq Avant'

View File

@ -491,9 +491,9 @@ TXT input supports a number of options to differentiate how paragraphs are detec
:guilabel:`Process using markdown`
|app| also supports running TXT input though a transformation preprocessor known as markdown. Markdown
allows for basic formatting to be added to TXT documents, such as bold, italics, section headings, tables,
loists, a Table of Contents, etc. Marking chapter headings with a leading # and setting the chapter XPath detection
lists, a Table of Contents, etc. Marking chapter headings with a leading # and setting the chapter XPath detection
expression to "//h:h1" is the easiest way to have a proper table of contents generated from a TXT document.
You can learn more about the markdown syntax at http://daringfireball.net/projects/markdown/syntax.
You can learn more about the markdown syntax `here <http://daringfireball.net/projects/markdown/syntax>`_.
Convert PDF documents

View File

@ -145,7 +145,7 @@ First perform the following steps in |app|
For an iPad:
Install the ReadMe app on your iPad using iTunes. Open Safari and browse to::
Install the ReadMe app on your iPad using iTunes. Open the Readme builtin browser and browse to::
http://192.168.1.2:8080/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -4,9 +4,9 @@
#
msgid ""
msgstr ""
"Project-Id-Version: calibre 0.6.53\n"
"POT-Creation-Date: 2010-05-15 21:26+MDT\n"
"PO-Revision-Date: 2010-05-15 21:26+MDT\n"
"Project-Id-Version: calibre 0.6.54\n"
"POT-Creation-Date: 2010-05-21 15:44+MDT\n"
"PO-Revision-Date: 2010-05-21 15:44+MDT\n"
"Last-Translator: Automatically generated\n"
"Language-Team: LANGUAGE\n"
"MIME-Version: 1.0\n"
@ -95,8 +95,8 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/rotate.py:63
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/split.py:81
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/split.py:82
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/writer.py:28
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/writer.py:29
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/writer.py:87
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/writer.py:88
#: /home/kovid/work/calibre/src/calibre/ebooks/rtf/input.py:233
#: /home/kovid/work/calibre/src/calibre/ebooks/rtf/input.py:235
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:279
@ -135,7 +135,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/library/server.py:671
#: /home/kovid/work/calibre/src/calibre/library/server.py:747
#: /home/kovid/work/calibre/src/calibre/library/server.py:794
#: /home/kovid/work/calibre/src/calibre/utils/localization.py:113
#: /home/kovid/work/calibre/src/calibre/utils/localization.py:114
#: /home/kovid/work/calibre/src/calibre/utils/podofo/__init__.py:45
#: /home/kovid/work/calibre/src/calibre/utils/podofo/__init__.py:63
#: /home/kovid/work/calibre/src/calibre/utils/podofo/__init__.py:77
@ -247,7 +247,7 @@ msgid "This profile tries to provide sane defaults and is useful if you know not
msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:57
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:256
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:258
msgid "This profile is intended for the SONY PRS line. The 500/505/600/700 etc."
msgstr ""
@ -256,62 +256,62 @@ msgid "This profile is intended for the SONY PRS 300."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:78
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:290
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:292
msgid "This profile is intended for the SONY PRS-900."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:86
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:320
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:322
msgid "This profile is intended for the Microsoft Reader."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:97
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:331
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:333
msgid "This profile is intended for the Mobipocket books."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:110
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:344
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:346
msgid "This profile is intended for the Hanlin V3 and its clones."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:122
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:356
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:358
msgid "This profile is intended for the Hanlin V5 and its clones."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:132
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:364
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:366
msgid "This profile is intended for the Cybook G3."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:145
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:377
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:379
msgid "This profile is intended for the Cybook Opus."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:157
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:388
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:390
msgid "This profile is intended for the Amazon Kindle."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:169
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:423
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:425
msgid "This profile is intended for the Irex Illiad."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:181
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:436
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:438
msgid "This profile is intended for the IRex Digital Reader 1000."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:194
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:450
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:452
msgid "This profile is intended for the IRex Digital Reader 800."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:206
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:464
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:466
msgid "This profile is intended for the B&N Nook."
msgstr ""
@ -323,23 +323,27 @@ msgstr ""
msgid "This profile tries to provide sane defaults and is useful if you want to produce a document intended to be read at a computer or on a range of devices."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:269
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:248
msgid "Intended for the iPad and similar devices with a resolution of 768x1024"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:271
msgid "This profile is intended for the Kobo Reader."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:281
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:283
msgid "This profile is intended for the SONY PRS-300."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:299
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:301
msgid "This profile is intended for the 5-inch JetBook."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:308
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:310
msgid "This profile is intended for the SONY PRS line. The 500/505/700 etc, in landscape mode. Mainly useful for comics."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:406
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:408
msgid "This profile is intended for the Amazon Kindle DX."
msgstr ""
@ -403,11 +407,11 @@ msgstr ""
msgid "Communicate with Android phones."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/devices/android/driver.py:36
#: /home/kovid/work/calibre/src/calibre/devices/android/driver.py:39
msgid "Comma separated list of directories to send e-books to on the device. The first one that exists will be used"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/devices/android/driver.py:64
#: /home/kovid/work/calibre/src/calibre/devices/android/driver.py:67
msgid "Communicate with S60 phones."
msgstr ""
@ -523,7 +527,7 @@ msgstr ""
msgid "Communicate with the Kobo Reader"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/devices/misc.py:55
#: /home/kovid/work/calibre/src/calibre/devices/misc.py:56
msgid "Communicate with the Booq Avant"
msgstr ""
@ -604,6 +608,14 @@ msgstr ""
msgid "Communicate with the Teclast K3 reader."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/devices/teclast/driver.py:45
msgid "Communicate with the Newsmy reader."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/devices/teclast/driver.py:60
msgid "Communicate with the iPapyrus reader."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/devices/usbms/device.py:252
msgid "Unable to detect the %s disk drive. Try rebooting."
msgstr ""
@ -916,280 +928,288 @@ msgstr ""
msgid "Output saved to"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:94
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:95
msgid "Level of verbosity. Specify multiple times for greater verbosity."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:101
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:102
msgid "Save the output from different stages of the conversion pipeline to the specified directory. Useful if you are unsure at which stage of the conversion process a bug is occurring."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:110
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:111
msgid "Specify the input profile. The input profile gives the conversion system information on how to interpret various information in the input document. For example resolution dependent lengths (i.e. lengths in pixels). Choices are:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:121
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:122
msgid "Specify the output profile. The output profile tells the conversion system how to optimize the created document for the specified device. In some cases, an output profile is required to produce documents that will work on a device. For example EPUB on the SONY reader. Choices are:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:132
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:133
msgid "The base font size in pts. All font sizes in the produced book will be rescaled based on this size. By choosing a larger size you can make the fonts in the output bigger and vice versa. By default, the base font size is chosen based on the output profile you chose."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:142
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:143
msgid "Mapping from CSS font names to font sizes in pts. An example setting is 12,12,14,16,18,20,22,24. These are the mappings for the sizes xx-small to xx-large, with the final size being for huge fonts. The font rescaling algorithm uses these sizes to intelligently rescale fonts. The default is to use a mapping based on the output profile you chose."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:154
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:155
msgid "Disable all rescaling of font sizes."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:161
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:162
msgid "The line height in pts. Controls spacing between consecutive lines of text. By default no line height manipulation is performed."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:169
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:170
msgid "Some badly designed documents use tables to control the layout of text on the page. When converted these documents often have text that runs off the page and other artifacts. This option will extract the content from the tables and present it in a linear fashion."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:179
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:180
msgid "XPath expression that specifies all tags that should be added to the Table of Contents at level one. If this is specified, it takes precedence over other forms of auto-detection."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:188
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:189
msgid "XPath expression that specifies all tags that should be added to the Table of Contents at level two. Each entry is added under the previous level one entry."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:196
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:197
msgid "XPath expression that specifies all tags that should be added to the Table of Contents at level three. Each entry is added under the previous level two entry."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:204
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:205
msgid "Normally, if the source file already has a Table of Contents, it is used in preference to the auto-generated one. With this option, the auto-generated one is always used."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:212
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:213
msgid "Don't add auto-detected chapters to the Table of Contents."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:219
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:220
msgid "If fewer than this number of chapters is detected, then links are added to the Table of Contents. Default: %default"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:226
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:227
msgid "Maximum number of links to insert into the TOC. Set to 0 to disable. Default is: %default. Links are only added to the TOC if less than the threshold number of chapters were detected."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:234
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:235
msgid "Remove entries from the Table of Contents whose titles match the specified regular expression. Matching entries and all their children are removed."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:245
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:246
msgid "An XPath expression to detect chapter titles. The default is to consider <h1> or <h2> tags that contain the words \"chapter\",\"book\",\"section\" or \"part\" as chapter titles as well as any tags that have class=\"chapter\". The expression used must evaluate to a list of elements. To disable chapter detection, use the expression \"/\". See the XPath Tutorial in the calibre User Manual for further help on using this feature."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:259
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:260
msgid "Specify how to mark detected chapters. A value of \"pagebreak\" will insert page breaks before chapters. A value of \"rule\" will insert a line before chapters. A value of \"none\" will disable chapter marking and a value of \"both\" will use both page breaks and lines to mark chapters."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:269
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:270
msgid "Either the path to a CSS stylesheet or raw CSS. This CSS will be appended to the style rules from the source file, so it can be used to override those rules."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:278
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:279
msgid "An XPath expression. Page breaks are inserted before the specified elements."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:284
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:285
msgid "Set the top margin in pts. Default is %default. Note: 72 pts equals 1 inch"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:289
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:290
msgid "Set the bottom margin in pts. Default is %default. Note: 72 pts equals 1 inch"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:294
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:295
msgid "Set the left margin in pts. Default is %default. Note: 72 pts equals 1 inch"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:299
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:300
msgid "Set the right margin in pts. Default is %default. Note: 72 pts equals 1 inch"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:305
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:306
msgid "Change text justification. A value of \"left\" converts all justified text in the source to left aligned (i.e. unjustified) text. A value of \"justify\" converts all unjustified text to justified. A value of \"original\" (the default) does not change justification in the source file. Note that only some output formats support justification."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:315
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:316
msgid "Remove spacing between paragraphs. Also sets an indent on paragraphs of 1.5em. Spacing removal will not work if the source file does not use paragraphs (<p> or <div> tags)."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:322
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:323
msgid "When calibre removes inter paragraph spacing, it automatically sets a paragraph indent, to ensure that paragraphs can be easily distinguished. This option controls the width of that indent."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:329
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:330
msgid "Use the cover detected from the source file in preference to the specified cover."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:335
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:336
msgid "Insert a blank line between paragraphs. Will not work if the source file does not use paragraphs (<p> or <div> tags)."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:342
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:343
msgid "Remove the first image from the input ebook. Useful if the first image in the source file is a cover and you are specifying an external cover."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:350
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:351
msgid "Insert the book metadata at the start of the book. This is useful if your ebook reader does not support displaying/searching metadata directly."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:358
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:359
msgid "Attempt to detect and correct hard line breaks and other problems in the source file. This may make things worse, so use with care."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:366
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:367
msgid "Use a regular expression to try and remove the header."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:373
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:374
msgid "The regular expression to use to remove the header."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:379
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:380
msgid "Use a regular expression to try and remove the footer."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:386
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:387
msgid "The regular expression to use to remove the footer."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:393
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:394
msgid "Read metadata from the specified OPF file. Metadata read from this file will override any metadata in the source file."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:400
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:401
msgid "Transliterate unicode characters to an ASCII representation. Use with care because this will replace unicode characters with ASCII. For instance it will replace \"%s\" with \"Mikhail Gorbachiov\". Also, note that in cases where there are multiple representations of a character (characters shared by Chinese and Japanese for instance) the representation used by the largest number of people will be used (Chinese in the previous example)."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:415
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:416
msgid "Preserve ligatures present in the input document. A ligature is a special rendering of a pair of characters like ff, fi, fl et cetera. Most readers do not have support for ligatures in their default fonts, so they are unlikely to render correctly. By default, calibre will turn a ligature into the corresponding pair of normal characters. This option will preserve them instead."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:428
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:38
msgid "Set the title."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:419
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:432
msgid "Set the authors. Multiple authors should be separated by ampersands."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:424
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:437
msgid "The version of the title to be used for sorting. "
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:428
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:441
msgid "String to be used when sorting by author. "
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:432
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:445
msgid "Set the cover to the specified file or URL"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:436
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:449
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:54
msgid "Set the ebook description."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:440
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:453
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:56
msgid "Set the ebook publisher."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:444
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:457
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:60
msgid "Set the series this ebook belongs to."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:448
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:461
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:62
msgid "Set the index of the book in this series."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:452
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:465
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:64
msgid "Set the rating. Should be a number between 1 and 5."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:456
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:469
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:66
msgid "Set the ISBN of the book."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:460
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:473
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:68
msgid "Set the tags for the book. Should be a comma separated list."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:464
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:477
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:70
msgid "Set the book producer."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:468
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:481
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:72
msgid "Set the language."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:472
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:485
msgid "Set the publication date."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:476
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:489
msgid "Set the book timestamp (used by the date column in calibre)."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:576
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:589
msgid "Could not find an ebook inside the archive"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:634
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:647
msgid "Values of series index and rating must be numbers. Ignoring"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:641
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:654
msgid "Failed to parse date/time"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:788
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:802
msgid "Converting input to HTML..."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:815
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:829
msgid "Running transforms on ebook..."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:902
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:916
msgid "Creating"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/output.py:58
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/output.py:205
msgid "Extract the contents of the generated EPUB file to the specified directory. The contents of the directory are first deleted, so be careful."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/output.py:64
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/output.py:211
msgid "Turn off splitting at page breaks. Normally, input files are automatically split at every page break into two files. This gives an output ebook that can be parsed faster and with less resources. However, splitting is slow and if your source file contains a very large number of page breaks, you should turn off splitting on page breaks."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/output.py:75
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/output.py:222
msgid "Split all HTML files larger than this size (in KB). This is necessary as most EPUB readers cannot handle large file sizes. The default of %defaultKB is the size required for Adobe Digital Editions."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/output.py:82
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/output.py:229
msgid "Normally, if the input file has no cover and you don't specify one, a default cover is generated with the title, authors, etc. This option disables the generation of this cover."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/output.py:88
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/output.py:235
msgid "Do not use SVG for the book cover. Use this option if your EPUB is going to be used ona device that does not support SVG, like the iPhone or the JetBook Lite. Without this option, such devices will display the cover as a blank page."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/output.py:243
msgid "When using an SVG cover, this option will cause the cover to scale to cover the available screen area, but still preserve its aspect ratio (ratio of width to height). That means there may be white borders at the sides or top and bottom of the image, but the image will never be distorted. Without this option the image may be slightly distorted, but there will be no borders."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/fb2/fb2ml.py:144
#: /home/kovid/work/calibre/src/calibre/ebooks/rb/rbml.py:102
#: /home/kovid/work/calibre/src/calibre/ebooks/txt/txtml.py:77
@ -2026,19 +2046,19 @@ msgstr ""
msgid "Split Options:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/output.py:31
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/output.py:59
msgid "The unit of measure. Default is inch. Choices are %s Note: This does not override the unit for margins!"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/output.py:36
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/output.py:64
msgid "The size of the paper. This size will be overridden when an output profile is used. Default is letter. Choices are %s"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/output.py:40
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/output.py:68
msgid "Custom size of the document. Use the form widthxheight EG. `123x321` to specify the width and height. This overrides any specified paper-size."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/output.py:45
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/output.py:73
msgid "The orientation of the page. Default is portrait. Choices are %s"
msgstr ""
@ -2307,10 +2327,10 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_tab_template_ui.py:27
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:88
#: /home/kovid/work/calibre/src/calibre/gui2/convert/debug_ui.py:49
#: /home/kovid/work/calibre/src/calibre/gui2/convert/epub_output_ui.py:44
#: /home/kovid/work/calibre/src/calibre/gui2/convert/epub_output_ui.py:48
#: /home/kovid/work/calibre/src/calibre/gui2/convert/fb2_input_ui.py:28
#: /home/kovid/work/calibre/src/calibre/gui2/convert/fb2_output_ui.py:28
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:125
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:119
#: /home/kovid/work/calibre/src/calibre/gui2/convert/lrf_output_ui.py:115
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:166
#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output_ui.py:66
@ -2512,7 +2532,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/debug_ui.py:52
#: /home/kovid/work/calibre/src/calibre/gui2/convert/debug_ui.py:53
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:131
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:125
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:171
#: /home/kovid/work/calibre/src/calibre/gui2/convert/xexp_edit_ui.py:52
#: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget_ui.py:76
@ -2558,26 +2578,30 @@ msgstr ""
msgid "EPUB Output"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/epub_output_ui.py:45
#: /home/kovid/work/calibre/src/calibre/gui2/convert/epub_output_ui.py:49
msgid "Do not &split on page breaks"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/epub_output_ui.py:46
msgid "Split files &larger than:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/epub_output_ui.py:47
msgid " KB"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/epub_output_ui.py:48
#: /home/kovid/work/calibre/src/calibre/gui2/convert/epub_output_ui.py:50
msgid "No default &cover"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/epub_output_ui.py:49
#: /home/kovid/work/calibre/src/calibre/gui2/convert/epub_output_ui.py:51
msgid "No &SVG cover"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/epub_output_ui.py:52
msgid "Preserve cover &aspect ratio"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/epub_output_ui.py:53
msgid "Split files &larger than:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/epub_output_ui.py:54
msgid " KB"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/fb2_input.py:12
msgid "FB2 Input"
msgstr ""
@ -2618,15 +2642,15 @@ msgid "&Base font size:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/font_key_ui.py:105
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:129
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:123
msgid "Font size &key:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/font_key_ui.py:106
#: /home/kovid/work/calibre/src/calibre/gui2/convert/font_key_ui.py:110
#: /home/kovid/work/calibre/src/calibre/gui2/convert/font_key_ui.py:112
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:128
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:133
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:122
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:127
#: /home/kovid/work/calibre/src/calibre/gui2/convert/lrf_output_ui.py:118
#: /home/kovid/work/calibre/src/calibre/gui2/convert/lrf_output_ui.py:120
#: /home/kovid/work/calibre/src/calibre/gui2/convert/lrf_output_ui.py:125
@ -2665,72 +2689,76 @@ msgstr ""
msgid "Control the look and feel of the output"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:126
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel.py:30
msgid "Original"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel.py:31
msgid "Left align"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel.py:32
msgid "Justify text"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:120
msgid "&Disable font size rescaling"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:127
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:121
msgid "Base &font size:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:130
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:124
msgid "Wizard to help you choose an appropriate font size key"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:132
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:126
msgid "Line &height:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:134
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:128
msgid "Input character &encoding:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:135
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:129
msgid "Remove &spacing between paragraphs"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:136
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:130
msgid "Indent size:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:137
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:131
msgid "<p>When calibre removes inter paragraph spacing, it automatically sets a paragraph indent, to ensure that paragraphs can be easily distinguished. This option controls the width of that indent."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:138
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:132
msgid " em"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:139
msgid "&Linearize tables"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:140
msgid "&Transliterate unicode characters to ASCII."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:141
msgid "Extra &CSS"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:142
msgid "Insert &blank line"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:143
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:133
msgid "Text justification:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:144
msgid "justify"
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:134
msgid "&Linearize tables"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:145
msgid "left"
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:135
msgid "Extra &CSS"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:146
msgid "original"
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:136
msgid "&Transliterate unicode characters to ASCII"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:137
msgid "Insert &blank line"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:138
msgid "Keep &ligatures"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/lrf_output.py:19
@ -7833,18 +7861,22 @@ msgid "English (Ireland)"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/localization.py:109
msgid "Spanish (Paraguay)"
msgid "English (China)"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/localization.py:110
msgid "German (AT)"
msgid "Spanish (Paraguay)"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/localization.py:111
msgid "Dutch (NL)"
msgid "German (AT)"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/localization.py:112
msgid "Dutch (NL)"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/localization.py:113
msgid "Dutch (BE)"
msgstr ""
@ -7868,13 +7900,13 @@ msgstr ""
msgid "Control email delivery"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/web/feeds/__init__.py:102
#: /home/kovid/work/calibre/src/calibre/web/feeds/__init__.py:124
#: /home/kovid/work/calibre/src/calibre/web/feeds/__init__.py:113
#: /home/kovid/work/calibre/src/calibre/web/feeds/__init__.py:135
msgid "Unknown feed"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/web/feeds/__init__.py:142
#: /home/kovid/work/calibre/src/calibre/web/feeds/__init__.py:165
#: /home/kovid/work/calibre/src/calibre/web/feeds/__init__.py:153
#: /home/kovid/work/calibre/src/calibre/web/feeds/__init__.py:178
msgid "Untitled article"
msgstr ""
@ -7970,23 +8002,23 @@ msgstr ""
msgid "Untitled Article"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1228
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1230
msgid "Article downloaded: %s"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1239
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1241
msgid "Article download failed: %s"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1256
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1258
msgid "Fetching feed"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1403
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1405
msgid "Failed to log in, check your username and password for the calibre Periodicals service."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1419
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1421
msgid "You do not have permission to download this issue. Either your subscription has expired or you have exceeded the maximum allowed downloads for today."
msgstr ""

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -106,6 +106,7 @@ _extra_lang_codes = {
'en_SG' : _('English (Singapore)'),
'en_YE' : _('English (Yemen)'),
'en_IE' : _('English (Ireland)'),
'en_CN' : _('English (China)'),
'es_PY' : _('Spanish (Paraguay)'),
'de_AT' : _('German (AT)'),
'nl' : _('Dutch (NL)'),

View File

@ -49,6 +49,17 @@ class Article(object):
self.date = published
self.utctime = dt_factory(self.date, assume_utc=True, as_utc=True)
self.localtime = self.utctime.astimezone(local_tz)
self._formatted_date = None
@dynamic_property
def formatted_date(self):
def fget(self):
if self._formatted_date is None:
self._formatted_date = self.localtime.strftime(" [%a, %d %b %H:%M]")
return self._formatted_date
def fset(self, val):
self._formatted_date = val
return property(fget=fget, fset=fset)
@dynamic_property
def title(self):
@ -150,6 +161,8 @@ class Feed(object):
self.articles.append(article)
else:
self.logger.debug('Skipping article %s (%s) from feed %s as it is too old.'%(title, article.localtime.strftime('%a, %d %b, %Y %H:%M'), self.title))
d = item.get('date', '')
article.formatted_date = d
def parse_article(self, item):

View File

@ -1179,6 +1179,8 @@ class BasicNewsRecipe(Recipe):
body.insert(len(body.contents), elem)
with open(last, 'wb') as fi:
fi.write(unicode(soup).encode('utf-8'))
if len(feeds) == 0:
raise Exception('All feeds are empty, aborting.')
if len(feeds) > 1:
for i, f in enumerate(feeds):

Some files were not shown because too many files have changed in this diff Show More