mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
0.7.27 updates
This commit is contained in:
commit
c243416d71
@ -4,6 +4,95 @@
|
||||
# for important features/bug fixes.
|
||||
# Also, each release can have new and improved recipes.
|
||||
|
||||
- version: 0.7.27
|
||||
date: 2010-11-05
|
||||
|
||||
new features:
|
||||
- title: "The book list behavior has changed"
|
||||
type: major
|
||||
description: >
|
||||
"Now double clicking on an entry in the book list will open it in the viewer. To edit metadata single click a previously selected entry instead. This is consistent with
|
||||
the usage in most operating systems, so should be most intuitive for new users. Also typing any key no longer starts an edit, instead press F2 (Enter on OS X) to start editing
|
||||
the current cell. Also you now have to double click instead of single clicking the book details panel to open the detailed info dialog for the book."
|
||||
|
||||
- title: "Added a new HTML output format plugin, which converts the input document to a ZIP file. The zip file contains HTML pages suitable for display in a website"
|
||||
|
||||
- title: "Support for iRiver Cover Story and Digma Q600"
|
||||
|
||||
- title: "Add a search button (labelled Go!) to explicitly run a search with the text currently in the quick search box"
|
||||
|
||||
- title: "Add author to the calibre geenrated book jacket"
|
||||
tickets: [7402]
|
||||
|
||||
- title: "Add the title of the destination book to the merge dialog warning message"
|
||||
|
||||
- title: "calibre-server: Make auto reload control separate from --devlop with a new command line option --auto-reload"
|
||||
|
||||
bug fixes:
|
||||
- title: "Fix book details panel not being updated after a delete-merge"
|
||||
tickets: [7426]
|
||||
|
||||
- title: "Fix clicking in the search box launches a search if you have search as you type enabled"
|
||||
tickets: [7425]
|
||||
|
||||
- title: "Use a browser widget to display book details for more robustness and better performance when vieweing large HTML comments"
|
||||
|
||||
- title: "Fix cover browser not updated after copy to library and delete"
|
||||
tickets: [7416]
|
||||
|
||||
- title: "Fix regression that broke sending non calibre EPUB files to the iPad. Also handle failure to set cover in iTunes gracefully"
|
||||
tickets: [7356]
|
||||
|
||||
- title: "News download: Workaround lack of thread safety in python mechanize, causing corrupted network packets (degrading network performance) on Ubuntu Maverick 64bit kernels"
|
||||
|
||||
- title: "Convert comments to HTML for book details panel in separate thread to make scrolling through the book list faster when large comments are present"
|
||||
|
||||
- title: "calibre-server: Fix regression that broke --daemonize"
|
||||
|
||||
- title: "EPUB Input: Handle ncx files that have <navpoint> elements with no content correctly."
|
||||
tickets: [7396]
|
||||
|
||||
- title: "SNBOutput: Fixed a bug in handling pre tag"
|
||||
|
||||
- title: "MOBI Output: Don't ignore hidden anchors."
|
||||
tickets: [7384]
|
||||
|
||||
- title: "Fix switching libraries and generating a catalog could generate a catalog for the wrong library"
|
||||
|
||||
- title: "MOBI Output: Fix regression that broke conversion of anchors inside superscripts/subscripts."
|
||||
tickets: [7368]
|
||||
|
||||
- title: "Content server: Fix various minor bugs"
|
||||
tickets: [7379, 6768, 7354]
|
||||
|
||||
- title: "Amazon metadata download plugin: Make it more robust and add option to auto convert HTML to text"
|
||||
|
||||
- title: "Re-arrange send to device menu to make it harder to accidentally trigger the send and delete actions"
|
||||
|
||||
|
||||
improved recipes:
|
||||
- Danas
|
||||
- Fudzilla
|
||||
- Zeit Online
|
||||
- New York Times
|
||||
- Mediapart
|
||||
|
||||
new recipes:
|
||||
- title: "Ynet and Calcalist"
|
||||
author: "marbs"
|
||||
|
||||
- title: "El Faro de Vigo"
|
||||
author: "Jefferson Frantz"
|
||||
|
||||
- title: "Clic_RBS"
|
||||
author: "avoredo"
|
||||
|
||||
- title: "Correio da Manha"
|
||||
author: "jmst"
|
||||
|
||||
- title: "Rue89"
|
||||
author: "Louis Gesbert"
|
||||
|
||||
- version: 0.7.26
|
||||
date: 2010-10-30
|
||||
|
||||
|
@ -39,7 +39,16 @@
|
||||
.cbj_title {
|
||||
font-size: x-large;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Author
|
||||
*/
|
||||
.cbj_author {
|
||||
font-size: medium;
|
||||
text-align: center;
|
||||
margin-bottom: 1ex;
|
||||
}
|
||||
|
||||
/*
|
||||
** Table containing Series, Publication Year, Rating and Tags
|
||||
|
@ -7,6 +7,7 @@
|
||||
<body>
|
||||
<div class="cbj_banner">
|
||||
<div class="cbj_title">{title}</div>
|
||||
<div class="cbj_author">{author}</div>
|
||||
<table class="cbj_header">
|
||||
<tr class="cbj_series">
|
||||
<td class="cbj_label">{series_label}:</td>
|
||||
|
43
resources/recipes/calcalist.recipe
Normal file
43
resources/recipes/calcalist.recipe
Normal file
@ -0,0 +1,43 @@
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
from calibre.ebooks.BeautifulSoup import re
|
||||
|
||||
class AdvancedUserRecipe1283848012(BasicNewsRecipe):
|
||||
description = 'This is a recipe of Calcalist.co.il. The recipe downloads the article page to not hurt the sites advertising income.'
|
||||
cover_url = 'http://ftp5.bizportal.co.il/web/giflib/news/calcalist.JPG'
|
||||
title = u'Calcalist'
|
||||
language = 'he'
|
||||
__author__ = 'marbs'
|
||||
extra_css='img {max-width:100%;} body{direction: rtl;},title{direction: rtl; } ,article_description{direction: rtl; }, a.article{direction: rtl; } ,calibre_feed_description{direction: rtl; }'
|
||||
simultaneous_downloads = 5
|
||||
remove_javascript = True
|
||||
timefmt = '[%a, %d %b, %Y]'
|
||||
oldest_article = 1
|
||||
max_articles_per_feed = 100
|
||||
remove_attributes = ['width']
|
||||
simultaneous_downloads = 5
|
||||
keep_only_tags =dict(name='div', attrs={'id':'articleContainer'})
|
||||
remove_tags = [dict(name='p', attrs={'text':[' ']})]
|
||||
max_articles_per_feed = 100
|
||||
preprocess_regexps = [
|
||||
(re.compile(r'<p> </p>', re.DOTALL|re.IGNORECASE), lambda match: '')
|
||||
]
|
||||
|
||||
|
||||
feeds = [(u'\u05d3\u05e3 \u05d4\u05d1\u05d9\u05ea', u'http://www.calcalist.co.il/integration/StoryRss8.xml'),
|
||||
(u'24/7', u'http://www.calcalist.co.il/integration/StoryRss3674.xml'),
|
||||
(u'\u05d1\u05d0\u05d6\u05d6', u'http://www.calcalist.co.il/integration/StoryRss3674.xml'),
|
||||
(u'\u05de\u05d1\u05d6\u05e7\u05d9\u05dd', u'http://www.calcalist.co.il/integration/StoryRss184.xml'),
|
||||
(u'\u05d4\u05e9\u05d5\u05e7', u'http://www.calcalist.co.il/integration/StoryRss2.xml'),
|
||||
(u'\u05d1\u05d0\u05e8\u05e5', u'http://www.calcalist.co.il/integration/StoryRss14.xml'),
|
||||
(u'\u05d4\u05db\u05e1\u05e3', u'http://www.calcalist.co.il/integration/StoryRss9.xml'),
|
||||
(u'\u05e0\u05d3\u05dc"\u05df', u'http://www.calcalist.co.il/integration/StoryRss7.xml'),
|
||||
(u'\u05e2\u05d5\u05dc\u05dd', u'http://www.calcalist.co.il/integration/StoryRss13.xml'),
|
||||
(u'\u05e4\u05e8\u05e1\u05d5\u05dd \u05d5\u05e9\u05d9\u05d5\u05d5\u05e7', u'http://www.calcalist.co.il/integration/StoryRss5.xml'),
|
||||
(u'\u05e4\u05e0\u05d0\u05d9', u'http://www.calcalist.co.il/integration/StoryRss3.xml'),
|
||||
(u'\u05d8\u05db\u05e0\u05d5\u05dc\u05d5\u05d2\u05d9', u'http://www.calcalist.co.il/integration/StoryRss4.xml'),
|
||||
(u'\u05e2\u05e1\u05e7\u05d9 \u05e1\u05e4\u05d5\u05e8\u05d8', u'http://www.calcalist.co.il/integration/StoryRss18.xml')]
|
||||
|
||||
def print_version(self, url):
|
||||
split1 = url.split("-")
|
||||
print_url = 'http://www.calcalist.co.il/Ext/Comp/ArticleLayout/CdaArticlePrintPreview/1,2506,L-' + split1[1]
|
||||
return print_url
|
@ -59,6 +59,9 @@ class Danas(BasicNewsRecipe):
|
||||
,(re.compile(u'\u201d'), lambda match: '”') # right double quotation mark
|
||||
,(re.compile(u'\u201e'), lambda match: '“') # double low-9 quotation mark
|
||||
,(re.compile(u'\u201f'), lambda match: '”') # double high-reversed-9 quotation mark
|
||||
,(re.compile(u'\u00f4'), lambda match: '“') # latin small letter o with circumflex
|
||||
,(re.compile(u'\u00f6'), lambda match: '”') # latin small letter o with dieaeresis
|
||||
,(re.compile(u'\u00e1'), lambda match: ' ' ) # latin small letter a with acute
|
||||
]
|
||||
|
||||
keep_only_tags = [dict(name='div', attrs={'id':'left'})]
|
||||
|
@ -1,38 +0,0 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
|
||||
'''
|
||||
Fetch elektrolese.
|
||||
'''
|
||||
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
|
||||
class elektrolese(BasicNewsRecipe):
|
||||
|
||||
title = u'elektrolese'
|
||||
description = 'News about electronic publishing'
|
||||
__author__ = 'Oliver Niesner'
|
||||
use_embedded_content = False
|
||||
timefmt = ' [%a %d %b %Y]'
|
||||
language = 'de'
|
||||
|
||||
oldest_article = 14
|
||||
max_articles_per_feed = 50
|
||||
no_stylesheets = True
|
||||
conversion_options = {'linearize_tables':True}
|
||||
encoding = 'utf-8'
|
||||
|
||||
|
||||
remove_tags_after = [dict(id='comments')]
|
||||
filter_regexps = [r'ad\.doubleclick\.net']
|
||||
|
||||
remove_tags = [dict(name='div', attrs={'class':'bannerSuperBanner'}),
|
||||
dict(id='comments'),
|
||||
dict(id='Navbar1')]
|
||||
|
||||
|
||||
|
||||
feeds = [ (u'elektrolese', u'http://elektrolese.blogspot.com/feeds/posts/default?alt=rss') ]
|
||||
|
||||
|
@ -25,15 +25,15 @@ class Fudzilla(BasicNewsRecipe):
|
||||
remove_tags_before = dict(name='div', attrs={'class':['padding']})
|
||||
|
||||
remove_tags = [dict(name='td', attrs={'class':['left','right']}),
|
||||
dict(name='div', attrs={'id':['toolbar','buttons']}),
|
||||
dict(name='div', attrs={'class':['artbannersxtd','back_button']}),
|
||||
dict(name='span', attrs={'class':['pathway']}),
|
||||
dict(name='th', attrs={'class':['pagenav_next','pagenav_prev']}),
|
||||
dict(name='table', attrs={'class':['headlines']}),
|
||||
dict(name='div', attrs={'id':['toolbar','buttons']}),
|
||||
dict(name='div', attrs={'class':['artbannersxtd','back_button']}),
|
||||
dict(name='span', attrs={'class':['pathway']}),
|
||||
dict(name='th', attrs={'class':['pagenav_next','pagenav_prev']}),
|
||||
dict(name='table', attrs={'class':['headlines']}),
|
||||
]
|
||||
|
||||
feeds = [
|
||||
(u'Posts', u'http://www.fudzilla.com/index.php?option=com_rss&feed=RSS2.0&no_html=1')
|
||||
(u'Posts', u'http://www.fudzilla.com/?format=feed')
|
||||
]
|
||||
|
||||
preprocess_regexps = [
|
||||
|
@ -38,6 +38,7 @@ class LaJornada_mx(BasicNewsRecipe):
|
||||
.loc{font-weight: bold}
|
||||
.carton{text-align: center}
|
||||
.credit{font-weight: bold}
|
||||
.sumario{font-weight: bold; text-align: center}
|
||||
.text{margin-top: 1.4em}
|
||||
p.inicial{display: inline; font-size: xx-large; font-weight: bold}
|
||||
p.s-s{display: inline; text-indent: 0}
|
||||
@ -53,7 +54,10 @@ class LaJornada_mx(BasicNewsRecipe):
|
||||
preprocess_regexps = [
|
||||
(re.compile( r'<div class="inicial">(.*)</div><p class="s-s">'
|
||||
,re.DOTALL|re.IGNORECASE)
|
||||
,lambda match: '<p class="inicial">' + match.group(1) + '</p><p class="s-s">')
|
||||
,lambda match: '<p class="inicial">' + match.group(1) + '</p><p class="s-s">'),
|
||||
(re.compile( r'<q>(.*?)</q>'
|
||||
,re.DOTALL|re.IGNORECASE)
|
||||
,lambda match: '"' + match.group(1) + '"')
|
||||
]
|
||||
|
||||
keep_only_tags = [
|
||||
|
@ -5,65 +5,61 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
'''
|
||||
nytimes.com
|
||||
'''
|
||||
import re
|
||||
import time
|
||||
from calibre import entity_to_unicode
|
||||
import re, string, time
|
||||
from calibre import entity_to_unicode, strftime
|
||||
from calibre.web.feeds.recipes import BasicNewsRecipe
|
||||
from calibre.ebooks.BeautifulSoup import BeautifulSoup, Tag, NavigableString, \
|
||||
Comment, BeautifulStoneSoup
|
||||
from calibre.ebooks.BeautifulSoup import BeautifulSoup, Tag, BeautifulStoneSoup
|
||||
|
||||
class NYTimes(BasicNewsRecipe):
|
||||
|
||||
title = 'New York Times Top Stories'
|
||||
__author__ = 'GRiker'
|
||||
language = 'en'
|
||||
requires_version = (0, 7, 5)
|
||||
description = 'Top Stories from the New York Times'
|
||||
# set headlinesOnly to True for the headlines-only version
|
||||
headlinesOnly = True
|
||||
|
||||
# List of sections typically included in Top Stories. Use a keyword from the
|
||||
# right column in the excludeSectionKeywords[] list to skip downloading that section
|
||||
sections = {
|
||||
'arts' : 'Arts',
|
||||
'business' : 'Business',
|
||||
'diningwine' : 'Dining & Wine',
|
||||
'editorials' : 'Editorials',
|
||||
'health' : 'Health',
|
||||
'magazine' : 'Magazine',
|
||||
'mediaadvertising' : 'Media & Advertising',
|
||||
'newyorkregion' : 'New York/Region',
|
||||
'oped' : 'Op-Ed',
|
||||
'politics' : 'Politics',
|
||||
'science' : 'Science',
|
||||
'sports' : 'Sports',
|
||||
'technology' : 'Technology',
|
||||
'topstories' : 'Top Stories',
|
||||
'travel' : 'Travel',
|
||||
'us' : 'U.S.',
|
||||
'world' : 'World'
|
||||
}
|
||||
# includeSections: List of sections to include. If empty, all sections found will be included.
|
||||
# Otherwise, only the sections named will be included. For example,
|
||||
#
|
||||
# includeSections = ['Politics','Sports']
|
||||
#
|
||||
# would cause only the Politics and Sports sections to be included.
|
||||
|
||||
# Add section keywords from the right column above to skip that section
|
||||
# For example, to skip sections containing the word 'Sports' or 'Dining', use:
|
||||
# excludeSectionKeywords = ['Sports', 'Dining']
|
||||
# Fetch only Business and Technology
|
||||
# excludeSectionKeywords = ['Arts','Dining','Editorials','Health','Magazine','Media','Region','Op-Ed','Politics','Science','Sports','Top Stories','Travel','U.S.','World']
|
||||
# Fetch only Top Stories
|
||||
# excludeSectionKeywords = ['Arts','Business','Dining','Editorials','Health','Magazine','Media','Region','Op-Ed','Politics','Science','Sports','Technology','Travel','U.S.','World']
|
||||
# By default, no sections are skipped.
|
||||
excludeSectionKeywords = []
|
||||
includeSections = [] # by default, all sections included
|
||||
|
||||
# excludeSections: List of sections to exclude. If empty, all sections found will be included.
|
||||
# Otherwise, the sections named will be excluded. For example,
|
||||
#
|
||||
# excludeSections = ['Politics','Sports']
|
||||
#
|
||||
# would cause the Politics and Sports sections to be excluded. This parameter can be used
|
||||
# in conjuction with includeSections although in most cases using one or the other, but
|
||||
# not both, is sufficient.
|
||||
|
||||
excludeSections = []
|
||||
|
||||
# one_picture_per_article specifies that calibre should only use the first image
|
||||
# from an article (if one exists). If one_picture_per_article = True, the image
|
||||
# will be moved to a location between the headline and the byline.
|
||||
# If one_picture_per_article = False, all images from the article will be included
|
||||
|
||||
# and shown in their original location.
|
||||
one_picture_per_article = True
|
||||
|
||||
# The maximum number of articles that will be downloaded
|
||||
max_articles_per_feed = 40
|
||||
max_articles_per_feed = 100
|
||||
|
||||
|
||||
if headlinesOnly:
|
||||
title='New York Times Headlines'
|
||||
description = 'Headlines from the New York Times'
|
||||
else:
|
||||
title='New York Times'
|
||||
description = 'Today\'s New York Times'
|
||||
|
||||
__author__ = 'GRiker/Kovid Goyal/Nick Redding'
|
||||
language = 'en'
|
||||
requires_version = (0, 7, 5)
|
||||
|
||||
|
||||
timefmt = ''
|
||||
needs_subscription = True
|
||||
masthead_url = 'http://graphics8.nytimes.com/images/misc/nytlogo379x64.gif'
|
||||
cover_margins = (18,18,'grey99')
|
||||
|
||||
@ -82,6 +78,7 @@ class NYTimes(BasicNewsRecipe):
|
||||
'entry-response module',
|
||||
'icon enlargeThis',
|
||||
'leftNavTabs',
|
||||
'metaFootnote',
|
||||
'module box nav',
|
||||
'nextArticleLink',
|
||||
'nextArticleLink clearfix',
|
||||
@ -89,12 +86,13 @@ class NYTimes(BasicNewsRecipe):
|
||||
'relatedSearchesModule',
|
||||
'side_tool',
|
||||
'singleAd',
|
||||
'subNavigation clearfix',
|
||||
'subNavigation tabContent active',
|
||||
'subNavigation tabContent active clearfix',
|
||||
re.compile('^subNavigation'),
|
||||
re.compile('^leaderboard'),
|
||||
re.compile('^module'),
|
||||
]}),
|
||||
dict(id=[
|
||||
'adxLeaderboard',
|
||||
'adxSponLink',
|
||||
'archive',
|
||||
'articleExtras',
|
||||
'articleInline',
|
||||
@ -105,87 +103,98 @@ class NYTimes(BasicNewsRecipe):
|
||||
'footer',
|
||||
'header',
|
||||
'header_search',
|
||||
'inlineBox',
|
||||
'login',
|
||||
'masthead',
|
||||
'masthead-nav',
|
||||
'memberTools',
|
||||
'navigation',
|
||||
'portfolioInline',
|
||||
'readerReviews',
|
||||
'readerReviewsCount',
|
||||
'relatedArticles',
|
||||
'relatedTopics',
|
||||
'respond',
|
||||
'side_search',
|
||||
'side_index',
|
||||
'side_tool',
|
||||
'toolsRight',
|
||||
]),
|
||||
dict(name=['script', 'noscript', 'style'])]
|
||||
|
||||
dict(name=['script', 'noscript', 'style','form','hr'])]
|
||||
no_stylesheets = True
|
||||
extra_css = '.headline {text-align: left;}\n \
|
||||
.byline {font-family: monospace; \
|
||||
text-align: left; \
|
||||
margin-top: 0px; \
|
||||
margin-bottom: 0px;}\n \
|
||||
.dateline {font-size: small; \
|
||||
margin-top: 0px; \
|
||||
margin-bottom: 0px;}\n \
|
||||
.timestamp {font-size: small; \
|
||||
margin-top: 0px; \
|
||||
margin-bottom: 0px;}\n \
|
||||
.source {text-align: left;}\n \
|
||||
.image {text-align: center;}\n \
|
||||
.credit {text-align: right; \
|
||||
font-size: small; \
|
||||
margin-top: 0px; \
|
||||
margin-bottom: 0px;}\n \
|
||||
.articleBody {text-align: left;}\n \
|
||||
.authorId {text-align: left; \
|
||||
font-style: italic;}\n '
|
||||
extra_css = '''
|
||||
.articleHeadline { text-align: left; margin-top:0.5em; margin-bottom:0.25em; }
|
||||
.credit { text-align: right; font-size: small; line-height:1em; margin-top:5px; margin-left:0; margin-right:0; margin-bottom: 0; }
|
||||
.byline { text-align: left; font-size: small; line-height:1em; margin-top:10px; margin-left:0; margin-right:0; margin-bottom: 0; }
|
||||
.dateline { text-align: left; font-size: small; line-height:1em;margin-top:5px; margin-left:0; margin-right:0; margin-bottom: 0; }
|
||||
.kicker { font-size: small; line-height:1em;margin-top:5px; margin-left:0; margin-right:0; margin-bottom: 0; }
|
||||
.timestamp { text-align: left; font-size: small; }
|
||||
.caption { font-size: small; font-style:italic; line-height:1em; margin-top:5px; margin-left:0; margin-right:0; margin-bottom: 0; }
|
||||
a:link {text-decoration: none; }
|
||||
.articleBody { }
|
||||
.authorId {text-align: left; }
|
||||
.image {text-align: center;}
|
||||
.source {text-align: left; }'''
|
||||
|
||||
def dump_ans(self, ans) :
|
||||
def filter_ans(self, ans) :
|
||||
total_article_count = 0
|
||||
for section in ans :
|
||||
idx = 0
|
||||
idx_max = len(ans)-1
|
||||
while idx <= idx_max:
|
||||
if self.includeSections != []:
|
||||
if ans[idx][0] not in self.includeSections:
|
||||
print "SECTION NOT INCLUDED: ",ans[idx][0]
|
||||
del ans[idx]
|
||||
idx_max = idx_max-1
|
||||
continue
|
||||
if ans[idx][0] in self.excludeSections:
|
||||
print "SECTION EXCLUDED: ",ans[idx][0]
|
||||
del ans[idx]
|
||||
idx_max = idx_max-1
|
||||
continue
|
||||
if self.verbose:
|
||||
self.log("section %s: %d articles" % (section[0], len(section[1])) )
|
||||
for article in section[1]:
|
||||
self.log("Section %s: %d articles" % (ans[idx][0], len(ans[idx][1])) )
|
||||
for article in ans[idx][1]:
|
||||
total_article_count += 1
|
||||
if self.verbose:
|
||||
self.log("\t%-40.40s... \t%-60.60s..." % (article['title'].encode('cp1252','replace'),
|
||||
article['url'].encode('cp1252','replace')))
|
||||
idx = idx+1
|
||||
|
||||
self.log( "Queued %d articles" % total_article_count )
|
||||
return ans
|
||||
|
||||
def fixChars(self,string):
|
||||
# Replace lsquo (\x91)
|
||||
fixed = re.sub("\x91","‘",string)
|
||||
fixed = re.sub("\x91","‘",string)
|
||||
|
||||
# Replace rsquo (\x92)
|
||||
fixed = re.sub("\x92","’",fixed)
|
||||
fixed = re.sub("\x92","’",fixed)
|
||||
|
||||
# Replace ldquo (\x93)
|
||||
fixed = re.sub("\x93","“",fixed)
|
||||
fixed = re.sub("\x93","“",fixed)
|
||||
|
||||
# Replace rdquo (\x94)
|
||||
fixed = re.sub("\x94","”",fixed)
|
||||
fixed = re.sub("\x94","”",fixed)
|
||||
|
||||
# Replace ndash (\x96)
|
||||
fixed = re.sub("\x96","–",fixed)
|
||||
fixed = re.sub("\x96","–",fixed)
|
||||
|
||||
# Replace mdash (\x97)
|
||||
fixed = re.sub("\x97","—",fixed)
|
||||
fixed = re.sub("\x97","—",fixed)
|
||||
|
||||
return fixed
|
||||
|
||||
def get_browser(self):
|
||||
br = BasicNewsRecipe.get_browser()
|
||||
if self.username is not None and self.password is not None:
|
||||
try:
|
||||
br.open('http://www.nytimes.com/auth/login')
|
||||
br.select_form(name='login')
|
||||
br['USERID'] = self.username
|
||||
br['PASSWORD'] = self.password
|
||||
br.submit()
|
||||
except:
|
||||
self.log("\nFailed to login")
|
||||
br.open('http://www.nytimes.com/auth/login')
|
||||
br.select_form(name='login')
|
||||
br['USERID'] = self.username
|
||||
br['PASSWORD'] = self.password
|
||||
raw = br.submit().read()
|
||||
if 'Please try again' in raw:
|
||||
raise Exception('Your username and password are incorrect')
|
||||
return br
|
||||
|
||||
def skip_ad_pages(self, soup):
|
||||
@ -213,6 +222,9 @@ class NYTimes(BasicNewsRecipe):
|
||||
cover = None
|
||||
return cover
|
||||
|
||||
def short_title(self):
|
||||
return self.title
|
||||
|
||||
def index_to_soup(self, url_or_raw, raw=False):
|
||||
'''
|
||||
OVERRIDE of class method
|
||||
@ -255,157 +267,184 @@ class NYTimes(BasicNewsRecipe):
|
||||
# Kindle TOC descriptions won't render certain characters
|
||||
if description:
|
||||
massaged = unicode(BeautifulStoneSoup(description, convertEntities=BeautifulStoneSoup.HTML_ENTITIES))
|
||||
# Replace '&' with '&'
|
||||
massaged = re.sub("&","&", massaged)
|
||||
# Replace '&' with '&'
|
||||
massaged = re.sub("&","&", massaged)
|
||||
return self.fixChars(massaged)
|
||||
else:
|
||||
return description
|
||||
|
||||
def parse_index(self):
|
||||
def parse_todays_index(self):
|
||||
|
||||
def feed_title(div):
|
||||
return ''.join(div.findAll(text=True, recursive=True)).strip()
|
||||
|
||||
articles = {}
|
||||
key = None
|
||||
ans = []
|
||||
url_list = []
|
||||
|
||||
def handle_article(div):
|
||||
a = div.find('a', href=True)
|
||||
if not a:
|
||||
return
|
||||
url = re.sub(r'\?.*', '', a['href'])
|
||||
if not url.startswith("http"):
|
||||
return
|
||||
if not url.endswith(".html"):
|
||||
return
|
||||
if 'podcast' in url:
|
||||
return
|
||||
if '/video/' in url:
|
||||
return
|
||||
url += '?pagewanted=all'
|
||||
if url in url_list:
|
||||
return
|
||||
url_list.append(url)
|
||||
title = self.tag_to_string(a, use_alt=True).strip()
|
||||
description = ''
|
||||
pubdate = strftime('%a, %d %b')
|
||||
summary = div.find(True, attrs={'class':'summary'})
|
||||
if summary:
|
||||
description = self.tag_to_string(summary, use_alt=False)
|
||||
author = ''
|
||||
authorAttribution = div.find(True, attrs={'class':'byline'})
|
||||
if authorAttribution:
|
||||
author = self.tag_to_string(authorAttribution, use_alt=False)
|
||||
else:
|
||||
authorAttribution = div.find(True, attrs={'class':'byline'})
|
||||
if authorAttribution:
|
||||
author = self.tag_to_string(authorAttribution, use_alt=False)
|
||||
feed = key if key is not None else 'Uncategorized'
|
||||
if not articles.has_key(feed):
|
||||
ans.append(feed)
|
||||
articles[feed] = []
|
||||
articles[feed].append(
|
||||
dict(title=title, url=url, date=pubdate,
|
||||
description=description, author=author,
|
||||
content=''))
|
||||
|
||||
|
||||
soup = self.index_to_soup('http://www.nytimes.com/pages/todayspaper/index.html')
|
||||
|
||||
|
||||
# Find each article
|
||||
for div in soup.findAll(True,
|
||||
attrs={'class':['section-headline', 'story', 'story headline','sectionHeader','headlinesOnly multiline flush']}):
|
||||
|
||||
if div['class'] in ['section-headline','sectionHeader']:
|
||||
key = string.capwords(feed_title(div))
|
||||
key = key.replace('Op-ed','Op-Ed')
|
||||
key = key.replace('U.s.','U.S.')
|
||||
elif div['class'] in ['story', 'story headline'] :
|
||||
handle_article(div)
|
||||
elif div['class'] == 'headlinesOnly multiline flush':
|
||||
for lidiv in div.findAll('li'):
|
||||
handle_article(lidiv)
|
||||
|
||||
ans = [(key, articles[key]) for key in ans if articles.has_key(key)]
|
||||
return self.filter_ans(ans)
|
||||
|
||||
def parse_headline_index(self):
|
||||
|
||||
articles = {}
|
||||
ans = []
|
||||
|
||||
feed = key = 'All Top Stories'
|
||||
articles[key] = []
|
||||
ans.append(key)
|
||||
self.log("Scanning 1 section ...")
|
||||
url_list = []
|
||||
|
||||
soup = self.index_to_soup('http://www.nytimes.com/pages/todaysheadlines/')
|
||||
|
||||
# Fetch the outer table
|
||||
table = soup.find('table')
|
||||
previousTable = table
|
||||
# Fetch the content table
|
||||
content_table = soup.find('table',{'id':'content'})
|
||||
if content_table is None:
|
||||
self.log("FATAL ERROR: CANNOT FIND CONTENT TABLE")
|
||||
return None
|
||||
|
||||
# Find the deepest table containing the stories
|
||||
while True :
|
||||
table = table.find('table')
|
||||
if table.find(text=re.compile('top stories start')) :
|
||||
previousTable = table
|
||||
continue
|
||||
else :
|
||||
table = previousTable
|
||||
break
|
||||
# Within this table are <td id=".*Column.*"> entries, each containing one or more h6 tags which represent sections
|
||||
|
||||
# There are multiple subtables, find the one containing the stories
|
||||
for block in table.findAll('table') :
|
||||
if block.find(text=re.compile('top stories start')) :
|
||||
table = block
|
||||
break
|
||||
else :
|
||||
continue
|
||||
for td_col in content_table.findAll('td', {'id' : re.compile('Column')}):
|
||||
for div_sec in td_col.findAll('div',recursive=False):
|
||||
for h6_sec_name in div_sec.findAll('h6',{'style' : re.compile('text-transform: *uppercase')}):
|
||||
section_name = self.tag_to_string(h6_sec_name,use_alt=False)
|
||||
section_name = re.sub(r'^ *$','',section_name)
|
||||
if section_name == '':
|
||||
continue
|
||||
section_name=string.capwords(section_name)
|
||||
if section_name == 'U.s.':
|
||||
section_name = 'U.S.'
|
||||
elif section_name == 'Op-ed':
|
||||
section_name = 'Op-Ed'
|
||||
pubdate = strftime('%a, %d %b')
|
||||
|
||||
# Again there are multiple subtables, find the one containing the stories
|
||||
for storyblock in table.findAll('table') :
|
||||
if storyblock.find(text=re.compile('top stories start')) :
|
||||
break
|
||||
else :
|
||||
continue
|
||||
|
||||
skipThisSection = False
|
||||
todays_article_count = 0
|
||||
# Within this table are <font face="times new roman, times, san serif"> entries
|
||||
self.log("Fetching feed Top Stories")
|
||||
for tr in storyblock.findAllNext('tr'):
|
||||
if tr.find('span') is not None :
|
||||
|
||||
sectionblock = tr.find(True, attrs={'face':['times new roman, times,sans serif',
|
||||
'times new roman,times, sans serif',
|
||||
'times new roman, times, sans serif']})
|
||||
section = None
|
||||
bylines = []
|
||||
descriptions = []
|
||||
pubdate = None
|
||||
|
||||
# Get the Section title
|
||||
for (x,i) in enumerate(sectionblock.contents) :
|
||||
skipThisSection = False
|
||||
# Extract the section title
|
||||
if ('Comment' in str(i.__class__)) :
|
||||
if 'start(name=' in i :
|
||||
section = i[i.find('=')+1:-2]
|
||||
|
||||
if not self.sections.has_key(section) :
|
||||
skipThisSection = True
|
||||
search_div = div_sec
|
||||
for next_tag in h6_sec_name.findNextSiblings(True):
|
||||
if next_tag.__class__.__name__ == 'Tag':
|
||||
if next_tag.name == 'div':
|
||||
search_div = next_tag
|
||||
break
|
||||
|
||||
# Check for excluded section
|
||||
if len(self.excludeSectionKeywords):
|
||||
key = self.sections[section]
|
||||
excluded = re.compile('|'.join(self.excludeSectionKeywords))
|
||||
if excluded.search(key) or articles.has_key(key):
|
||||
skipThisSection = True
|
||||
break
|
||||
|
||||
# Get the bylines and descriptions
|
||||
if not skipThisSection :
|
||||
lines = sectionblock.contents
|
||||
contentStrings = []
|
||||
|
||||
for line in lines:
|
||||
if not isinstance(line, Comment) and line.strip and line.strip() > "":
|
||||
contentStrings.append(line.strip())
|
||||
|
||||
# Gather the byline/description pairs
|
||||
bylines = []
|
||||
descriptions = []
|
||||
for contentString in contentStrings:
|
||||
if contentString[0:3] == 'By ' and contentString[3].isupper() :
|
||||
bylines.append(contentString)
|
||||
# Get the articles
|
||||
for h3_item in search_div.findAll('h3'):
|
||||
byline = h3_item.h6
|
||||
if byline is not None:
|
||||
author = self.tag_to_string(byline,usa_alt=False)
|
||||
else:
|
||||
descriptions.append(contentString)
|
||||
|
||||
# Fetch the article titles and URLs
|
||||
articleCount = len(sectionblock.findAll('span'))
|
||||
todays_article_count += articleCount
|
||||
for (i,span) in enumerate(sectionblock.findAll(attrs={'class':'headlineWrapper'})) :
|
||||
a = span.find('a', href=True)
|
||||
author = ''
|
||||
a = h3_item.find('a', href=True)
|
||||
if not a:
|
||||
continue
|
||||
url = re.sub(r'\?.*', '', a['href'])
|
||||
if not url.startswith("http"):
|
||||
continue
|
||||
if not url.endswith(".html"):
|
||||
continue
|
||||
if 'podcast' in url:
|
||||
continue
|
||||
if 'video' in url:
|
||||
continue
|
||||
url += '?pagewanted=all'
|
||||
if url in url_list:
|
||||
continue
|
||||
url_list.append(url)
|
||||
self.log("URL %s" % url)
|
||||
title = self.tag_to_string(a, use_alt=True).strip()
|
||||
desc = h3_item.find('p')
|
||||
if desc is not None:
|
||||
description = self.tag_to_string(desc,use_alt=False)
|
||||
else:
|
||||
description = ''
|
||||
if not articles.has_key(section_name):
|
||||
ans.append(section_name)
|
||||
articles[section_name] = []
|
||||
articles[section_name].append(dict(title=title, url=url, date=pubdate, description=description, author=author, content=''))
|
||||
|
||||
title = self.tag_to_string(a, use_alt=True)
|
||||
# prepend the section name
|
||||
title = self.sections[section] + " · " + title
|
||||
|
||||
if not isinstance(title, unicode):
|
||||
title = title.decode('utf-8', 'replace')
|
||||
|
||||
# Allow for unattributed, undescribed entries "Editor's Note"
|
||||
if i >= len(descriptions) :
|
||||
description = None
|
||||
else :
|
||||
description = descriptions[i]
|
||||
|
||||
if len(bylines) == articleCount :
|
||||
author = bylines[i]
|
||||
else :
|
||||
author = None
|
||||
|
||||
# Check for duplicates
|
||||
duplicateFound = False
|
||||
if len(articles[feed]) > 1:
|
||||
for article in articles[feed] :
|
||||
if url == article['url'] :
|
||||
duplicateFound = True
|
||||
break
|
||||
|
||||
if duplicateFound:
|
||||
# Continue fetching, don't add this article
|
||||
todays_article_count -= 1
|
||||
continue
|
||||
|
||||
if not articles.has_key(feed):
|
||||
articles[feed] = []
|
||||
articles[feed].append(
|
||||
dict(title=title, url=url, date=pubdate,
|
||||
description=description, author=author, content=''))
|
||||
# self.log("Queuing %d articles from %s" % (todays_article_count, "Top Stories"))
|
||||
|
||||
ans = self.sort_index_by(ans, {'Top Stories':-1})
|
||||
ans = [(key, articles[key]) for key in ans if articles.has_key(key)]
|
||||
self.dump_ans(ans)
|
||||
return ans
|
||||
return self.filter_ans(ans)
|
||||
|
||||
def parse_index(self):
|
||||
if self.headlinesOnly:
|
||||
return self.parse_headline_index()
|
||||
else:
|
||||
return self.parse_todays_index()
|
||||
|
||||
def strip_anchors(self,soup):
|
||||
paras = soup.findAll(True)
|
||||
for para in paras:
|
||||
aTags = para.findAll('a')
|
||||
for a in aTags:
|
||||
if a.img is None:
|
||||
a.replaceWith(a.renderContents().decode('cp1252','replace'))
|
||||
return soup
|
||||
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
|
||||
kicker_tag = soup.find(attrs={'class':'kicker'})
|
||||
if kicker_tag: # remove Op_Ed author head shots
|
||||
tagline = self.tag_to_string(kicker_tag)
|
||||
if tagline=='Op-Ed Columnist':
|
||||
img_div = soup.find('div','inlineImage module')
|
||||
if img_div:
|
||||
img_div.extract()
|
||||
return self.strip_anchors(soup)
|
||||
|
||||
def postprocess_html(self,soup, True):
|
||||
@ -422,8 +461,9 @@ class NYTimes(BasicNewsRecipe):
|
||||
firstImg = inlineImgs[0]
|
||||
for inlineImg in inlineImgs[1:]:
|
||||
inlineImg.extract()
|
||||
# Move firstImg after headline
|
||||
cgFirst = soup.find(True, {'class':'columnGroup first'})
|
||||
# Move firstImg before article body
|
||||
#article_body = soup.find(True, {'id':'articleBody'})
|
||||
cgFirst = soup.find(True, {'class':re.compile('columnGroup *first')})
|
||||
if cgFirst:
|
||||
# Strip all sibling NavigableStrings: noise
|
||||
navstrings = cgFirst.findAll(text=True, recursive=False)
|
||||
@ -443,30 +483,18 @@ class NYTimes(BasicNewsRecipe):
|
||||
if headline_found:
|
||||
cgFirst.insert(insertLoc,firstImg)
|
||||
else:
|
||||
self.log(">>> No class:'columnGroup first' found <<<")
|
||||
# Change class="kicker" to <h3>
|
||||
kicker = soup.find(True, {'class':'kicker'})
|
||||
if kicker and kicker.contents[0]:
|
||||
h3Tag = Tag(soup, "h3")
|
||||
h3Tag.insert(0, self.fixChars(self.tag_to_string(kicker,
|
||||
use_alt=False)))
|
||||
kicker.replaceWith(h3Tag)
|
||||
self.log(">>> No class:'columnGroup first' found <<<")
|
||||
|
||||
# Change captions to italic -1
|
||||
# Change captions to italic
|
||||
for caption in soup.findAll(True, {'class':'caption'}) :
|
||||
if caption and caption.contents[0]:
|
||||
emTag = Tag(soup, "em")
|
||||
cTag = Tag(soup, "p", [("class", "caption")])
|
||||
c = self.fixChars(self.tag_to_string(caption,use_alt=False)).strip()
|
||||
mp_off = c.find("More Photos")
|
||||
if mp_off >= 0:
|
||||
c = c[:mp_off]
|
||||
emTag.insert(0, c)
|
||||
#hrTag = Tag(soup, 'hr')
|
||||
#hrTag['class'] = 'caption_divider'
|
||||
hrTag = Tag(soup, 'div')
|
||||
hrTag['class'] = 'divider'
|
||||
emTag.insert(1, hrTag)
|
||||
caption.replaceWith(emTag)
|
||||
cTag.insert(0, c)
|
||||
caption.replaceWith(cTag)
|
||||
|
||||
# Change <nyt_headline> to <h2>
|
||||
h1 = soup.find('h1')
|
||||
@ -506,17 +534,6 @@ class NYTimes(BasicNewsRecipe):
|
||||
bTag.insert(0, subhead.contents[0])
|
||||
subhead.replaceWith(bTag)
|
||||
|
||||
# Synthesize a section header
|
||||
dsk = soup.find('meta', attrs={'name':'dsk'})
|
||||
if dsk and dsk.has_key('content'):
|
||||
hTag = Tag(soup,'h3')
|
||||
hTag['class'] = 'section'
|
||||
hTag.insert(0,NavigableString(dsk['content']))
|
||||
articleTag = soup.find(True, attrs={'id':'article'})
|
||||
if articleTag:
|
||||
articleTag.insert(0,hTag)
|
||||
|
||||
# Add class="articleBody" to <div> so we can format with CSS
|
||||
divTag = soup.find('div',attrs={'id':'articleBody'})
|
||||
if divTag:
|
||||
divTag['class'] = divTag['id']
|
||||
@ -532,11 +549,3 @@ class NYTimes(BasicNewsRecipe):
|
||||
|
||||
return soup
|
||||
|
||||
def strip_anchors(self,soup):
|
||||
paras = soup.findAll(True)
|
||||
for para in paras:
|
||||
aTags = para.findAll('a')
|
||||
for a in aTags:
|
||||
if a.img is None:
|
||||
a.replaceWith(a.renderContents().decode('cp1252','replace'))
|
||||
return soup
|
||||
|
@ -5,52 +5,186 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
'''
|
||||
nytimes.com
|
||||
'''
|
||||
import string, re, time
|
||||
from calibre import strftime
|
||||
import re, string, time
|
||||
from calibre import entity_to_unicode, strftime
|
||||
from calibre.web.feeds.recipes import BasicNewsRecipe
|
||||
from calibre.ebooks.BeautifulSoup import BeautifulSoup
|
||||
|
||||
def decode(self, src):
|
||||
enc = 'utf-8'
|
||||
if 'iso-8859-1' in src:
|
||||
enc = 'cp1252'
|
||||
return src.decode(enc, 'ignore')
|
||||
from calibre.ebooks.BeautifulSoup import BeautifulSoup, Tag, BeautifulStoneSoup
|
||||
|
||||
class NYTimes(BasicNewsRecipe):
|
||||
|
||||
title = u'New York Times'
|
||||
__author__ = 'Kovid Goyal/Nick Redding'
|
||||
language = 'en'
|
||||
requires_version = (0, 6, 36)
|
||||
# set headlinesOnly to True for the headlines-only version
|
||||
headlinesOnly = False
|
||||
|
||||
description = 'Daily news from the New York Times (subscription version)'
|
||||
timefmt = ' [%b %d]'
|
||||
# includeSections: List of sections to include. If empty, all sections found will be included.
|
||||
# Otherwise, only the sections named will be included. For example,
|
||||
#
|
||||
# includeSections = ['Politics','Sports']
|
||||
#
|
||||
# would cause only the Politics and Sports sections to be included.
|
||||
|
||||
includeSections = [] # by default, all sections included
|
||||
|
||||
# excludeSections: List of sections to exclude. If empty, all sections found will be included.
|
||||
# Otherwise, the sections named will be excluded. For example,
|
||||
#
|
||||
# excludeSections = ['Politics','Sports']
|
||||
#
|
||||
# would cause the Politics and Sports sections to be excluded. This parameter can be used
|
||||
# in conjuction with includeSections although in most cases using one or the other, but
|
||||
# not both, is sufficient.
|
||||
|
||||
excludeSections = []
|
||||
|
||||
# one_picture_per_article specifies that calibre should only use the first image
|
||||
# from an article (if one exists). If one_picture_per_article = True, the image
|
||||
# will be moved to a location between the headline and the byline.
|
||||
# If one_picture_per_article = False, all images from the article will be included
|
||||
|
||||
# and shown in their original location.
|
||||
one_picture_per_article = True
|
||||
|
||||
# The maximum number of articles that will be downloaded
|
||||
max_articles_per_feed = 100
|
||||
|
||||
|
||||
if headlinesOnly:
|
||||
title='New York Times Headlines'
|
||||
description = 'Headlines from the New York Times'
|
||||
else:
|
||||
title='New York Times'
|
||||
description = 'Today\'s New York Times'
|
||||
|
||||
__author__ = 'GRiker/Kovid Goyal/Nick Redding'
|
||||
language = 'en'
|
||||
requires_version = (0, 7, 5)
|
||||
|
||||
|
||||
timefmt = ''
|
||||
needs_subscription = True
|
||||
masthead_url = 'http://graphics8.nytimes.com/images/misc/nytlogo379x64.gif'
|
||||
cover_margins = (18,18,'grey99')
|
||||
|
||||
remove_tags_before = dict(id='article')
|
||||
remove_tags_after = dict(id='article')
|
||||
remove_tags = [dict(attrs={'class':['articleTools', 'post-tools', 'side_tool','nextArticleLink',
|
||||
'nextArticleLink clearfix','columnGroup doubleRule','doubleRule','entry-meta',
|
||||
'icon enlargeThis','columnGroup last','relatedSearchesModule']}),
|
||||
dict({'class':re.compile('^subNavigation')}),
|
||||
dict({'class':re.compile('^leaderboard')}),
|
||||
dict({'class':re.compile('^module')}),
|
||||
dict({'class':'metaFootnote'}),
|
||||
dict(id=['inlineBox','footer', 'toolsRight', 'articleInline','login','masthead',
|
||||
'navigation', 'archive', 'side_search', 'blog_sidebar','cCol','portfolioInline',
|
||||
'side_tool', 'side_index','header','readerReviewsCount','readerReviews',
|
||||
'relatedArticles', 'relatedTopics', 'adxSponLink']),
|
||||
remove_tags = [dict(attrs={'class':[
|
||||
'articleFooter',
|
||||
'articleTools',
|
||||
'columnGroup doubleRule',
|
||||
'columnGroup singleRule',
|
||||
'columnGroup last',
|
||||
'columnGroup last',
|
||||
'doubleRule',
|
||||
'dottedLine',
|
||||
'entry-meta',
|
||||
'entry-response module',
|
||||
'icon enlargeThis',
|
||||
'leftNavTabs',
|
||||
'metaFootnote',
|
||||
'module box nav',
|
||||
'nextArticleLink',
|
||||
'nextArticleLink clearfix',
|
||||
'post-tools',
|
||||
'relatedSearchesModule',
|
||||
'side_tool',
|
||||
'singleAd',
|
||||
re.compile('^subNavigation'),
|
||||
re.compile('^leaderboard'),
|
||||
re.compile('^module'),
|
||||
]}),
|
||||
dict(id=[
|
||||
'adxLeaderboard',
|
||||
'adxSponLink',
|
||||
'archive',
|
||||
'articleExtras',
|
||||
'articleInline',
|
||||
'blog_sidebar',
|
||||
'businessSearchBar',
|
||||
'cCol',
|
||||
'entertainmentSearchBar',
|
||||
'footer',
|
||||
'header',
|
||||
'header_search',
|
||||
'inlineBox',
|
||||
'login',
|
||||
'masthead',
|
||||
'masthead-nav',
|
||||
'memberTools',
|
||||
'navigation',
|
||||
'portfolioInline',
|
||||
'readerReviews',
|
||||
'readerReviewsCount',
|
||||
'relatedArticles',
|
||||
'relatedTopics',
|
||||
'respond',
|
||||
'side_search',
|
||||
'side_index',
|
||||
'side_tool',
|
||||
'toolsRight',
|
||||
]),
|
||||
dict(name=['script', 'noscript', 'style','form','hr'])]
|
||||
encoding = decode
|
||||
no_stylesheets = True
|
||||
extra_css = '''
|
||||
.articleHeadline { margin-top:0.5em; margin-bottom:0.25em; }
|
||||
.credit { font-size: small; font-style:italic; line-height:1em; margin-top:5px; margin-left:0; margin-right:0; margin-bottom: 0; }
|
||||
.byline { font-size: small; font-style:italic; line-height:1em; margin-top:10px; margin-left:0; margin-right:0; margin-bottom: 0; }
|
||||
.dateline { font-size: small; line-height:1em;margin-top:5px; margin-left:0; margin-right:0; margin-bottom: 0; }
|
||||
.articleHeadline { text-align: left; margin-top:0.5em; margin-bottom:0.25em; }
|
||||
.credit { text-align: right; font-size: small; line-height:1em; margin-top:5px; margin-left:0; margin-right:0; margin-bottom: 0; }
|
||||
.byline { text-align: left; font-size: small; line-height:1em; margin-top:10px; margin-left:0; margin-right:0; margin-bottom: 0; }
|
||||
.dateline { text-align: left; font-size: small; line-height:1em;margin-top:5px; margin-left:0; margin-right:0; margin-bottom: 0; }
|
||||
.kicker { font-size: small; line-height:1em;margin-top:5px; margin-left:0; margin-right:0; margin-bottom: 0; }
|
||||
.timestamp { font-size: small; }
|
||||
.caption { font-size: small; line-height:1em; margin-top:5px; margin-left:0; margin-right:0; margin-bottom: 0; }
|
||||
a:link {text-decoration: none; }'''
|
||||
.timestamp { text-align: left; font-size: small; }
|
||||
.caption { font-size: small; font-style:italic; line-height:1em; margin-top:5px; margin-left:0; margin-right:0; margin-bottom: 0; }
|
||||
a:link {text-decoration: none; }
|
||||
.articleBody { }
|
||||
.authorId {text-align: left; }
|
||||
.image {text-align: center;}
|
||||
.source {text-align: left; }'''
|
||||
|
||||
def filter_ans(self, ans) :
|
||||
total_article_count = 0
|
||||
idx = 0
|
||||
idx_max = len(ans)-1
|
||||
while idx <= idx_max:
|
||||
if self.includeSections != []:
|
||||
if ans[idx][0] not in self.includeSections:
|
||||
print "SECTION NOT INCLUDED: ",ans[idx][0]
|
||||
del ans[idx]
|
||||
idx_max = idx_max-1
|
||||
continue
|
||||
if ans[idx][0] in self.excludeSections:
|
||||
print "SECTION EXCLUDED: ",ans[idx][0]
|
||||
del ans[idx]
|
||||
idx_max = idx_max-1
|
||||
continue
|
||||
if self.verbose:
|
||||
self.log("Section %s: %d articles" % (ans[idx][0], len(ans[idx][1])) )
|
||||
for article in ans[idx][1]:
|
||||
total_article_count += 1
|
||||
if self.verbose:
|
||||
self.log("\t%-40.40s... \t%-60.60s..." % (article['title'].encode('cp1252','replace'),
|
||||
article['url'].encode('cp1252','replace')))
|
||||
idx = idx+1
|
||||
|
||||
self.log( "Queued %d articles" % total_article_count )
|
||||
return ans
|
||||
|
||||
def fixChars(self,string):
|
||||
# Replace lsquo (\x91)
|
||||
fixed = re.sub("\x91","‘",string)
|
||||
|
||||
# Replace rsquo (\x92)
|
||||
fixed = re.sub("\x92","’",fixed)
|
||||
|
||||
# Replace ldquo (\x93)
|
||||
fixed = re.sub("\x93","“",fixed)
|
||||
|
||||
# Replace rdquo (\x94)
|
||||
fixed = re.sub("\x94","”",fixed)
|
||||
|
||||
# Replace ndash (\x96)
|
||||
fixed = re.sub("\x96","–",fixed)
|
||||
|
||||
# Replace mdash (\x97)
|
||||
fixed = re.sub("\x97","—",fixed)
|
||||
|
||||
return fixed
|
||||
|
||||
def get_browser(self):
|
||||
br = BasicNewsRecipe.get_browser()
|
||||
@ -60,22 +194,19 @@ class NYTimes(BasicNewsRecipe):
|
||||
br['USERID'] = self.username
|
||||
br['PASSWORD'] = self.password
|
||||
raw = br.submit().read()
|
||||
if 'Sorry, we could not find the combination you entered. Please try again.' in raw:
|
||||
if 'Please try again' in raw:
|
||||
raise Exception('Your username and password are incorrect')
|
||||
#open('/t/log.html', 'wb').write(raw)
|
||||
return br
|
||||
|
||||
def get_masthead_url(self):
|
||||
masthead = 'http://graphics8.nytimes.com/images/misc/nytlogo379x64.gif'
|
||||
#masthead = 'http://members.cox.net/nickredding/nytlogo.gif'
|
||||
br = BasicNewsRecipe.get_browser()
|
||||
try:
|
||||
br.open(masthead)
|
||||
except:
|
||||
self.log("\nMasthead unavailable")
|
||||
masthead = None
|
||||
return masthead
|
||||
|
||||
def skip_ad_pages(self, soup):
|
||||
# Skip ad pages served before actual article
|
||||
skip_tag = soup.find(True, {'name':'skip'})
|
||||
if skip_tag is not None:
|
||||
self.log.warn("Found forwarding link: %s" % skip_tag.parent['href'])
|
||||
url = 'http://www.nytimes.com' + re.sub(r'\?.*', '', skip_tag.parent['href'])
|
||||
url += '?pagewanted=all'
|
||||
self.log.warn("Skipping ad to article at '%s'" % url)
|
||||
return self.index_to_soup(url, raw=True)
|
||||
|
||||
def get_cover_url(self):
|
||||
cover = None
|
||||
@ -93,12 +224,57 @@ class NYTimes(BasicNewsRecipe):
|
||||
return cover
|
||||
|
||||
def short_title(self):
|
||||
return 'New York Times'
|
||||
return self.title
|
||||
|
||||
def parse_index(self):
|
||||
self.encoding = 'cp1252'
|
||||
soup = self.index_to_soup('http://www.nytimes.com/pages/todayspaper/index.html')
|
||||
self.encoding = decode
|
||||
def index_to_soup(self, url_or_raw, raw=False):
|
||||
'''
|
||||
OVERRIDE of class method
|
||||
deals with various page encodings between index and articles
|
||||
'''
|
||||
def get_the_soup(docEncoding, url_or_raw, raw=False) :
|
||||
if re.match(r'\w+://', url_or_raw):
|
||||
f = self.browser.open(url_or_raw)
|
||||
_raw = f.read()
|
||||
f.close()
|
||||
if not _raw:
|
||||
raise RuntimeError('Could not fetch index from %s'%url_or_raw)
|
||||
else:
|
||||
_raw = url_or_raw
|
||||
if raw:
|
||||
return _raw
|
||||
|
||||
if not isinstance(_raw, unicode) and self.encoding:
|
||||
_raw = _raw.decode(docEncoding, 'replace')
|
||||
massage = list(BeautifulSoup.MARKUP_MASSAGE)
|
||||
massage.append((re.compile(r'&(\S+?);'), lambda match: entity_to_unicode(match, encoding=self.encoding)))
|
||||
return BeautifulSoup(_raw, markupMassage=massage)
|
||||
|
||||
# Entry point
|
||||
print "index_to_soup()"
|
||||
soup = get_the_soup( self.encoding, url_or_raw )
|
||||
contentType = soup.find(True,attrs={'http-equiv':'Content-Type'})
|
||||
docEncoding = str(contentType)[str(contentType).find('charset=') + len('charset='):str(contentType).rfind('"')]
|
||||
if docEncoding == '' :
|
||||
docEncoding = self.encoding
|
||||
|
||||
if self.verbose > 2:
|
||||
self.log( " document encoding: '%s'" % docEncoding)
|
||||
if docEncoding != self.encoding :
|
||||
soup = get_the_soup(docEncoding, url_or_raw)
|
||||
|
||||
return soup
|
||||
|
||||
def massageNCXText(self, description):
|
||||
# Kindle TOC descriptions won't render certain characters
|
||||
if description:
|
||||
massaged = unicode(BeautifulStoneSoup(description, convertEntities=BeautifulStoneSoup.HTML_ENTITIES))
|
||||
# Replace '&' with '&'
|
||||
massaged = re.sub("&","&", massaged)
|
||||
return self.fixChars(massaged)
|
||||
else:
|
||||
return description
|
||||
|
||||
def parse_todays_index(self):
|
||||
|
||||
def feed_title(div):
|
||||
return ''.join(div.findAll(text=True, recursive=True)).strip()
|
||||
@ -119,12 +295,13 @@ class NYTimes(BasicNewsRecipe):
|
||||
return
|
||||
if 'podcast' in url:
|
||||
return
|
||||
if '/video/' in url:
|
||||
return
|
||||
url += '?pagewanted=all'
|
||||
if url in url_list:
|
||||
return
|
||||
url_list.append(url)
|
||||
title = self.tag_to_string(a, use_alt=True).strip()
|
||||
#self.log("Title: %s" % title)
|
||||
description = ''
|
||||
pubdate = strftime('%a, %d %b')
|
||||
summary = div.find(True, attrs={'class':'summary'})
|
||||
@ -140,6 +317,7 @@ class NYTimes(BasicNewsRecipe):
|
||||
author = self.tag_to_string(authorAttribution, use_alt=False)
|
||||
feed = key if key is not None else 'Uncategorized'
|
||||
if not articles.has_key(feed):
|
||||
ans.append(feed)
|
||||
articles[feed] = []
|
||||
articles[feed].append(
|
||||
dict(title=title, url=url, date=pubdate,
|
||||
@ -147,46 +325,228 @@ class NYTimes(BasicNewsRecipe):
|
||||
content=''))
|
||||
|
||||
|
||||
soup = self.index_to_soup('http://www.nytimes.com/pages/todayspaper/index.html')
|
||||
|
||||
# Find each instance of class="section-headline", class="story", class="story headline"
|
||||
|
||||
# Find each article
|
||||
for div in soup.findAll(True,
|
||||
attrs={'class':['section-headline', 'story', 'story headline','sectionHeader','headlinesOnly multiline flush']}):
|
||||
|
||||
if div['class'] in ['section-headline','sectionHeader']:
|
||||
key = string.capwords(feed_title(div))
|
||||
articles[key] = []
|
||||
ans.append(key)
|
||||
#self.log('Section: %s' % key)
|
||||
|
||||
key = key.replace('Op-ed','Op-Ed')
|
||||
key = key.replace('U.s.','U.S.')
|
||||
elif div['class'] in ['story', 'story headline'] :
|
||||
handle_article(div)
|
||||
elif div['class'] == 'headlinesOnly multiline flush':
|
||||
for lidiv in div.findAll('li'):
|
||||
handle_article(lidiv)
|
||||
|
||||
# ans = self.sort_index_by(ans, {'The Front Page':-1,
|
||||
# 'Dining In, Dining Out':1,
|
||||
# 'Obituaries':2})
|
||||
ans = [(key, articles[key]) for key in ans if articles.has_key(key)]
|
||||
return self.filter_ans(ans)
|
||||
|
||||
def parse_headline_index(self):
|
||||
|
||||
articles = {}
|
||||
ans = []
|
||||
url_list = []
|
||||
|
||||
soup = self.index_to_soup('http://www.nytimes.com/pages/todaysheadlines/')
|
||||
|
||||
# Fetch the content table
|
||||
content_table = soup.find('table',{'id':'content'})
|
||||
if content_table is None:
|
||||
self.log("FATAL ERROR: CANNOT FIND CONTENT TABLE")
|
||||
return None
|
||||
|
||||
# Within this table are <td id=".*Column.*"> entries, each containing one or more h6 tags which represent sections
|
||||
|
||||
for td_col in content_table.findAll('td', {'id' : re.compile('Column')}):
|
||||
for div_sec in td_col.findAll('div',recursive=False):
|
||||
for h6_sec_name in div_sec.findAll('h6',{'style' : re.compile('text-transform: *uppercase')}):
|
||||
section_name = self.tag_to_string(h6_sec_name,use_alt=False)
|
||||
section_name = re.sub(r'^ *$','',section_name)
|
||||
if section_name == '':
|
||||
continue
|
||||
section_name=string.capwords(section_name)
|
||||
if section_name == 'U.s.':
|
||||
section_name = 'U.S.'
|
||||
elif section_name == 'Op-ed':
|
||||
section_name = 'Op-Ed'
|
||||
pubdate = strftime('%a, %d %b')
|
||||
|
||||
search_div = div_sec
|
||||
for next_tag in h6_sec_name.findNextSiblings(True):
|
||||
if next_tag.__class__.__name__ == 'Tag':
|
||||
if next_tag.name == 'div':
|
||||
search_div = next_tag
|
||||
break
|
||||
|
||||
# Get the articles
|
||||
for h3_item in search_div.findAll('h3'):
|
||||
byline = h3_item.h6
|
||||
if byline is not None:
|
||||
author = self.tag_to_string(byline,usa_alt=False)
|
||||
else:
|
||||
author = ''
|
||||
a = h3_item.find('a', href=True)
|
||||
if not a:
|
||||
continue
|
||||
url = re.sub(r'\?.*', '', a['href'])
|
||||
if not url.startswith("http"):
|
||||
continue
|
||||
if not url.endswith(".html"):
|
||||
continue
|
||||
if 'podcast' in url:
|
||||
continue
|
||||
if 'video' in url:
|
||||
continue
|
||||
url += '?pagewanted=all'
|
||||
if url in url_list:
|
||||
continue
|
||||
url_list.append(url)
|
||||
self.log("URL %s" % url)
|
||||
title = self.tag_to_string(a, use_alt=True).strip()
|
||||
desc = h3_item.find('p')
|
||||
if desc is not None:
|
||||
description = self.tag_to_string(desc,use_alt=False)
|
||||
else:
|
||||
description = ''
|
||||
if not articles.has_key(section_name):
|
||||
ans.append(section_name)
|
||||
articles[section_name] = []
|
||||
articles[section_name].append(dict(title=title, url=url, date=pubdate, description=description, author=author, content=''))
|
||||
|
||||
|
||||
ans = [(key, articles[key]) for key in ans if articles.has_key(key)]
|
||||
return self.filter_ans(ans)
|
||||
|
||||
def parse_index(self):
|
||||
if self.headlinesOnly:
|
||||
return self.parse_headline_index()
|
||||
else:
|
||||
return self.parse_todays_index()
|
||||
|
||||
def strip_anchors(self,soup):
|
||||
paras = soup.findAll(True)
|
||||
for para in paras:
|
||||
aTags = para.findAll('a')
|
||||
for a in aTags:
|
||||
if a.img is None:
|
||||
a.replaceWith(a.renderContents().decode('cp1252','replace'))
|
||||
return soup
|
||||
|
||||
return ans
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
|
||||
kicker_tag = soup.find(attrs={'class':'kicker'})
|
||||
if kicker_tag:
|
||||
if kicker_tag: # remove Op_Ed author head shots
|
||||
tagline = self.tag_to_string(kicker_tag)
|
||||
#self.log("FOUND KICKER %s" % tagline)
|
||||
if tagline=='Op-Ed Columnist':
|
||||
img_div = soup.find('div','inlineImage module')
|
||||
#self.log("Searching for photo")
|
||||
if img_div:
|
||||
img_div.extract()
|
||||
#self.log("Photo deleted")
|
||||
refresh = soup.find('meta', {'http-equiv':'refresh'})
|
||||
if refresh is None:
|
||||
return soup
|
||||
content = refresh.get('content').partition('=')[2]
|
||||
raw = self.browser.open_novisit('http://www.nytimes.com'+content).read()
|
||||
return BeautifulSoup(raw.decode('cp1252', 'replace'))
|
||||
return self.strip_anchors(soup)
|
||||
|
||||
def postprocess_html(self,soup, True):
|
||||
|
||||
if self.one_picture_per_article:
|
||||
# Remove all images after first
|
||||
largeImg = soup.find(True, {'class':'articleSpanImage'})
|
||||
inlineImgs = soup.findAll(True, {'class':'inlineImage module'})
|
||||
if largeImg:
|
||||
for inlineImg in inlineImgs:
|
||||
inlineImg.extract()
|
||||
else:
|
||||
if inlineImgs:
|
||||
firstImg = inlineImgs[0]
|
||||
for inlineImg in inlineImgs[1:]:
|
||||
inlineImg.extract()
|
||||
# Move firstImg before article body
|
||||
#article_body = soup.find(True, {'id':'articleBody'})
|
||||
cgFirst = soup.find(True, {'class':re.compile('columnGroup *first')})
|
||||
if cgFirst:
|
||||
# Strip all sibling NavigableStrings: noise
|
||||
navstrings = cgFirst.findAll(text=True, recursive=False)
|
||||
[ns.extract() for ns in navstrings]
|
||||
headline_found = False
|
||||
tag = cgFirst.find(True)
|
||||
insertLoc = 0
|
||||
while True:
|
||||
insertLoc += 1
|
||||
if hasattr(tag,'class') and tag['class'] == 'articleHeadline':
|
||||
headline_found = True
|
||||
break
|
||||
tag = tag.nextSibling
|
||||
if not tag:
|
||||
headline_found = False
|
||||
break
|
||||
if headline_found:
|
||||
cgFirst.insert(insertLoc,firstImg)
|
||||
else:
|
||||
self.log(">>> No class:'columnGroup first' found <<<")
|
||||
|
||||
# Change captions to italic
|
||||
for caption in soup.findAll(True, {'class':'caption'}) :
|
||||
if caption and caption.contents[0]:
|
||||
cTag = Tag(soup, "p", [("class", "caption")])
|
||||
c = self.fixChars(self.tag_to_string(caption,use_alt=False)).strip()
|
||||
mp_off = c.find("More Photos")
|
||||
if mp_off >= 0:
|
||||
c = c[:mp_off]
|
||||
cTag.insert(0, c)
|
||||
caption.replaceWith(cTag)
|
||||
|
||||
# Change <nyt_headline> to <h2>
|
||||
h1 = soup.find('h1')
|
||||
if h1:
|
||||
headline = h1.find("nyt_headline")
|
||||
if headline:
|
||||
tag = Tag(soup, "h2")
|
||||
tag['class'] = "headline"
|
||||
tag.insert(0, self.fixChars(headline.contents[0]))
|
||||
h1.replaceWith(tag)
|
||||
else:
|
||||
# Blog entry - replace headline, remove <hr> tags
|
||||
headline = soup.find('title')
|
||||
if headline:
|
||||
tag = Tag(soup, "h2")
|
||||
tag['class'] = "headline"
|
||||
tag.insert(0, self.fixChars(headline.contents[0]))
|
||||
soup.insert(0, tag)
|
||||
hrs = soup.findAll('hr')
|
||||
for hr in hrs:
|
||||
hr.extract()
|
||||
|
||||
# Change <h1> to <h3> - used in editorial blogs
|
||||
masthead = soup.find("h1")
|
||||
if masthead:
|
||||
# Nuke the href
|
||||
if masthead.a:
|
||||
del(masthead.a['href'])
|
||||
tag = Tag(soup, "h3")
|
||||
tag.insert(0, self.fixChars(masthead.contents[0]))
|
||||
masthead.replaceWith(tag)
|
||||
|
||||
# Change <span class="bold"> to <b>
|
||||
for subhead in soup.findAll(True, {'class':'bold'}) :
|
||||
if subhead.contents:
|
||||
bTag = Tag(soup, "b")
|
||||
bTag.insert(0, subhead.contents[0])
|
||||
subhead.replaceWith(bTag)
|
||||
|
||||
divTag = soup.find('div',attrs={'id':'articleBody'})
|
||||
if divTag:
|
||||
divTag['class'] = divTag['id']
|
||||
|
||||
# Add class="authorId" to <div> so we can format with CSS
|
||||
divTag = soup.find('div',attrs={'id':'authorId'})
|
||||
if divTag and divTag.contents[0]:
|
||||
tag = Tag(soup, "p")
|
||||
tag['class'] = "authorId"
|
||||
tag.insert(0, self.fixChars(self.tag_to_string(divTag.contents[0],
|
||||
use_alt=False)))
|
||||
divTag.replaceWith(tag)
|
||||
|
||||
return soup
|
||||
|
||||
|
@ -4,7 +4,7 @@ class Tagesschau(BasicNewsRecipe):
|
||||
title = 'Tagesschau'
|
||||
description = 'Nachrichten der ARD'
|
||||
publisher = 'ARD'
|
||||
language = 'de_DE'
|
||||
language = 'de'
|
||||
|
||||
__author__ = 'Florian Andreas Pfaff'
|
||||
oldest_article = 7
|
||||
|
72
resources/recipes/ynet.recipe
Normal file
72
resources/recipes/ynet.recipe
Normal file
@ -0,0 +1,72 @@
|
||||
import re
|
||||
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
import mechanize
|
||||
|
||||
class AdvancedUserRecipe1283848012(BasicNewsRecipe):
|
||||
description = 'This is a recipe of Ynet.co.il. The recipe opens the article page and clicks on an advertisement to not hurt the sites advertising income.'
|
||||
cover_url = 'http://www.bneiakiva.net/uploads/images/ynet%282%29.jpg'
|
||||
title = u'Ynet'
|
||||
__author__ = 'marbs'
|
||||
language = 'he'
|
||||
extra_css='img {max-width:100%;direction: rtl;} #article{direction: rtl;} div{direction: rtl;} title{direction: rtl; } article_description{direction: rtl; } a.article{direction: rtl; } calibre_feed_description{direction: rtl; } body{direction: ltr;}'
|
||||
remove_attributes = ['width']
|
||||
simultaneous_downloads = 5
|
||||
keep_only_tags =dict(name='div', attrs={'id':'articleContainer'})
|
||||
remove_javascript = True
|
||||
timefmt = '[%a, %d %b, %Y]'
|
||||
oldest_article = 1
|
||||
remove_tags = [dict(name='p', attrs={'text':[' ']})]
|
||||
max_articles_per_feed = 100
|
||||
preprocess_regexps = [
|
||||
(re.compile(r'<p> </p>', re.DOTALL|re.IGNORECASE), lambda match: '')
|
||||
]
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
soup.html['dir'] = 'rtl'
|
||||
soup.body['dir'] = 'rtl'
|
||||
return soup
|
||||
|
||||
feeds =[(u'\u05d7\u05d3\u05e9\u05d5\u05ea',
|
||||
u'http://www.ynet.co.il/Integration/StoryRss2.xml'),
|
||||
(u'\u05db\u05dc\u05db\u05dc\u05d4',
|
||||
u'http://www.ynet.co.il/Integration/StoryRss6.xml'),
|
||||
(u'\u05e6\u05e8\u05db\u05e0\u05d5\u05ea',
|
||||
u'http://www.ynet.co.il/Integration/StoryRss437.xml'),
|
||||
(u'\u05e1\u05e4\u05d5\u05e8\u05d8',
|
||||
u'http://www.ynet.co.il/Integration/StoryRss3.xml'),
|
||||
(u'\u05ea\u05e8\u05d1\u05d5\u05ea',
|
||||
u'http://www.ynet.co.il/Integration/StoryRss538.xml'),
|
||||
(u'\u05de\u05e2\u05d5\u05e8\u05d1\u05d5\u05ea \u05d5\u05d7\u05d1\u05e8\u05d4',
|
||||
u'http://www.ynet.co.il/Integration/StoryRss3262.xml'),
|
||||
(u'\u05d1\u05e8\u05d9\u05d0\u05d5\u05ea',
|
||||
u'http://www.ynet.co.il/Integration/StoryRss1208.xml'),
|
||||
(u'\u05d9\u05e8\u05d5\u05e7',
|
||||
u'http://www.ynet.co.il/Integration/StoryRss4872.xml'),
|
||||
(u'\u05de\u05d7\u05e9\u05d1\u05d9\u05dd',
|
||||
u'http://www.ynet.co.il/Integration/StoryRss544.xml'),
|
||||
(u'\u05e8\u05db\u05d1', u'http://www.ynet.co.il/Integration/StoryRss550.xml'),
|
||||
(u'\u05ea\u05d9\u05d9\u05e8\u05d5\u05ea',
|
||||
u'http://www.ynet.co.il/Integration/StoryRss598.xml'),
|
||||
(u'\u05d4\u05d5\u05e8\u05d9\u05dd',
|
||||
u'http://www.ynet.co.il/Integration/StoryRss3052.xml'),
|
||||
(u'\u05d0\u05d5\u05db\u05dc',
|
||||
u'http://www.ynet.co.il/Integration/StoryRss975.xml'),
|
||||
(u'\u05d9\u05d4\u05d3\u05d5\u05ea',
|
||||
u'http://www.ynet.co.il/Integration/StoryRss4403.xml'),
|
||||
(u'\u05de\u05d3\u05e2 \u05d5\u05d8\u05d1\u05e2',
|
||||
u'http://www.ynet.co.il/Integration/StoryRss2142.xml'),
|
||||
(u'\u05d9\u05d7\u05e1\u05d9\u05dd',
|
||||
u'http://www.ynet.co.il/Integration/StoryRss3925.xml'),
|
||||
(u'\u05d3\u05e2\u05d5\u05ea',
|
||||
u'http://www.ynet.co.il/Integration/StoryRss194.xml')]
|
||||
|
||||
def print_version(self, url):
|
||||
#remove from here
|
||||
br = BasicNewsRecipe.get_browser()
|
||||
br.open(url)
|
||||
br.follow_link(mechanize.Link(base_url = '', url =url, text = '', tag = 'a', attrs = [{'id':'buzzerATop'}]))
|
||||
#to here to stop supporting ynet...
|
||||
split1 = url.split("-")
|
||||
print_url = 'http://www.ynet.co.il/Ext/Comp/ArticleLayout/CdaArticlePrintPreview/1,2506,L-' + split1[1]
|
||||
return print_url
|
@ -6,22 +6,25 @@ Fetch Die Zeit.
|
||||
'''
|
||||
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
from calibre.ebooks.BeautifulSoup import Tag
|
||||
|
||||
class ZeitDe(BasicNewsRecipe):
|
||||
|
||||
title = 'ZEIT Online'
|
||||
description = 'ZEIT Online'
|
||||
title = 'Zeit Online'
|
||||
description = 'Zeit Online'
|
||||
language = 'de'
|
||||
lang = 'de_DE'
|
||||
|
||||
__author__ = 'Martin Pitt, Sujata Raman and Ingo Paschke'
|
||||
use_embedded_content = False
|
||||
__author__ = 'Martin Pitt, Sujata Raman, Ingo Paschke and Marc Toensing'
|
||||
|
||||
max_articles_per_feed = 40
|
||||
remove_empty_feeds = True
|
||||
no_stylesheets = True
|
||||
no_javascript = True
|
||||
encoding = 'utf-8'
|
||||
|
||||
remove_tags = [
|
||||
dict(name='iframe'),
|
||||
dict(name='div', attrs={'class':["response","pagination block","pagenav","inline link", "copyright"] }),
|
||||
dict(name='p', attrs={'class':["ressortbacklink", "copyright"] }),
|
||||
dict(name='div', attrs={'id':["place_5","place_4","comments"]})
|
||||
]
|
||||
|
||||
keep_only_tags = [dict(id=['main'])]
|
||||
|
||||
feeds = [
|
||||
('Seite 1', 'http://newsfeed.zeit.de/index_xml'),
|
||||
@ -40,43 +43,15 @@ class ZeitDe(BasicNewsRecipe):
|
||||
('Sport', 'http://newsfeed.zeit.de/sport/index'),
|
||||
]
|
||||
|
||||
extra_css = '''
|
||||
.supertitle{color:#990000; font-family:Arial,Helvetica,sans-serif;font-size:xx-small;}
|
||||
.excerpt{font-family:Georgia,Palatino,Palatino Linotype,FreeSerif,serif;font-size:small;}
|
||||
.title{font-family:Arial,Helvetica,sans-serif;font-size:large;clear:right;}
|
||||
.caption{color:#666666; font-family:Arial,Helvetica,sans-serif;font-size:xx-small;}
|
||||
.copyright{color:#666666; font-family:Arial,Helvetica,sans-serif;font-size:xx-small;}
|
||||
.article{font-family:Georgia,Palatino,Palatino Linotype,FreeSerif,serif;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}
|
||||
.headline iconportrait_inline{font-family:Arial,Helvetica,sans-serif;font-size:x-small}
|
||||
.inline{float:left;margin-top:0;margin-right:15px;position:relative;width:180px; }
|
||||
img.inline{float:none}
|
||||
.intertitle{font-family:Georgia,Palatino,Palatino Linotype,FreeSerif,serif;font-size:x-small;font-weight:700}
|
||||
.ebinfobox{font-family:Georgia,Palatino,Palatino Linotype,FreeSerif,serif;font-size:xx-small;list-style-type:none;float:right;margin-top:0;border-left-style:solid;border-left-width:1px;padding-left:10px;}
|
||||
.infobox {border-style: solid; border-width: 1px;padding:8px;}
|
||||
.infobox dt {font-weight:700;}
|
||||
'''
|
||||
extra_css = '.reaktion,.taglist,.comments,.reponse,.responsetitle,.responsebody,.reponse,.inline,.date{display:none;}li.date{display:block}'
|
||||
|
||||
#filter_regexps = [r'ad.de.doubleclick.net/']
|
||||
|
||||
keep_only_tags = [
|
||||
dict(name='div', attrs={'class':["article"]}) ,
|
||||
dict(name='ul', attrs={'class':["tools"]}) ,
|
||||
]
|
||||
remove_tags = [
|
||||
dict(name='link'), dict(name='iframe'),dict(name='style'),dict(name='meta'),
|
||||
dict(name='div', attrs={'class':["pagination block","pagenav","inline link", "copyright"] }),
|
||||
dict(name='p', attrs={'class':["ressortbacklink", "copyright"] }),
|
||||
dict(name='div', attrs={'id':["place_5","place_4","comments"]})
|
||||
]
|
||||
|
||||
remove_attributes = ['style', 'font']
|
||||
|
||||
def get_article_url(self, article):
|
||||
ans = article.get('link',None)
|
||||
ans += "?page=all"
|
||||
ans += "?page=all&print=true"
|
||||
|
||||
if 'video' in ans or 'quiz' in ans :
|
||||
if 'video' in ans or 'quiz' in ans or 'blog' in ans :
|
||||
ans = None
|
||||
return ans
|
||||
|
||||
@ -86,25 +61,3 @@ class ZeitDe(BasicNewsRecipe):
|
||||
return inhalt.find('div', attrs={'class':'singlearchive clearfix'}).img['src'].replace('icon_','')
|
||||
except:
|
||||
return 'http://images.zeit.de/bilder/titelseiten_zeit/1946/001_001.jpg'
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
soup.html['xml:lang'] = self.lang
|
||||
soup.html['lang'] = self.lang
|
||||
mtag = '<meta http-equiv="Content-Type" content="text/html; charset=' + self.encoding + '">'
|
||||
soup.head.insert(0,mtag)
|
||||
title = soup.find('h2', attrs={'class':'title'})
|
||||
if title is None:
|
||||
print "no title"
|
||||
return soup
|
||||
info = Tag(soup,'ul',[('class','ebinfobox')])
|
||||
tools = soup.find('ul', attrs={'class':'tools'})
|
||||
#author = tools.find('li','author first')
|
||||
for tag in ['author first', 'date', 'date first', 'author', 'source']:
|
||||
line = tools.find('li', tag)
|
||||
if line:
|
||||
info.insert(0,line)
|
||||
title.parent.insert(0,info)
|
||||
tools.extract()
|
||||
return soup
|
||||
|
||||
|
||||
|
60
resources/templates/html_export_default.css
Normal file
60
resources/templates/html_export_default.css
Normal file
@ -0,0 +1,60 @@
|
||||
body{
|
||||
margin:0px;
|
||||
padding: 0.5em;
|
||||
background-color:#F6F3E9;
|
||||
font-size:12px;
|
||||
font-family:Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
.calibreMeta{
|
||||
background-color:#39322B;
|
||||
color:white;
|
||||
padding:10px;
|
||||
}
|
||||
|
||||
.calibreMeta a, .calibreEbNav a, .calibreEbNavTop a, .calibreToc a{
|
||||
color:white;
|
||||
}
|
||||
|
||||
.calibreMeta h1{
|
||||
margin:0px;
|
||||
font-size:18px;
|
||||
background-color:#39322B;
|
||||
}
|
||||
|
||||
.calibreEbookContent{
|
||||
padding:20px;
|
||||
}
|
||||
|
||||
.calibreEbNav, .calibreEbNavTop{
|
||||
clear:both;
|
||||
background-color:#39322B;
|
||||
color:white;
|
||||
padding:10px;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.calibreEbNavTop{
|
||||
margin-bottom:20px;
|
||||
}
|
||||
|
||||
.calibreEbNav a, .calibreEbNavTop a{
|
||||
padding:0px 5px;
|
||||
}
|
||||
|
||||
.calibreTocIndex{
|
||||
line-height:18px;
|
||||
}
|
||||
|
||||
.calibreToc{
|
||||
float:left;
|
||||
margin:20px;
|
||||
width:300px;
|
||||
background-color:#39322B;
|
||||
color:white;
|
||||
padding:10px;
|
||||
}
|
||||
.calibreEbookContent{
|
||||
width:600px;
|
||||
float:left;
|
||||
}
|
74
resources/templates/html_export_default.tmpl
Normal file
74
resources/templates/html_export_default.tmpl
Normal file
@ -0,0 +1,74 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
${head_content}$
|
||||
|
||||
<link href="${cssLink}$" type="text/css" rel="stylesheet" />
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="calibreMeta">
|
||||
<div class="calibreMetaTitle">
|
||||
${pos1=1}$
|
||||
${for title in meta.titles():}$
|
||||
${if pos1:}$
|
||||
<h1>
|
||||
<a href="${tocUrl}$">${print title}$</a>
|
||||
</h1>
|
||||
${:else:}$
|
||||
<div class="calibreMetaSubtitle">${print title}$</div>
|
||||
${:endif}$
|
||||
${pos1=0}$
|
||||
${:endfor}$
|
||||
</div>
|
||||
<div class="calibreMetaAuthor">
|
||||
${print ', '.join(meta.creators())}$
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="calibreMain">
|
||||
|
||||
<div class="calibreEbookContent">
|
||||
${if prevLink or nextLink:}$
|
||||
<div class="calibreEbNavTop">
|
||||
${if prevLink:}$
|
||||
<a href="${prevLink}$" class="calibreAPrev">${print _('previous page'),}$</a>
|
||||
${:else:}$
|
||||
<a href="${tocUrl}$" class="calibreAPrev">${print _('previous page'),}$</a>
|
||||
${:endif}$
|
||||
|
||||
${if nextLink:}$
|
||||
<a href="${nextLink}$" class="calibreANext">${print _('next page'),}$</a>
|
||||
${:endif}$
|
||||
</div>
|
||||
${:endif}$
|
||||
|
||||
${ebookContent}$
|
||||
</div>
|
||||
|
||||
${if has_toc:}$
|
||||
<div class="calibreToc">
|
||||
<h2><a href="${tocUrl}$">${print _('Table of contents'),}$</a></h2>
|
||||
${print toc()}$
|
||||
</div>
|
||||
${:endif}$
|
||||
|
||||
<div class="calibreEbNav">
|
||||
${if prevLink:}$
|
||||
<a href="${prevLink}$" class="calibreAPrev">${print _('previous page'),}$</a>
|
||||
${:else:}$
|
||||
<a href="${tocUrl}$" class="calibreAPrev">${print _('previous page'),}$</a>
|
||||
${:endif}$
|
||||
|
||||
<a href="${tocUrl}$" class="calibreAHome">${print _('start'),}$</a>
|
||||
|
||||
${if nextLink:}$
|
||||
<a href="${nextLink}$" class="calibreANext">${print _('next page'),}$</a>
|
||||
${:endif}$
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
61
resources/templates/html_export_default_index.tmpl
Normal file
61
resources/templates/html_export_default_index.tmpl
Normal file
@ -0,0 +1,61 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
|
||||
<link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" />
|
||||
<link rel="schema.DCTERMS" href="http://purl.org/dc/terms/" />
|
||||
|
||||
<title>${print ', '.join(meta.creators()),}$ - ${print meta.titles().next(); meta.titles().close()}$</title>
|
||||
|
||||
${for item in meta:}$
|
||||
<meta ${print 'name="DC.'+item['name']+'"',}$ ${print 'content="'+item['value']+'"',}$ />
|
||||
${:endfor}$
|
||||
|
||||
<link href="${cssLink}$" type="text/css" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="calibreMeta">
|
||||
<div class="calibreMetaTitle">
|
||||
${pos1=1}$
|
||||
${for title in meta.titles():}$
|
||||
${if pos1:}$
|
||||
<h1>
|
||||
<a href="${tocUrl}$">${print title}$</a>
|
||||
</h1>
|
||||
${:else:}$
|
||||
<div class="calibreMetaSubtitle">${print title}$</div>
|
||||
${:endif}$
|
||||
${pos1=0}$
|
||||
${:endfor}$
|
||||
</div>
|
||||
<div class="calibreMetaAuthor">
|
||||
${print ', '.join(meta.creators()),}$
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="calibreMain">
|
||||
<div class="calibreEbookContent">
|
||||
|
||||
${if has_toc:}$
|
||||
<div class="calibreTocIndex">
|
||||
<h2>${print _('Table of contents'),}$</h2>
|
||||
${toc}$
|
||||
</div>
|
||||
${:else:}$
|
||||
<h2>${print _('No table of contents present'),}$</h2>
|
||||
<div><strong><a href="${nextLink}$">${print _('begin to read'),}$</a></strong></div>
|
||||
${:endif}$
|
||||
|
||||
</div>
|
||||
|
||||
<div class="calibreEbNav">
|
||||
${if nextLink:}$
|
||||
<a href="${nextLink}$" class="calibreANext">${print _('next page'),}$</a>
|
||||
${:endif}$
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -11,7 +11,7 @@ import subprocess, tempfile, os, time
|
||||
from setup import Command, installer_name
|
||||
from setup.build_environment import HOST, PROJECT
|
||||
|
||||
BASE_RSYNC = 'rsync -avz --delete'.split()
|
||||
BASE_RSYNC = ['rsync', '-avz', '--delete']
|
||||
EXCLUDES = []
|
||||
for x in [
|
||||
'src/calibre/plugins', 'src/calibre/manual', 'src/calibre/trac',
|
||||
@ -42,7 +42,8 @@ class Push(Command):
|
||||
threads = []
|
||||
for host in (
|
||||
r'Owner@winxp:/cygdrive/c/Documents\ and\ Settings/Owner/calibre',
|
||||
'kovid@ox:calibre'
|
||||
'kovid@ox:calibre',
|
||||
r'kovid@win7:/cygdrive/c/Users/kovid/calibre',
|
||||
):
|
||||
rcmd = BASE_RSYNC + EXCLUDES + ['.', host]
|
||||
print '\n\nPushing to:', host, '\n'
|
||||
|
@ -89,7 +89,7 @@ class Server(Command):
|
||||
t = telnetlib.Telnet('localhost', 4242)
|
||||
t.read_until("repl>")
|
||||
t.write('BrowserReload();')
|
||||
print t.read_until("repl>")
|
||||
t.read_until("repl>")
|
||||
t.close()
|
||||
except:
|
||||
print 'Failed to reload browser'
|
||||
|
@ -21,8 +21,6 @@ from calibre.constants import iswindows, isosx, islinux, isfreebsd, isfrozen, \
|
||||
filesystem_encoding, plugins, config_dir
|
||||
from calibre.startup import winutil, winutilerror
|
||||
|
||||
import mechanize
|
||||
|
||||
uuid.uuid4() # Imported before PyQt4 to workaround PyQt4 util-linux conflict on gentoo
|
||||
|
||||
if False:
|
||||
@ -269,7 +267,8 @@ def browser(honor_time=True, max_time=2, mobile_browser=False):
|
||||
:param honor_time: If True honors pause time in refresh requests
|
||||
:param max_time: Maximum time in seconds to wait during a refresh request
|
||||
'''
|
||||
opener = mechanize.Browser()
|
||||
from calibre.utils.browser import Browser
|
||||
opener = Browser()
|
||||
opener.set_handle_refresh(True, max_time=max_time, honor_time=honor_time)
|
||||
opener.set_handle_robots(False)
|
||||
opener.addheaders = [('User-agent', ' Mozilla/5.0 (Windows; U; Windows CE 5.1; rv:1.8.1a3) Gecko/20060610 Minimo/0.016' if mobile_browser else \
|
||||
|
@ -2,7 +2,7 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
__appname__ = 'calibre'
|
||||
__version__ = '0.7.26'
|
||||
__version__ = '0.7.27'
|
||||
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
|
||||
|
||||
import re
|
||||
@ -105,7 +105,9 @@ else:
|
||||
os.makedirs(config_dir, mode=CONFIG_DIR_MODE)
|
||||
except:
|
||||
pass
|
||||
if not os.access(config_dir, os.W_OK) or not os.access(config_dir, os.X_OK):
|
||||
if not os.path.exists(config_dir) or \
|
||||
not os.access(config_dir, os.W_OK) or not \
|
||||
os.access(config_dir, os.X_OK):
|
||||
print 'No write acces to', config_dir, 'using a temporary dir instead'
|
||||
import tempfile, atexit
|
||||
config_dir = tempfile.mkdtemp(prefix='calibre-config-')
|
||||
|
@ -446,6 +446,7 @@ from calibre.ebooks.rb.output import RBOutput
|
||||
from calibre.ebooks.rtf.output import RTFOutput
|
||||
from calibre.ebooks.tcr.output import TCROutput
|
||||
from calibre.ebooks.txt.output import TXTOutput
|
||||
from calibre.ebooks.html.output import HTMLOutput
|
||||
from calibre.ebooks.snb.output import SNBOutput
|
||||
|
||||
from calibre.customize.profiles import input_profiles, output_profiles
|
||||
@ -525,6 +526,7 @@ plugins += [
|
||||
RTFOutput,
|
||||
TCROutput,
|
||||
TXTOutput,
|
||||
HTMLOutput,
|
||||
SNBOutput,
|
||||
]
|
||||
# Order here matters. The first matched device is the one used.
|
||||
@ -893,4 +895,3 @@ plugins += [LookAndFeel, Behavior, Columns, Toolbar, InputOptions,
|
||||
Email, Server, Plugins, Tweaks, Misc]
|
||||
|
||||
#}}}
|
||||
|
||||
|
@ -17,15 +17,15 @@ class IRIVER_STORY(USBMS):
|
||||
supported_platforms = ['windows', 'osx', 'linux']
|
||||
|
||||
# Ordered list of supported formats
|
||||
FORMATS = ['epub', 'pdf', 'txt']
|
||||
FORMATS = ['epub', 'fb2', 'pdf', 'djvu', 'txt']
|
||||
|
||||
VENDOR_ID = [0x1006]
|
||||
PRODUCT_ID = [0x4023]
|
||||
PRODUCT_ID = [0x4023, 0x4025]
|
||||
BCD = [0x0323]
|
||||
|
||||
VENDOR_NAME = 'IRIVER'
|
||||
WINDOWS_MAIN_MEM = 'STORY'
|
||||
WINDOWS_CARD_A_MEM = 'STORY'
|
||||
WINDOWS_MAIN_MEM = ['STORY', 'STORY_EB05']
|
||||
WINDOWS_CARD_A_MEM = ['STORY', 'STORY_SD']
|
||||
|
||||
#OSX_MAIN_MEM = 'Kindle Internal Storage Media'
|
||||
#OSX_CARD_A_MEM = 'Kindle Card Storage Media'
|
||||
|
@ -124,12 +124,15 @@ class PDNOVEL_KOBO(PDNOVEL):
|
||||
|
||||
BCD = [0x222]
|
||||
|
||||
EBOOK_DIR_MAIN = 'eBooks/Kobo'
|
||||
EBOOK_DIR_MAIN = 'eBooks'
|
||||
|
||||
def upload_cover(self, path, filename, metadata, filepath):
|
||||
coverdata = getattr(metadata, 'thumbnail', None)
|
||||
if coverdata and coverdata[2]:
|
||||
with open(os.path.join(path, '.thumbnail', filename+'.jpg'), 'wb') as coverfile:
|
||||
dirpath = os.path.join(path, '.thumbnail')
|
||||
if not os.path.exists(dirpath):
|
||||
os.makedirs(dirpath)
|
||||
with open(os.path.join(dirpath, filename+'.jpg'), 'wb') as coverfile:
|
||||
coverfile.write(coverdata[2])
|
||||
|
||||
|
||||
|
@ -32,7 +32,7 @@ def detect(aBuf):
|
||||
ENCODING_PATS = [
|
||||
re.compile(r'<\?[^<>]+encoding\s*=\s*[\'"](.*?)[\'"][^<>]*>',
|
||||
re.IGNORECASE),
|
||||
re.compile(r'''<meta\s+?[^<>]+?content\s*=\s*['"][^'"]*?charset=([-a-z0-9]+)[^'"]*?['"][^<>]*>''',
|
||||
re.compile(r'''<meta\s+?[^<>]*?content\s*=\s*['"][^'"]*?charset=([-a-z0-9]+)[^'"]*?['"][^<>]*>''',
|
||||
re.IGNORECASE)
|
||||
]
|
||||
ENTITY_PATTERN = re.compile(r'&(\S+?);')
|
||||
|
@ -144,7 +144,10 @@ class DocAnalysis(object):
|
||||
|
||||
# Normalize the histogram into percents
|
||||
totalLines = len(self.lines)
|
||||
h = [ float(count)/totalLines for count in hRaw ]
|
||||
if totalLines > 0:
|
||||
h = [ float(count)/totalLines for count in hRaw ]
|
||||
else:
|
||||
h = []
|
||||
#print "\nhRaw histogram lengths are: "+str(hRaw)
|
||||
#print " percents are: "+str(h)+"\n"
|
||||
|
||||
|
33
src/calibre/ebooks/html/meta.py
Normal file
33
src/calibre/ebooks/html/meta.py
Normal file
@ -0,0 +1,33 @@
|
||||
from __future__ import with_statement
|
||||
__license__ = 'GPL 3'
|
||||
__copyright__ = '2010, Fabian Grassl <fg@jusmeum.de>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
|
||||
from calibre.ebooks.oeb.base import namespace, barename, DC11_NS
|
||||
|
||||
class EasyMeta(object):
|
||||
|
||||
def __init__(self, meta):
|
||||
self.meta = meta
|
||||
|
||||
def __iter__(self):
|
||||
meta = self.meta
|
||||
for item_name in meta.items:
|
||||
for item in meta[item_name]:
|
||||
if namespace(item.term) == DC11_NS:
|
||||
yield { 'name': barename(item.term), 'value': item.value }
|
||||
|
||||
def __len__(self):
|
||||
count = 0
|
||||
for item in self:
|
||||
count = count+1
|
||||
return count
|
||||
|
||||
def titles(self):
|
||||
for item in self.meta['title']:
|
||||
yield item.value
|
||||
|
||||
def creators(self):
|
||||
for item in self.meta['creator']:
|
||||
yield item.value
|
209
src/calibre/ebooks/html/output.py
Normal file
209
src/calibre/ebooks/html/output.py
Normal file
@ -0,0 +1,209 @@
|
||||
from __future__ import with_statement
|
||||
__license__ = 'GPL 3'
|
||||
__copyright__ = '2010, Fabian Grassl <fg@jusmeum.de>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import os, re, shutil
|
||||
|
||||
from calibre.utils import zipfile
|
||||
|
||||
from os.path import dirname, abspath, relpath, exists, basename
|
||||
|
||||
from lxml import etree
|
||||
from templite import Templite
|
||||
|
||||
from calibre.ebooks.oeb.base import element
|
||||
from calibre.customize.conversion import OutputFormatPlugin, OptionRecommendation
|
||||
from calibre import CurrentDir
|
||||
from calibre.ptempfile import PersistentTemporaryDirectory
|
||||
from calibre.utils.zipfile import ZipFile
|
||||
|
||||
from urllib import unquote
|
||||
|
||||
from calibre.ebooks.html.meta import EasyMeta
|
||||
|
||||
class HTMLOutput(OutputFormatPlugin):
|
||||
|
||||
name = 'HTML Output'
|
||||
author = 'Fabian Grassl'
|
||||
file_type = 'zip'
|
||||
|
||||
options = set([
|
||||
OptionRecommendation(name='template_css',
|
||||
help=_('CSS file used for the output instead of the default file')),
|
||||
|
||||
OptionRecommendation(name='template_html_index',
|
||||
help=_('Template used for generation of the html index file instead of the default file')),
|
||||
|
||||
OptionRecommendation(name='template_html',
|
||||
help=_('Template used for the generation of the html contents of the book instead of the default file')),
|
||||
|
||||
OptionRecommendation(name='extract_to',
|
||||
help=_('Extract the contents of the generated ZIP file to the '
|
||||
'specified directory. WARNING: The contents of the directory '
|
||||
'will be deleted.')
|
||||
),
|
||||
])
|
||||
|
||||
recommendations = set([('pretty_print', True, OptionRecommendation.HIGH)])
|
||||
|
||||
def generate_toc(self, oeb_book, ref_url, output_dir):
|
||||
'''
|
||||
Generate table of contents
|
||||
'''
|
||||
with CurrentDir(output_dir):
|
||||
def build_node(current_node, parent=None):
|
||||
if parent is None:
|
||||
parent = etree.Element('ul')
|
||||
elif len(current_node.nodes):
|
||||
parent = element(parent, ('ul'))
|
||||
for node in current_node.nodes:
|
||||
point = element(parent, 'li')
|
||||
href = relpath(abspath(unquote(node.href)), dirname(ref_url))
|
||||
link = element(point, 'a', href=href)
|
||||
title = node.title
|
||||
if title:
|
||||
title = re.sub(r'\s+', ' ', title)
|
||||
link.text=title
|
||||
build_node(node, point)
|
||||
return parent
|
||||
wrap = etree.Element('div')
|
||||
wrap.append(build_node(oeb_book.toc))
|
||||
return wrap
|
||||
|
||||
def generate_html_toc(self, oeb_book, ref_url, output_dir):
|
||||
root = self.generate_toc(oeb_book, ref_url, output_dir)
|
||||
return etree.tostring(root, pretty_print=True, encoding='utf-8',
|
||||
xml_declaration=False)
|
||||
|
||||
def convert(self, oeb_book, output_path, input_plugin, opts, log):
|
||||
|
||||
# read template files
|
||||
if opts.template_html_index is not None:
|
||||
template_html_index_data = open(opts.template_html_index, 'rb').read()
|
||||
else:
|
||||
template_html_index_data = P('templates/html_export_default_index.tmpl', data=True)
|
||||
|
||||
if opts.template_html is not None:
|
||||
template_html_data = open(opts.template_html, 'rb').read()
|
||||
else:
|
||||
template_html_data = P('templates/html_export_default.tmpl', data=True)
|
||||
|
||||
if opts.template_css is not None:
|
||||
template_css_data = open(opts.template_css, 'rb').read()
|
||||
else:
|
||||
template_css_data = P('templates/html_export_default.css', data=True)
|
||||
|
||||
template_html_index_data = template_html_index_data.decode('utf-8')
|
||||
template_html_data = template_html_data.decode('utf-8')
|
||||
template_css_data = template_css_data.decode('utf-8')
|
||||
|
||||
self.log = log
|
||||
self.opts = opts
|
||||
meta = EasyMeta(oeb_book.metadata)
|
||||
|
||||
tempdir = os.path.realpath(PersistentTemporaryDirectory())
|
||||
output_file = os.path.join(tempdir,
|
||||
basename(re.sub(r'\.zip', '', output_path)+'.html'))
|
||||
output_dir = re.sub(r'\.html', '', output_file)+'_files'
|
||||
|
||||
if not exists(output_dir):
|
||||
os.makedirs(output_dir)
|
||||
|
||||
css_path = output_dir+os.sep+'calibreHtmlOutBasicCss.css'
|
||||
with open(css_path, 'wb') as f:
|
||||
f.write(template_css_data.encode('utf-8'))
|
||||
|
||||
with open(output_file, 'wb') as f:
|
||||
html_toc = self.generate_html_toc(oeb_book, output_file, output_dir)
|
||||
templite = Templite(template_html_index_data)
|
||||
nextLink = oeb_book.spine[0].href
|
||||
nextLink = relpath(output_dir+os.sep+nextLink, dirname(output_file))
|
||||
cssLink = relpath(abspath(css_path), dirname(output_file))
|
||||
tocUrl = relpath(output_file, dirname(output_file))
|
||||
t = templite.render(has_toc=bool(oeb_book.toc.count()),
|
||||
toc=html_toc, meta=meta, nextLink=nextLink,
|
||||
tocUrl=tocUrl, cssLink=cssLink,
|
||||
firstContentPageLink=nextLink)
|
||||
f.write(t)
|
||||
|
||||
with CurrentDir(output_dir):
|
||||
for item in oeb_book.manifest:
|
||||
path = abspath(unquote(item.href))
|
||||
dir = dirname(path)
|
||||
if not exists(dir):
|
||||
os.makedirs(dir)
|
||||
if item.spine_position is not None:
|
||||
with open(path, 'wb') as f:
|
||||
pass
|
||||
else:
|
||||
with open(path, 'wb') as f:
|
||||
f.write(str(item))
|
||||
item.unload_data_from_memory(memory=path)
|
||||
|
||||
for item in oeb_book.spine:
|
||||
path = abspath(unquote(item.href))
|
||||
dir = dirname(path)
|
||||
root = item.data.getroottree()
|
||||
|
||||
# get & clean HTML <HEAD>-data
|
||||
head = root.xpath('//h:head', namespaces={'h': 'http://www.w3.org/1999/xhtml'})[0]
|
||||
head_content = etree.tostring(head, pretty_print=True, encoding='utf-8')
|
||||
head_content = re.sub(r'\<\/?head.*\>', '', head_content)
|
||||
head_content = re.sub(re.compile(r'\<style.*\/style\>', re.M|re.S), '', head_content)
|
||||
head_content = re.sub(r'<(title)([^>]*)/>', r'<\1\2></\1>', head_content)
|
||||
|
||||
# get & clean HTML <BODY>-data
|
||||
body = root.xpath('//h:body', namespaces={'h': 'http://www.w3.org/1999/xhtml'})[0]
|
||||
ebook_content = etree.tostring(body, pretty_print=True, encoding='utf-8')
|
||||
ebook_content = re.sub(r'\<\/?body.*\>', '', ebook_content)
|
||||
ebook_content = re.sub(r'<(div|a|span)([^>]*)/>', r'<\1\2></\1>', ebook_content)
|
||||
|
||||
# generate link to next page
|
||||
if item.spine_position+1 < len(oeb_book.spine):
|
||||
nextLink = oeb_book.spine[item.spine_position+1].href
|
||||
nextLink = relpath(abspath(nextLink), dir)
|
||||
else:
|
||||
nextLink = None
|
||||
|
||||
# generate link to previous page
|
||||
if item.spine_position > 0:
|
||||
prevLink = oeb_book.spine[item.spine_position-1].href
|
||||
prevLink = relpath(abspath(prevLink), dir)
|
||||
else:
|
||||
prevLink = None
|
||||
|
||||
cssLink = relpath(abspath(css_path), dir)
|
||||
tocUrl = relpath(output_file, dir)
|
||||
firstContentPageLink = oeb_book.spine[0].href
|
||||
|
||||
# render template
|
||||
templite = Templite(template_html_data)
|
||||
toc = lambda: self.generate_html_toc(oeb_book, path, output_dir)
|
||||
t = templite.render(ebookContent=ebook_content,
|
||||
prevLink=prevLink, nextLink=nextLink,
|
||||
has_toc=bool(oeb_book.toc.count()), toc=toc,
|
||||
tocUrl=tocUrl, head_content=head_content,
|
||||
meta=meta, cssLink=cssLink,
|
||||
firstContentPageLink=firstContentPageLink)
|
||||
|
||||
# write html to file
|
||||
with open(path, 'wb') as f:
|
||||
f.write(t)
|
||||
item.unload_data_from_memory(memory=path)
|
||||
|
||||
zfile = ZipFile(output_path, "w")
|
||||
zfile.add_dir(output_dir, basename(output_dir))
|
||||
zfile.write(output_file, basename(output_file), zipfile.ZIP_DEFLATED)
|
||||
|
||||
if opts.extract_to:
|
||||
if os.path.exists(opts.extract_to):
|
||||
shutil.rmtree(opts.extract_to)
|
||||
os.makedirs(opts.extract_to)
|
||||
zfile.extractall(opts.extract_to)
|
||||
self.log('Zip file extracted to', opts.extract_to)
|
||||
|
||||
zfile.close()
|
||||
|
||||
# cleanup temp dir
|
||||
shutil.rmtree(tempdir)
|
@ -49,13 +49,12 @@ def get_social_metadata(title, authors, publisher, isbn):
|
||||
return mi
|
||||
br = browser()
|
||||
asin = to_asin(br, isbn)
|
||||
if asin:
|
||||
if get_metadata(br, asin, mi):
|
||||
return mi
|
||||
if asin and get_metadata(br, asin, mi):
|
||||
return mi
|
||||
from calibre.ebooks.metadata.xisbn import xisbn
|
||||
for i in xisbn.get_associated_isbns(isbn):
|
||||
asin = to_asin(br, i)
|
||||
if get_metadata(br, asin, mi):
|
||||
if asin and get_metadata(br, asin, mi):
|
||||
return mi
|
||||
return mi
|
||||
|
||||
@ -113,13 +112,12 @@ def get_metadata(br, asin, mi):
|
||||
|
||||
def main(args=sys.argv):
|
||||
# Test xisbn
|
||||
#print get_social_metadata('Learning Python', None, None, '8324616489')
|
||||
#print
|
||||
print get_social_metadata('Learning Python', None, None, '8324616489')
|
||||
print
|
||||
|
||||
# Test sophisticated comment formatting
|
||||
print get_social_metadata('Angels & Demons', None, None, '9781416580829')
|
||||
print
|
||||
return
|
||||
|
||||
# Random tests
|
||||
print get_social_metadata('Star Trek: Destiny: Mere Mortals', None, None, '9781416551720')
|
||||
|
@ -12,6 +12,7 @@ from calibre.utils.logging import default_log
|
||||
from calibre.utils.titlecase import titlecase
|
||||
from calibre.customize import Plugin
|
||||
from calibre.ebooks.metadata.covers import check_for_cover
|
||||
from calibre.utils.html2text import html2text
|
||||
|
||||
metadata_config = None
|
||||
|
||||
@ -48,6 +49,11 @@ class MetadataSource(Plugin): # {{{
|
||||
#: member.
|
||||
string_customization_help = None
|
||||
|
||||
#: Set this to true if your plugin returns HTML markup in comments.
|
||||
#: Then if the user disables HTML, calibre will automagically convert
|
||||
#: the HTML to Markdown.
|
||||
has_html_comments = False
|
||||
|
||||
type = _('Metadata download')
|
||||
|
||||
def __call__(self, title, author, publisher, isbn, verbose, log=None,
|
||||
@ -79,6 +85,13 @@ class MetadataSource(Plugin): # {{{
|
||||
mi.comments = None
|
||||
if not c.get('tags', True):
|
||||
mi.tags = []
|
||||
if self.has_html_comments and mi.comments and \
|
||||
c.get('textcomments', False):
|
||||
try:
|
||||
mi.comments = html2text(mi.comments)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
mi.comments = None
|
||||
|
||||
except Exception, e:
|
||||
self.exception = e
|
||||
@ -132,11 +145,17 @@ class MetadataSource(Plugin): # {{{
|
||||
setattr(w, '_'+x, cb)
|
||||
cb.setChecked(c.get(x, True))
|
||||
w._layout.addWidget(cb)
|
||||
|
||||
cb = QCheckBox(_('Convert comments downloaded from %s to plain text')%(self.name))
|
||||
setattr(w, '_textcomments', cb)
|
||||
cb.setChecked(c.get('textcomments', False))
|
||||
w._layout.addWidget(cb)
|
||||
|
||||
return w
|
||||
|
||||
def save_settings(self, w):
|
||||
dl_settings = {}
|
||||
for x in ('rating', 'tags', 'comments'):
|
||||
for x in ('rating', 'tags', 'comments', 'textcomments'):
|
||||
dl_settings[x] = getattr(w, '_'+x).isChecked()
|
||||
c = self.config_store()
|
||||
c.set(self.name, dl_settings)
|
||||
@ -210,6 +229,8 @@ class Amazon(MetadataSource): # {{{
|
||||
metadata_type = 'social'
|
||||
description = _('Downloads social metadata from amazon.com')
|
||||
|
||||
has_html_comments = True
|
||||
|
||||
def fetch(self):
|
||||
if not self.isbn:
|
||||
return
|
||||
|
@ -182,6 +182,7 @@ class TOC(list):
|
||||
except:
|
||||
play_order = 1
|
||||
href = fragment = text = None
|
||||
nd = dest
|
||||
nl = nl_path(np)
|
||||
if nl:
|
||||
nl = nl[0]
|
||||
@ -190,17 +191,14 @@ class TOC(list):
|
||||
text += etree.tostring(txt, method='text',
|
||||
encoding=unicode, with_tail=False)
|
||||
content = content_path(np)
|
||||
if not content or not text:
|
||||
return
|
||||
content = content[0]
|
||||
src = get_attr(content, attr='src')
|
||||
if src is None:
|
||||
return
|
||||
|
||||
purl = urlparse(unquote(content.get('src')))
|
||||
href, fragment = purl[2], purl[5]
|
||||
nd = dest.add_item(href, fragment, text)
|
||||
nd.play_order = play_order
|
||||
if content and text:
|
||||
content = content[0]
|
||||
src = get_attr(content, attr='src')
|
||||
if src:
|
||||
purl = urlparse(unquote(content.get('src')))
|
||||
href, fragment = purl[2], purl[5]
|
||||
nd = dest.add_item(href, fragment, text)
|
||||
nd.play_order = play_order
|
||||
|
||||
for c in np_path(np):
|
||||
process_navpoint(c, nd)
|
||||
|
@ -275,7 +275,15 @@ class MobiMLizer(object):
|
||||
# <mbp:frame-set/> does not exist lalalala
|
||||
if style['display'] in ('none', 'oeb-page-head', 'oeb-page-foot') \
|
||||
or style['visibility'] == 'hidden':
|
||||
return
|
||||
id_ = elem.get('id', None)
|
||||
if id_:
|
||||
# Keep anchors so people can use display:none
|
||||
# to generate hidden TOCs
|
||||
elem.clear()
|
||||
elem.text = None
|
||||
elem.set('id', id_)
|
||||
else:
|
||||
return
|
||||
tag = barename(elem.tag)
|
||||
istate = copy.copy(istates[-1])
|
||||
istate.rendered = False
|
||||
@ -378,6 +386,15 @@ class MobiMLizer(object):
|
||||
for attr in ('rowspan', 'colspan','width','border','scope'):
|
||||
if attr in elem.attrib:
|
||||
istate.attrib[attr] = elem.attrib[attr]
|
||||
if tag == 'q':
|
||||
t = elem.text
|
||||
if not t:
|
||||
t = ''
|
||||
elem.text = u'\u201c' + t
|
||||
t = elem.tail
|
||||
if not t:
|
||||
t = ''
|
||||
elem.tail = u'\u201d' + t
|
||||
text = None
|
||||
if elem.text:
|
||||
if istate.preserve:
|
||||
@ -406,6 +423,12 @@ class MobiMLizer(object):
|
||||
parent = bstate.para if bstate.inline is None else bstate.inline
|
||||
if parent is not None:
|
||||
vtag = etree.SubElement(parent, XHTML(vtag))
|
||||
# Add anchors
|
||||
for child in vbstate.body:
|
||||
if child is not vbstate.para:
|
||||
vtag.append(child)
|
||||
else:
|
||||
break
|
||||
for child in vbstate.para:
|
||||
vtag.append(child)
|
||||
return
|
||||
|
@ -49,5 +49,3 @@ class OEBOutput(OutputFormatPlugin):
|
||||
with open(path, 'wb') as f:
|
||||
f.write(str(item))
|
||||
item.unload_data_from_memory(memory=path)
|
||||
|
||||
|
||||
|
@ -143,11 +143,17 @@ def render_jacket(mi, output_profile,
|
||||
if comments:
|
||||
comments = comments_to_html(comments)
|
||||
|
||||
try:
|
||||
author = mi.format_authors()
|
||||
except:
|
||||
author = ''
|
||||
|
||||
def generate_html(comments):
|
||||
args = dict(xmlns=XHTML_NS,
|
||||
title_str=title_str,
|
||||
css=css,
|
||||
title=title,
|
||||
author=author,
|
||||
pubdate_label=_('Published'), pubdate=pubdate,
|
||||
series_label=_('Series'), series=series,
|
||||
rating_label=_('Rating'), rating=rating,
|
||||
|
@ -101,11 +101,12 @@ class SNBMLizer(object):
|
||||
subitem = ''
|
||||
bodyTree = trees[subitem].find(".//body")
|
||||
for line in output.splitlines():
|
||||
if not line.find(CALIBRE_SNB_PRE_TAG) == 0:
|
||||
pos = line.find(CALIBRE_SNB_PRE_TAG)
|
||||
if pos == -1:
|
||||
line = line.strip(u' \t\n\r\u3000')
|
||||
else:
|
||||
etree.SubElement(bodyTree, "text").text = \
|
||||
etree.CDATA(line[len(CALIBRE_SNB_PRE_TAG):])
|
||||
etree.CDATA(line[pos+len(CALIBRE_SNB_PRE_TAG):])
|
||||
continue
|
||||
if len(line) != 0:
|
||||
if line.find(CALIBRE_SNB_IMG_TAG) == 0:
|
||||
|
@ -715,13 +715,13 @@ def build_forms(srcdir, info=None):
|
||||
dat = re.compile(r'QtGui.QApplication.translate\(.+?,\s+"(.+?)(?<!\\)",.+?\)', re.DOTALL).sub(r'_("\1")', dat)
|
||||
dat = dat.replace('_("MMM yyyy")', '"MMM yyyy"')
|
||||
dat = pat.sub(sub, dat)
|
||||
dat = dat.replace('from QtWebKit.QWebView import QWebView',
|
||||
'from PyQt4 import QtWebKit\nfrom PyQt4.QtWebKit import QWebView')
|
||||
|
||||
if form.endswith('viewer%smain.ui'%os.sep):
|
||||
info('\t\tPromoting WebView')
|
||||
dat = dat.replace('self.view = QtWebKit.QWebView(', 'self.view = DocumentView(')
|
||||
dat = dat.replace('self.view = QWebView(', 'self.view = DocumentView(')
|
||||
dat = dat.replace('from QtWebKit.QWebView import QWebView',
|
||||
'from PyQt4 import QtWebKit\nfrom PyQt4.QtWebKit import QWebView')
|
||||
dat += '\n\nfrom calibre.gui2.viewer.documentview import DocumentView'
|
||||
|
||||
open(compiled_form, 'wb').write(dat)
|
||||
|
@ -192,14 +192,15 @@ class EditMetadataAction(InterfaceAction):
|
||||
_('At least two books must be selected for merging'),
|
||||
show=True)
|
||||
dest_id, src_books, src_ids = self.books_to_merge(rows)
|
||||
title = self.gui.library_view.model().db.title(dest_id, index_is_id=True)
|
||||
if safe_merge:
|
||||
if not confirm('<p>'+_(
|
||||
'Book formats and metadata from the selected books '
|
||||
'will be added to the <b>first selected book.</b> '
|
||||
'will be added to the <b>first selected book</b> (%s). '
|
||||
'ISBN will <i>not</i> be merged.<br><br> '
|
||||
'The second and subsequently selected books will not '
|
||||
'be deleted or changed.<br><br>'
|
||||
'Please confirm you want to proceed.')
|
||||
'Please confirm you want to proceed.')%title
|
||||
+'</p>', 'merge_books_safe', self.gui):
|
||||
return
|
||||
self.add_formats(dest_id, src_books)
|
||||
@ -207,14 +208,14 @@ class EditMetadataAction(InterfaceAction):
|
||||
else:
|
||||
if not confirm('<p>'+_(
|
||||
'Book formats and metadata from the selected books will be merged '
|
||||
'into the <b>first selected book</b>. '
|
||||
'into the <b>first selected book</b> (%s). '
|
||||
'ISBN will <i>not</i> be merged.<br><br>'
|
||||
'After merger the second and '
|
||||
'subsequently selected books will be <b>deleted</b>. <br><br>'
|
||||
'All book formats of the first selected book will be kept '
|
||||
'and any duplicate formats in the second and subsequently selected books '
|
||||
'will be permanently <b>deleted</b> from your computer.<br><br> '
|
||||
'Are you <b>sure</b> you want to proceed?')
|
||||
'Are you <b>sure</b> you want to proceed?')%title
|
||||
+'</p>', 'merge_books', self.gui):
|
||||
return
|
||||
if len(rows)>5:
|
||||
@ -233,6 +234,7 @@ class EditMetadataAction(InterfaceAction):
|
||||
ci = self.gui.library_view.model().index(dest_row, 0)
|
||||
if ci.isValid():
|
||||
self.gui.library_view.setCurrentIndex(ci)
|
||||
self.gui.library_view.model().current_changed(ci, ci)
|
||||
|
||||
def add_formats(self, dest_id, src_books, replace=False):
|
||||
for src_book in src_books:
|
||||
|
@ -35,7 +35,6 @@ class ViewAction(InterfaceAction):
|
||||
self.qaction.setMenu(self.view_menu)
|
||||
ac.triggered.connect(self.view_specific_format, type=Qt.QueuedConnection)
|
||||
|
||||
|
||||
def location_selected(self, loc):
|
||||
enabled = loc == 'library'
|
||||
for action in list(self.view_menu.actions())[1:]:
|
||||
@ -134,6 +133,9 @@ class ViewAction(InterfaceAction):
|
||||
rows = self.gui.current_view().selectionModel().selectedRows()
|
||||
self._view_books(rows)
|
||||
|
||||
def view_triggered(self, index):
|
||||
self._view_books([index])
|
||||
|
||||
def view_specific_book(self, index):
|
||||
self._view_books([index])
|
||||
|
||||
|
@ -5,11 +5,13 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import os, collections
|
||||
import os, collections, sys
|
||||
from Queue import Queue
|
||||
|
||||
from PyQt4.Qt import QLabel, QPixmap, QSize, QWidget, Qt, pyqtSignal, \
|
||||
QVBoxLayout, QScrollArea, QPropertyAnimation, QEasingCurve, \
|
||||
QSizePolicy, QPainter, QRect, pyqtProperty
|
||||
from PyQt4.Qt import QPixmap, QSize, QWidget, Qt, pyqtSignal, \
|
||||
QPropertyAnimation, QEasingCurve, QThread, QApplication, QFontInfo, \
|
||||
QSizePolicy, QPainter, QRect, pyqtProperty, QLayout, QPalette
|
||||
from PyQt4.QtWebKit import QWebView
|
||||
|
||||
from calibre import fit_image, prepare_string_for_xml
|
||||
from calibre.gui2.widgets import IMAGE_EXTENSIONS
|
||||
@ -67,10 +69,7 @@ class CoverView(QWidget): # {{{
|
||||
|
||||
def __init__(self, vertical, parent=None):
|
||||
QWidget.__init__(self, parent)
|
||||
self.setMaximumSize(QSize(120, 120))
|
||||
self.setMinimumSize(QSize(120 if vertical else 20, 120 if vertical else
|
||||
20))
|
||||
self._current_pixmap_size = self.maximumSize()
|
||||
self._current_pixmap_size = QSize(120, 120)
|
||||
self.vertical = vertical
|
||||
|
||||
self.animation = QPropertyAnimation(self, 'current_pixmap_size', self)
|
||||
@ -79,8 +78,9 @@ class CoverView(QWidget): # {{{
|
||||
self.animation.setStartValue(QSize(0, 0))
|
||||
self.animation.valueChanged.connect(self.value_changed)
|
||||
|
||||
self.setSizePolicy(QSizePolicy.Expanding if vertical else
|
||||
QSizePolicy.Minimum, QSizePolicy.Expanding)
|
||||
self.setSizePolicy(
|
||||
QSizePolicy.Expanding if vertical else QSizePolicy.Minimum,
|
||||
QSizePolicy.Expanding)
|
||||
|
||||
self.default_pixmap = QPixmap(I('book.png'))
|
||||
self.pixmap = self.default_pixmap
|
||||
@ -109,20 +109,6 @@ class CoverView(QWidget): # {{{
|
||||
self.current_pixmap_size = QSize(self.pwidth, self.pheight)
|
||||
self.animation.setEndValue(self.current_pixmap_size)
|
||||
|
||||
def relayout(self, parent_size):
|
||||
if self.vertical:
|
||||
self.setMaximumSize(parent_size.width(),
|
||||
min(int(parent_size.height()/2.),int(4/3. * parent_size.width())+1))
|
||||
else:
|
||||
self.setMaximumSize(1+int(3/4. * parent_size.height()),
|
||||
parent_size.height())
|
||||
self.resize(self.maximumSize())
|
||||
self.animation.stop()
|
||||
self.do_layout()
|
||||
|
||||
def sizeHint(self):
|
||||
return self.maximumSize()
|
||||
|
||||
def show_data(self, data):
|
||||
self.animation.stop()
|
||||
same_item = data.get('id', True) == self.data.get('id', False)
|
||||
@ -165,70 +151,185 @@ class CoverView(QWidget): # {{{
|
||||
# }}}
|
||||
|
||||
# Book Info {{{
|
||||
class Label(QLabel):
|
||||
|
||||
mr = pyqtSignal(object)
|
||||
class RenderComments(QThread):
|
||||
|
||||
rdone = pyqtSignal(object, object)
|
||||
|
||||
def __init__(self, parent):
|
||||
QThread.__init__(self, parent)
|
||||
self.queue = Queue()
|
||||
self.start()
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
try:
|
||||
rows, comments = self.queue.get()
|
||||
except:
|
||||
break
|
||||
import time
|
||||
time.sleep(0.001)
|
||||
oint = sys.getcheckinterval()
|
||||
sys.setcheckinterval(5)
|
||||
try:
|
||||
self.rdone.emit(rows, comments_to_html(comments))
|
||||
except:
|
||||
pass
|
||||
sys.setcheckinterval(oint)
|
||||
|
||||
|
||||
class BookInfo(QWebView):
|
||||
|
||||
link_clicked = pyqtSignal(object)
|
||||
|
||||
def __init__(self):
|
||||
QLabel.__init__(self)
|
||||
self.setTextFormat(Qt.RichText)
|
||||
self.setText('')
|
||||
self.setWordWrap(True)
|
||||
self.setAlignment(Qt.AlignTop)
|
||||
self.linkActivated.connect(self.link_activated)
|
||||
def __init__(self, vertical, parent=None):
|
||||
QWebView.__init__(self, parent)
|
||||
self.vertical = vertical
|
||||
self.renderer = RenderComments(self)
|
||||
self.renderer.rdone.connect(self._show_data, type=Qt.QueuedConnection)
|
||||
self.page().setLinkDelegationPolicy(self.page().DelegateAllLinks)
|
||||
self.linkClicked.connect(self.link_activated)
|
||||
self._link_clicked = False
|
||||
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||
|
||||
def link_activated(self, link):
|
||||
self._link_clicked = True
|
||||
link = unicode(link)
|
||||
link = unicode(link.toString())
|
||||
self.link_clicked.emit(link)
|
||||
|
||||
def mouseReleaseEvent(self, ev):
|
||||
QLabel.mouseReleaseEvent(self, ev)
|
||||
if not self._link_clicked:
|
||||
self.mr.emit(ev)
|
||||
self._link_clicked = False
|
||||
|
||||
class BookInfo(QScrollArea):
|
||||
|
||||
def __init__(self, vertical, parent=None):
|
||||
QScrollArea.__init__(self, parent)
|
||||
self.vertical = vertical
|
||||
self.setWidgetResizable(True)
|
||||
self.label = Label()
|
||||
self.setWidget(self.label)
|
||||
self.link_clicked = self.label.link_clicked
|
||||
self.mr = self.label.mr
|
||||
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||
def turnoff_scrollbar(self, *args):
|
||||
self.page().mainFrame().setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff)
|
||||
|
||||
def show_data(self, data):
|
||||
self.label.setText('')
|
||||
rows = render_rows(data)
|
||||
rows = u'\n'.join([u'<tr><td valign="top"><b>%s:</b></td><td valign="top">%s</td></tr>'%(k,t) for
|
||||
k, t in rows])
|
||||
comments = ''
|
||||
if data.get(_('Comments'), '') not in ('', u'None'):
|
||||
comments = data[_('Comments')]
|
||||
comments = comments_to_html(comments)
|
||||
comments = data.get(_('Comments'), '')
|
||||
if comments and comments != u'None':
|
||||
self.renderer.queue.put((rows, comments))
|
||||
self._show_data(rows, '')
|
||||
|
||||
|
||||
def _show_data(self, rows, comments):
|
||||
f = QFontInfo(QApplication.font(self.parent())).pixelSize()
|
||||
p = unicode(QApplication.palette().color(QPalette.Normal,
|
||||
QPalette.Base).name())
|
||||
templ = u'''\
|
||||
<html>
|
||||
<head>
|
||||
<style type="text/css">
|
||||
body, td {background-color: %s; font-size: %dpx}
|
||||
a { text-decoration: none; color: blue }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
%%s
|
||||
</body>
|
||||
<html>
|
||||
'''%(p, f)
|
||||
if self.vertical:
|
||||
if comments:
|
||||
rows += u'<tr><td colspan="2">%s</td></tr>'%comments
|
||||
self.label.setText(u'<table>%s</table>'%rows)
|
||||
self.setHtml(templ%(u'<table>%s</table>'%rows))
|
||||
else:
|
||||
left_pane = u'<table>%s</table>'%rows
|
||||
right_pane = u'<div>%s</div>'%comments
|
||||
self.label.setText(u'<table><tr><td valign="top" '
|
||||
self.setHtml(templ%(u'<table><tr><td valign="top" '
|
||||
'style="padding-right:2em">%s</td><td valign="top">%s</td></tr></table>'
|
||||
% (left_pane, right_pane))
|
||||
% (left_pane, right_pane)))
|
||||
|
||||
def mouseDoubleClickEvent(self, ev):
|
||||
ev.ignore()
|
||||
|
||||
# }}}
|
||||
|
||||
class DetailsLayout(QLayout): # {{{
|
||||
|
||||
def __init__(self, vertical, parent):
|
||||
QLayout.__init__(self, parent)
|
||||
self.vertical = vertical
|
||||
self._children = []
|
||||
|
||||
self.min_size = QSize(190, 200) if vertical else QSize(120, 120)
|
||||
self.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
def minimumSize(self):
|
||||
return QSize(self.min_size)
|
||||
|
||||
def addItem(self, child):
|
||||
if len(self._children) > 2:
|
||||
raise ValueError('This layout can only manage two children')
|
||||
self._children.append(child)
|
||||
|
||||
def itemAt(self, i):
|
||||
try:
|
||||
return self._children[i]
|
||||
except:
|
||||
pass
|
||||
return None
|
||||
|
||||
def takeAt(self, i):
|
||||
try:
|
||||
self._children.pop(i)
|
||||
except:
|
||||
pass
|
||||
return None
|
||||
|
||||
def count(self):
|
||||
return len(self._children)
|
||||
|
||||
def sizeHint(self):
|
||||
return QSize(self.min_size)
|
||||
|
||||
def setGeometry(self, r):
|
||||
QLayout.setGeometry(self, r)
|
||||
self.do_layout(r)
|
||||
|
||||
def cover_height(self, r):
|
||||
mh = min(int(r.height()/2.), int(4/3. * r.width())+1)
|
||||
try:
|
||||
ph = self._children[0].widget().pixmap.height()
|
||||
except:
|
||||
ph = 0
|
||||
if ph > 0:
|
||||
mh = min(mh, ph)
|
||||
return mh
|
||||
|
||||
def cover_width(self, r):
|
||||
mw = 1 + int(3/4. * r.height())
|
||||
try:
|
||||
pw = self._children[0].widget().pixmap.width()
|
||||
except:
|
||||
pw = 0
|
||||
if pw > 0:
|
||||
mw = min(mw, pw)
|
||||
return mw
|
||||
|
||||
|
||||
def do_layout(self, rect):
|
||||
if len(self._children) != 2:
|
||||
return
|
||||
left, top, right, bottom = self.getContentsMargins()
|
||||
r = rect.adjusted(+left, +top, -right, -bottom)
|
||||
x = r.x()
|
||||
y = r.y()
|
||||
cover, details = self._children
|
||||
if self.vertical:
|
||||
ch = self.cover_height(r)
|
||||
cover.setGeometry(QRect(x, y, r.width(), ch))
|
||||
cover.widget().do_layout()
|
||||
y += ch + 5
|
||||
details.setGeometry(QRect(x, y, r.width(), r.height()-ch-5))
|
||||
else:
|
||||
cw = self.cover_width(r)
|
||||
cover.setGeometry(QRect(x, y, cw, r.height()))
|
||||
cover.widget().do_layout()
|
||||
x += cw + 5
|
||||
details.setGeometry(QRect(x, y, r.width() - cw - 5, r.height()))
|
||||
|
||||
# }}}
|
||||
|
||||
class BookDetails(QWidget): # {{{
|
||||
|
||||
resized = pyqtSignal(object)
|
||||
show_book_info = pyqtSignal()
|
||||
open_containing_folder = pyqtSignal(int)
|
||||
view_specific_format = pyqtSignal(int, object)
|
||||
@ -269,23 +370,14 @@ class BookDetails(QWidget): # {{{
|
||||
def __init__(self, vertical, parent=None):
|
||||
QWidget.__init__(self, parent)
|
||||
self.setAcceptDrops(True)
|
||||
self._layout = QVBoxLayout()
|
||||
if not vertical:
|
||||
self._layout.setDirection(self._layout.LeftToRight)
|
||||
self._layout = DetailsLayout(vertical, self)
|
||||
self.setLayout(self._layout)
|
||||
|
||||
self.cover_view = CoverView(vertical, self)
|
||||
self.cover_view.relayout(self.size())
|
||||
self.resized.connect(self.cover_view.relayout, type=Qt.QueuedConnection)
|
||||
self._layout.addWidget(self.cover_view)
|
||||
self.book_info = BookInfo(vertical, self)
|
||||
self._layout.addWidget(self.book_info)
|
||||
self.book_info.link_clicked.connect(self._link_clicked)
|
||||
self.book_info.mr.connect(self.mouseReleaseEvent)
|
||||
if vertical:
|
||||
self.setMinimumSize(QSize(190, 200))
|
||||
else:
|
||||
self.setMinimumSize(120, 120)
|
||||
self.setCursor(Qt.PointingHandCursor)
|
||||
|
||||
def _link_clicked(self, link):
|
||||
@ -299,17 +391,15 @@ class BookDetails(QWidget): # {{{
|
||||
open_local_file(val)
|
||||
|
||||
|
||||
def mouseReleaseEvent(self, ev):
|
||||
def mouseDoubleClickEvent(self, ev):
|
||||
ev.accept()
|
||||
self.show_book_info.emit()
|
||||
|
||||
def resizeEvent(self, ev):
|
||||
self.resized.emit(self.size())
|
||||
|
||||
def show_data(self, data):
|
||||
self.cover_view.show_data(data)
|
||||
self.book_info.show_data(data)
|
||||
self.setToolTip('<p>'+_('Click to open Book Details window') +
|
||||
self.cover_view.show_data(data)
|
||||
self._layout.do_layout(self.rect())
|
||||
self.setToolTip('<p>'+_('Double-click to open Book Details window') +
|
||||
'<br><br>' + _('Path') + ': ' + data.get(_('Path'), ''))
|
||||
|
||||
def reset_info(self):
|
||||
|
@ -28,6 +28,8 @@ def gui_catalog(fmt, title, dbspec, ids, out_file_name, sync, fmt_options, conne
|
||||
if log is None:
|
||||
log = Log()
|
||||
from calibre.library import db
|
||||
from calibre.utils.config import prefs
|
||||
prefs.refresh()
|
||||
db = db()
|
||||
db.catalog_plugin_on_device_temp_mapping = dbspec
|
||||
|
||||
|
@ -108,7 +108,7 @@ class BookInfo(QDialog, Ui_BookInfo):
|
||||
lines = comments.splitlines()
|
||||
lines = [x if x.strip() else '<br><br>' for x in lines]
|
||||
comments = '\n'.join(lines)
|
||||
self.comments.setText('<div>%s</div>' % comments)
|
||||
self.comments.setHtml('<div>%s</div>' % comments)
|
||||
cdata = info.pop('cover', '')
|
||||
self.cover_pixmap = QPixmap.fromImage(cdata)
|
||||
self.resize_cover()
|
||||
|
@ -49,7 +49,19 @@
|
||||
</property>
|
||||
<layout class="QGridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QTextBrowser" name="comments"/>
|
||||
<widget class="QWebView" name="comments">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>350</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="url">
|
||||
<url>
|
||||
<string>about:blank</string>
|
||||
</url>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
@ -91,6 +103,13 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QWebView</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>QtWebKit/QWebView</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../../../../resources/images.qrc"/>
|
||||
</resources>
|
||||
|
@ -456,7 +456,7 @@ Using this button to create author sort will change author sort from red to gree
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>130</height>
|
||||
<height>140</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="dragDropMode">
|
||||
|
@ -8,7 +8,7 @@ __docformat__ = 'restructuredtext en'
|
||||
from functools import partial
|
||||
|
||||
from PyQt4.Qt import QIcon, Qt, QWidget, QToolBar, QSize, \
|
||||
pyqtSignal, QToolButton, \
|
||||
pyqtSignal, QToolButton, QPushButton, \
|
||||
QObject, QVBoxLayout, QSizePolicy, QLabel, QHBoxLayout, QActionGroup, \
|
||||
QMenu
|
||||
|
||||
@ -151,6 +151,7 @@ class SearchBar(QWidget): # {{{
|
||||
QWidget.__init__(self, parent)
|
||||
self._layout = l = QHBoxLayout()
|
||||
self.setLayout(self._layout)
|
||||
self._layout.setContentsMargins(0,5,0,0)
|
||||
|
||||
x = ComboBoxWithHelp(self)
|
||||
x.setMaximumSize(QSize(150, 16777215))
|
||||
@ -170,16 +171,20 @@ class SearchBar(QWidget): # {{{
|
||||
l.addWidget(x)
|
||||
x.setToolTip(_("Advanced search"))
|
||||
|
||||
self.label = x = QLabel(_('&Search:'))
|
||||
l.addWidget(self.label)
|
||||
x.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
|
||||
|
||||
x = parent.search = SearchBox2(self)
|
||||
x.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
|
||||
x.setObjectName("search")
|
||||
x.setToolTip(_("<p>Search the list of books by title, author, publisher, tags, comments, etc.<br><br>Words separated by spaces are ANDed"))
|
||||
l.addWidget(x)
|
||||
|
||||
self.search_button = QPushButton(_('&Go!'))
|
||||
l.addWidget(self.search_button)
|
||||
self.search_button.setSizePolicy(QSizePolicy.Minimum,
|
||||
QSizePolicy.Minimum)
|
||||
self.search_button.clicked.connect(parent.search.do_search)
|
||||
self.search_button.setToolTip(
|
||||
_('Do Quick Search (you can also press the Enter key)'))
|
||||
|
||||
x = parent.clear_button = QToolButton(self)
|
||||
x.setIcon(QIcon(I('clear_left.png')))
|
||||
x.setObjectName("clear_button")
|
||||
@ -210,7 +215,6 @@ class SearchBar(QWidget): # {{{
|
||||
l.addWidget(x)
|
||||
x.setToolTip(_("Delete current saved search"))
|
||||
|
||||
self.label.setBuddy(parent.search)
|
||||
|
||||
|
||||
# }}}
|
||||
|
@ -233,17 +233,10 @@ class BooksModel(QAbstractTableModel): # {{{
|
||||
|
||||
def delete_books_by_id(self, ids):
|
||||
for id in ids:
|
||||
try:
|
||||
row = self.db.row(id)
|
||||
except:
|
||||
row = -1
|
||||
if row > -1:
|
||||
self.beginRemoveRows(QModelIndex(), row, row)
|
||||
self.db.delete_book(id)
|
||||
if row > -1:
|
||||
self.endRemoveRows()
|
||||
self.count_changed()
|
||||
self.clear_caches()
|
||||
self.reset()
|
||||
|
||||
def books_added(self, num):
|
||||
if num > 0:
|
||||
@ -335,7 +328,7 @@ class BooksModel(QAbstractTableModel): # {{{
|
||||
sidx = self.db.series_index(idx)
|
||||
sidx = fmt_sidx(sidx, use_roman = self.use_roman_numbers)
|
||||
data[_('Series')] = \
|
||||
_('Book <font face="serif">%s</font> of %s.')%\
|
||||
_('Book %s of %s.')%\
|
||||
(sidx, prepare_string_for_xml(series))
|
||||
mi = self.db.get_metadata(idx)
|
||||
for key in mi.custom_field_keys():
|
||||
|
@ -50,6 +50,8 @@ class BooksView(QTableView): # {{{
|
||||
def __init__(self, parent, modelcls=BooksModel):
|
||||
QTableView.__init__(self, parent)
|
||||
|
||||
self.setEditTriggers(self.SelectedClicked|self.EditKeyPressed)
|
||||
|
||||
self.drag_allowed = True
|
||||
self.setDragEnabled(True)
|
||||
self.setDragDropOverwriteMode(False)
|
||||
@ -98,6 +100,8 @@ class BooksView(QTableView): # {{{
|
||||
self._model.about_to_be_sorted.connect(self.about_to_be_sorted)
|
||||
self._model.sorting_done.connect(self.sorting_done)
|
||||
|
||||
self.doubleClicked.connect(parent.iactions['View'].view_triggered)
|
||||
|
||||
# Column Header Context Menu {{{
|
||||
def column_header_context_handler(self, action=None, column=None):
|
||||
if not action or not column:
|
||||
@ -385,7 +389,8 @@ class BooksView(QTableView): # {{{
|
||||
self.save_state()
|
||||
self._model.set_database(db)
|
||||
self.tags_delegate.set_database(db)
|
||||
self.authors_delegate.set_auto_complete_function(db.all_authors)
|
||||
self.authors_delegate.set_auto_complete_function(
|
||||
lambda: [(x, y.replace('|', ',')) for (x, y) in db.all_authors()])
|
||||
self.series_delegate.set_auto_complete_function(db.all_series)
|
||||
self.publisher_delegate.set_auto_complete_function(db.all_publishers)
|
||||
|
||||
|
@ -345,6 +345,7 @@ def main(args=sys.argv):
|
||||
# On windows only singleinstance can be trusted
|
||||
otherinstance = True if iswindows else False
|
||||
if not otherinstance:
|
||||
sys.setcheckinterval(50) # Make GUI more responsive
|
||||
return run_gui(opts, args, actions, listener, app)
|
||||
|
||||
communicate(args)
|
||||
|
@ -148,6 +148,10 @@ class SearchBox2(QComboBox):
|
||||
self.line_edit.setStyleSheet('QLineEdit { color: black; background-color: %s; }' % col)
|
||||
|
||||
def key_pressed(self, event):
|
||||
k = event.key()
|
||||
if k in (Qt.Key_Left, Qt.Key_Right, Qt.Key_Up, Qt.Key_Down,
|
||||
Qt.Key_Home, Qt.Key_End, Qt.Key_PageUp, Qt.Key_PageDown):
|
||||
return
|
||||
self.normalize_state()
|
||||
if self._in_a_search:
|
||||
self.emit(SIGNAL('changed()'))
|
||||
@ -159,8 +163,11 @@ class SearchBox2(QComboBox):
|
||||
|
||||
def mouse_released(self, event):
|
||||
self.normalize_state()
|
||||
if self.as_you_type:
|
||||
self.timer.start(1500)
|
||||
# Dont trigger a search since it make
|
||||
# re-positioning the cursor using the mouse
|
||||
# impossible
|
||||
#if self.as_you_type:
|
||||
# self.timer.start(1500)
|
||||
|
||||
def timer_event(self):
|
||||
self.do_search()
|
||||
@ -176,7 +183,7 @@ class SearchBox2(QComboBox):
|
||||
return ''
|
||||
return text
|
||||
|
||||
def do_search(self):
|
||||
def do_search(self, *args):
|
||||
text = unicode(self.currentText()).strip()
|
||||
if not text or text == self.help_text:
|
||||
return self.clear()
|
||||
@ -365,7 +372,7 @@ class SearchBoxMixin(object):
|
||||
self.search.setMaximumWidth(self.width()-150)
|
||||
self.action_focus_search = QAction(self)
|
||||
shortcuts = QKeySequence.keyBindings(QKeySequence.Find)
|
||||
shortcuts = list(shortcuts) + [QKeySequence('/')]
|
||||
shortcuts = list(shortcuts) + [QKeySequence('/'), QKeySequence('Alt+S')]
|
||||
self.action_focus_search.setShortcuts(shortcuts)
|
||||
self.action_focus_search.triggered.connect(lambda x:
|
||||
self.search.setFocus(Qt.OtherFocusReason))
|
||||
|
@ -861,6 +861,7 @@ class TagBrowserWidget(QWidget): # {{{
|
||||
QWidget.__init__(self, parent)
|
||||
self._layout = QVBoxLayout()
|
||||
self.setLayout(self._layout)
|
||||
self._layout.setContentsMargins(0,0,0,0)
|
||||
|
||||
parent.tags_view = TagsView(parent)
|
||||
self._layout.addWidget(parent.tags_view)
|
||||
|
@ -358,10 +358,11 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
|
||||
def toc_clicked(self, index):
|
||||
item = self.toc_model.itemFromIndex(index)
|
||||
url = QUrl.fromLocalFile(item.abspath)
|
||||
if item.fragment:
|
||||
url.setFragment(item.fragment)
|
||||
self.link_clicked(url)
|
||||
if item.abspath is not None:
|
||||
url = QUrl.fromLocalFile(item.abspath)
|
||||
if item.fragment:
|
||||
url.setFragment(item.fragment)
|
||||
self.link_clicked(url)
|
||||
|
||||
def selection_changed(self, selected_text):
|
||||
self.selected_text = selected_text.strip()
|
||||
|
@ -128,7 +128,7 @@ class ContentServer(object):
|
||||
if want_mobile:
|
||||
return self.mobile()
|
||||
|
||||
return self.browse_toplevel()
|
||||
return self.browse_catalog()
|
||||
|
||||
def old(self, **kwargs):
|
||||
return self.static('index.html').replace('{prefix}',
|
||||
|
@ -5,7 +5,7 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import sys
|
||||
import sys, os
|
||||
from threading import Thread
|
||||
|
||||
from calibre.library.server import server_config as config
|
||||
@ -63,15 +63,47 @@ The OPDS interface is advertised via BonJour automatically.
|
||||
' work in all environments.'))
|
||||
return parser
|
||||
|
||||
def daemonize(stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
|
||||
try:
|
||||
pid = os.fork()
|
||||
if pid > 0:
|
||||
# exit first parent
|
||||
sys.exit(0)
|
||||
except OSError, e:
|
||||
print >>sys.stderr, "fork #1 failed: %d (%s)" % (e.errno, e.strerror)
|
||||
sys.exit(1)
|
||||
|
||||
# decouple from parent environment
|
||||
os.chdir("/")
|
||||
os.setsid()
|
||||
os.umask(0)
|
||||
|
||||
# do second fork
|
||||
try:
|
||||
pid = os.fork()
|
||||
if pid > 0:
|
||||
# exit from second parent
|
||||
sys.exit(0)
|
||||
except OSError, e:
|
||||
print >>sys.stderr, "fork #2 failed: %d (%s)" % (e.errno, e.strerror)
|
||||
sys.exit(1)
|
||||
|
||||
# Redirect standard file descriptors.
|
||||
si = file(stdin, 'r')
|
||||
so = file(stdout, 'a+')
|
||||
se = file(stderr, 'a+', 0)
|
||||
os.dup2(si.fileno(), sys.stdin.fileno())
|
||||
os.dup2(so.fileno(), sys.stdout.fileno())
|
||||
os.dup2(se.fileno(), sys.stderr.fileno())
|
||||
|
||||
|
||||
|
||||
def main(args=sys.argv):
|
||||
from calibre.library.database2 import LibraryDatabase2
|
||||
parser = option_parser()
|
||||
opts, args = parser.parse_args(args)
|
||||
if opts.daemonize and not iswindows:
|
||||
from cherrypy.process.plugins import Daemonizer
|
||||
d = Daemonizer(cherrypy.engine)
|
||||
d.subscribe()
|
||||
daemonize()
|
||||
if opts.pidfile is not None:
|
||||
from cherrypy.process.plugins import PIDFile
|
||||
PIDFile(cherrypy.engine, opts.pidfile).subscribe()
|
||||
|
@ -338,6 +338,8 @@ Calibre has several keyboard shortcuts to save you time and mouse movement. Thes
|
||||
|
||||
* - Keyboard Shortcut
|
||||
- Action
|
||||
* - :kbd:`F2 (Enter in OS X)`
|
||||
- Edit the metadata of the currently selected field in the book list.
|
||||
* - :kbd:`A`
|
||||
- Add Books
|
||||
* - :kbd:`C`
|
||||
|
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
@ -7,14 +7,14 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: calibre\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2010-10-28 00:31+0000\n"
|
||||
"PO-Revision-Date: 2010-10-28 17:43+0000\n"
|
||||
"POT-Creation-Date: 2010-10-29 19:59+0000\n"
|
||||
"PO-Revision-Date: 2010-10-29 19:53+0000\n"
|
||||
"Last-Translator: Antón Méixome <meixome@gmail.com>\n"
|
||||
"Language-Team: Galician <gl@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: 2010-10-29 05:23+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-10-30 05:03+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:43
|
||||
@ -38,8 +38,8 @@ msgstr "Non facer nada"
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/chm/metadata.py:56
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:407
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/periodical.py:124
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/fb2/input.py:70
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/fb2/input.py:72
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/fb2/input.py:93
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/fb2/input.py:95
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/html/input.py:336
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/html/input.py:339
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1894
|
||||
@ -54,7 +54,7 @@ msgstr "Non facer nada"
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:606
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/ereader.py:36
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/ereader.py:61
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/fb2.py:49
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/fb2.py:50
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/fetch.py:333
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/meta.py:36
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/meta.py:64
|
||||
@ -145,7 +145,7 @@ msgstr "Non facer nada"
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:2161
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:2163
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:2295
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:224
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:228
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:139
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:142
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/xml.py:78
|
||||
@ -267,45 +267,45 @@ msgstr "Define os metadatos nos ficheiros %s"
|
||||
msgid "Set metadata from %s files"
|
||||
msgstr "Define os metadatos desde os ficheiros %s"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:706
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:708
|
||||
msgid "Look and Feel"
|
||||
msgstr "Aparencia e comportamento"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:708
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:720
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:731
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:742
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:710
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:722
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:733
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:744
|
||||
msgid "Interface"
|
||||
msgstr "Interface"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:712
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:714
|
||||
msgid "Adjust the look and feel of the calibre interface to suit your tastes"
|
||||
msgstr ""
|
||||
"Axuste a aparencia e comportamento da interface do Calibre para que se "
|
||||
"adapte aos seus gustos"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:718
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:720
|
||||
msgid "Behavior"
|
||||
msgstr "Comportamento"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:724
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:726
|
||||
msgid "Change the way calibre behaves"
|
||||
msgstr "Cambiar o modo en que se comporta o Calibre"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:729
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:731
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:202
|
||||
msgid "Add your own columns"
|
||||
msgstr "Engadir as súas propias columnas"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:735
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:737
|
||||
msgid "Add/remove your own columns to the calibre book list"
|
||||
msgstr "Engadir/retirar as columnas propias da lista de libros do Calibre"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:740
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:742
|
||||
msgid "Customize the toolbar"
|
||||
msgstr "Personalizar a barra de ferramentas"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:746
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:748
|
||||
msgid ""
|
||||
"Customize the toolbars and context menus, changing which actions are "
|
||||
"available in each"
|
||||
@ -313,60 +313,60 @@ msgstr ""
|
||||
"Personalizar as barras de ferramentas e os menús de contexto, cambiando as "
|
||||
"accións que estarán dispoñíbeis en cada un"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:752
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:754
|
||||
msgid "Input Options"
|
||||
msgstr "Opcións de entrada"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:754
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:765
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:776
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:756
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:767
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:778
|
||||
msgid "Conversion"
|
||||
msgstr "Conversión"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:758
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:760
|
||||
msgid "Set conversion options specific to each input format"
|
||||
msgstr ""
|
||||
"Estabelecer as opcións de conversión específicas para cada formato de entrada"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:763
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:765
|
||||
msgid "Common Options"
|
||||
msgstr "Opcións comúns"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:769
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:771
|
||||
msgid "Set conversion options common to all formats"
|
||||
msgstr "Estabelecer as opcións de conversión comúns para todos os formatos"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:774
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:776
|
||||
msgid "Output Options"
|
||||
msgstr "Opcións de saída"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:780
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:782
|
||||
msgid "Set conversion options specific to each output format"
|
||||
msgstr ""
|
||||
"Estabelece as opcións específicas de conversión para cada formato de saída"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:785
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:787
|
||||
msgid "Adding books"
|
||||
msgstr "Adición de libros"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:787
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:799
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:811
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:823
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:789
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:801
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:813
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:825
|
||||
msgid "Import/Export"
|
||||
msgstr "Importar/exportar"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:791
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:793
|
||||
msgid "Control how calibre reads metadata from files when adding books"
|
||||
msgstr ""
|
||||
"Controla o modo como Calibre le os metadatos dos ficheiros na proceso de "
|
||||
"adición de libros"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:797
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:799
|
||||
msgid "Saving books to disk"
|
||||
msgstr "Gardado de libros no disco"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:803
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:805
|
||||
msgid ""
|
||||
"Control how calibre exports files from its database to disk when using Save "
|
||||
"to disk"
|
||||
@ -374,33 +374,33 @@ msgstr ""
|
||||
"Controla o modo como Calibre exporta ficheiros da súa base de datos no "
|
||||
"disco no proceso de Gardado no disco"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:809
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:811
|
||||
msgid "Sending books to devices"
|
||||
msgstr "Envío de libros a dispositivos"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:815
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:817
|
||||
msgid "Control how calibre transfers files to your ebook reader"
|
||||
msgstr ""
|
||||
"Controla cando Calibre transfere os ficheiros ao seu lector de libros"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:821
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:823
|
||||
msgid "Metadata plugboards"
|
||||
msgstr "Plugboards de metadatos"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:827
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:829
|
||||
msgid "Change metadata fields before saving/sending"
|
||||
msgstr "Cambiar campos de metadatos antes do gardado/envío"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:832
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:834
|
||||
msgid "Sharing books by email"
|
||||
msgstr "Compartición de libros por correo"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:834
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:846
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:836
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:848
|
||||
msgid "Sharing"
|
||||
msgstr "Compartición"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:838
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:840
|
||||
msgid ""
|
||||
"Setup sharing of books via email. Can be used for automatic sending of "
|
||||
"downloaded news to your devices"
|
||||
@ -408,11 +408,11 @@ msgstr ""
|
||||
"Configura a compartición de libros por correo electrónico. Pódese usar para "
|
||||
"enviar automticamente as noticias descargadas aos seus dispositivos"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:844
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:846
|
||||
msgid "Sharing over the net"
|
||||
msgstr "Compartición na rede"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:850
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:852
|
||||
msgid ""
|
||||
"Setup the calibre Content Server which will give you access to your calibre "
|
||||
"library from anywhere, on any device, over the internet"
|
||||
@ -421,33 +421,33 @@ msgstr ""
|
||||
"biblioteca do Calibre en calquera lugar, con calquera dispositivo, a través "
|
||||
"da Internet."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:857
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:859
|
||||
msgid "Plugins"
|
||||
msgstr "Complementos"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:859
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:871
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:882
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:861
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:873
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:884
|
||||
msgid "Advanced"
|
||||
msgstr "Avanzado"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:863
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:865
|
||||
msgid "Add/remove/customize various bits of calibre functionality"
|
||||
msgstr "Engadir/eliminar/configurar diversas funcións do Calibre"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:869
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:871
|
||||
msgid "Tweaks"
|
||||
msgstr "Axustes"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:875
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:877
|
||||
msgid "Fine tune how calibre behaves in various contexts"
|
||||
msgstr "Axuste fino de como se comporta o Calibre en diversos contextos"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:880
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:882
|
||||
msgid "Miscellaneous"
|
||||
msgstr "Miscelánea"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:886
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:888
|
||||
msgid "Miscellaneous advanced configuration"
|
||||
msgstr "Configuración miscelánea avanzada"
|
||||
|
||||
@ -611,7 +611,7 @@ msgstr ""
|
||||
msgid "This profile is intended for the Amazon Kindle DX."
|
||||
msgstr "Este perfil é o propio o Amazon Kindle DX."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:663
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:664
|
||||
msgid "This profile is intended for the Sanda Bambook."
|
||||
msgstr "Este perfil está pensado para o Sandra Bambook."
|
||||
|
||||
@ -1024,11 +1024,11 @@ msgstr "Comunicar co Kogan"
|
||||
msgid "Communicate with the Pandigital Novel"
|
||||
msgstr "Conectar co Pandigital Novel"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/misc.py:124
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/misc.py:130
|
||||
msgid "Communicate with the VelocityMicro"
|
||||
msgstr "Comunicar con VelocityMono"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/misc.py:142
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/misc.py:148
|
||||
msgid "Communicate with the GM2000"
|
||||
msgstr "Comunicar co GM2000"
|
||||
|
||||
@ -1089,11 +1089,15 @@ msgstr "Comunicar co lector Teclast K3/K5."
|
||||
msgid "Communicate with the Newsmy reader."
|
||||
msgstr "Comunicar co lector de Newsmy"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/teclast/driver.py:48
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/teclast/driver.py:47
|
||||
msgid "Communicate with the Pico reader."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/teclast/driver.py:57
|
||||
msgid "Communicate with the iPapyrus reader."
|
||||
msgstr "Comunicar co lector de iPapyrus."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/teclast/driver.py:59
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/teclast/driver.py:68
|
||||
msgid "Communicate with the Sovos reader."
|
||||
msgstr "Comunicar co lector Sovos."
|
||||
|
||||
@ -2040,7 +2044,7 @@ msgstr ""
|
||||
"opción, a imaxe pode distorsionarse, mais non terá bordos."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/output.py:170
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:205
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:203
|
||||
msgid "Start"
|
||||
msgstr "Iniciar"
|
||||
|
||||
@ -2435,7 +2439,7 @@ msgstr "Si"
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:380
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:930
|
||||
#: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:303
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:569
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:570
|
||||
msgid "Title"
|
||||
msgstr "Título"
|
||||
|
||||
@ -2479,7 +2483,7 @@ msgstr "Comentarios"
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:320
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1134
|
||||
#: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:160
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:608
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:618
|
||||
msgid "Tags"
|
||||
msgstr "Etiquetas"
|
||||
|
||||
@ -2909,7 +2913,7 @@ msgstr "Opcións da xeración HTM TOC"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/transforms/jacket.py:153
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:71
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:606
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:616
|
||||
msgid "Rating"
|
||||
msgstr "Avaliación"
|
||||
|
||||
@ -3279,7 +3283,7 @@ msgstr ""
|
||||
"Calibre. Convértao primeiro a HTML e ténteo despois.\n"
|
||||
"%s"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:32
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:25
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/tcr/output.py:23
|
||||
msgid ""
|
||||
"Specify the character encoding of the output document. The default is utf-8."
|
||||
@ -3287,7 +3291,7 @@ msgstr ""
|
||||
"Especifique a codificación de caracteres do documento de saída. A "
|
||||
"predeterminada é UTF-8."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:39
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:29
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/txt/output.py:38
|
||||
msgid ""
|
||||
"The maximum number of characters per line. This splits on the first space "
|
||||
@ -3301,17 +3305,34 @@ msgstr ""
|
||||
"de haber un mínimo de 25 caracteres. Se, pola contra, desexa desactivar a "
|
||||
"quebra de liña, empregue o 0."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:124
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:36
|
||||
msgid ""
|
||||
"Specify whether or not to insert an empty line between two paragraphs."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:40
|
||||
msgid ""
|
||||
"Specify whether or not to insert two space characters to indent the first "
|
||||
"line of each paragraph."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:44
|
||||
msgid ""
|
||||
"Specify whether or not to hide the chapter title for each chapter. Useful "
|
||||
"for image-only output (eg. comics)."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:122
|
||||
msgid "Start Page"
|
||||
msgstr "Páxina de inicio"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:132
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:134
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:136
|
||||
msgid "Cover Pages"
|
||||
msgstr "Portadas"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:149
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:152
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:147
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:150
|
||||
msgid " (Preface)"
|
||||
msgstr " (Prefacio)"
|
||||
|
||||
@ -3492,7 +3513,7 @@ msgid "Disable UI animations"
|
||||
msgstr "Desactivar as animacións UI"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:183
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:487
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:494
|
||||
msgid "Copied"
|
||||
msgstr "Copiado"
|
||||
|
||||
@ -3504,7 +3525,7 @@ msgstr "Copiar"
|
||||
msgid "Copy to Clipboard"
|
||||
msgstr "Copiar no Portapapeis"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:466
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:467
|
||||
msgid "Choose Files"
|
||||
msgstr "Escoller os Ficheiros"
|
||||
|
||||
@ -4410,7 +4431,7 @@ msgid "Click the show details button to see which ones."
|
||||
msgstr "Prema o botón de amosar detalles para os ver."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/show_book_details.py:16
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:613
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:623
|
||||
msgid "Show book details"
|
||||
msgstr "Amosar os detalles do libro"
|
||||
|
||||
@ -4868,7 +4889,7 @@ msgstr "saída"
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_input_ui.py:43
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:47
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/rb_output_ui.py:33
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/snb_output_ui.py:28
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/snb_output_ui.py:39
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/structure_detection_ui.py:80
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/toc_ui.py:67
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/txt_input_ui.py:51
|
||||
@ -5768,6 +5789,18 @@ msgstr ""
|
||||
msgid "SNB Output"
|
||||
msgstr "Saída SNB"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/snb_output_ui.py:40
|
||||
msgid "Hide chapter name"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/snb_output_ui.py:41
|
||||
msgid "Insert space before the first line for each paragraph"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/snb_output_ui.py:42
|
||||
msgid "Insert empty line between paragraphs"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/structure_detection.py:17
|
||||
msgid ""
|
||||
"Structure\n"
|
||||
@ -6166,8 +6199,8 @@ msgid "Send and delete from library"
|
||||
msgstr "Enviar e borrar da biblioteca"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/device.py:492
|
||||
msgid "Send specific format"
|
||||
msgstr "Enviar un formato específico"
|
||||
msgid "Send specific format to"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/device.py:528
|
||||
msgid "Eject device"
|
||||
@ -6505,7 +6538,7 @@ msgid "No location selected"
|
||||
msgstr "Non seleccionou unha localización"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_library.py:84
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:628
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:635
|
||||
msgid "Bad location"
|
||||
msgstr "Localización incorrecta"
|
||||
|
||||
@ -6586,7 +6619,7 @@ msgstr "Localización"
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:932
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/preferences/create_custom_column.py:31
|
||||
#: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:294
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:568
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:569
|
||||
msgid "Date"
|
||||
msgstr "Data"
|
||||
|
||||
@ -7234,76 +7267,77 @@ msgid "This ISBN number is invalid"
|
||||
msgstr "O ISBN non é correcto"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:611
|
||||
msgid "Cannot use tag editor"
|
||||
msgstr "Non se pode empregar o editor de etiquetas"
|
||||
msgid "Tags changed"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:612
|
||||
msgid "The tags editor cannot be used if you have modified the tags"
|
||||
msgid ""
|
||||
"You have changed the tags. In order to use the tags editor, you must either "
|
||||
"discard or apply these changes"
|
||||
msgstr ""
|
||||
"O editor de etiquetas non se pode empregar se se modificaron as etiquetas"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:632
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:639
|
||||
msgid "Downloading cover..."
|
||||
msgstr "A descargar a capa..."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:644
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:649
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:655
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:660
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:651
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:656
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:662
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:667
|
||||
msgid "Cannot fetch cover"
|
||||
msgstr "Non se puido obter a capa"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:645
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:656
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:661
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:652
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:663
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:668
|
||||
msgid "<b>Could not fetch cover.</b><br/>"
|
||||
msgstr "<b>Non se puido obter a capa</b><br/>"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:646
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:653
|
||||
msgid "The download timed out."
|
||||
msgstr "Expirou o tempo de descarga"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:650
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:657
|
||||
msgid "Could not find cover for this book. Try specifying the ISBN first."
|
||||
msgstr ""
|
||||
"Non se achou unha capa para este libro; tente especificar primeiro o ISBN."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:662
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:669
|
||||
msgid ""
|
||||
"For the error message from each cover source, click Show details below."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:669
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:676
|
||||
msgid "Bad cover"
|
||||
msgstr "Capa incorrecta"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:670
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:677
|
||||
msgid "The cover is not a valid picture"
|
||||
msgstr "A capa non é unha imaxe válida"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:703
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:710
|
||||
msgid "There were errors"
|
||||
msgstr "Houbo algúns erros"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:704
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:711
|
||||
msgid "There were errors downloading social metadata"
|
||||
msgstr "Houbo algúns erros ao descargar os metadatos sociais"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:735
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:742
|
||||
msgid "Cannot fetch metadata"
|
||||
msgstr "Non é posíbel oter metadatos"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:736
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:743
|
||||
msgid "You must specify at least one of ISBN, Title, Authors or Publisher"
|
||||
msgstr ""
|
||||
"Ten de especificar, cando menos, un dos seguintes: ISBN, título, autoría ou "
|
||||
"editorial."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:823
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:833
|
||||
msgid "Permission denied"
|
||||
msgstr "Permiso denegado"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:824
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:834
|
||||
msgid "Could not open %s. Is it being used by another program?"
|
||||
msgstr "Non se pode abri %s. Estará a se empregar cun outro programa?"
|
||||
|
||||
@ -8645,7 +8679,7 @@ msgid "Do not check for updates"
|
||||
msgstr "Non comprobar se hai actualizacións"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:58
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:636
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:643
|
||||
msgid "Calibre Library"
|
||||
msgstr "Biblioteca do Calibre"
|
||||
|
||||
@ -8813,7 +8847,7 @@ msgid "Successfully downloaded metadata for %d out of %d books"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/metadata.py:287
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:612
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:622
|
||||
msgid "Details"
|
||||
msgstr ""
|
||||
|
||||
@ -10726,59 +10760,59 @@ msgstr ""
|
||||
msgid "Toggle"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:378
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:385
|
||||
msgid ""
|
||||
"If you use the WordPlayer e-book app on your Android phone, you can access "
|
||||
"your calibre book collection directly on the device. To do this you have to "
|
||||
"turn on the content server."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:382
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:389
|
||||
msgid ""
|
||||
"Remember to leave calibre running as the server only runs as long as calibre "
|
||||
"is running."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:384
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:391
|
||||
msgid ""
|
||||
"You have to add the URL http://myhostname:8080 as your calibre library in "
|
||||
"WordPlayer. Here myhostname should be the fully qualified hostname or the IP "
|
||||
"address of the computer calibre is running on."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:461
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:468
|
||||
msgid "Moving library..."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:477
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:478
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:484
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:485
|
||||
msgid "Failed to move library"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:532
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:539
|
||||
msgid "Invalid database"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:533
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:540
|
||||
msgid ""
|
||||
"<p>An invalid library already exists at %s, delete it before trying to move "
|
||||
"the existing library.<br>Error: %s"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:544
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:551
|
||||
msgid "Could not move library"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:615
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:622
|
||||
msgid "Select location for books"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:629
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:636
|
||||
msgid ""
|
||||
"You must choose an empty folder for the calibre library. %s is not empty."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:703
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:710
|
||||
msgid "welcome wizard"
|
||||
msgstr ""
|
||||
|
||||
@ -11956,12 +11990,18 @@ msgid ""
|
||||
"disable grouping."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/base.py:131
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/__init__.py:48
|
||||
msgid ""
|
||||
"Prefix to prepend to all URLs. Useful for reverseproxying to this server "
|
||||
"from Apache/nginx/etc."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/base.py:149
|
||||
msgid "Password to access your calibre library. Username is "
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:51
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:399
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:401
|
||||
msgid "Loading, please wait"
|
||||
msgstr ""
|
||||
|
||||
@ -12006,74 +12046,74 @@ msgstr ""
|
||||
msgid "Sort by"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:307
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:505
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:568
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:308
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:512
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:569
|
||||
msgid "Newest"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:308
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:506
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:309
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:513
|
||||
msgid "All books"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:340
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:341
|
||||
msgid "Browse books by"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:345
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:346
|
||||
msgid "Choose a category to browse by:"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:418
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:421
|
||||
msgid "Browsing by"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:419
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:422
|
||||
msgid "Up"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:535
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:543
|
||||
msgid "in"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:538
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:546
|
||||
msgid "Books in"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:588
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:597
|
||||
msgid "Other formats"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:595
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:604
|
||||
msgid "Read %s in the %s format"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:600
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:609
|
||||
msgid "Get"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:614
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:624
|
||||
msgid "Permalink"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:615
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:625
|
||||
msgid "A permanent link to this book"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:626
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:636
|
||||
msgid "This book has been deleted"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:707
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:720
|
||||
msgid "in search"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:709
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:722
|
||||
msgid "Matching books"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/main.py:28
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/main.py:39
|
||||
msgid ""
|
||||
"[options]\n"
|
||||
"\n"
|
||||
@ -12086,15 +12126,15 @@ msgid ""
|
||||
"The OPDS interface is advertised via BonJour automatically.\n"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/main.py:41
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/main.py:52
|
||||
msgid "Path to the library folder to serve with the content server"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/main.py:43
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/main.py:54
|
||||
msgid "Write process PID to the specified file"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/main.py:47
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/main.py:58
|
||||
msgid ""
|
||||
"Specifies a restriction to be used for this invocation. This option "
|
||||
"overrides any per-library settings specified in the GUI"
|
||||
@ -12424,93 +12464,93 @@ msgstr ""
|
||||
msgid "Unknown News Source"
|
||||
msgstr "Fonte de Novas Descoñecida"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:615
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:614
|
||||
msgid "The \"%s\" recipe needs a username and password."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:714
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:713
|
||||
msgid "Download finished"
|
||||
msgstr "Rematou a descarga"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:716
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:715
|
||||
msgid "Failed to download the following articles:"
|
||||
msgstr "Produciuse un fallo na descarga dos seguintes artigos:"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:722
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:721
|
||||
msgid "Failed to download parts of the following articles:"
|
||||
msgstr "Produciuse un fallo na descarga de partes do seguintes artigos:"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:724
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:723
|
||||
msgid " from "
|
||||
msgstr " desde "
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:726
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:725
|
||||
msgid "\tFailed links:"
|
||||
msgstr "\tLigazóns erradas:"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:815
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:814
|
||||
msgid "Could not fetch article. Run with -vv to see the reason"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:836
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:835
|
||||
msgid "Fetching feeds..."
|
||||
msgstr "A obter os fluxos..."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:841
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:840
|
||||
msgid "Got feeds from index page"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:850
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:849
|
||||
msgid "Trying to download cover..."
|
||||
msgstr "Tratando de descargar a capa..."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:852
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:851
|
||||
msgid "Generating masthead..."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:933
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:932
|
||||
msgid "Starting download [%d thread(s)]..."
|
||||
msgstr "A comezar a descarga [%d fío(s)]..."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:949
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:948
|
||||
msgid "Feeds downloaded to %s"
|
||||
msgstr "Fluxos descargados en %s"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:958
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:957
|
||||
msgid "Could not download cover: %s"
|
||||
msgstr "Non se puido descargar a capa: %s"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:965
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:964
|
||||
msgid "Downloading cover from %s"
|
||||
msgstr "A descargar a capa desde %s"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1010
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1009
|
||||
msgid "Masthead image downloaded"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1178
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1177
|
||||
msgid "Untitled Article"
|
||||
msgstr "Artigo sen Título"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1249
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1248
|
||||
msgid "Article downloaded: %s"
|
||||
msgstr "Artigo descargado: %s"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1260
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1259
|
||||
msgid "Article download failed: %s"
|
||||
msgstr "Erro ao descargar o artigo: %s"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1277
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1276
|
||||
msgid "Fetching feed"
|
||||
msgstr "A obter o fluxo"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1424
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1423
|
||||
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:1439
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1438
|
||||
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."
|
||||
@ -12779,6 +12819,9 @@ msgstr "Non descargar follas de estilo CSS"
|
||||
#~ msgid "Force maximum line lenght"
|
||||
#~ msgstr "Obrigar á lonxitude máxima da liña"
|
||||
|
||||
#~ msgid "Send specific format"
|
||||
#~ msgstr "Enviar un formato específico"
|
||||
|
||||
#~ msgid "Fit &cover to view"
|
||||
#~ msgstr "Axustar a &capa á xanela"
|
||||
|
||||
@ -12944,6 +12987,13 @@ msgstr "Non descargar follas de estilo CSS"
|
||||
#~ "Así, se seleccionou o libro A e despois o Libro B,\n"
|
||||
#~ "o libro A será o número 1 e o libro B o número 2."
|
||||
|
||||
#~ msgid "Cannot use tag editor"
|
||||
#~ msgstr "Non se pode empregar o editor de etiquetas"
|
||||
|
||||
#~ msgid "The tags editor cannot be used if you have modified the tags"
|
||||
#~ msgstr ""
|
||||
#~ "O editor de etiquetas non se pode empregar se se modificaron as etiquetas"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Automatically create the author sort entry based on the current author entry"
|
||||
#~ msgstr ""
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -6,14 +6,14 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: calibre 0.4.55\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2010-10-28 00:31+0000\n"
|
||||
"PO-Revision-Date: 2010-10-28 13:56+0000\n"
|
||||
"Last-Translator: Vitaliy Starostin <Unknown>\n"
|
||||
"POT-Creation-Date: 2010-10-29 19:59+0000\n"
|
||||
"PO-Revision-Date: 2010-10-29 19:54+0000\n"
|
||||
"Last-Translator: Kovid Goyal <Unknown>\n"
|
||||
"Language-Team: American English <kde-i18n-doc@lists.kde.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2010-10-29 05:24+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-10-30 05:03+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
"X-Poedit-Country: RUSSIAN FEDERATION\n"
|
||||
"X-Poedit-Language: Russian\n"
|
||||
@ -42,8 +42,8 @@ msgstr "Ничего не делает"
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/chm/metadata.py:56
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:407
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/periodical.py:124
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/fb2/input.py:70
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/fb2/input.py:72
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/fb2/input.py:93
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/fb2/input.py:95
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/html/input.py:336
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/html/input.py:339
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1894
|
||||
@ -58,7 +58,7 @@ msgstr "Ничего не делает"
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:606
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/ereader.py:36
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/ereader.py:61
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/fb2.py:49
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/fb2.py:50
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/fetch.py:333
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/meta.py:36
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/meta.py:64
|
||||
@ -149,7 +149,7 @@ msgstr "Ничего не делает"
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:2161
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:2163
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:2295
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:224
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:228
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:139
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:142
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/xml.py:78
|
||||
@ -271,130 +271,130 @@ msgstr "Внести метаданные в файлы %s"
|
||||
msgid "Set metadata from %s files"
|
||||
msgstr "Внести метаданные из файлов %s"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:706
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:708
|
||||
msgid "Look and Feel"
|
||||
msgstr "Оформление"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:708
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:720
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:731
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:742
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:710
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:722
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:733
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:744
|
||||
msgid "Interface"
|
||||
msgstr "Интерфейс"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:712
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:714
|
||||
msgid "Adjust the look and feel of the calibre interface to suit your tastes"
|
||||
msgstr "Настройте внешний вид calibre по-своему вкусу"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:718
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:720
|
||||
msgid "Behavior"
|
||||
msgstr "Предпочтения"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:724
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:726
|
||||
msgid "Change the way calibre behaves"
|
||||
msgstr "Настройка поведения calibre"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:729
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:731
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:202
|
||||
msgid "Add your own columns"
|
||||
msgstr "Добавление колонок"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:735
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:737
|
||||
msgid "Add/remove your own columns to the calibre book list"
|
||||
msgstr "Добавление/удаление личных колонок в списке книг"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:740
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:742
|
||||
msgid "Customize the toolbar"
|
||||
msgstr "Настройка панели инструментов"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:746
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:748
|
||||
msgid ""
|
||||
"Customize the toolbars and context menus, changing which actions are "
|
||||
"available in each"
|
||||
msgstr ""
|
||||
"Настройка панели инструментов и контекстных меню, выбор доступных команд"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:752
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:754
|
||||
msgid "Input Options"
|
||||
msgstr "Параметры импорта"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:754
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:765
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:776
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:756
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:767
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:778
|
||||
msgid "Conversion"
|
||||
msgstr "Преобразование"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:758
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:760
|
||||
msgid "Set conversion options specific to each input format"
|
||||
msgstr "Установка параметров импорта, специфичных для каждого формата"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:763
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:765
|
||||
msgid "Common Options"
|
||||
msgstr "Общие настройки"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:769
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:771
|
||||
msgid "Set conversion options common to all formats"
|
||||
msgstr "Установка общих для всех форматов параметров конвертации"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:774
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:776
|
||||
msgid "Output Options"
|
||||
msgstr "Выходные параметры"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:780
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:782
|
||||
msgid "Set conversion options specific to each output format"
|
||||
msgstr "Установка параметров экспорта, специфичных для каждого формата"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:785
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:787
|
||||
msgid "Adding books"
|
||||
msgstr "Добавление книг"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:787
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:799
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:811
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:823
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:789
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:801
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:813
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:825
|
||||
msgid "Import/Export"
|
||||
msgstr "Импорт/Экспорт"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:791
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:793
|
||||
msgid "Control how calibre reads metadata from files when adding books"
|
||||
msgstr "Настройки чтения метаданных из добавляемых в библиотеку книг"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:797
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:799
|
||||
msgid "Saving books to disk"
|
||||
msgstr "Сохранить книги на диск"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:803
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:805
|
||||
msgid ""
|
||||
"Control how calibre exports files from its database to disk when using Save "
|
||||
"to disk"
|
||||
msgstr "Настройки записи книг из базы данных на диск"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:809
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:811
|
||||
msgid "Sending books to devices"
|
||||
msgstr "Отправить книги на устройство"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:815
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:817
|
||||
msgid "Control how calibre transfers files to your ebook reader"
|
||||
msgstr "Контроль передачи книжек на устройство"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:821
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:823
|
||||
msgid "Metadata plugboards"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:827
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:829
|
||||
msgid "Change metadata fields before saving/sending"
|
||||
msgstr "Изменять поля метаданных до сохранения/отправки"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:832
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:834
|
||||
msgid "Sharing books by email"
|
||||
msgstr "Отправить книжку по e-mail"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:834
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:846
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:836
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:848
|
||||
msgid "Sharing"
|
||||
msgstr "Общий доступ к файлам"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:838
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:840
|
||||
msgid ""
|
||||
"Setup sharing of books via email. Can be used for automatic sending of "
|
||||
"downloaded news to your devices"
|
||||
@ -402,11 +402,11 @@ msgstr ""
|
||||
"Настройка рассылки книг по e-mail. Может быть использована для "
|
||||
"автоматической доставки загруженных новостных лент на устройство"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:844
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:846
|
||||
msgid "Sharing over the net"
|
||||
msgstr "Сетевой доступ"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:850
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:852
|
||||
msgid ""
|
||||
"Setup the calibre Content Server which will give you access to your calibre "
|
||||
"library from anywhere, on any device, over the internet"
|
||||
@ -414,33 +414,33 @@ msgstr ""
|
||||
"Настройка http-сервера calibre, предоставляющего доступ к библиотеке с "
|
||||
"любого устройства, подключенного к сети интернет"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:857
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:859
|
||||
msgid "Plugins"
|
||||
msgstr "Модули"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:859
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:871
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:882
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:861
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:873
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:884
|
||||
msgid "Advanced"
|
||||
msgstr "Расширенный"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:863
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:865
|
||||
msgid "Add/remove/customize various bits of calibre functionality"
|
||||
msgstr "Добавить/удалить/изменить различные части функциональности calibre"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:869
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:871
|
||||
msgid "Tweaks"
|
||||
msgstr "Расширенные настройки"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:875
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:877
|
||||
msgid "Fine tune how calibre behaves in various contexts"
|
||||
msgstr "Тонкая настройка поведения calibre при различных контекстах"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:880
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:882
|
||||
msgid "Miscellaneous"
|
||||
msgstr "Разное"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:886
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:888
|
||||
msgid "Miscellaneous advanced configuration"
|
||||
msgstr "Различная продвинутая конфигурация"
|
||||
|
||||
@ -602,7 +602,7 @@ msgstr ""
|
||||
msgid "This profile is intended for the Amazon Kindle DX."
|
||||
msgstr "Профиль для Amazon Kindle DX."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:663
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:664
|
||||
msgid "This profile is intended for the Sanda Bambook."
|
||||
msgstr "Этот профиль предназначен для Sanda Bambook."
|
||||
|
||||
@ -1006,11 +1006,11 @@ msgstr "Соединиться с Kogan"
|
||||
msgid "Communicate with the Pandigital Novel"
|
||||
msgstr "Соединиться с Pandigital Novel"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/misc.py:124
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/misc.py:130
|
||||
msgid "Communicate with the VelocityMicro"
|
||||
msgstr "Подключиться к VelocityMicro"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/misc.py:142
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/misc.py:148
|
||||
msgid "Communicate with the GM2000"
|
||||
msgstr "Подключиться к GM2000"
|
||||
|
||||
@ -1071,11 +1071,15 @@ msgstr "Соединиться с Teclast K3/K5"
|
||||
msgid "Communicate with the Newsmy reader."
|
||||
msgstr "Соединиться с Newsmy"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/teclast/driver.py:48
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/teclast/driver.py:47
|
||||
msgid "Communicate with the Pico reader."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/teclast/driver.py:57
|
||||
msgid "Communicate with the iPapyrus reader."
|
||||
msgstr "Соединиться с iPapyrus"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/teclast/driver.py:59
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/teclast/driver.py:68
|
||||
msgid "Communicate with the Sovos reader."
|
||||
msgstr "Подключиться к Sovos"
|
||||
|
||||
@ -2003,7 +2007,7 @@ msgstr ""
|
||||
"полей по краям."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/output.py:170
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:205
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:203
|
||||
msgid "Start"
|
||||
msgstr "Начать"
|
||||
|
||||
@ -2396,7 +2400,7 @@ msgstr "Да"
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:380
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:930
|
||||
#: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:303
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:569
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:570
|
||||
msgid "Title"
|
||||
msgstr "Заголовок"
|
||||
|
||||
@ -2440,7 +2444,7 @@ msgstr "Комментарии"
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:320
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1134
|
||||
#: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:160
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:608
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:618
|
||||
msgid "Tags"
|
||||
msgstr "Теги"
|
||||
|
||||
@ -2863,7 +2867,7 @@ msgstr "Варианты создания HTML содержания"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/transforms/jacket.py:153
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:71
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:606
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:616
|
||||
msgid "Rating"
|
||||
msgstr "Оценка"
|
||||
|
||||
@ -3225,13 +3229,13 @@ msgstr ""
|
||||
"Преобразуйте его в HTML и попробуйте еще раз\n"
|
||||
"%s"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:32
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:25
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/tcr/output.py:23
|
||||
msgid ""
|
||||
"Specify the character encoding of the output document. The default is utf-8."
|
||||
msgstr "Укажите кодировку для создаваемого документа. По умолчанию utf-8."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:39
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:29
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/txt/output.py:38
|
||||
msgid ""
|
||||
"The maximum number of characters per line. This splits on the first space "
|
||||
@ -3246,17 +3250,34 @@ msgstr ""
|
||||
"строке превысит указанное. Минимально возможное значение - 25 символов. "
|
||||
"Укажите 0 для запрета переноса строк."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:124
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:36
|
||||
msgid ""
|
||||
"Specify whether or not to insert an empty line between two paragraphs."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:40
|
||||
msgid ""
|
||||
"Specify whether or not to insert two space characters to indent the first "
|
||||
"line of each paragraph."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:44
|
||||
msgid ""
|
||||
"Specify whether or not to hide the chapter title for each chapter. Useful "
|
||||
"for image-only output (eg. comics)."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:122
|
||||
msgid "Start Page"
|
||||
msgstr "Начальная страница"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:132
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:134
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:136
|
||||
msgid "Cover Pages"
|
||||
msgstr "Обложки"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:149
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:152
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:147
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:150
|
||||
msgid " (Preface)"
|
||||
msgstr " (Предисловие)"
|
||||
|
||||
@ -3424,7 +3445,7 @@ msgid "Disable UI animations"
|
||||
msgstr "Отключить анимацию пользовальского интерфейса"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:183
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:487
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:494
|
||||
msgid "Copied"
|
||||
msgstr "Скопирована"
|
||||
|
||||
@ -3436,7 +3457,7 @@ msgstr "Копировать"
|
||||
msgid "Copy to Clipboard"
|
||||
msgstr "Копирования в буфер обмена"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:466
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:467
|
||||
msgid "Choose Files"
|
||||
msgstr "Выберите файлы"
|
||||
|
||||
@ -4316,7 +4337,7 @@ msgid "Click the show details button to see which ones."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/show_book_details.py:16
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:613
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:623
|
||||
msgid "Show book details"
|
||||
msgstr "Показать подробности"
|
||||
|
||||
@ -4771,7 +4792,7 @@ msgstr "вывод"
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_input_ui.py:43
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:47
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/rb_output_ui.py:33
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/snb_output_ui.py:28
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/snb_output_ui.py:39
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/structure_detection_ui.py:80
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/toc_ui.py:67
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/txt_input_ui.py:51
|
||||
@ -5651,6 +5672,18 @@ msgstr "Использовать сохраненные настройки пр
|
||||
msgid "SNB Output"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/snb_output_ui.py:40
|
||||
msgid "Hide chapter name"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/snb_output_ui.py:41
|
||||
msgid "Insert space before the first line for each paragraph"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/snb_output_ui.py:42
|
||||
msgid "Insert empty line between paragraphs"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/structure_detection.py:17
|
||||
msgid ""
|
||||
"Structure\n"
|
||||
@ -6040,8 +6073,8 @@ msgid "Send and delete from library"
|
||||
msgstr "Отправить и удалить из библиотеки"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/device.py:492
|
||||
msgid "Send specific format"
|
||||
msgstr "Отправить определенный формат"
|
||||
msgid "Send specific format to"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/device.py:528
|
||||
msgid "Eject device"
|
||||
@ -6368,7 +6401,7 @@ msgid "No location selected"
|
||||
msgstr "Путь не выбран"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_library.py:84
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:628
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:635
|
||||
msgid "Bad location"
|
||||
msgstr "Неправильный путь"
|
||||
|
||||
@ -6447,7 +6480,7 @@ msgstr ""
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:932
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/preferences/create_custom_column.py:31
|
||||
#: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:294
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:568
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:569
|
||||
msgid "Date"
|
||||
msgstr "Дата"
|
||||
|
||||
@ -7043,72 +7076,74 @@ msgid "This ISBN number is invalid"
|
||||
msgstr "Этот номер ISBN недопустим"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:611
|
||||
msgid "Cannot use tag editor"
|
||||
msgstr "Не возможно использовать редактор тэгов"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:612
|
||||
msgid "The tags editor cannot be used if you have modified the tags"
|
||||
msgid "Tags changed"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:632
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:612
|
||||
msgid ""
|
||||
"You have changed the tags. In order to use the tags editor, you must either "
|
||||
"discard or apply these changes"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:639
|
||||
msgid "Downloading cover..."
|
||||
msgstr "Загрузка обложки..."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:644
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:649
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:655
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:660
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:651
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:656
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:662
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:667
|
||||
msgid "Cannot fetch cover"
|
||||
msgstr "Не могу получить обложку"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:645
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:656
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:661
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:652
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:663
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:668
|
||||
msgid "<b>Could not fetch cover.</b><br/>"
|
||||
msgstr "<b>Не могу получить обложку.</b><br/>"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:646
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:653
|
||||
msgid "The download timed out."
|
||||
msgstr "Таймаут загрузки"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:650
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:657
|
||||
msgid "Could not find cover for this book. Try specifying the ISBN first."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:662
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:669
|
||||
msgid ""
|
||||
"For the error message from each cover source, click Show details below."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:669
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:676
|
||||
msgid "Bad cover"
|
||||
msgstr "Плохая обложка"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:670
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:677
|
||||
msgid "The cover is not a valid picture"
|
||||
msgstr "Обложка с неправильной картинкой"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:703
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:710
|
||||
msgid "There were errors"
|
||||
msgstr "Произошли ошибки"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:704
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:711
|
||||
msgid "There were errors downloading social metadata"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:735
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:742
|
||||
msgid "Cannot fetch metadata"
|
||||
msgstr "Не могу доставить метаданные"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:736
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:743
|
||||
msgid "You must specify at least one of ISBN, Title, Authors or Publisher"
|
||||
msgstr "Нужно указаить ISBN, название, автора или издателя"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:823
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:833
|
||||
msgid "Permission denied"
|
||||
msgstr "Доступ запрещён"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:824
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:834
|
||||
msgid "Could not open %s. Is it being used by another program?"
|
||||
msgstr ""
|
||||
|
||||
@ -8412,7 +8447,7 @@ msgid "Do not check for updates"
|
||||
msgstr "Не проверять наличие обновлений"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:58
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:636
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:643
|
||||
msgid "Calibre Library"
|
||||
msgstr ""
|
||||
|
||||
@ -8572,7 +8607,7 @@ msgid "Successfully downloaded metadata for %d out of %d books"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/metadata.py:287
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:612
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:622
|
||||
msgid "Details"
|
||||
msgstr ""
|
||||
|
||||
@ -10467,59 +10502,59 @@ msgstr "Скрыть"
|
||||
msgid "Toggle"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:378
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:385
|
||||
msgid ""
|
||||
"If you use the WordPlayer e-book app on your Android phone, you can access "
|
||||
"your calibre book collection directly on the device. To do this you have to "
|
||||
"turn on the content server."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:382
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:389
|
||||
msgid ""
|
||||
"Remember to leave calibre running as the server only runs as long as calibre "
|
||||
"is running."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:384
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:391
|
||||
msgid ""
|
||||
"You have to add the URL http://myhostname:8080 as your calibre library in "
|
||||
"WordPlayer. Here myhostname should be the fully qualified hostname or the IP "
|
||||
"address of the computer calibre is running on."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:461
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:468
|
||||
msgid "Moving library..."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:477
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:478
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:484
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:485
|
||||
msgid "Failed to move library"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:532
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:539
|
||||
msgid "Invalid database"
|
||||
msgstr "Неверная база данных"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:533
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:540
|
||||
msgid ""
|
||||
"<p>An invalid library already exists at %s, delete it before trying to move "
|
||||
"the existing library.<br>Error: %s"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:544
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:551
|
||||
msgid "Could not move library"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:615
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:622
|
||||
msgid "Select location for books"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:629
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:636
|
||||
msgid ""
|
||||
"You must choose an empty folder for the calibre library. %s is not empty."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:703
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:710
|
||||
msgid "welcome wizard"
|
||||
msgstr ""
|
||||
|
||||
@ -11774,12 +11809,18 @@ msgid ""
|
||||
"disable grouping."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/base.py:131
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/__init__.py:48
|
||||
msgid ""
|
||||
"Prefix to prepend to all URLs. Useful for reverseproxying to this server "
|
||||
"from Apache/nginx/etc."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/base.py:149
|
||||
msgid "Password to access your calibre library. Username is "
|
||||
msgstr "Пароль для доступа в библиотеку. Имя пользователя "
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:51
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:399
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:401
|
||||
msgid "Loading, please wait"
|
||||
msgstr ""
|
||||
|
||||
@ -11824,74 +11865,74 @@ msgstr ""
|
||||
msgid "Sort by"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:307
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:505
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:568
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:308
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:512
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:569
|
||||
msgid "Newest"
|
||||
msgstr "Самый новый"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:308
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:506
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:309
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:513
|
||||
msgid "All books"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:340
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:341
|
||||
msgid "Browse books by"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:345
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:346
|
||||
msgid "Choose a category to browse by:"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:418
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:421
|
||||
msgid "Browsing by"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:419
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:422
|
||||
msgid "Up"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:535
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:543
|
||||
msgid "in"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:538
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:546
|
||||
msgid "Books in"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:588
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:597
|
||||
msgid "Other formats"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:595
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:604
|
||||
msgid "Read %s in the %s format"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:600
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:609
|
||||
msgid "Get"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:614
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:624
|
||||
msgid "Permalink"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:615
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:625
|
||||
msgid "A permanent link to this book"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:626
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:636
|
||||
msgid "This book has been deleted"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:707
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:720
|
||||
msgid "in search"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:709
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:722
|
||||
msgid "Matching books"
|
||||
msgstr "Соответствие книг"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/main.py:28
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/main.py:39
|
||||
msgid ""
|
||||
"[options]\n"
|
||||
"\n"
|
||||
@ -11904,15 +11945,15 @@ msgid ""
|
||||
"The OPDS interface is advertised via BonJour automatically.\n"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/main.py:41
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/main.py:52
|
||||
msgid "Path to the library folder to serve with the content server"
|
||||
msgstr "Путь к папке библиотеки, для обслуживания сервером"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/main.py:43
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/main.py:54
|
||||
msgid "Write process PID to the specified file"
|
||||
msgstr "Записать PID процесса в указанный файл"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/main.py:47
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/main.py:58
|
||||
msgid ""
|
||||
"Specifies a restriction to be used for this invocation. This option "
|
||||
"overrides any per-library settings specified in the GUI"
|
||||
@ -12249,87 +12290,87 @@ msgstr "Не загружать последнюю версию встроенн
|
||||
msgid "Unknown News Source"
|
||||
msgstr "Неизвестный новостной ресурс"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:615
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:614
|
||||
msgid "The \"%s\" recipe needs a username and password."
|
||||
msgstr "Рецепт \"%s\" требует имя пользожателя и пароль"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:714
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:713
|
||||
msgid "Download finished"
|
||||
msgstr "Закачка завершена"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:716
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:715
|
||||
msgid "Failed to download the following articles:"
|
||||
msgstr "Неудачная загрузка следующих статей:"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:722
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:721
|
||||
msgid "Failed to download parts of the following articles:"
|
||||
msgstr "Неудачная загрузка частей следующих статей:"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:724
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:723
|
||||
msgid " from "
|
||||
msgstr " из "
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:726
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:725
|
||||
msgid "\tFailed links:"
|
||||
msgstr "\tБитые ссылки:"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:815
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:814
|
||||
msgid "Could not fetch article. Run with -vv to see the reason"
|
||||
msgstr "Не может быть вызвана статья. Запустите с -w чтобы увидеть причину."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:836
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:835
|
||||
msgid "Fetching feeds..."
|
||||
msgstr "Вызываются заготовки..."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:841
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:840
|
||||
msgid "Got feeds from index page"
|
||||
msgstr "Получить заготовки для оглавления"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:850
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:849
|
||||
msgid "Trying to download cover..."
|
||||
msgstr "Попытка скачать обложку..."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:852
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:851
|
||||
msgid "Generating masthead..."
|
||||
msgstr "Создаем титульные данные..."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:933
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:932
|
||||
msgid "Starting download [%d thread(s)]..."
|
||||
msgstr "Начало загрузки [%d поток(и)]..."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:949
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:948
|
||||
msgid "Feeds downloaded to %s"
|
||||
msgstr "Заготовки закачиватся в %s"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:958
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:957
|
||||
msgid "Could not download cover: %s"
|
||||
msgstr "Невозможно скачать обложку: %s"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:965
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:964
|
||||
msgid "Downloading cover from %s"
|
||||
msgstr "Скачивается обложка из %s"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1010
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1009
|
||||
msgid "Masthead image downloaded"
|
||||
msgstr "Выходные данные изображения загрузили"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1178
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1177
|
||||
msgid "Untitled Article"
|
||||
msgstr "Статья без названия"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1249
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1248
|
||||
msgid "Article downloaded: %s"
|
||||
msgstr "Статья скачена: %s"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1260
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1259
|
||||
msgid "Article download failed: %s"
|
||||
msgstr "Ошибка загрузки статьи: %s"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1277
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1276
|
||||
msgid "Fetching feed"
|
||||
msgstr "Доставляется материал"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1424
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1423
|
||||
msgid ""
|
||||
"Failed to log in, check your username and password for the calibre "
|
||||
"Periodicals service."
|
||||
@ -12337,7 +12378,7 @@ msgstr ""
|
||||
"Не удалось выполнить вход, проверьте свое имя пользователя и пароль для "
|
||||
"службы Периодических изданий Calibre."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1439
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1438
|
||||
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."
|
||||
@ -14711,6 +14752,9 @@ msgstr "Не скачивать файлы стилей CSS."
|
||||
#~ msgid "&Saving books"
|
||||
#~ msgstr "&Сохранение книг"
|
||||
|
||||
#~ msgid "Cannot use tag editor"
|
||||
#~ msgstr "Не возможно использовать редактор тэгов"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Automatically create the author sort entry based on the current author entry"
|
||||
#~ msgstr ""
|
||||
@ -14767,6 +14811,9 @@ msgstr "Не скачивать файлы стилей CSS."
|
||||
#~ "навсегда <b>удалены</b> с вашего компьютера.<br><br> Вы <b>уверены</b> что "
|
||||
#~ "хотите продолжить?"
|
||||
|
||||
#~ msgid "Send specific format"
|
||||
#~ msgstr "Отправить определенный формат"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "The value <b>%d</b> you have chosen for the content server port is a system "
|
||||
#~ "port. Your operating system <b>may</b> not allow the server to run on this "
|
||||
|
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
@ -7,14 +7,14 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: calibre\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2010-10-28 00:31+0000\n"
|
||||
"PO-Revision-Date: 2010-10-29 01:45+0000\n"
|
||||
"Last-Translator: Li Fanxi <Unknown>\n"
|
||||
"POT-Creation-Date: 2010-10-29 19:59+0000\n"
|
||||
"PO-Revision-Date: 2010-10-29 19:52+0000\n"
|
||||
"Last-Translator: Kovid Goyal <Unknown>\n"
|
||||
"Language-Team: Simplified Chinese <wanglihao@gmail.com>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2010-10-29 05:26+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-10-30 05:04+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
"X-Poedit-Country: CHINA\n"
|
||||
"X-Poedit-Language: Chinese\n"
|
||||
@ -40,8 +40,8 @@ msgstr "不做任何处理"
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/chm/metadata.py:56
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:407
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/periodical.py:124
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/fb2/input.py:70
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/fb2/input.py:72
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/fb2/input.py:93
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/fb2/input.py:95
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/html/input.py:336
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/html/input.py:339
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1894
|
||||
@ -56,7 +56,7 @@ msgstr "不做任何处理"
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:606
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/ereader.py:36
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/ereader.py:61
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/fb2.py:49
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/fb2.py:50
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/fetch.py:333
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/meta.py:36
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/meta.py:64
|
||||
@ -147,7 +147,7 @@ msgstr "不做任何处理"
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:2161
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:2163
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:2295
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:224
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:228
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:139
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:142
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/xml.py:78
|
||||
@ -262,171 +262,171 @@ msgstr "设置 %s 文件的元数据"
|
||||
msgid "Set metadata from %s files"
|
||||
msgstr "从 %s 文件设置元数据"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:706
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:708
|
||||
msgid "Look and Feel"
|
||||
msgstr "外表和感受"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:708
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:720
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:731
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:742
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:710
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:722
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:733
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:744
|
||||
msgid "Interface"
|
||||
msgstr "界面"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:712
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:714
|
||||
msgid "Adjust the look and feel of the calibre interface to suit your tastes"
|
||||
msgstr "调整成你喜欢的外观"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:718
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:720
|
||||
msgid "Behavior"
|
||||
msgstr "操作方式"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:724
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:726
|
||||
msgid "Change the way calibre behaves"
|
||||
msgstr "改变calibre的操作方式"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:729
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:731
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:202
|
||||
msgid "Add your own columns"
|
||||
msgstr "增加栏目"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:735
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:737
|
||||
msgid "Add/remove your own columns to the calibre book list"
|
||||
msgstr "向calibre书籍列表中增加或删除你自定义的栏目"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:740
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:742
|
||||
msgid "Customize the toolbar"
|
||||
msgstr "自定义工具栏"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:746
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:748
|
||||
msgid ""
|
||||
"Customize the toolbars and context menus, changing which actions are "
|
||||
"available in each"
|
||||
msgstr "自定义工具栏和上下文菜单,设置它们所可以提供的功能"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:752
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:754
|
||||
msgid "Input Options"
|
||||
msgstr "输入选项"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:754
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:765
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:776
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:756
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:767
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:778
|
||||
msgid "Conversion"
|
||||
msgstr "转换"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:758
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:760
|
||||
msgid "Set conversion options specific to each input format"
|
||||
msgstr "设置针对特定输入格式的转换选项"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:763
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:765
|
||||
msgid "Common Options"
|
||||
msgstr "常规选项"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:769
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:771
|
||||
msgid "Set conversion options common to all formats"
|
||||
msgstr "设置所有输入格式共有的转换选项"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:774
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:776
|
||||
msgid "Output Options"
|
||||
msgstr "输出选项"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:780
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:782
|
||||
msgid "Set conversion options specific to each output format"
|
||||
msgstr "设置针对特定输出格式的转换选项"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:785
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:787
|
||||
msgid "Adding books"
|
||||
msgstr "增加图书"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:787
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:799
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:811
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:823
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:789
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:801
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:813
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:825
|
||||
msgid "Import/Export"
|
||||
msgstr "导入/导出"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:791
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:793
|
||||
msgid "Control how calibre reads metadata from files when adding books"
|
||||
msgstr "控制向calibre添加书籍时读取元数据的方式"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:797
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:799
|
||||
msgid "Saving books to disk"
|
||||
msgstr "保存图书到磁盘"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:803
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:805
|
||||
msgid ""
|
||||
"Control how calibre exports files from its database to disk when using Save "
|
||||
"to disk"
|
||||
msgstr "控制使用“保存到磁盘”功能时calibre从数据库导出文件的方式"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:809
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:811
|
||||
msgid "Sending books to devices"
|
||||
msgstr "发送图书到设备"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:815
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:817
|
||||
msgid "Control how calibre transfers files to your ebook reader"
|
||||
msgstr "控制calibre将文件传输到电子阅读器的方式"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:821
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:823
|
||||
msgid "Metadata plugboards"
|
||||
msgstr "元数据控制板"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:827
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:829
|
||||
msgid "Change metadata fields before saving/sending"
|
||||
msgstr "保存或发送前更改元数据域"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:832
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:834
|
||||
msgid "Sharing books by email"
|
||||
msgstr "通过Email分享图书"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:834
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:846
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:836
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:848
|
||||
msgid "Sharing"
|
||||
msgstr "分享"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:838
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:840
|
||||
msgid ""
|
||||
"Setup sharing of books via email. Can be used for automatic sending of "
|
||||
"downloaded news to your devices"
|
||||
msgstr "设置通过电子邮件分享图书。可用于在向阅读器下载新内容时自动发送通知。"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:844
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:846
|
||||
msgid "Sharing over the net"
|
||||
msgstr "通过网络分享"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:850
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:852
|
||||
msgid ""
|
||||
"Setup the calibre Content Server which will give you access to your calibre "
|
||||
"library from anywhere, on any device, over the internet"
|
||||
msgstr "设置calibre内容服务器以便通过网络在任何设备和地点访问到calibre书库。"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:857
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:859
|
||||
msgid "Plugins"
|
||||
msgstr "插件"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:859
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:871
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:882
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:861
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:873
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:884
|
||||
msgid "Advanced"
|
||||
msgstr "高级"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:863
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:865
|
||||
msgid "Add/remove/customize various bits of calibre functionality"
|
||||
msgstr "添回/删除/自定义各种calibre功能"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:869
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:871
|
||||
msgid "Tweaks"
|
||||
msgstr "优化调整"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:875
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:877
|
||||
msgid "Fine tune how calibre behaves in various contexts"
|
||||
msgstr "微调calibre在各种情况下的行为"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:880
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:882
|
||||
msgid "Miscellaneous"
|
||||
msgstr "杂项"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:886
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:888
|
||||
msgid "Miscellaneous advanced configuration"
|
||||
msgstr "其它高级选项"
|
||||
|
||||
@ -574,7 +574,7 @@ msgstr "该配置文件适用 SONY PRS 产品线,如 500/505/700 型号等,
|
||||
msgid "This profile is intended for the Amazon Kindle DX."
|
||||
msgstr "该配置文件适用 Amazon Kindle DX。"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:663
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:664
|
||||
msgid "This profile is intended for the Sanda Bambook."
|
||||
msgstr "该配置文件适用于盛大锦书(Bambook)。"
|
||||
|
||||
@ -970,11 +970,11 @@ msgstr "与 Kogan 通信"
|
||||
msgid "Communicate with the Pandigital Novel"
|
||||
msgstr "与Pandigital Novel通信"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/misc.py:124
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/misc.py:130
|
||||
msgid "Communicate with the VelocityMicro"
|
||||
msgstr "与VelocityMicro进行通讯"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/misc.py:142
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/misc.py:148
|
||||
msgid "Communicate with the GM2000"
|
||||
msgstr "与 GM2000 通信"
|
||||
|
||||
@ -1033,11 +1033,15 @@ msgstr "与 Teclast K3/K5 阅读器通信。"
|
||||
msgid "Communicate with the Newsmy reader."
|
||||
msgstr "与Newsmy阅读器通信。"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/teclast/driver.py:48
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/teclast/driver.py:47
|
||||
msgid "Communicate with the Pico reader."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/teclast/driver.py:57
|
||||
msgid "Communicate with the iPapyrus reader."
|
||||
msgstr "与iPapyrus阅读器通信。"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/teclast/driver.py:59
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/teclast/driver.py:68
|
||||
msgid "Communicate with the Sovos reader."
|
||||
msgstr "与 Sovos 阅读器通信。"
|
||||
|
||||
@ -1827,7 +1831,7 @@ msgstr ""
|
||||
"是图像本身不会被扭曲变形。不选该选项的话,图像可能会产生轻微的扭曲变形,但优点是不会出现空白边界。"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/output.py:170
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:205
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:203
|
||||
msgid "Start"
|
||||
msgstr "开始"
|
||||
|
||||
@ -2193,7 +2197,7 @@ msgstr "是"
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:380
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:930
|
||||
#: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:303
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:569
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:570
|
||||
msgid "Title"
|
||||
msgstr "标题"
|
||||
|
||||
@ -2237,7 +2241,7 @@ msgstr "注释"
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:320
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1134
|
||||
#: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:160
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:608
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:618
|
||||
msgid "Tags"
|
||||
msgstr "标签"
|
||||
|
||||
@ -2642,7 +2646,7 @@ msgstr "HTML 目录生成选项。"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/transforms/jacket.py:153
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:71
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:606
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:616
|
||||
msgid "Rating"
|
||||
msgstr "评分"
|
||||
|
||||
@ -2981,13 +2985,13 @@ msgstr ""
|
||||
"RTF 文件有 calibre 不支持的特性。先转换到 HTML 再试。\n"
|
||||
"%s"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:32
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:25
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/tcr/output.py:23
|
||||
msgid ""
|
||||
"Specify the character encoding of the output document. The default is utf-8."
|
||||
msgstr "指定输出文档的字符集编码。默认为 utf-8。"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:39
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:29
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/txt/output.py:38
|
||||
msgid ""
|
||||
"The maximum number of characters per line. This splits on the first space "
|
||||
@ -2997,17 +3001,34 @@ msgid ""
|
||||
msgstr ""
|
||||
"每行最多容纳字符数。程序将会自动寻找行中最后一个空格换行。如果行内无空格,则行宽将会超过超越此值,在下个空格处换行。此外,最小值为25。使用 0 禁用分行"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:124
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:36
|
||||
msgid ""
|
||||
"Specify whether or not to insert an empty line between two paragraphs."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:40
|
||||
msgid ""
|
||||
"Specify whether or not to insert two space characters to indent the first "
|
||||
"line of each paragraph."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:44
|
||||
msgid ""
|
||||
"Specify whether or not to hide the chapter title for each chapter. Useful "
|
||||
"for image-only output (eg. comics)."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:122
|
||||
msgid "Start Page"
|
||||
msgstr "起始页"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:132
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:134
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:136
|
||||
msgid "Cover Pages"
|
||||
msgstr "封面"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:149
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:152
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:147
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:150
|
||||
msgid " (Preface)"
|
||||
msgstr " 引言"
|
||||
|
||||
@ -3166,7 +3187,7 @@ msgid "Disable UI animations"
|
||||
msgstr "禁用界面动画"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:183
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:487
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:494
|
||||
msgid "Copied"
|
||||
msgstr "已复制"
|
||||
|
||||
@ -3178,7 +3199,7 @@ msgstr "复制"
|
||||
msgid "Copy to Clipboard"
|
||||
msgstr "复制到剪贴板"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:466
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:467
|
||||
msgid "Choose Files"
|
||||
msgstr "选择文件"
|
||||
|
||||
@ -4047,7 +4068,7 @@ msgid "Click the show details button to see which ones."
|
||||
msgstr "点击显示详情按钮查看具体哪些。"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/actions/show_book_details.py:16
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:613
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:623
|
||||
msgid "Show book details"
|
||||
msgstr "显示书籍详情"
|
||||
|
||||
@ -4482,7 +4503,7 @@ msgstr "输出"
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_input_ui.py:43
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:47
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/rb_output_ui.py:33
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/snb_output_ui.py:28
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/snb_output_ui.py:39
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/structure_detection_ui.py:80
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/toc_ui.py:67
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/txt_input_ui.py:51
|
||||
@ -5337,6 +5358,18 @@ msgstr "为指定书籍使用已存转换设定(&S)"
|
||||
msgid "SNB Output"
|
||||
msgstr "SNB 输出"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/snb_output_ui.py:40
|
||||
msgid "Hide chapter name"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/snb_output_ui.py:41
|
||||
msgid "Insert space before the first line for each paragraph"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/snb_output_ui.py:42
|
||||
msgid "Insert empty line between paragraphs"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/structure_detection.py:17
|
||||
msgid ""
|
||||
"Structure\n"
|
||||
@ -5727,8 +5760,8 @@ msgid "Send and delete from library"
|
||||
msgstr "发送并从书库中删除"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/device.py:492
|
||||
msgid "Send specific format"
|
||||
msgstr "发送指定格式"
|
||||
msgid "Send specific format to"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/device.py:528
|
||||
msgid "Eject device"
|
||||
@ -6049,7 +6082,7 @@ msgid "No location selected"
|
||||
msgstr "没有选择位置"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_library.py:84
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:628
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:635
|
||||
msgid "Bad location"
|
||||
msgstr "错误的位置"
|
||||
|
||||
@ -6128,7 +6161,7 @@ msgstr "位置"
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:932
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/preferences/create_custom_column.py:31
|
||||
#: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:294
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:568
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:569
|
||||
msgid "Date"
|
||||
msgstr "日期"
|
||||
|
||||
@ -6722,72 +6755,74 @@ msgid "This ISBN number is invalid"
|
||||
msgstr "ISBN 编号无效"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:611
|
||||
msgid "Cannot use tag editor"
|
||||
msgstr "无法使用标签编辑器"
|
||||
msgid "Tags changed"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:612
|
||||
msgid "The tags editor cannot be used if you have modified the tags"
|
||||
msgstr "如果你已经修改了标签,那么标签编辑器就无法使用"
|
||||
msgid ""
|
||||
"You have changed the tags. In order to use the tags editor, you must either "
|
||||
"discard or apply these changes"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:632
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:639
|
||||
msgid "Downloading cover..."
|
||||
msgstr "正在下载封面..."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:644
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:649
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:655
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:660
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:651
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:656
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:662
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:667
|
||||
msgid "Cannot fetch cover"
|
||||
msgstr "无法抓取封面"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:645
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:656
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:661
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:652
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:663
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:668
|
||||
msgid "<b>Could not fetch cover.</b><br/>"
|
||||
msgstr "<b>无法抓取封面。</b><br/>"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:646
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:653
|
||||
msgid "The download timed out."
|
||||
msgstr "下载超时。"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:650
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:657
|
||||
msgid "Could not find cover for this book. Try specifying the ISBN first."
|
||||
msgstr "无法找到书籍对应的封面。请尝试首先指定 ISBN。"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:662
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:669
|
||||
msgid ""
|
||||
"For the error message from each cover source, click Show details below."
|
||||
msgstr "每个封面源文件中的错误信息,点击在下边查看详情"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:669
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:676
|
||||
msgid "Bad cover"
|
||||
msgstr "非法封面"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:670
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:677
|
||||
msgid "The cover is not a valid picture"
|
||||
msgstr "封面不是有效图片"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:703
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:710
|
||||
msgid "There were errors"
|
||||
msgstr "出错"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:704
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:711
|
||||
msgid "There were errors downloading social metadata"
|
||||
msgstr "下载社会性元数据出错"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:735
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:742
|
||||
msgid "Cannot fetch metadata"
|
||||
msgstr "无法抓取元数据"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:736
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:743
|
||||
msgid "You must specify at least one of ISBN, Title, Authors or Publisher"
|
||||
msgstr "您必须设定 ISBN,标题,作者或出版商中的至少一个条件"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:823
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:833
|
||||
msgid "Permission denied"
|
||||
msgstr "权限拒绝"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:824
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:834
|
||||
msgid "Could not open %s. Is it being used by another program?"
|
||||
msgstr "无法打开 %s。它是否被其它程序占用。"
|
||||
|
||||
@ -8092,7 +8127,7 @@ msgid "Do not check for updates"
|
||||
msgstr "不检测更新"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:58
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:636
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:643
|
||||
msgid "Calibre Library"
|
||||
msgstr "Calibre 书库"
|
||||
|
||||
@ -8249,7 +8284,7 @@ msgid "Successfully downloaded metadata for %d out of %d books"
|
||||
msgstr "成功下载%d本书的元数据(共%d本)"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/metadata.py:287
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:612
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:622
|
||||
msgid "Details"
|
||||
msgstr ""
|
||||
|
||||
@ -10101,7 +10136,7 @@ msgstr "隐藏"
|
||||
msgid "Toggle"
|
||||
msgstr "触发器"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:378
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:385
|
||||
msgid ""
|
||||
"If you use the WordPlayer e-book app on your Android phone, you can access "
|
||||
"your calibre book collection directly on the device. To do this you have to "
|
||||
@ -10109,13 +10144,13 @@ msgid ""
|
||||
msgstr ""
|
||||
"若您使用 Android 手机上的 WordPlayer 电子书程序,您可以用设备直接访问您的 Calibre 书库。这需要您打开内容服务器。"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:382
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:389
|
||||
msgid ""
|
||||
"Remember to leave calibre running as the server only runs as long as calibre "
|
||||
"is running."
|
||||
msgstr "请记住保持 Calibre 运行,如此它才能一直提供服务。"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:384
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:391
|
||||
msgid ""
|
||||
"You have to add the URL http://myhostname:8080 as your calibre library in "
|
||||
"WordPlayer. Here myhostname should be the fully qualified hostname or the IP "
|
||||
@ -10124,39 +10159,39 @@ msgstr ""
|
||||
"您需要将 URL http://myhostname:8080 添加到您 WordPlayer 中的 Calibre 书库。此处 myhostname "
|
||||
"应为有效主机名或者您运行 Calibre 电脑的 IP 地址。"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:461
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:468
|
||||
msgid "Moving library..."
|
||||
msgstr "正在移动书库..."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:477
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:478
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:484
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:485
|
||||
msgid "Failed to move library"
|
||||
msgstr "移动书库错误"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:532
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:539
|
||||
msgid "Invalid database"
|
||||
msgstr "无效数据库"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:533
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:540
|
||||
msgid ""
|
||||
"<p>An invalid library already exists at %s, delete it before trying to move "
|
||||
"the existing library.<br>Error: %s"
|
||||
msgstr "<p>在 %s 已有无效书库,在试图移动现有书库前删除它。<br>错误:%s"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:544
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:551
|
||||
msgid "Could not move library"
|
||||
msgstr "无法移动书库"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:615
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:622
|
||||
msgid "Select location for books"
|
||||
msgstr "选择书籍位置"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:629
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:636
|
||||
msgid ""
|
||||
"You must choose an empty folder for the calibre library. %s is not empty."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:703
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:710
|
||||
msgid "welcome wizard"
|
||||
msgstr "欢迎向导"
|
||||
|
||||
@ -11397,12 +11432,18 @@ msgid ""
|
||||
"disable grouping."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/base.py:131
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/__init__.py:48
|
||||
msgid ""
|
||||
"Prefix to prepend to all URLs. Useful for reverseproxying to this server "
|
||||
"from Apache/nginx/etc."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/base.py:149
|
||||
msgid "Password to access your calibre library. Username is "
|
||||
msgstr "密码以访问您的 Calibre 书库。用户名为 "
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:51
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:399
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:401
|
||||
msgid "Loading, please wait"
|
||||
msgstr ""
|
||||
|
||||
@ -11447,74 +11488,74 @@ msgstr ""
|
||||
msgid "Sort by"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:307
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:505
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:568
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:308
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:512
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:569
|
||||
msgid "Newest"
|
||||
msgstr "最新"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:308
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:506
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:309
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:513
|
||||
msgid "All books"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:340
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:341
|
||||
msgid "Browse books by"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:345
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:346
|
||||
msgid "Choose a category to browse by:"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:418
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:421
|
||||
msgid "Browsing by"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:419
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:422
|
||||
msgid "Up"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:535
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:543
|
||||
msgid "in"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:538
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:546
|
||||
msgid "Books in"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:588
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:597
|
||||
msgid "Other formats"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:595
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:604
|
||||
msgid "Read %s in the %s format"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:600
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:609
|
||||
msgid "Get"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:614
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:624
|
||||
msgid "Permalink"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:615
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:625
|
||||
msgid "A permanent link to this book"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:626
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:636
|
||||
msgid "This book has been deleted"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:707
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:720
|
||||
msgid "in search"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:709
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:722
|
||||
msgid "Matching books"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/main.py:28
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/main.py:39
|
||||
msgid ""
|
||||
"[options]\n"
|
||||
"\n"
|
||||
@ -11527,15 +11568,15 @@ msgid ""
|
||||
"The OPDS interface is advertised via BonJour automatically.\n"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/main.py:41
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/main.py:52
|
||||
msgid "Path to the library folder to serve with the content server"
|
||||
msgstr "内容服务器上书库目录路径"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/main.py:43
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/main.py:54
|
||||
msgid "Write process PID to the specified file"
|
||||
msgstr "指定文件写进程 PID"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/main.py:47
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server/main.py:58
|
||||
msgid ""
|
||||
"Specifies a restriction to be used for this invocation. This option "
|
||||
"overrides any per-library settings specified in the GUI"
|
||||
@ -11865,93 +11906,93 @@ msgstr "不从 calire 服务器下载最新订阅清单"
|
||||
msgid "Unknown News Source"
|
||||
msgstr "未知新闻来源"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:615
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:614
|
||||
msgid "The \"%s\" recipe needs a username and password."
|
||||
msgstr "订阅清单“%s”需要用户名与密码。"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:714
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:713
|
||||
msgid "Download finished"
|
||||
msgstr "下载完成"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:716
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:715
|
||||
msgid "Failed to download the following articles:"
|
||||
msgstr "下载下列文章失败:"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:722
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:721
|
||||
msgid "Failed to download parts of the following articles:"
|
||||
msgstr "下载下列文章的某些部分失败:"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:724
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:723
|
||||
msgid " from "
|
||||
msgstr " 自 "
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:726
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:725
|
||||
msgid "\tFailed links:"
|
||||
msgstr "\t失败链接:"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:815
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:814
|
||||
msgid "Could not fetch article. Run with -vv to see the reason"
|
||||
msgstr "无法抓取文章。使用 -vv 选项运行察看原因。"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:836
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:835
|
||||
msgid "Fetching feeds..."
|
||||
msgstr "正在抓取源..."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:841
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:840
|
||||
msgid "Got feeds from index page"
|
||||
msgstr "从索引页面获取了源"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:850
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:849
|
||||
msgid "Trying to download cover..."
|
||||
msgstr "正在尝试下载封面..."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:852
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:851
|
||||
msgid "Generating masthead..."
|
||||
msgstr "正在生成刊头..."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:933
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:932
|
||||
msgid "Starting download [%d thread(s)]..."
|
||||
msgstr "开始下载 [ %d 线程数]..."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:949
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:948
|
||||
msgid "Feeds downloaded to %s"
|
||||
msgstr "新闻源下载到 %s"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:958
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:957
|
||||
msgid "Could not download cover: %s"
|
||||
msgstr "无法下载封面:%s"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:965
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:964
|
||||
msgid "Downloading cover from %s"
|
||||
msgstr "正在从 %s 下载封面"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1010
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1009
|
||||
msgid "Masthead image downloaded"
|
||||
msgstr "已下载刊头图像"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1178
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1177
|
||||
msgid "Untitled Article"
|
||||
msgstr "无标题文章"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1249
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1248
|
||||
msgid "Article downloaded: %s"
|
||||
msgstr "已下载文章:%s"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1260
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1259
|
||||
msgid "Article download failed: %s"
|
||||
msgstr "下载失败文章:%s"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1277
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1276
|
||||
msgid "Fetching feed"
|
||||
msgstr "抓取源"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1424
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1423
|
||||
msgid ""
|
||||
"Failed to log in, check your username and password for the calibre "
|
||||
"Periodicals service."
|
||||
msgstr "登录失败,检查您 calibre 期刊服务的用户名密码。"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1439
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1438
|
||||
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."
|
||||
@ -12468,6 +12509,9 @@ msgstr "不下载 CSS 样式表。"
|
||||
#~ msgid " "
|
||||
#~ msgstr " "
|
||||
|
||||
#~ msgid "Send specific format"
|
||||
#~ msgstr "发送指定格式"
|
||||
|
||||
#~ msgid "Library backup status..."
|
||||
#~ msgstr "书库备份状态..."
|
||||
|
||||
@ -12479,3 +12523,9 @@ msgstr "不下载 CSS 样式表。"
|
||||
|
||||
#~ msgid "Run the check"
|
||||
#~ msgstr "运行检查"
|
||||
|
||||
#~ msgid "Cannot use tag editor"
|
||||
#~ msgstr "无法使用标签编辑器"
|
||||
|
||||
#~ msgid "The tags editor cannot be used if you have modified the tags"
|
||||
#~ msgstr "如果你已经修改了标签,那么标签编辑器就无法使用"
|
||||
|
98
src/calibre/utils/browser.py
Normal file
98
src/calibre/utils/browser.py
Normal file
@ -0,0 +1,98 @@
|
||||
#!/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 copy
|
||||
from cookielib import CookieJar
|
||||
|
||||
from mechanize import Browser as B
|
||||
|
||||
class Browser(B):
|
||||
'A cloneable mechanize browser'
|
||||
|
||||
def __init__(self):
|
||||
self._clone_actions = {}
|
||||
|
||||
B.__init__(self)
|
||||
self.set_cookiejar(CookieJar())
|
||||
|
||||
def set_handle_refresh(self, *args, **kwargs):
|
||||
B.set_handle_refresh(self, *args, **kwargs)
|
||||
self._clone_actions['set_handle_refresh'] = ('set_handle_refresh',
|
||||
args, kwargs)
|
||||
|
||||
def set_cookiejar(self, *args, **kwargs):
|
||||
B.set_cookiejar(self, *args, **kwargs)
|
||||
self._clone_actions['set_cookiejar'] = ('set_cookiejar', args, kwargs)
|
||||
|
||||
def set_handle_redirect(self, *args, **kwargs):
|
||||
B.set_handle_redirect(self, *args, **kwargs)
|
||||
self._clone_actions['set_handle_redirect'] = ('set_handle_redirect',
|
||||
args, kwargs)
|
||||
|
||||
def set_handle_equiv(self, *args, **kwargs):
|
||||
B.set_handle_equiv(self, *args, **kwargs)
|
||||
self._clone_actions['set_handle_equiv'] = ('set_handle_equiv',
|
||||
args, kwargs)
|
||||
|
||||
def set_handle_gzip(self, *args, **kwargs):
|
||||
B.set_handle_gzip(self, *args, **kwargs)
|
||||
self._clone_actions['set_handle_gzip'] = ('set_handle_gzip',
|
||||
args, kwargs)
|
||||
|
||||
def set_debug_redirect(self, *args, **kwargs):
|
||||
B.set_debug_redirect(self, *args, **kwargs)
|
||||
self._clone_actions['set_debug_redirect'] = ('set_debug_redirect',
|
||||
args, kwargs)
|
||||
|
||||
def set_debug_responses(self, *args, **kwargs):
|
||||
B.set_debug_responses(self, *args, **kwargs)
|
||||
self._clone_actions['set_debug_responses'] = ('set_debug_responses',
|
||||
args, kwargs)
|
||||
|
||||
def set_debug_http(self, *args, **kwargs):
|
||||
B.set_debug_http(self, *args, **kwargs)
|
||||
self._clone_actions['set_debug_http'] = ('set_debug_http',
|
||||
args, kwargs)
|
||||
|
||||
def set_handle_robots(self, *args, **kwargs):
|
||||
B.set_handle_robots(self, *args, **kwargs)
|
||||
self._clone_actions['set_handle_robots'] = ('set_handle_robots',
|
||||
args, kwargs)
|
||||
|
||||
def set_proxies(self, *args, **kwargs):
|
||||
B.set_proxies(self, *args, **kwargs)
|
||||
self._clone_actions['set_proxies'] = ('set_proxies', args, kwargs)
|
||||
|
||||
def add_password(self, *args, **kwargs):
|
||||
B.add_password(self, *args, **kwargs)
|
||||
self._clone_actions['add_password'] = ('add_password', args, kwargs)
|
||||
|
||||
def add_proxy_password(self, *args, **kwargs):
|
||||
B.add_proxy_password(self, *args, **kwargs)
|
||||
self._clone_actions['add_proxy_password'] = ('add_proxy_password', args, kwargs)
|
||||
|
||||
def clone_browser(self):
|
||||
clone = Browser()
|
||||
clone.addheaders = copy.deepcopy(self.addheaders)
|
||||
for func, args, kwargs in self._clone_actions.values():
|
||||
func = getattr(clone, func)
|
||||
func(*args, **kwargs)
|
||||
return clone
|
||||
|
||||
if __name__ == '__main__':
|
||||
from calibre import browser
|
||||
from pprint import pprint
|
||||
orig = browser()
|
||||
clone = orig.clone_browser()
|
||||
pprint( orig._ua_handlers)
|
||||
pprint(clone._ua_handlers)
|
||||
assert orig._ua_handlers.keys() == clone._ua_handlers.keys()
|
||||
assert orig._ua_handlers['_cookies'].cookiejar is \
|
||||
clone._ua_handlers['_cookies'].cookiejar
|
||||
assert orig.addheaders == clone.addheaders
|
||||
|
||||
|
@ -82,9 +82,6 @@ class BasicNewsRecipe(Recipe):
|
||||
#: Automatically reduced to 1 if :attr:`BasicNewsRecipe.delay` > 0
|
||||
simultaneous_downloads = 5
|
||||
|
||||
#: If False the remote server is contacted by only one thread at a time
|
||||
multithreaded_fetch = False
|
||||
|
||||
#: Timeout for fetching files from server in seconds
|
||||
timeout = 120.0
|
||||
|
||||
@ -402,6 +399,23 @@ class BasicNewsRecipe(Recipe):
|
||||
'''
|
||||
return browser(*args, **kwargs)
|
||||
|
||||
def clone_browser(self, br):
|
||||
'''
|
||||
Clone the browser br. Cloned browsers are used for multi-threaded
|
||||
downloads, since mechanize is not thread safe. The default cloning
|
||||
routines should capture most browser customization, but if you do
|
||||
something exotic in your recipe, you should override this method in
|
||||
your recipe and clone manually.
|
||||
|
||||
Cloned browser instances use the same, thread-safe CookieJar by
|
||||
default, unless you have customized cookie handling.
|
||||
'''
|
||||
if callable(getattr(br, 'clone_browser', None)):
|
||||
return br.clone_browser()
|
||||
|
||||
# Uh-oh recipe using something exotic, call get_browser
|
||||
return self.get_browser()
|
||||
|
||||
def get_article_url(self, article):
|
||||
'''
|
||||
Override in a subclass to customize extraction of the :term:`URL` that points
|
||||
@ -798,17 +812,23 @@ class BasicNewsRecipe(Recipe):
|
||||
extra_css=css).render(doctype='xhtml')
|
||||
|
||||
|
||||
def _fetch_article(self, url, dir, f, a, num_of_feeds):
|
||||
self.web2disk_options.browser = self.get_browser() if self.multithreaded_fetch else self.browser
|
||||
def _fetch_article(self, url, dir_, f, a, num_of_feeds):
|
||||
br = self.browser
|
||||
if self.get_browser.im_func is BasicNewsRecipe.get_browser.im_func:
|
||||
# We are using the default get_browser, which means no need to
|
||||
# clone
|
||||
br = BasicNewsRecipe.get_browser(self)
|
||||
else:
|
||||
br = self.clone_browser(self.browser)
|
||||
self.web2disk_options.browser = br
|
||||
fetcher = RecursiveFetcher(self.web2disk_options, self.log,
|
||||
self.image_map, self.css_map,
|
||||
(url, f, a, num_of_feeds))
|
||||
fetcher.base_dir = dir
|
||||
fetcher.current_dir = dir
|
||||
fetcher.browser = br
|
||||
fetcher.base_dir = dir_
|
||||
fetcher.current_dir = dir_
|
||||
fetcher.show_progress = False
|
||||
fetcher.image_url_processor = self.image_url_processor
|
||||
if self.multithreaded_fetch:
|
||||
fetcher.browser_lock = fetcher.DUMMY_LOCK
|
||||
res, path, failures = fetcher.start_fetch(url), fetcher.downloaded_paths, fetcher.failed_links
|
||||
if not res or not os.path.exists(res):
|
||||
raise Exception(_('Could not fetch article. Run with -vv to see the reason'))
|
||||
@ -1387,7 +1407,7 @@ class CustomIndexRecipe(BasicNewsRecipe):
|
||||
def download(self):
|
||||
index = os.path.abspath(self.custom_index())
|
||||
url = 'file:'+index if iswindows else 'file://'+index
|
||||
self.web2disk_options.browser = self.browser
|
||||
self.web2disk_options.browser = self.clone_browser(self.browser)
|
||||
fetcher = RecursiveFetcher(self.web2disk_options, self.log)
|
||||
fetcher.base_dir = self.output_dir
|
||||
fetcher.current_dir = self.output_dir
|
||||
|
@ -86,11 +86,6 @@ class response(str):
|
||||
obj.newurl = None
|
||||
return obj
|
||||
|
||||
class DummyLock(object):
|
||||
|
||||
def __enter__(self, *args): return self
|
||||
def __exit__(self, *args): pass
|
||||
|
||||
def default_is_link_wanted(url, tag):
|
||||
raise NotImplementedError()
|
||||
|
||||
@ -104,7 +99,6 @@ class RecursiveFetcher(object):
|
||||
# )
|
||||
CSS_IMPORT_PATTERN = re.compile(r'\@import\s+url\((.*?)\)', re.IGNORECASE)
|
||||
default_timeout = socket.getdefaulttimeout() # Needed here as it is used in __del__
|
||||
DUMMY_LOCK = DummyLock()
|
||||
|
||||
def __init__(self, options, log, image_map={}, css_map={}, job_info=None):
|
||||
self.base_dir = os.path.abspath(os.path.expanduser(options.dir))
|
||||
|
87
src/templite/__init__.py
Normal file
87
src/templite/__init__.py
Normal file
@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Templite+
|
||||
# A light-weight, fully functional, general purpose templating engine
|
||||
#
|
||||
# Copyright (c) 2009 joonis new media
|
||||
# Author: Thimo Kraemer <thimo.kraemer@joonis.de>
|
||||
#
|
||||
# Based on Templite - Tomer Filiba
|
||||
# http://code.activestate.com/recipes/496702/
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
import sys, re
|
||||
|
||||
class Templite(object):
|
||||
auto_emit = re.compile('(^[\'\"])|(^[a-zA-Z0-9_\[\]\'\"]+$)')
|
||||
|
||||
def __init__(self, template, start='${', end='}$'):
|
||||
if len(start) != 2 or len(end) != 2:
|
||||
raise ValueError('each delimiter must be two characters long')
|
||||
delimiter = re.compile('%s(.*?)%s' % (re.escape(start), re.escape(end)), re.DOTALL)
|
||||
offset = 0
|
||||
tokens = []
|
||||
for i, part in enumerate(delimiter.split(template)):
|
||||
part = part.replace('\\'.join(list(start)), start)
|
||||
part = part.replace('\\'.join(list(end)), end)
|
||||
if i % 2 == 0:
|
||||
if not part: continue
|
||||
part = part.replace('\\', '\\\\').replace('"', '\\"')
|
||||
part = '\t' * offset + 'emit("""%s""")' % part
|
||||
else:
|
||||
part = part.rstrip()
|
||||
if not part: continue
|
||||
if part.lstrip().startswith(':'):
|
||||
if not offset:
|
||||
raise SyntaxError('no block statement to terminate: ${%s}$' % part)
|
||||
offset -= 1
|
||||
part = part.lstrip()[1:]
|
||||
if not part.endswith(':'): continue
|
||||
elif self.auto_emit.match(part.lstrip()):
|
||||
part = 'emit(%s)' % part.lstrip()
|
||||
lines = part.splitlines()
|
||||
margin = min(len(l) - len(l.lstrip()) for l in lines if l.strip())
|
||||
part = '\n'.join('\t' * offset + l[margin:] for l in lines)
|
||||
if part.endswith(':'):
|
||||
offset += 1
|
||||
tokens.append(part)
|
||||
if offset:
|
||||
raise SyntaxError('%i block statement(s) not terminated' % offset)
|
||||
self.__code = compile('\n'.join(tokens), '<templite %r>' % template[:20], 'exec')
|
||||
|
||||
def render(self, __namespace=None, **kw):
|
||||
"""
|
||||
renders the template according to the given namespace.
|
||||
__namespace - a dictionary serving as a namespace for evaluation
|
||||
**kw - keyword arguments which are added to the namespace
|
||||
"""
|
||||
namespace = {}
|
||||
if __namespace: namespace.update(__namespace)
|
||||
if kw: namespace.update(kw)
|
||||
namespace['emit'] = self.write
|
||||
|
||||
__stdout = sys.stdout
|
||||
sys.stdout = self
|
||||
self.__output = []
|
||||
eval(self.__code, namespace)
|
||||
sys.stdout = __stdout
|
||||
return ''.join(self.__output)
|
||||
|
||||
def write(self, *args):
|
||||
for a in args:
|
||||
self.__output.append(str(a))
|
Loading…
x
Reference in New Issue
Block a user