Sync to trunk.

This commit is contained in:
John Schember 2011-09-18 18:39:38 -04:00
commit 8f95d10d27
109 changed files with 22043 additions and 17772 deletions

View File

@ -19,6 +19,68 @@
# new recipes:
# - title:
- version: 0.8.19
date: 2011-09-16
new features:
- title: "Driver for Sony Ericsson Xperia Arc"
- title: "MOBI Output: Add option in Preferences->Output Options->MOBI Output to enable the share via Facebook feature for calibre produced MOBI files. Note that enabling this disables the sync last read position across multiple devices feature. Don't ask me why, ask Amazon."
- title: "Content server: Update metadata when sending MOBI as well as EPUB files"
- title: "News download: Add an auto_cleanup_keep variable that allows recipe writers to tell the auto cleanup to never remove a specified element"
- title: "Conversion: Remove paragraph spacing: If you set the indent size negative, calibre will now leave the indents specified in the input document"
bug fixes:
- title: "Fix regression in 0.8.18 that broke PDF Output"
- title: "MOBI Output: Revert change in 0.8.18 that marked news downloads with a single section as blogs, as the Kindle does not auto archive them"
- title: "PDF output on OSX now generates proper non image based documents"
- title: "RTF Input: Fix handling of internal links and underlined text"
tickets: [845328]
- title: "Fix language sometimes not getting set when downloading metadata in the edit metadata dialog"
- title: "Fix regression that broke killing of multiple jobs"
tickets: [850764]
- title: "Fix bug processing author names with initials when downloading metadata from ozon.ru."
tickets: [845420]
- title: "Fix a memory leak in the Copy to library operation which also fixes the metadata.db being held open in the destination library"
tickets: [849469]
- title: "Keyboard shortcuts: Allow use of symbol keys like >,*,etc."
tickets: [847378]
- title: "EPUB Output: When splitting be a little cleverer about discarding 'empty' pages"
improved recipes:
- Twitch Films
- Japan Times
- People/US Magazine mashup
- Business World India
- Inquirer.net
- Guardian/Observer
new recipes:
- title: RT
author: Darko Miletic
- title: CIO Magazine
author: Julio Map
- title: India Today and Hindustan Times
author: Krittika Goyal
- title: Pagina 12 Print Edition
author: Pablo Marfil
- version: 0.8.18
date: 2011-09-09
@ -39,6 +101,7 @@
- title: "TXT Output: Preserve as much formatting as possible when generating Markdown output including various CSS styles"
bug fixes:
- title: "Fix pubdate incorrect when used in save to disk template in timezones ahead of GMT."
tickets: [844445]

View File

@ -0,0 +1,61 @@
from calibre.web.feeds.recipes import BasicNewsRecipe
import re
class SportsIllustratedRecipe(BasicNewsRecipe) :
__author__ = 'ape'
__copyright__ = 'ape'
__license__ = 'GPL v3'
language = 'de'
description = 'Berliner Zeitung'
version = 2
title = u'Berliner Zeitung'
timefmt = ' [%d.%m.%Y]'
no_stylesheets = True
remove_javascript = True
use_embedded_content = False
publication_type = 'newspaper'
keep_only_tags = [dict(name='div', attrs={'class':'teaser t_split t_artikel'})]
INDEX = 'http://www.berlinonline.de/berliner-zeitung/'
def parse_index(self):
base = 'http://www.berlinonline.de'
answer = []
articles = {}
more = 1
soup = self.index_to_soup(self.INDEX)
# Get list of links to ressorts from index page
ressort_list = soup.findAll('ul', attrs={'class': re.compile('ressortlist')})
for ressort in ressort_list[0].findAll('a'):
feed_title = ressort.string
print 'Analyzing', feed_title
if not articles.has_key(feed_title):
articles[feed_title] = []
answer.append(feed_title)
# Load ressort page.
feed = self.index_to_soup('http://www.berlinonline.de' + ressort['href'])
# find mainbar div which contains the list of all articles
for article_container in feed.findAll('div', attrs={'class': re.compile('mainbar')}):
# iterate over all articles
for article_teaser in article_container.findAll('div', attrs={'class': re.compile('teaser')}):
# extract title of article
if article_teaser.h3 != None:
article = {'title' : article_teaser.h3.a.string, 'date' : u'', 'url' : base + article_teaser.h3.a['href'], 'description' : u''}
articles[feed_title].append(article)
else:
# Skip teasers for missing photos
if article_teaser.div.p.contents[0].find('Foto:') > -1:
continue
article = {'title': 'Weitere Artikel ' + str(more), 'date': u'', 'url': base + article_teaser.div.p.a['href'], 'description': u''}
articles[feed_title].append(article)
more += 1
answer = [[key, articles[key]] for key in answer if articles.has_key(key)]
return answer
def get_masthead_url(self):
return 'http://www.berlinonline.de/.img/berliner-zeitung/blz_logo.gif'

29
recipes/china_post.recipe Normal file
View File

@ -0,0 +1,29 @@
from calibre.web.feeds.news import BasicNewsRecipe
class CP(BasicNewsRecipe):
title = u'China Post'
language = 'en_CN'
__author__ = 'Krittika Goyal'
oldest_article = 1 #days
max_articles_per_feed = 25
use_embedded_content = False
no_stylesheets = True
auto_cleanup = True
feeds = [
('Top Stories',
'http://www.chinapost.com.tw/rss/front.xml'),
('Taiwan',
'http://www.chinapost.com.tw/rss/taiwan.xml'),
('China',
'http://www.chinapost.com.tw/rss/china.xml'),
('Business',
'http://www.chinapost.com.tw/rss/business.xml'),
('World',
'http://www.chinapost.com.tw/rss/international.xml'),
('Sports',
'http://www.chinapost.com.tw/rss/sports.xml'),
]

View File

@ -1,35 +1,38 @@
from calibre.web.feeds.news import BasicNewsRecipe
class Cicero(BasicNewsRecipe):
timefmt = ' [%Y-%m-%d]'
title = u'Cicero'
__author__ = 'mad@sharktooth.de'
description = u'Magazin f\xfcr politische Kultur'
oldest_article = 7
language = 'de'
class BasicUserRecipe1316245412(BasicNewsRecipe):
title = u'Cicero Online'
description = u'Magazin f\xfcr politische Kultur'
publisher = 'Ringier Publishing GmbH'
category = 'news, politics, Germany'
language = 'de'
encoding = 'UTF-8'
__author__ = 'Armin Geller' # 2011-09-17
oldest_article = 7
max_articles_per_feed = 100
no_stylesheets = True
use_embedded_content = False
publisher = 'Ringier Publishing'
category = 'news, politics, Germany'
encoding = 'iso-8859-1'
publication_type = 'magazine'
masthead_url = 'http://www.cicero.de/img2/cicero_logo_rss.gif'
feeds = [
(u'Das gesamte Portfolio', u'http://www.cicero.de/rss/rss.php?ress_id='),
#(u'Alle Heft-Inhalte', u'http://www.cicero.de/rss/rss.php?ress_id=heft'),
#(u'Alle Online-Inhalte', u'http://www.cicero.de/rss/rss.php?ress_id=online'),
#(u'Berliner Republik', u'http://www.cicero.de/rss/rss.php?ress_id=4'),
#(u'Weltb\xfchne', u'http://www.cicero.de/rss/rss.php?ress_id=1'),
#(u'Salon', u'http://www.cicero.de/rss/rss.php?ress_id=7'),
#(u'Kapital', u'http://www.cicero.de/rss/rss.php?ress_id=6'),
#(u'Netzst\xfccke', u'http://www.cicero.de/rss/rss.php?ress_id=9'),
#(u'Leinwand', u'http://www.cicero.de/rss/rss.php?ress_id=12'),
#(u'Bibliothek', u'http://www.cicero.de/rss/rss.php?ress_id=15'),
(u'Kolumne - Alle Kolulmnen', u'http://www.cicero.de/rss/rss2.php?ress_id='),
#(u'Kolumne - Schreiber, Berlin', u'http://www.cicero.de/rss/rss2.php?ress_id=35'),
#(u'Kolumne - TV Kritik', u'http://www.cicero.de/rss/rss2.php?ress_id=34')
]
no_stylesheets = True
auto_cleanup = False
remove_tags = [
dict(name='div', attrs={'id':["header", "navigation", "skip-link", "header-print", "header-print-url", "meta-toolbar", "footer"]}),
dict(name='div', attrs={'class':["region region-sidebar-first column sidebar", "breadcrumb", "breadcrumb-title", "meta", "comment-wrapper",
"field field-name-field-show-teaser-right field-type-list-boolean field-label-above"]}),
dict(name='div', attrs={'title':["Dossier Auswahl"]}),
dict(name='h2', attrs={'class':["title comment-form"]}),
dict(name='form', attrs={'class':["comment-form user-info-from-cookie"]}),
]
feeds = [
(u'Das gesamte Portfolio', u'http://www.cicero.de/rss.xml'),
(u'Berliner Republik', u'http://www.cicero.de/berliner-republik.xml'),
(u'Weltb\xfchne', u'http://www.cicero.de/weltbuehne.xml'),
(u'Kapital', u'http://www.cicero.de/kapital.xml'),
(u'Salon', u'http://www.cicero.de/salon.xml'),
(u'Blogs', u'http://www.cicero.de/blogs.xml'), #seems not to be in use at the moment
]
def print_version(self, url):
return 'http://www.cicero.de/page_print.php?' + url.rpartition('?')[2]
return url + '?print'

View File

@ -46,7 +46,9 @@ class LATimes(BasicNewsRecipe):
remove_tags_after=dict(name='p', attrs={'class':'copyright'})
remove_tags = [
dict(name=['meta','link','iframe','object','embed'])
,dict(attrs={'class':['toolSet','articlerail','googleAd','entry-footer-left','entry-footer-right','entry-footer-social','google-ad-story-bottom','sphereTools']})
,dict(attrs={'class':['toolSet','articlerail','googleAd','entry-footer-left',
'entry-footer-right','entry-footer-social','google-ad-story-bottom',
'sphereTools', 'nextgen-share-tools']})
,dict(attrs={'id':['article-promo','googleads','moduleArticleToolsContainer','gallery-subcontent']})
]
remove_attributes=['lang','xmlns:fb','xmlns:og','border','xtags','i','article_body']

View File

@ -2,7 +2,6 @@ from calibre.web.feeds.news import BasicNewsRecipe
class AdvancedUserRecipe1306097511(BasicNewsRecipe):
title = u'Metro Nieuws NL'
description = u'Metro Nieuws - NL'
# Version 1.2, updated cover image to match the changed website.
# added info date on title
oldest_article = 2
@ -11,14 +10,14 @@ class AdvancedUserRecipe1306097511(BasicNewsRecipe):
description = u'Metro Nederland'
language = u'nl'
simultaneous_downloads = 5
delay = 1
# timefmt = ' [%A, %d %B, %Y]'
#delay = 1
auto_cleanup = True
auto_cleanup_keep = '//div[@class="article-image-caption-2column"]|//div[@id="date"]'
timefmt = ' [%A, %d %b %Y]'
no_stylesheets = True
remove_javascript = True
remove_empty_feeds = True
cover_url = 'http://www.oldreadmetro.com/img/en/metroholland/last/1/small.jpg'
remove_empty_feeds = True
publication_type = 'newspaper'
remove_tags_before = dict(name='div', attrs={'id':'date'})
remove_tags_after = dict(name='div', attrs={'id':'column-1-3'})

View File

@ -51,14 +51,13 @@ class pcWorld(BasicNewsRecipe):
keep_only_tags = [
dict(name='div', attrs={'class':'article'})
]
remove_tags = [
dict(name='div', attrs={'class':['toolBar','mac_tags','toolBar btmTools','recommend longRecommend','recommend shortRecommend','textAds']}),
dict(name='div', attrs={'id':['sidebar','comments','mac_tags']}),
dict(name='ul', attrs={'class':'tools'}),
dict(name='li', attrs={'class':'sub'})
dict(name='ul', attrs={'class':['tools', 'tools clearfix']}),
dict(name='li', attrs={'class':'sub'}),
dict(name='p', attrs={'id':'userDesire'})
]
feeds = [
(u'PCWorld Headlines', u'http://feeds.pcworld.com/pcworld/latestnews'),
(u'How-To', u'http://feeds.pcworld.com/pcworld/update/howto'),

View File

@ -15,12 +15,12 @@ class Time(BasicNewsRecipe):
# ' publish complete articles on the web.')
title = u'Time'
__author__ = 'Kovid Goyal'
description = 'Weekly magazine'
description = ('Weekly US magazine.')
encoding = 'utf-8'
no_stylesheets = True
language = 'en'
remove_javascript = True
#needs_subscription = 'optional'
keep_only_tags = [
{
@ -41,6 +41,21 @@ class Time(BasicNewsRecipe):
preprocess_regexps = [(re.compile(
r'<meta .+/>'), lambda m:'')]
def get_browser(self):
br = BasicNewsRecipe.get_browser(self)
if False and self.username and self.password:
# This site uses javascript in its login process
res = br.open('http://www.time.com/time/magazine')
br.select_form(nr=1)
br['username'] = self.username
br['password'] = self.password
res = br.submit()
raw = res.read()
if '>Log Out<' not in raw:
raise ValueError('Failed to login to time.com, check'
' your username and password')
return br
def parse_index(self):
raw = self.index_to_soup('http://www.time.com/time/magazine', raw=True)
root = html.fromstring(raw)

View File

@ -18,23 +18,23 @@ msgstr ""
"Report-Msgid-Bugs-To: Debian iso-codes team <pkg-isocodes-"
"devel@lists.alioth.debian.org>\n"
"POT-Creation-Date: 2011-09-02 16:21+0000\n"
"PO-Revision-Date: 2011-08-27 06:01+0000\n"
"Last-Translator: Wolfgang Rohdewald <wolfgang@rohdewald.de>\n"
"PO-Revision-Date: 2011-09-13 16:28+0000\n"
"Last-Translator: frenkx <Unknown>\n"
"Language-Team: German <debian-l10n-german@lists.debian.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2011-09-03 05:03+0000\n"
"X-Generator: Launchpad (build 13830)\n"
"X-Launchpad-Export-Date: 2011-09-14 04:40+0000\n"
"X-Generator: Launchpad (build 13921)\n"
"Language: de\n"
#. name for aaa
msgid "Ghotuo"
msgstr ""
msgstr "Ghotuo"
#. name for aab
msgid "Alumu-Tesu"
msgstr ""
msgstr "Alumu-Tesu"
#. name for aac
msgid "Ari"
@ -120,9 +120,10 @@ msgstr ""
msgid "Amarasi"
msgstr ""
# auch: Abbé, Abbey oder Abi
#. name for aba
msgid "Abé"
msgstr ""
msgstr "Abé"
#. name for abb
msgid "Bankon"
@ -150,7 +151,7 @@ msgstr ""
#. name for abh
msgid "Arabic, Tajiki"
msgstr ""
msgstr "Arabisch, Tadschikisch"
#. name for abi
msgid "Abidji"
@ -190,7 +191,7 @@ msgstr ""
#. name for abr
msgid "Abron"
msgstr ""
msgstr "Abron"
#. name for abs
msgid "Malay, Ambonese"
@ -374,7 +375,7 @@ msgstr ""
#. name for ads
msgid "Adamorobe Sign Language"
msgstr ""
msgstr "Adamorobe-Gebärdensprache"
#. name for adt
msgid "Adnyamathanha"
@ -626,7 +627,7 @@ msgstr ""
#. name for aha
msgid "Ahanta"
msgstr ""
msgstr "Ahanta"
#. name for ahb
msgid "Axamb"
@ -1192,9 +1193,10 @@ msgstr ""
msgid "Andra-Hus"
msgstr ""
# auch: Anyi, Agni
#. name for any
msgid "Anyin"
msgstr ""
msgstr "Anyin"
#. name for anz
msgid "Anem"
@ -1418,7 +1420,7 @@ msgstr ""
#. name for arc
msgid "Aramaic, Official (700-300 BCE)"
msgstr ""
msgstr "Aramäisch"
#. name for ard
msgid "Arabana"
@ -2114,7 +2116,7 @@ msgstr ""
#. name for bar
msgid "Bavarian"
msgstr ""
msgstr "Bairisch"
#. name for bas
msgid "Basa (Cameroon)"
@ -2526,7 +2528,7 @@ msgstr ""
#. name for bet
msgid "Béte, Guiberoua"
msgstr ""
msgstr "Guiberouabété"
#. name for beu
msgid "Blagar"
@ -2534,7 +2536,7 @@ msgstr ""
#. name for bev
msgid "Bété, Daloa"
msgstr ""
msgstr "Daloabété"
#. name for bew
msgid "Betawi"
@ -3954,7 +3956,7 @@ msgstr ""
#. name for btg
msgid "Bété, Gagnoa"
msgstr ""
msgstr "Gagnoabété"
#. name for bth
msgid "Bidayuh, Biatah"
@ -4884,9 +4886,10 @@ msgstr ""
msgid "Chaudangsi"
msgstr ""
# auch: Östlicher Min-Dialekt
#. name for cdo
msgid "Chinese, Min Dong"
msgstr ""
msgstr "Min Dong, Chinesisch"
#. name for cdr
msgid "Cinda-Regi-Tiyal"
@ -5034,7 +5037,7 @@ msgstr ""
#. name for chu
msgid "Slavonic, Old"
msgstr ""
msgstr "Altkirchenslawisch"
#. name for chv
msgid "Chuvash"
@ -5162,7 +5165,7 @@ msgstr ""
#. name for ckb
msgid "Kurdish, Central"
msgstr ""
msgstr "Zentralkurdisch"
#. name for ckh
msgid "Chak"
@ -5172,9 +5175,10 @@ msgstr ""
msgid "Cibak"
msgstr ""
# auch: Chokosi, Chakosi, Kyokosi, Tchokossi, Tiokossi
#. name for cko
msgid "Anufo"
msgstr ""
msgstr "Anufo"
#. name for ckq
msgid "Kajakse"
@ -5288,9 +5292,10 @@ msgstr ""
msgid "Michigamea"
msgstr ""
# auch: Mandarin
#. name for cmn
msgid "Chinese, Mandarin"
msgstr ""
msgstr "Hochchinesisch"
#. name for cmo
msgid "Mnong, Central"
@ -6294,7 +6299,7 @@ msgstr ""
#. name for dic
msgid "Dida, Lakota"
msgstr ""
msgstr "Lakota Dida"
#. name for did
msgid "Didinga"
@ -6964,9 +6969,10 @@ msgstr ""
msgid "Jola-Fonyi"
msgstr ""
# auch: Dyula, Jula
#. name for dyu
msgid "Dyula"
msgstr "Dyula"
msgstr "Dioula"
#. name for dyy
msgid "Dyaabugay"
@ -7532,9 +7538,10 @@ msgstr ""
msgid "Persian"
msgstr "Persisch"
# auch: Fanti, Fannti, Odschi, Fante-Twi
#. name for fat
msgid "Fanti"
msgstr "Fanti"
msgstr "Fante"
#. name for fau
msgid "Fayu"
@ -8058,7 +8065,7 @@ msgstr ""
#. name for gct
msgid "German, Colonia Tovar"
msgstr ""
msgstr "Alemán Coloniero Tovar"
#. name for gda
msgid "Lohar, Gade"
@ -8406,7 +8413,7 @@ msgstr ""
#. name for gkp
msgid "Kpelle, Guinea"
msgstr ""
msgstr "Kpelle, Guinea"
#. name for gla
msgid "Gaelic, Scottish"
@ -8482,11 +8489,11 @@ msgstr ""
#. name for gmh
msgid "German, Middle High (ca. 1050-1500)"
msgstr ""
msgstr "Mittelhochdeutsch (ca. 1050-1500)"
#. name for gml
msgid "German, Middle Low"
msgstr ""
msgstr "Mittelniederdeutsch"
#. name for gmm
msgid "Gbaya-Mbodomo"
@ -8602,7 +8609,7 @@ msgstr ""
#. name for god
msgid "Godié"
msgstr ""
msgstr "Godié"
#. name for goe
msgid "Gongduk"
@ -8618,7 +8625,7 @@ msgstr ""
#. name for goh
msgid "German, Old High (ca. 750-1050)"
msgstr ""
msgstr "Althochdeutsch (ca. 750-1050)"
#. name for goi
msgid "Gobasi"
@ -8802,7 +8809,7 @@ msgstr ""
#. name for gsg
msgid "German Sign Language"
msgstr ""
msgstr "Deutsche Gebärdensprache"
#. name for gsl
msgid "Gusilay"
@ -8830,7 +8837,7 @@ msgstr ""
#. name for gsw
msgid "German, Swiss"
msgstr ""
msgstr "Schweizerdeutsch"
#. name for gta
msgid "Guató"
@ -8854,7 +8861,7 @@ msgstr ""
#. name for gud
msgid "Dida, Yocoboué"
msgstr ""
msgstr "Yocoboué Dida"
#. name for gue
msgid "Gurinji"
@ -9158,7 +9165,7 @@ msgstr ""
#. name for hak
msgid "Chinese, Hakka"
msgstr ""
msgstr "Hakka, Chinesisch"
#. name for hal
msgid "Halang"
@ -9694,7 +9701,7 @@ msgstr ""
#. name for hsb
msgid "Sorbian, Upper"
msgstr ""
msgstr "Obersorbisch"
#. name for hsh
msgid "Hungarian Sign Language"
@ -11020,9 +11027,10 @@ msgstr ""
msgid "Javanese, Caribbean"
msgstr ""
# auch: Pepesa-Jwira
#. name for jwi
msgid "Jwira-Pepesa"
msgstr ""
msgstr "Jwira-Pepesa"
#. name for jya
msgid "Jiarong"
@ -12318,11 +12326,11 @@ msgstr ""
#. name for kmq
msgid "Kwama"
msgstr ""
msgstr "Kwama"
#. name for kmr
msgid "Kurdish, Northern"
msgstr ""
msgstr "Nordkurdisch"
#. name for kms
msgid "Kamasau"
@ -12886,7 +12894,7 @@ msgstr ""
#. name for ksh
msgid "Kölsch"
msgstr ""
msgstr "Kölsch"
#. name for ksi
msgid "Krisa"
@ -13498,7 +13506,7 @@ msgstr ""
#. name for kyf
msgid "Kouya"
msgstr ""
msgstr "Kouya"
#. name for kyg
msgid "Keyagana"
@ -14826,7 +14834,7 @@ msgstr ""
#. name for ltg
msgid "Latgalian"
msgstr ""
msgstr "Lettgallisch"
#. name for lti
msgid "Leti (Indonesia)"
@ -16382,9 +16390,10 @@ msgstr ""
msgid "Mnong, Southern"
msgstr ""
# auch: nördliches Min
#. name for mnp
msgid "Chinese, Min Bei"
msgstr ""
msgstr "Min Bei, Chinesisch"
#. name for mnq
msgid "Minriq"
@ -17662,9 +17671,10 @@ msgstr ""
msgid "Nangikurrunggurr"
msgstr ""
# auch: Südliche Min-Sprache
#. name for nan
msgid "Chinese, Min Nan"
msgstr ""
msgstr "Min Nan, Chinesisch"
#. name for nao
msgid "Naaba"
@ -19306,9 +19316,10 @@ msgstr ""
msgid "Nawathinehena"
msgstr ""
# auch: Nyaboa
#. name for nwb
msgid "Nyabwa"
msgstr ""
msgstr "Nyabwa"
#. name for nwc
msgid "Newari, Old"
@ -19494,9 +19505,10 @@ msgstr ""
msgid "Njebi"
msgstr ""
# auch: Nzima, Appolo
#. name for nzi
msgid "Nzima"
msgstr "Nzima"
msgstr "Nzema"
#. name for nzk
msgid "Nzakara"
@ -22702,7 +22714,7 @@ msgstr ""
#. name for sdh
msgid "Kurdish, Southern"
msgstr ""
msgstr "Südkurdisch"
#. name for sdj
msgid "Suundi"
@ -22864,9 +22876,10 @@ msgstr ""
msgid "South African Sign Language"
msgstr ""
# auch: Sefwi, Asahyue
#. name for sfw
msgid "Sehwi"
msgstr ""
msgstr "Sehwi"
#. name for sga
msgid "Irish, Old (to 900)"
@ -23414,7 +23427,7 @@ msgstr ""
#. name for sme
msgid "Sami, Northern"
msgstr ""
msgstr "Nordsamisch"
#. name for smf
msgid "Auwe"
@ -24228,7 +24241,7 @@ msgstr ""
#. name for swg
msgid "Swabian"
msgstr ""
msgstr "Schwäbisch"
#. name for swh
msgid "Swahili (individual language)"
@ -24648,9 +24661,10 @@ msgstr ""
msgid "Tabaru"
msgstr ""
# auch: Ditamari, Tamari, Somba, Soma, Some, Tamberma
#. name for tbz
msgid "Ditammari"
msgstr ""
msgstr "Ditammari"
#. name for tca
msgid "Ticuna"
@ -25356,7 +25370,7 @@ msgstr ""
#. name for tlh
msgid "Klingon"
msgstr ""
msgstr "Klingonisch"
#. name for tli
msgid "Tlingit"
@ -26596,7 +26610,7 @@ msgstr "Udmurt"
#. name for udu
msgid "Uduk"
msgstr ""
msgstr "Uduk"
#. name for ues
msgid "Kioko"
@ -27412,7 +27426,7 @@ msgstr ""
#. name for wae
msgid "Walser"
msgstr ""
msgstr "Walser"
#. name for waf
msgid "Wakoná"
@ -28180,7 +28194,7 @@ msgstr ""
#. name for wuu
msgid "Chinese, Wu"
msgstr ""
msgstr "Wu, Chinesisch"
#. name for wuv
msgid "Wuvulu-Aua"
@ -28868,7 +28882,7 @@ msgstr ""
#. name for xom
msgid "Komo (Sudan)"
msgstr ""
msgstr "Komo (Sudan)"
#. name for xon
msgid "Konkomba"
@ -28896,7 +28910,7 @@ msgstr ""
#. name for xpe
msgid "Kpelle, Liberia"
msgstr ""
msgstr "Kpelle, Liberia"
#. name for xpg
msgid "Phrygian"

View File

@ -8,13 +8,13 @@ msgstr ""
"Project-Id-Version: calibre\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2011-09-02 16:21+0000\n"
"PO-Revision-Date: 2011-09-08 10:13+0000\n"
"PO-Revision-Date: 2011-09-09 13:18+0000\n"
"Last-Translator: Jellby <Unknown>\n"
"Language-Team: Spanish <es@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2011-09-09 04:37+0000\n"
"X-Launchpad-Export-Date: 2011-09-10 05:01+0000\n"
"X-Generator: Launchpad (build 13900)\n"
#. name for aaa
@ -1615,7 +1615,7 @@ msgstr "Atemble"
#. name for atg
msgid "Ivbie North-Okpela-Arhe"
msgstr ""
msgstr "Ivbie norte-okpela-arhe"
#. name for ati
msgid "Attié"
@ -2803,7 +2803,7 @@ msgstr "Bima"
#. name for bhq
msgid "Tukang Besi South"
msgstr ""
msgstr "Tukang besi sur"
#. name for bhr
msgid "Malagasy, Bara"
@ -4375,19 +4375,19 @@ msgstr "Barikanchi"
#. name for bxp
msgid "Bebil"
msgstr ""
msgstr "Bebil"
#. name for bxq
msgid "Beele"
msgstr ""
msgstr "Beele"
#. name for bxr
msgid "Buriat, Russia"
msgstr ""
msgstr "Buriat de Rusia"
#. name for bxs
msgid "Busam"
msgstr ""
msgstr "Busam"
#. name for bxu
msgid "Buriat, China"
@ -4463,11 +4463,11 @@ msgstr "Bidyara"
#. name for byn
msgid "Bilin"
msgstr ""
msgstr "Bilin"
#. name for byo
msgid "Biyo"
msgstr ""
msgstr "Biyo"
#. name for byp
msgid "Bumaji"
@ -4659,19 +4659,19 @@ msgstr "Carolinio"
#. name for cam
msgid "Cemuhî"
msgstr ""
msgstr "Cemuhî"
#. name for can
msgid "Chambri"
msgstr ""
msgstr "Chambri"
#. name for cao
msgid "Chácobo"
msgstr ""
msgstr "Chácobo"
#. name for cap
msgid "Chipaya"
msgstr ""
msgstr "Chipaya"
#. name for caq
msgid "Nicobarese, Car"
@ -4679,11 +4679,11 @@ msgstr "Nicobarés de Car"
#. name for car
msgid "Carib, Galibi"
msgstr ""
msgstr "Caribe galibí"
#. name for cas
msgid "Tsimané"
msgstr ""
msgstr "Tsimané"
#. name for cat
msgid "Catalan"
@ -4691,175 +4691,175 @@ msgstr "Catalán"
#. name for cav
msgid "Cavineña"
msgstr ""
msgstr "Cavineña"
#. name for caw
msgid "Callawalla"
msgstr ""
msgstr "Callawalla"
#. name for cax
msgid "Chiquitano"
msgstr ""
msgstr "Chiquitano"
#. name for cay
msgid "Cayuga"
msgstr ""
msgstr "Cayuga"
#. name for caz
msgid "Canichana"
msgstr ""
msgstr "Canichana"
#. name for cbb
msgid "Cabiyarí"
msgstr ""
msgstr "Cabiyarí"
#. name for cbc
msgid "Carapana"
msgstr ""
msgstr "Carapana"
#. name for cbd
msgid "Carijona"
msgstr ""
msgstr "Carijona"
#. name for cbe
msgid "Chipiajes"
msgstr ""
msgstr "Chipiajes"
#. name for cbg
msgid "Chimila"
msgstr ""
msgstr "Chimila"
#. name for cbh
msgid "Cagua"
msgstr ""
msgstr "Cagua"
#. name for cbi
msgid "Chachi"
msgstr ""
msgstr "Chachi"
#. name for cbj
msgid "Ede Cabe"
msgstr ""
msgstr "Ede cabe"
#. name for cbk
msgid "Chavacano"
msgstr ""
msgstr "Chabacano"
#. name for cbl
msgid "Chin, Bualkhaw"
msgstr ""
msgstr "Chin bualkhaw"
#. name for cbn
msgid "Nyahkur"
msgstr ""
msgstr "Nyahkur"
#. name for cbo
msgid "Izora"
msgstr ""
msgstr "Izora"
#. name for cbr
msgid "Cashibo-Cacataibo"
msgstr ""
msgstr "Cashibo-cacataibo"
#. name for cbs
msgid "Cashinahua"
msgstr ""
msgstr "Cashinahua"
#. name for cbt
msgid "Chayahuita"
msgstr ""
msgstr "Chayahuita"
#. name for cbu
msgid "Candoshi-Shapra"
msgstr ""
msgstr "Candoshi-Shapra"
#. name for cbv
msgid "Cacua"
msgstr ""
msgstr "Cacua"
#. name for cbw
msgid "Kinabalian"
msgstr ""
msgstr "Kinabalian"
#. name for cby
msgid "Carabayo"
msgstr ""
msgstr "Carabayo"
#. name for cca
msgid "Cauca"
msgstr ""
msgstr "Cauca"
#. name for ccc
msgid "Chamicuro"
msgstr ""
msgstr "Chamicuro"
#. name for ccd
msgid "Creole, Cafundo"
msgstr ""
msgstr "Criollo de Cafundo"
#. name for cce
msgid "Chopi"
msgstr ""
msgstr "Chopi"
#. name for ccg
msgid "Daka, Samba"
msgstr ""
msgstr "Samba daka"
#. name for cch
msgid "Atsam"
msgstr ""
msgstr "Atsam"
#. name for ccj
msgid "Kasanga"
msgstr ""
msgstr "Kasanga"
#. name for ccl
msgid "Cutchi-Swahili"
msgstr ""
msgstr "Cutchi-suajili"
#. name for ccm
msgid "Creole Malay, Malaccan"
msgstr ""
msgstr "Malayo criollo de Malaca"
#. name for cco
msgid "Chinantec, Comaltepec"
msgstr ""
msgstr "Chinanteco de Comaltepec"
#. name for ccp
msgid "Chakma"
msgstr ""
msgstr "Chakma"
#. name for ccq
msgid "Chaungtha"
msgstr ""
msgstr "Chaungtha"
#. name for ccr
msgid "Cacaopera"
msgstr ""
msgstr "Cacaopera"
#. name for cda
msgid "Choni"
msgstr ""
msgstr "Choni"
#. name for cde
msgid "Chenchu"
msgstr ""
msgstr "Chenchu"
#. name for cdf
msgid "Chiru"
msgstr ""
msgstr "Chiru"
#. name for cdg
msgid "Chamari"
msgstr ""
msgstr "Chamari"
#. name for cdh
msgid "Chambeali"
msgstr ""
msgstr "Chambeali"
#. name for cdi
msgid "Chodri"
msgstr ""
msgstr "Chodri"
#. name for cdj
msgid "Churahi"
@ -4867,7 +4867,7 @@ msgstr ""
#. name for cdm
msgid "Chepang"
msgstr ""
msgstr "Chepang"
#. name for cdn
msgid "Chaudangsi"
@ -11743,7 +11743,7 @@ msgstr ""
#. name for khc
msgid "Tukang Besi North"
msgstr ""
msgstr "Tukang besi norte"
#. name for khd
msgid "Kanum, Bädi"
@ -24187,11 +24187,11 @@ msgstr "Suajili (macrolengua)"
#. name for swb
msgid "Comorian, Maore"
msgstr ""
msgstr "Comorense de Mayotte"
#. name for swc
msgid "Swahili, Congo"
msgstr ""
msgstr "Suajili del Congo"
#. name for swe
msgid "Swedish"
@ -27759,7 +27759,7 @@ msgstr ""
#. name for wlc
msgid "Comorian, Mwali"
msgstr ""
msgstr "Comorense de Mohéli"
#. name for wle
msgid "Wolane"
@ -27899,7 +27899,7 @@ msgstr ""
#. name for wni
msgid "Comorian, Ndzwani"
msgstr ""
msgstr "Comorense de Anjouan"
#. name for wnk
msgid "Wanukaka"
@ -30263,7 +30263,7 @@ msgstr ""
#. name for zdj
msgid "Comorian, Ngazidja"
msgstr ""
msgstr "Comorense de Gran Comora"
#. name for zea
msgid "Zeeuws"

File diff suppressed because it is too large Load Diff

View File

@ -320,6 +320,28 @@ def get_parsed_proxy(typ='http', debug=True):
prints('Using http proxy', str(ans))
return ans
def get_proxy_info(proxy_scheme, proxy_string):
'''
Parse all proxy information from a proxy string (as returned by
get_proxies). The returned dict will have members set to None when the info
is not available in the string. If an exception occurs parsing the string
this method returns None.
'''
import urlparse
try:
proxy_url = u'%s://%s'%(proxy_scheme, proxy_string)
urlinfo = urlparse.urlparse(proxy_url)
ans = {
u'scheme': urlinfo.scheme,
u'hostname': urlinfo.hostname,
u'port': urlinfo.port,
u'username': urlinfo.username,
u'password': urlinfo.password,
}
except:
return None
return ans
USER_AGENT = 'Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.13) Gecko/20101210 Gentoo Firefox/3.6.13'
USER_AGENT_MOBILE = 'Mozilla/5.0 (Windows; U; Windows CE 5.1; rv:1.8.1a3) Gecko/20060610 Minimo/0.016'

View File

@ -4,7 +4,7 @@ __license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
__docformat__ = 'restructuredtext en'
__appname__ = u'calibre'
numeric_version = (0, 8, 18)
numeric_version = (0, 8, 19)
__version__ = u'.'.join(map(unicode, numeric_version))
__author__ = u"Kovid Goyal <kovid@kovidgoyal.net>"
@ -33,6 +33,7 @@ islinux = not(iswindows or isosx or isbsd)
isfrozen = hasattr(sys, 'frozen')
isunix = isosx or islinux
isportable = os.environ.get('CALIBRE_PORTABLE_BUILD', None) is not None
ispy3 = sys.version_info.major > 2
try:
preferred_encoding = locale.getpreferredencoding()

View File

@ -47,7 +47,10 @@ class ANDROID(USBMS):
},
# Sony Ericsson
0xfce : { 0xd12e : [0x0100]},
0xfce : {
0xd12e : [0x0100],
0xe14f : [0x0226],
},
# Google
0x18d1 : {

View File

@ -369,9 +369,8 @@ OptionRecommendation(name='remove_paragraph_spacing_indent_size',
help=_('When calibre removes blank lines between paragraphs, it automatically '
'sets a paragraph indent, to ensure that paragraphs can be easily '
'distinguished. This option controls the width of that indent (in em). '
'If you set this value to 0, then the indent specified in the input '
'document is used, unless you also set the insert line between '
'paragraphs option.')
'If you set this value negative, then the indent specified in the input '
'document is used, that is, calibre does not change the indentation.')
),
OptionRecommendation(name='prefer_metadata_cover',

View File

@ -11,7 +11,7 @@ __docformat__ = 'restructuredtext en'
Input plugin for HTML or OPF ebooks.
'''
import os, re, sys, uuid, tempfile, errno
import os, re, sys, uuid, tempfile, errno as gerrno
from urlparse import urlparse, urlunparse
from urllib import unquote
from functools import partial
@ -75,7 +75,7 @@ class IgnoreFile(Exception):
def __init__(self, msg, errno):
Exception.__init__(self, msg)
self.doesnt_exist = errno == errno.ENOENT
self.doesnt_exist = errno == gerrno.ENOENT
self.errno = errno
class HTMLFile(object):

View File

@ -330,9 +330,11 @@ class MetadataUpdater(object):
prefs = load_defaults('mobi_output')
pas = prefs.get('prefer_author_sort', False)
kindle_pdoc = prefs.get('personal_doc', None)
share_not_sync = prefs.get('share_not_sync', False)
except:
pas = False
kindle_pdoc = None
share_not_sync = False
if mi.author_sort and pas:
authors = mi.author_sort
update_exth_record((100, normalize(authors).encode(self.codec, 'replace')))
@ -358,7 +360,7 @@ class MetadataUpdater(object):
if kindle_pdoc and kindle_pdoc in mi.tags:
added_501 = True
update_exth_record((501, str('PDOC')))
update_exth_record((501, b'PDOC'))
if mi.pubdate:
update_exth_record((106, str(mi.pubdate).encode(self.codec, 'replace')))
@ -376,7 +378,7 @@ class MetadataUpdater(object):
# Add a 113 record if not present to allow Amazon syncing
if (113 not in self.original_exth_records and
self.original_exth_records.get(501, None) == 'EBOK' and
not added_501):
not added_501 and not share_not_sync):
from uuid import uuid4
update_exth_record((113, str(uuid4())))
if 503 in self.original_exth_records:

View File

@ -55,6 +55,11 @@ class MOBIOutput(OutputFormatPlugin):
' specified directory. If the directory already '
'exists, it will be deleted.')
),
OptionRecommendation(name='share_not_sync', recommended_value=False,
help=_('Enable sharing of book content via Facebook etc. '
' on the Kindle. WARNING: Using this feature means that '
' the book will not auto sync its last read position '
' on multiple devices. Complain to Amazon.'))
])
def check_for_periodical(self):

View File

@ -529,12 +529,13 @@ class MobiWriter(object):
if isinstance(uuid, unicode):
uuid = uuid.encode('utf-8')
exth.write(pack(b'>II', 113, len(uuid) + 8))
exth.write(uuid)
nrecs += 1
if not self.opts.share_not_sync:
exth.write(pack(b'>II', 113, len(uuid) + 8))
exth.write(uuid)
nrecs += 1
# Write cdetype
if not self.is_periodical:
if not self.is_periodical and not self.opts.share_not_sync:
exth.write(pack(b'>II', 501, 12))
exth.write(b'EBOK')
nrecs += 1

View File

@ -321,7 +321,7 @@ class CSSFlattener(object):
cssdict['margin-top'] = cssdict['margin-bottom'] = \
'%fem'%self.context.insert_blank_line_size
indent_size = self.context.remove_paragraph_spacing_indent_size
keep_indents = indent_size == 0.0 and not self.context.insert_blank_line
keep_indents = indent_size < 0.0
if (self.context.remove_paragraph_spacing and not keep_indents and
cssdict.get('text-align', None) not in ('center', 'right')):
cssdict['text-indent'] = "%1.1fem" % indent_size

View File

@ -753,15 +753,24 @@ def open_local_file(path):
url = QUrl.fromLocalFile(path)
open_url(url)
def is_ok_to_use_qt():
def must_use_qt():
global gui_thread, _store_app
if (islinux or isbsd) and ':' not in os.environ.get('DISPLAY', ''):
return False
raise RuntimeError('X server required. If you are running on a'
' headless machine, use xvfb')
if _store_app is None and QApplication.instance() is None:
_store_app = QApplication([])
if gui_thread is None:
gui_thread = QThread.currentThread()
return gui_thread is QThread.currentThread()
if gui_thread is not QThread.currentThread():
raise RuntimeError('Cannot use Qt in non GUI thread')
def is_ok_to_use_qt():
try:
must_use_qt()
except RuntimeError:
return False
return True
def is_gui_thread():
global gui_thread

View File

@ -29,7 +29,7 @@ class StoreAction(InterfaceAction):
('book', _('book'))]:
func = getattr(self, 'search_%s'%('author_title' if x == 'book'
else x))
ac = cm(x, _('Search for this %s'%t), triggered=func)
ac = cm(x, _('Search for this %s')%t, triggered=func)
setattr(self, 'action_search_by_'+x, ac)
self.store_menu.addSeparator()
self.store_list_menu = self.store_menu.addMenu(_('Stores'))

View File

@ -84,7 +84,7 @@
<string>...</string>
</property>
<property name="icon">
<iconset>
<iconset resource="../../../../resources/images.qrc">
<normaloff>:/images/wizard.png</normaloff>:/images/wizard.png</iconset>
</property>
<property name="iconSize">
@ -225,12 +225,21 @@
<property name="toolTip">
<string>&lt;p&gt;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.</string>
</property>
<property name="specialValueText">
<string>No change</string>
</property>
<property name="suffix">
<string> em</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>-0.100000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="6" column="3">

View File

@ -23,7 +23,7 @@ class PluginWidget(Widget, Ui_Form):
Widget.__init__(self, parent,
['prefer_author_sort', 'rescale_images', 'toc_title',
'mobi_ignore_margins', 'mobi_toc_at_start',
'dont_compress', 'no_inline_toc',
'dont_compress', 'no_inline_toc', 'share_not_sync',
'personal_doc']#, 'mobi_navpoints_only_deepest']
)
self.db, self.book_id = db, book_id

View File

@ -75,6 +75,13 @@
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="opt_share_not_sync">
<property name="text">
<string>Enable sharing of book content via Facebook, etc. WARNING: Disables last read syncing</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">

View File

@ -229,14 +229,14 @@ class CheckLibraryDialog(QDialog):
self.copy_button = QPushButton(_('Copy &to clipboard'))
self.copy_button.setDefault(False)
self.copy_button.clicked.connect(self.copy_to_clipboard)
self.ok_button = QPushButton('&Done')
self.ok_button = QPushButton(_('&Done'))
self.ok_button.setDefault(True)
self.ok_button.clicked.connect(self.accept)
self.delete_button = QPushButton('Delete &marked')
self.delete_button = QPushButton(_('Delete &marked'))
self.delete_button.setToolTip(_('Delete marked files (checked subitems)'))
self.delete_button.setDefault(False)
self.delete_button.clicked.connect(self.delete_marked)
self.fix_button = QPushButton('&Fix marked')
self.fix_button = QPushButton(_('&Fix marked'))
self.fix_button.setDefault(False)
self.fix_button.setEnabled(False)
self.fix_button.setToolTip(_('Fix marked sections (checked fixable items)'))

View File

@ -535,6 +535,8 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog):
val = [v.replace('|', ',') for v in val]
else:
val = []
if not val:
val = ['']
return val
def s_r_display_bounds_changed(self, i):

View File

@ -18,11 +18,7 @@ class NameTableWidgetItem(QTableWidgetItem):
def data(self, role):
if role == Qt.DisplayRole:
if self.initial_value != self.current_value:
return _('%(curr)s (was %(initial)s)')%dict(
curr=self.current_value, initial=self.initial_value)
else:
return self.current_value
return self.current_value
elif role == Qt.EditRole:
return self.current_value
else:
@ -105,13 +101,16 @@ class TagListEditor(QDialog, Ui_TagListEditor):
self.up_arrow_icon = QIcon(I('arrow-up.png'))
self.blank_icon = QIcon(I('blank.png'))
self.table.setColumnCount(2)
self.table.setColumnCount(3)
self.name_col = QTableWidgetItem(_('Tag'))
self.table.setHorizontalHeaderItem(0, self.name_col)
self.name_col.setIcon(self.up_arrow_icon)
self.count_col = QTableWidgetItem(_('Count'))
self.table.setHorizontalHeaderItem(1, self.count_col)
self.count_col.setIcon(self.blank_icon)
self.was_col = QTableWidgetItem(_('Was'))
self.table.setHorizontalHeaderItem(2, self.was_col)
self.count_col.setIcon(self.blank_icon)
# Capture clicks on the horizontal header to sort the table columns
hh = self.table.horizontalHeader();
@ -120,6 +119,7 @@ class TagListEditor(QDialog, Ui_TagListEditor):
hh.sectionResized.connect(self.table_column_resized)
self.name_order = 0
self.count_order = 1
self.was_order = 1
# Add the data
select_item = None
@ -135,6 +135,9 @@ class TagListEditor(QDialog, Ui_TagListEditor):
# only the name column can be selected
item.setFlags (item.flags() & ~Qt.ItemIsSelectable)
self.table.setItem(row, 1, item)
item = QTableWidgetItem('')
item.setFlags (item.flags() & ~Qt.ItemIsSelectable)
self.table.setItem(row, 2, item)
# Scroll to the selected item if there is one
if select_item is not None:
@ -187,6 +190,10 @@ class TagListEditor(QDialog, Ui_TagListEditor):
if item.text() != item.initial_text():
id_ = item.data(Qt.UserRole).toInt()[0]
self.to_rename[id_] = unicode(item.text())
orig = self.table.item(item.row(), 2)
self.table.blockSignals(True)
orig.setData(Qt.DisplayRole, item.initial_text())
self.table.blockSignals(False)
def rename_tag(self):
item = self.table.item(self.table.currentRow(), 0)
@ -223,8 +230,10 @@ class TagListEditor(QDialog, Ui_TagListEditor):
def header_clicked(self, idx):
if idx == 0:
self.do_sort_by_name()
else:
elif idx == 1:
self.do_sort_by_count()
else:
self.do_sort_by_was()
def do_sort_by_name(self):
self.name_order = 1 if self.name_order == 0 else 0
@ -232,6 +241,7 @@ class TagListEditor(QDialog, Ui_TagListEditor):
self.name_col.setIcon(self.down_arrow_icon if self.name_order
else self.up_arrow_icon)
self.count_col.setIcon(self.blank_icon)
self.was_col.setIcon(self.blank_icon)
def do_sort_by_count (self):
self.count_order = 1 if self.count_order == 0 else 0
@ -239,6 +249,15 @@ class TagListEditor(QDialog, Ui_TagListEditor):
self.count_col.setIcon(self.down_arrow_icon if self.count_order
else self.up_arrow_icon)
self.name_col.setIcon(self.blank_icon)
self.was_col.setIcon(self.blank_icon)
def do_sort_by_was(self):
self.was_order = 1 if self.was_order == 0 else 0
self.table.sortByColumn(2, self.was_order)
self.was_col.setIcon(self.down_arrow_icon if self.was_order
else self.up_arrow_icon)
self.name_col.setIcon(self.blank_icon)
self.count_col.setIcon(self.blank_icon)
def accepted(self):
self.save_geometry()

View File

@ -266,7 +266,7 @@ class JobManager(QAbstractTableModel): # {{{
def kill_multiple_jobs(self, rows, view):
jobs = [self.jobs[row] for row in rows]
devjobs = [j for j in jobs is isinstance(j, DeviceJob)]
devjobs = [j for j in jobs if isinstance(j, DeviceJob)]
if devjobs:
error_dialog(view, _('Cannot kill job'),
_('Cannot kill jobs that communicate with the device')).exec_()

View File

@ -25,6 +25,7 @@ from calibre.gui2.metadata.single_download import FullFetch
from calibre.gui2.custom_column_widgets import populate_metadata_page
from calibre.utils.config import tweaks
from calibre.ebooks.metadata.book.base import Metadata
from calibre.utils.localization import canonicalize_lang
BASE_TITLE = _('Edit Metadata')
@ -376,7 +377,10 @@ class MetadataSingleDialogBase(ResizableDialog):
if mi.series_index is not None:
self.series_index.current_val = float(mi.series_index)
if not mi.is_null('languages'):
self.languages.lang_codes = mi.languages
langs = [canonicalize_lang(x) for x in mi.languages]
langs = [x for x in langs if x is not None]
if langs:
self.languages.current_val = langs
if mi.comments and mi.comments.strip():
self.comments.current_val = mi.comments

View File

@ -1034,10 +1034,19 @@ class TagsModel(QAbstractItemModel): # {{{
def index_for_path(self, path):
parent = QModelIndex()
for i in path:
parent = self.index(i, 0, parent)
if not parent.isValid():
return QModelIndex()
for idx,v in enumerate(path):
tparent = self.index(v, 0, parent)
if not tparent.isValid():
if v > 0 and idx == len(path) - 1:
# Probably the last item went away. Use the one before it
tparent = self.index(v-1, 0, parent)
if not tparent.isValid():
# Not valid. Use the last valid index
break
else:
# There isn't one before it. Use the last valid index
break
parent = tparent
return parent
def index(self, row, column, parent):

View File

@ -167,16 +167,20 @@ class CheckLibrary(object):
if self.is_case_sensitive:
unknowns = frozenset(filenames-formats-NORMALS)
missing = book_formats - formats
# Check: any books that aren't formats or normally there?
for u in unknowns:
for fn in unknowns:
if fn in missing: # An unknown format correctly registered
continue
self.extra_files.append((title_dir,
os.path.join(db_path, u), book_id))
os.path.join(db_path, fn), book_id))
# Check: any book formats that should be there?
missing = book_formats - formats
for m in missing:
for fn in missing:
if fn in unknowns: # An unknown format correctly registered
continue
self.missing_formats.append((title_dir,
os.path.join(db_path, m), book_id))
os.path.join(db_path, fn), book_id))
# Check: any book formats that shouldn't be there?
extra = formats - book_formats - NORMALS
@ -185,25 +189,32 @@ class CheckLibrary(object):
os.path.join(db_path, e), book_id))
else:
def lc_map(fnames, fset):
m = {}
fn = {}
for f in fnames:
m[f.lower()] = f
return [m[f] for f in fset]
ff = f.lower()
if ff in fset:
fn[ff] = f
return fn
filenames_lc = frozenset([f.lower() for f in filenames])
formats_lc = frozenset([f.lower() for f in formats])
unknowns = frozenset(filenames_lc-formats_lc-NORMALS)
book_formats_lc = frozenset([f.lower() for f in book_formats])
missing = book_formats_lc - formats_lc
# Check: any books that aren't formats or normally there?
for f in lc_map(filenames, unknowns):
self.extra_files.append((title_dir, os.path.join(db_path, f),
for lcfn,ccfn in lc_map(filenames, unknowns).iteritems():
if lcfn in missing: # An unknown format correctly registered
continue
self.extra_files.append((title_dir, os.path.join(db_path, ccfn),
book_id))
book_formats_lc = frozenset([f.lower() for f in book_formats])
# Check: any book formats that should be there?
missing = book_formats_lc - formats_lc
for m in lc_map(book_formats, missing):
for lcfn,ccfn in lc_map(book_formats, missing).iteritems():
if lcfn in unknowns: # An unknown format correctly registered
continue
self.missing_formats.append((title_dir,
os.path.join(db_path, m), book_id))
os.path.join(db_path, ccfn), book_id))
# Check: any book formats that shouldn't be there?
extra = formats_lc - book_formats_lc - NORMALS

View File

@ -117,9 +117,9 @@ We just need some information from you:
* What ebook formats does your device support?
* Is there a special directory on the device in which all ebook files should be placed?
* We also need information about your device that |app| will collect automatically. First, if your
device supports SD cards, insert them. Then connect your device. In calibre go to :guilabel:`Preferences->Advanced->Miscellaneous`
device supports SD cards, insert them. Then connect your device to the computer. In calibre go to :guilabel:`Preferences->Advanced->Miscellaneous`
and click the "Debug device detection" button. This will create some debug output. Copy it to a file
and repeat the process, this time with your device disconnected.
and repeat the process, this time with your device disconnected from your computer.
* Send both the above outputs to us with the other information and we will write a device driver for your
device.

View File

@ -128,6 +128,8 @@ The functions available are listed below. Note that the definitive documentation
* ``human_readable()`` -- expects the value to be a number and returns a string representing that number in KB, MB, GB, etc.
* ``ifempty(text)`` -- if the field is not empty, return the value of the field. Otherwise return `text`.
* ``in_list(separator, pattern, found_val, not_found_val)`` -- interpret the field as a list of items separated by `separator`, comparing the `pattern` against each value in the list. If the pattern matches a value, return `found_val`, otherwise return `not_found_val`.
* ``language_codes(lang_strings)`` -- return the language codes for the strings passed in `lang_strings`. The strings must be in the language of the current locale. `Lang_strings` is a comma-separated list.
* ``language_strings(lang_codes, localize)`` -- return the strings for the language codes passed in `lang_codes`. If `localize` is zero, return the strings in English. If localize is not zero, return the strings in the language of the current locale. `Lang_codes` is a comma-separated list.
* ``list_item(index, separator)`` -- interpret the field as a list of items separated by `separator`, returning the `index`th item. The first item is number zero. The last item can be returned using `list_item(-1,separator)`. If the item is not in the list, then the empty value is returned. The separator has the same meaning as in the `count` function.
* ``re(pattern, replacement)`` -- return the field after applying the regular expression. All instances of `pattern` are replaced with `replacement`. As in all of |app|, these are python-compatible regular expressions.
* ``shorten(left chars, middle text, right chars)`` -- Return a shortened version of the field, consisting of `left chars` characters from the beginning of the field, followed by `middle text`, followed by `right chars` characters from the end of the string. `Left chars` and `right chars` must be integers. For example, assume the title of the book is `Ancient English Laws in the Times of Ivanhoe`, and you want it to fit in a space of at most 15 characters. If you use ``{title:shorten(9,-,5)}``, the result will be `Ancient E-nhoe`. If the field's length is less than ``left chars`` + ``right chars`` + the length of ``middle text``, then the field will be used intact. For example, the title `The Dome` would not be changed.

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

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

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

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