mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Sync to trunk.
This commit is contained in:
commit
5375c1bee0
@ -11,6 +11,7 @@ resources/localization
|
||||
resources/images.qrc
|
||||
resources/recipes.pickle
|
||||
resources/scripts.pickle
|
||||
resources/ebook-convert-complete.pickle
|
||||
setup/installer/windows/calibre/build.log
|
||||
src/calibre/translations/.errors
|
||||
src/cssutils/.svn/
|
||||
|
@ -55,6 +55,7 @@ p, dl, multicol {
|
||||
|
||||
dd {
|
||||
display: block;
|
||||
margin-left: 40px;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
|
210
resources/templates/lrf.xsl
Normal file
210
resources/templates/lrf.xsl
Normal file
@ -0,0 +1,210 @@
|
||||
<?xml version="1.0"?>
|
||||
<xsl:stylesheet
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:c="calibre"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:opf="http://www.idpf.org/2007/opf"
|
||||
xmlns:calibre="http://calibre.kovidgoyal.net/2009/metadata"
|
||||
extension-element-prefixes="c"
|
||||
xsl:version = "1.1"
|
||||
>
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<package version="2.0">
|
||||
<metadata>
|
||||
<xsl:call-template name="make-metadata"/>
|
||||
</metadata>
|
||||
<manifest>
|
||||
<xsl:call-template name="make-manifest"/>
|
||||
</manifest>
|
||||
<spine toc="ncx">
|
||||
<xsl:call-template name="make-spine"/>
|
||||
</spine>
|
||||
</package>
|
||||
<xsl:call-template name="make-ncx"/>
|
||||
<xsl:call-template name="make-css"/>
|
||||
<xsl:for-each select="//Page">
|
||||
<xsl:call-template name="make-page"/>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="make-css">
|
||||
<xsl:for-each select="//TextStyle|//BlockStyle">
|
||||
<c:styles/>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="make-page">
|
||||
<xsl:variable name="pid" select="@objid"/>
|
||||
<xsl:document href="{$pid}.xhtml" method="xml" indent="yes">
|
||||
<html>
|
||||
<head>
|
||||
<title><xsl:value-of select="//Title"/></title>
|
||||
<link rel="stylesheet" type="text/css" href="styles.css"/>
|
||||
</head>
|
||||
<body class="body">
|
||||
<xsl:apply-templates />
|
||||
</body>
|
||||
</html>
|
||||
</xsl:document>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="RuledLine">
|
||||
<c:ruled-line/>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="TextBlock">
|
||||
<c:text-block/>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="ImageBlock">
|
||||
<c:image-block/>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="Canvas">
|
||||
<c:canvas/>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="make-metadata">
|
||||
<xsl:for-each select='//BookInformation/Info/BookInfo'>
|
||||
<xsl:apply-templates select="Title"/>
|
||||
<xsl:apply-templates select="Author"/>
|
||||
<xsl:apply-templates select="Publisher"/>
|
||||
<xsl:apply-templates select="Category|Classification"/>
|
||||
</xsl:for-each>
|
||||
<xsl:for-each select='//BookInformation/Info/DocInfo'>
|
||||
<xsl:apply-templates select="Language"/>
|
||||
<xsl:apply-templates select="Producer"/>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="Title">
|
||||
<xsl:element name="dc:title">
|
||||
<xsl:if test="@reading and @reading != ''">
|
||||
<xsl:attribute name="opf:file-as"><xsl:value-of select="@reading"/></xsl:attribute>
|
||||
</xsl:if>
|
||||
<xsl:value-of select="."/>
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="Author">
|
||||
<xsl:element name="dc:creator">
|
||||
<xsl:attribute name="opf:role">aut</xsl:attribute>
|
||||
<xsl:if test="@reading and @reading != ''">
|
||||
<xsl:attribute name="opf:file-as"><xsl:value-of select="@reading"/></xsl:attribute>
|
||||
</xsl:if>
|
||||
<xsl:value-of select="."/>
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="Publisher">
|
||||
<xsl:element name="dc:publisher">
|
||||
<xsl:if test="@reading and @reading != ''">
|
||||
<xsl:attribute name="opf:file-as"><xsl:value-of select="@reading"/></xsl:attribute>
|
||||
</xsl:if>
|
||||
<xsl:value-of select="."/>
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="Producer">
|
||||
<xsl:element name="dc:creator">
|
||||
<xsl:attribute name="opf:role">bkp</xsl:attribute>
|
||||
<xsl:if test="@reading and @reading != ''">
|
||||
<xsl:attribute name="opf:file-as"><xsl:value-of select="@reading"/></xsl:attribute>
|
||||
</xsl:if>
|
||||
<xsl:value-of select="."/>
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="Language">
|
||||
<xsl:element name="dc:language">
|
||||
<xsl:value-of select="."/>
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="Category|Classification">
|
||||
<xsl:if test=".!=''">
|
||||
<xsl:element name="dc:subject">
|
||||
<xsl:value-of select="."/>
|
||||
</xsl:element>
|
||||
</xsl:if>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="make-manifest">
|
||||
<xsl:for-each select='//Page'>
|
||||
<xsl:element name="item">
|
||||
<xsl:attribute name="id"><xsl:value-of select="@objid"/></xsl:attribute>
|
||||
<xsl:attribute name="media-type"><xsl:text>application/xhtml+xml</xsl:text></xsl:attribute>
|
||||
<xsl:attribute name="href"><xsl:value-of select="@objid"/><xsl:text>.xhtml</xsl:text></xsl:attribute>
|
||||
</xsl:element>
|
||||
</xsl:for-each>
|
||||
<xsl:for-each select="//ImageStream">
|
||||
<xsl:element name="item">
|
||||
<xsl:attribute name="id"><xsl:value-of select="@objid"/></xsl:attribute>
|
||||
<xsl:attribute name="media-type"><c:media-type/></xsl:attribute>
|
||||
<xsl:attribute name="href"><xsl:value-of select="@file"/></xsl:attribute>
|
||||
</xsl:element>
|
||||
</xsl:for-each>
|
||||
<xsl:for-each select="//RegistFont">
|
||||
<xsl:element name="item">
|
||||
<xsl:attribute name="id"><xsl:value-of select="@objid"/></xsl:attribute>
|
||||
<xsl:attribute name="media-type"><c:media-type/></xsl:attribute>
|
||||
<xsl:attribute name="href"><xsl:value-of select="@file"/></xsl:attribute>
|
||||
</xsl:element>
|
||||
</xsl:for-each>
|
||||
<item id="ncx" href="toc.ncx" media-type="application/x-dtbncx+xml" />
|
||||
<item id="styles" href="styles.css" media-type="text/css" />
|
||||
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="make-spine">
|
||||
<xsl:for-each select='//Page'>
|
||||
<xsl:element name="itemref">
|
||||
<xsl:attribute name="idref"><xsl:value-of select="@objid"/></xsl:attribute>
|
||||
</xsl:element>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="*">
|
||||
<xsl:message>
|
||||
<xsl:text>no match for element: "</xsl:text>
|
||||
<xsl:value-of select="name(.)"/>
|
||||
<xsl:text>" 
</xsl:text>
|
||||
</xsl:message>
|
||||
<xsl:apply-templates/>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template name="make-ncx">
|
||||
<xsl:document href="toc.ncx" method="xml" indent="yes">
|
||||
<ncx version="2005-1"
|
||||
xmlns="http://www.daisy.org/z3986/2005/ncx/"
|
||||
xmlns:calibre="http://calibre.kovidgoyal.net/2009/metadata"
|
||||
>
|
||||
<head>
|
||||
<meta name="dtb:uid" content="uid"/>
|
||||
<meta name="dtb:depth" content="1"/>
|
||||
<meta name="dtb:generator" content="calibre"/>
|
||||
<meta name="dtb:totalPageCount" content="0"/>
|
||||
<meta name="dtb:maxPageNumber" content="0"/>
|
||||
</head>
|
||||
<docTitle><text>Table of Contents</text></docTitle>
|
||||
<navMap>
|
||||
<xsl:for-each select="//TOC/TocLabel">
|
||||
<xsl:element name="navPoint">
|
||||
<xsl:attribute name="id"><xsl:value-of select="count(preceding-sibling::*)"/></xsl:attribute>
|
||||
<xsl:attribute name="playOrder"><xsl:value-of select="count(preceding-sibling::*)+1"/></xsl:attribute>
|
||||
<navLabel><text><xsl:value-of select="."/></text></navLabel>
|
||||
<xsl:element name="content">
|
||||
<xsl:attribute name="src">
|
||||
<xsl:value-of select="@refpage"/>.xhtml#<xsl:value-of select="@refobj"/>
|
||||
</xsl:attribute>
|
||||
</xsl:element>
|
||||
</xsl:element>
|
||||
</xsl:for-each>
|
||||
</navMap>
|
||||
</ncx>
|
||||
</xsl:document>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
@ -1,27 +1,10 @@
|
||||
#########################################################################
|
||||
# #
|
||||
# #
|
||||
# copyright 2002 Paul Henry Tremblay #
|
||||
# #
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA #
|
||||
# 02111-1307 USA #
|
||||
# #
|
||||
# #
|
||||
#########################################################################
|
||||
|
||||
xhtml = '''\
|
||||
<?xml version="1.0"?>
|
||||
<xsl:stylesheet version="1.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
xmlns:rtf="http://rtf2xml.sourceforge.net/"
|
||||
xmlns:c="calibre"
|
||||
extension-element-prefixes="c"
|
||||
exclude-result-prefixes="rtf"
|
||||
>
|
||||
|
||||
@ -147,7 +130,7 @@ xhtml = '''\
|
||||
<xsl:text>generator</xsl:text>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="content">
|
||||
<xsl:text>http://rtf2xml.sourceforge.net/</xsl:text>
|
||||
<xsl:text>http://calibre-ebook.com</xsl:text>
|
||||
</xsl:attribute>
|
||||
</xsl:element>
|
||||
|
||||
@ -233,9 +216,7 @@ xhtml = '''\
|
||||
<xsl:text>span.italic-bold{font-style:italic;font-weight:bold}
</xsl:text>
|
||||
<xsl:text>span.italic-underline{font-style:italic;text-decoration:underline}
</xsl:text>
|
||||
<xsl:text>span.bold-underline{font-weight:bold;text-decoration:underline}
</xsl:text>
|
||||
<xsl:for-each select="//rtf:inline">
|
||||
<xsl:call-template name="parse-inline"/>
|
||||
</xsl:for-each>
|
||||
<xsl:text>
</xsl:text>
|
||||
</xsl:document>
|
||||
</xsl:template>
|
||||
|
||||
@ -287,52 +268,6 @@ xhtml = '''\
|
||||
</xsl:if>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="parse-inline">
|
||||
<xsl:variable name="num-attrs" select="count(@*)"/>
|
||||
<xsl:choose>
|
||||
<xsl:when test="$num-attrs = 1 and @italics"/>
|
||||
<xsl:when test="$num-attrs = 1 and @bold"/>
|
||||
<xsl:when test="$num-attrs = 1 and @underline"/>
|
||||
<xsl:when test="$num-attrs = 2 and @italics and @bold"/>
|
||||
<xsl:when test="$num-attrs = 2 and @italcs and @underline"/>
|
||||
<xsl:when test="$num-attrs = 2 and @bold and @underline"/>
|
||||
<xsl:otherwise>
|
||||
<xsl:text>span.</xsl:text>
|
||||
<xsl:value-of select="generate-id(.)"/>
|
||||
<xsl:text>{</xsl:text>
|
||||
<xsl:if test="@italics = 'true'">
|
||||
<xsl:text>font-style:italic;</xsl:text>
|
||||
</xsl:if>
|
||||
<xsl:if test="@italics = 'false'">
|
||||
<xsl:text>font-style:normal;</xsl:text>
|
||||
</xsl:if>
|
||||
<xsl:if test="@bold = 'true'">
|
||||
<xsl:text>font-weight:bold;</xsl:text>
|
||||
</xsl:if>
|
||||
<xsl:if test="@bold = 'false'">
|
||||
<xsl:text>font-weight:normal;</xsl:text>
|
||||
</xsl:if>
|
||||
<xsl:if test="@underline and @underline != 'false'">
|
||||
<xsl:text>text-decoration:underline;</xsl:text>
|
||||
</xsl:if>
|
||||
<xsl:if test="@underline= 'false'">
|
||||
<xsl:text>text-decoration:none;</xsl:text>
|
||||
</xsl:if>
|
||||
<xsl:if test="@strike-through = 'true'">
|
||||
<xsl:text>text-decoration:line-through;</xsl:text>
|
||||
</xsl:if>
|
||||
<xsl:if test="@strike-through = 'false'">
|
||||
<xsl:text>text-decoration:none;</xsl:text>
|
||||
</xsl:if>
|
||||
<xsl:if test="@font-size">
|
||||
<xsl:text>font-size:</xsl:text>
|
||||
<xsl:value-of select="@font-size"/>
|
||||
<xsl:text>pt;</xsl:text>
|
||||
</xsl:if>
|
||||
<xsl:text>}</xsl:text>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="rtf:inline">
|
||||
<xsl:variable name="num-attrs" select="count(@*)"/>
|
||||
@ -345,45 +280,7 @@ xhtml = '''\
|
||||
<xsl:otherwise>
|
||||
<xsl:element name="span">
|
||||
<xsl:attribute name="class">
|
||||
<xsl:choose>
|
||||
<xsl:when test="$num-attrs=1 and @italics='true'">
|
||||
<xsl:text>italic</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="$num-attrs=1 and @italics='false'">
|
||||
<xsl:text>no-italic</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="$num-attrs=1 and @bold='true'">
|
||||
<xsl:text>bold</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="$num-attrs=1 and @bold='true'">
|
||||
<xsl:text>bold</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="$num-attrs=1 and @bold='false'">
|
||||
<xsl:text>no-bold</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="$num-attrs=1 and @underlined">
|
||||
<xsl:choose>
|
||||
<xsl:when test="not(@underlined='false')">
|
||||
<xsl:text>underline</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:text>no-underline</xsl:text>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:when>
|
||||
<xsl:when test="$num-attrs=2 and @bold='true' and @italics='true'">
|
||||
<xsl:text>italic-bold</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="$num-attrs=2 and @italics='true' and @underline and @underline != 'false'">
|
||||
<xsl:text>italic-underline</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="$num-attrs=2 and @bold='true' and @underline and @underline != 'false'">
|
||||
<xsl:text>bold-underline</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:value-of select="generate-id(.)"/>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
<c:inline-class/>
|
||||
</xsl:attribute>
|
||||
<xsl:apply-templates/>
|
||||
</xsl:element>
|
||||
@ -539,4 +436,3 @@ xhtml = '''\
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||
'''
|
@ -16,7 +16,7 @@ from setup.build_environment import fc_inc, fc_lib, qt_inc, qt_lib, \
|
||||
fc_error, poppler_libs, poppler_lib, poppler_inc, podofo_inc, \
|
||||
podofo_lib, podofo_error, poppler_error, pyqt, OSX_SDK, NMAKE, \
|
||||
leopard_build, QMAKE, msvc, MT, win_inc, win_lib
|
||||
|
||||
MT
|
||||
isunix = islinux or isosx
|
||||
|
||||
make = 'make' if isunix else NMAKE
|
||||
@ -262,11 +262,11 @@ class Build(Command):
|
||||
print ' '.join(cmd)
|
||||
subprocess.check_call(cmd)
|
||||
if iswindows:
|
||||
manifest = dest+'.manifest'
|
||||
cmd = [MT, '-manifest', manifest, '-outputresource:%s;2'%dest]
|
||||
self.info(*cmd)
|
||||
subprocess.check_call(cmd)
|
||||
os.remove(manifest)
|
||||
#manifest = dest+'.manifest'
|
||||
#cmd = [MT, '-manifest', manifest, '-outputresource:%s;2'%dest]
|
||||
#self.info(*cmd)
|
||||
#subprocess.check_call(cmd)
|
||||
#os.remove(manifest)
|
||||
for x in ('.exp', '.lib'):
|
||||
x = os.path.splitext(dest)[0]+x
|
||||
if os.path.exists(x):
|
||||
|
@ -11,7 +11,7 @@ import sys, os, textwrap, subprocess, shutil, tempfile, atexit
|
||||
from setup import Command, islinux, basenames, modules, functions, \
|
||||
__appname__, __version__
|
||||
|
||||
TEMPLATE = '''\
|
||||
HEADER = '''\
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
@ -20,6 +20,9 @@ Do not modify it unless you know what you are doing.
|
||||
"""
|
||||
|
||||
import sys
|
||||
'''
|
||||
|
||||
TEMPLATE = HEADER+'''
|
||||
sys.path.insert(0, {path!r})
|
||||
|
||||
sys.resources_location = {resources!r}
|
||||
@ -29,6 +32,18 @@ from {module} import {func!s}
|
||||
sys.exit({func!s}())
|
||||
'''
|
||||
|
||||
COMPLETE_TEMPLATE = HEADER+'''
|
||||
import os
|
||||
sys.path.insert(0, {path!r})
|
||||
sys.path.insert(0, os.path.join({path!r}, 'calibre', 'utils'))
|
||||
import complete
|
||||
sys.path = sys.path[1:]
|
||||
|
||||
sys.resources_location = {resources!r}
|
||||
sys.extensions_location = {extensions!r}
|
||||
sys.exit(complete.main())
|
||||
'''
|
||||
|
||||
class Develop(Command):
|
||||
|
||||
description = textwrap.dedent('''\
|
||||
@ -43,8 +58,9 @@ class Develop(Command):
|
||||
sub_commands = ['build', 'resources', 'gui']
|
||||
|
||||
def add_options(self, parser):
|
||||
parser.add_option('--prefix', '--root',
|
||||
help='Binaries will be installed in <prefix>/bin')
|
||||
parser.add_option('--prefix',
|
||||
help='Binaries will be installed in <prefix>/bin')
|
||||
self.root = ''
|
||||
|
||||
def pre_sub_commands(self, opts):
|
||||
if not islinux:
|
||||
@ -76,7 +92,7 @@ class Develop(Command):
|
||||
return warn()
|
||||
import stat
|
||||
src = os.path.join(self.SRC, 'calibre', 'devices', 'linux_mount_helper.c')
|
||||
dest = os.path.join(self.bindir, 'calibre-mount-helper')
|
||||
dest = self.root + os.path.join(self.bindir, 'calibre-mount-helper')
|
||||
self.info('Installing mount helper to '+ dest)
|
||||
p = subprocess.Popen(['gcc', '-Wall', src, '-o', dest])
|
||||
ret = p.wait()
|
||||
@ -116,11 +132,12 @@ class Develop(Command):
|
||||
self.write_template(opts, 'calibre_postinstall', 'calibre.linux', 'main')
|
||||
|
||||
def write_template(self, opts, name, mod, func):
|
||||
script = TEMPLATE.format(
|
||||
template = COMPLETE_TEMPLATE if name == 'calibre-complete' else TEMPLATE
|
||||
script = template.format(
|
||||
module=mod, func=func,
|
||||
path=self.path, resources=self.resources,
|
||||
extensions=self.extensions)
|
||||
path = self.j(self.bindir, name)
|
||||
path = self.root + self.j(self.bindir, name)
|
||||
if not os.path.exists(self.bindir):
|
||||
os.makedirs(self.bindir)
|
||||
self.info('Installing binary:', path)
|
||||
@ -141,10 +158,13 @@ class Install(Develop):
|
||||
sub_commands = ['build', 'gui']
|
||||
|
||||
def add_options(self, parser):
|
||||
parser.add_option('--prefix', '--root', help='Installation prefix')
|
||||
parser.add_option('--prefix', help='Installation prefix')
|
||||
parser.add_option('--libdir', help='Where to put calibre library files')
|
||||
parser.add_option('--bindir', help='Where to install calibre binaries')
|
||||
parser.add_option('--sharedir', help='Where to install calibre data files')
|
||||
parser.add_option('--root', default='',
|
||||
help='Use a different installation root (mainly for packaging)')
|
||||
self.root = ''
|
||||
|
||||
def find_locations(self, opts):
|
||||
if opts.prefix is None:
|
||||
@ -160,13 +180,19 @@ class Install(Develop):
|
||||
self.path = opts.libdir
|
||||
self.resources = opts.sharedir
|
||||
self.extensions = self.j(self.path, 'calibre', 'plugins')
|
||||
self.root = opts.root
|
||||
|
||||
def install_files(self, opts):
|
||||
dest = self.path
|
||||
dest = self.root + self.path
|
||||
if os.path.exists(dest):
|
||||
shutil.rmtree(dest)
|
||||
shutil.copytree(self.SRC, dest)
|
||||
dest = self.resources
|
||||
for x in ('calibre/manual', 'calibre/trac',
|
||||
'calibre/ebooks/lrf/html/demo'):
|
||||
x = self.j(dest, x)
|
||||
if os.path.exists(dest):
|
||||
shutil.rmtree(x)
|
||||
dest = self.root + self.resources
|
||||
if os.path.exists(dest):
|
||||
shutil.rmtree(dest)
|
||||
shutil.copytree(self.RESOURCES, dest)
|
||||
|
@ -37,6 +37,7 @@ class LinuxFreeze(Command):
|
||||
|
||||
binary_includes = [
|
||||
'/usr/bin/pdftohtml',
|
||||
'/usr/lib/libwmflite-0.2.so.7',
|
||||
'/tmp/calibre-mount-helper',
|
||||
'/usr/lib/libunrar.so',
|
||||
'/usr/lib/libsqlite3.so.0',
|
||||
@ -202,6 +203,15 @@ class LinuxFreeze(Command):
|
||||
for f in matches:
|
||||
os.remove(f)
|
||||
|
||||
self.info('Adding ImageMagick...')
|
||||
im = glob.glob('/usr/lib/ImageMagick-*')[0]
|
||||
dest = os.path.join(FREEZE_DIR, 'ImageMagick')
|
||||
shutil.copytree(im, dest)
|
||||
for x in os.walk(dest):
|
||||
for f in x[-1]:
|
||||
if f.endswith('.a'):
|
||||
os.remove(os.path.join(x[0], f))
|
||||
|
||||
self.info('Adding calibre plugins...')
|
||||
os.makedirs(os.path.join(FREEZE_DIR, 'plugins'))
|
||||
for f in glob.glob(os.path.join(CALIBREPLUGINS, '*.so')):
|
||||
@ -230,6 +240,9 @@ class LinuxFreeze(Command):
|
||||
base=`dirname $path`
|
||||
loader=$base/loader
|
||||
export LD_LIBRARY_PATH=$base:$LD_LIBRARY_PATH
|
||||
export MAGICK_CONFIGURE_PATH=$base/ImageMagick/config
|
||||
export MAGICK_CODER_MODULE_PATH=$base/ImageMagick/modules-Q16/coders
|
||||
export MAGICK_CODER_FILTER_PATH=$base/ImageMagick/modules-Q16/filter
|
||||
$loader "$@"
|
||||
''')%exe)
|
||||
os.chmod(path, 0755)
|
||||
|
@ -10,6 +10,8 @@ import sys, os, shutil, plistlib, subprocess, glob, zipfile, tempfile, \
|
||||
py_compile, stat, operator
|
||||
abspath, join, basename = os.path.abspath, os.path.join, os.path.basename
|
||||
|
||||
#TODO: WMF support in ImageMagick
|
||||
|
||||
l = {}
|
||||
exec open('setup.py').read() in l
|
||||
VERSION = l['VERSION']
|
||||
|
@ -188,6 +188,31 @@ os.execv(python, args)
|
||||
self.fix_python_dependencies(deps)
|
||||
self.fix_misc_dependencies(deps)
|
||||
|
||||
def fix_image_magick_deps(self, root):
|
||||
modules = []
|
||||
frameworks_dir = os.path.dirname(root)
|
||||
for x in os.walk(root):
|
||||
for f in x[-1]:
|
||||
if f.endswith('.so'):
|
||||
modules.append(os.path.join(x[0], f))
|
||||
deps = {}
|
||||
for x in ('Core.1', 'Wand.1'):
|
||||
modules.append(os.path.join(root, 'lib', 'libMagick%s.dylib'%x))
|
||||
x = modules[-1]
|
||||
deps[os.path.join('/Users/kovid/ImageMagick/lib',
|
||||
os.path.basename(x))] = '@executable_path/../Frameworks/ImageMagick/lib/'+os.path.basename(x)
|
||||
subprocess.check_call(['install_name_tool', '-id',
|
||||
'@executable_path/../Frameworks/ImageMagick/lib/'+os.path.basename(x),
|
||||
x])
|
||||
for x in ('/usr/local/lib/libfreetype.6.dylib',
|
||||
'/Volumes/sw/lib/libwmflite-0.2.7.dylib'):
|
||||
deps[x] = '@executable_path/../Frameworks/'+ os.path.basename(x)
|
||||
|
||||
for x in modules:
|
||||
print 'Fixing deps in', x
|
||||
for f, t in deps.items():
|
||||
subprocess.check_call(['install_name_tool', '-change', f, t, x])
|
||||
|
||||
|
||||
def run(self):
|
||||
py2app.run(self)
|
||||
@ -252,11 +277,17 @@ os.execv(python, args)
|
||||
|
||||
|
||||
info('Adding ImageMagick')
|
||||
libwmf = '/Volumes/sw/lib/libwmflite-0.2.7.dylib'
|
||||
dest = os.path.join(frameworks_dir, os.path.basename(libwmf))
|
||||
shutil.copy2(libwmf, frameworks_dir)
|
||||
nid = '@executable_path/../Frameworks/'+os.path.basename(dest)
|
||||
subprocess.check_call(['install_name_tool', '-id', nid, dest])
|
||||
dest = os.path.join(frameworks_dir, 'ImageMagick')
|
||||
if os.path.exists(dest):
|
||||
shutil.rmtree(dest)
|
||||
shutil.copytree(os.path.expanduser('~/ImageMagick'), dest, True)
|
||||
shutil.copyfile('/usr/local/lib/libpng12.0.dylib', os.path.join(dest, 'lib', 'libpng12.0.dylib'))
|
||||
self.fix_image_magick_deps(dest)
|
||||
|
||||
|
||||
info('Installing prescipt')
|
||||
|
@ -34,6 +34,10 @@ class Stage2(Command):
|
||||
def pre_sub_commands(self, opts):
|
||||
for x in glob.glob(os.path.join(self.d(self.SRC), 'dist', '*')):
|
||||
os.remove(x)
|
||||
build = os.path.join(self.d(self.SRC), 'build')
|
||||
if os.path.exists(build):
|
||||
shutil.rmtree(build)
|
||||
|
||||
|
||||
|
||||
class Stage3(Command):
|
||||
|
@ -10,6 +10,18 @@ import os, cPickle
|
||||
|
||||
from setup import Command, basenames
|
||||
|
||||
def get_opts_from_parser(parser):
|
||||
def do_opt(opt):
|
||||
for x in opt._long_opts:
|
||||
yield x
|
||||
for x in opt._short_opts:
|
||||
yield x
|
||||
for o in parser.option_list:
|
||||
for x in do_opt(o): yield x
|
||||
for g in parser.option_groups:
|
||||
for o in g.option_list:
|
||||
for x in do_opt(o): yield x
|
||||
|
||||
class Resources(Command):
|
||||
|
||||
def get_recipes(self):
|
||||
@ -45,9 +57,42 @@ class Resources(Command):
|
||||
f = open(dest, 'wb')
|
||||
cPickle.dump(recipes, f, -1)
|
||||
|
||||
dest = self.j(self.RESOURCES, 'ebook-convert-complete.pickle')
|
||||
files = []
|
||||
for x in os.walk(self.j(self.SRC, 'calibre')):
|
||||
for f in x[-1]:
|
||||
if f.endswith('.py'):
|
||||
files.append(self.j(x[0], f))
|
||||
if self.newer(dest, files):
|
||||
self.info('\tCreating ebook-convert-complete.pickle')
|
||||
complete = {}
|
||||
from calibre.ebooks.conversion.plumber import supported_input_formats
|
||||
complete['input_fmts'] = set(supported_input_formats())
|
||||
from calibre.web.feeds.recipes import recipes
|
||||
complete['input_recipes'] = [t.title+'.recipe ' for t in recipes]
|
||||
from calibre.customize.ui import available_output_formats
|
||||
complete['output'] = set(available_output_formats())
|
||||
from calibre.ebooks.conversion.cli import create_option_parser
|
||||
from calibre.utils.logging import Log
|
||||
log = Log()
|
||||
#log.outputs = []
|
||||
for inf in supported_input_formats():
|
||||
if inf in ('zip', 'rar', 'oebzip'):
|
||||
continue
|
||||
for ouf in available_output_formats():
|
||||
of = ouf if ouf == 'oeb' else 'dummy.'+ouf
|
||||
p = create_option_parser(('ec', 'dummy1.'+inf, of, '-h'),
|
||||
log)[0]
|
||||
complete[(inf, ouf)] = [x+' 'for x in
|
||||
get_opts_from_parser(p)]
|
||||
|
||||
cPickle.dump(complete, open(dest, 'wb'), -1)
|
||||
|
||||
|
||||
|
||||
|
||||
def clean(self):
|
||||
for x in ('scripts', 'recipes'):
|
||||
for x in ('scripts', 'recipes', 'ebook-convert-complete'):
|
||||
x = self.j(self.RESOURCES, x+'.pickle')
|
||||
if os.path.exists(x):
|
||||
os.remove(x)
|
||||
|
@ -2,7 +2,7 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
__appname__ = 'calibre'
|
||||
__version__ = '0.6.12'
|
||||
__version__ = '0.6.13'
|
||||
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
|
||||
|
||||
import re
|
||||
|
@ -338,6 +338,7 @@ from calibre.ebooks.rb.input import RBInput
|
||||
from calibre.web.feeds.input import RecipeInput
|
||||
from calibre.ebooks.rtf.input import RTFInput
|
||||
from calibre.ebooks.txt.input import TXTInput
|
||||
from calibre.ebooks.lrf.input import LRFInput
|
||||
|
||||
from calibre.ebooks.epub.output import EPUBOutput
|
||||
from calibre.ebooks.fb2.output import FB2Output
|
||||
@ -385,6 +386,7 @@ plugins += [
|
||||
RecipeInput,
|
||||
RTFInput,
|
||||
TXTInput,
|
||||
LRFInput,
|
||||
]
|
||||
plugins += [
|
||||
EPUBOutput,
|
||||
|
@ -173,7 +173,7 @@ class PageProcessor(list):
|
||||
p.MagickDespeckleImage(wand)
|
||||
|
||||
p.MagickQuantizeImage(wand, self.opts.colors, p.RGBColorspace, 0, 1, 0)
|
||||
dest = '%d_%d.png'%(self.num, i)
|
||||
dest = '%d_%d.%s'%(self.num, i, self.opts.output_format)
|
||||
dest = os.path.join(self.dest, dest)
|
||||
p.MagickWriteImage(wand, dest+'8')
|
||||
os.rename(dest+'8', dest)
|
||||
@ -270,8 +270,10 @@ class ComicInput(InputFormatPlugin):
|
||||
is_image_collection = True
|
||||
|
||||
options = set([
|
||||
OptionRecommendation(name='colors', recommended_value=64,
|
||||
help=_('Number of colors for grayscale image conversion. Default: %default')),
|
||||
OptionRecommendation(name='colors', recommended_value=256,
|
||||
help=_('Number of colors for grayscale image conversion. Default: '
|
||||
'%default. Values of less than 256 may result in blurred text '
|
||||
'on your device if you are creating your comics in EPUB format.')),
|
||||
OptionRecommendation(name='dont_normalize', recommended_value=False,
|
||||
help=_('Disable normalize (improve contrast) color range '
|
||||
'for pictures. Default: False')),
|
||||
@ -298,6 +300,10 @@ class ComicInput(InputFormatPlugin):
|
||||
help=_("Don't sort the files found in the comic "
|
||||
"alphabetically by name. Instead use the order they were "
|
||||
"added to the comic.")),
|
||||
OptionRecommendation(name='output_format', choices=['png', 'jpg'],
|
||||
recommended_value='png', help=_('The format that images in the created ebook '
|
||||
'are converted to. You can experiment to see which format gives '
|
||||
'you optimal size and look on your device.')),
|
||||
OptionRecommendation(name='no_process', recommended_value=False,
|
||||
help=_("Apply no processing to the image")),
|
||||
])
|
||||
@ -365,7 +371,8 @@ class ComicInput(InputFormatPlugin):
|
||||
'(run with --verbose to see why):')
|
||||
for f in failures:
|
||||
self.log.warning('\t', f)
|
||||
thumbnail = os.path.join(tdir2, 'thumbnail.png')
|
||||
thumbnail = os.path.join(tdir2,
|
||||
'thumbnail.'+self.opts.output_format.lower())
|
||||
if not os.access(thumbnail, os.R_OK):
|
||||
thumbnail = None
|
||||
return new_pages
|
||||
|
@ -51,6 +51,9 @@ def load_specifics(db, book_id):
|
||||
r.from_string(raw)
|
||||
return r
|
||||
|
||||
def delete_specifics(db, book_id):
|
||||
db.delete_conversion_options(book_id, 'PIPE')
|
||||
|
||||
class GuiRecommendations(dict):
|
||||
|
||||
def __new__(cls, *args):
|
||||
|
@ -14,7 +14,8 @@ XMLDECL_RE = re.compile(r'^\s*<[?]xml.*?[?]>')
|
||||
SVG_NS = 'http://www.w3.org/2000/svg'
|
||||
XLINK_NS = 'http://www.w3.org/1999/xlink'
|
||||
|
||||
convert_entities = functools.partial(entity_to_unicode, exceptions=['quot', 'apos', 'lt', 'gt', 'amp'])
|
||||
convert_entities = functools.partial(entity_to_unicode, exceptions=['quot',
|
||||
'apos', 'lt', 'gt', 'amp', '#60', '#62'])
|
||||
_span_pat = re.compile('<span.*?</span>', re.DOTALL|re.IGNORECASE)
|
||||
|
||||
|
||||
|
412
src/calibre/ebooks/lrf/input.py
Normal file
412
src/calibre/ebooks/lrf/input.py
Normal file
@ -0,0 +1,412 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||
from __future__ import with_statement
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import os, textwrap
|
||||
from copy import deepcopy
|
||||
|
||||
from lxml import etree
|
||||
|
||||
from calibre.customize.conversion import InputFormatPlugin
|
||||
from calibre import guess_type
|
||||
|
||||
class Canvas(etree.XSLTExtension):
|
||||
|
||||
def __init__(self, doc, styles, text_block, log):
|
||||
self.doc = doc
|
||||
self.styles = styles
|
||||
self.text_block = text_block
|
||||
self.log = log
|
||||
self.processed = set([])
|
||||
|
||||
def execute(self, context, self_node, input_node, output_parent):
|
||||
cid = input_node.get('objid', None)
|
||||
if cid is None or cid in self.processed:
|
||||
return
|
||||
self.processed.add(cid)
|
||||
input_node = self.doc.xpath('//Canvas[@objid="%s"]'%cid)[0]
|
||||
|
||||
objects = list(self.get_objects(input_node))
|
||||
if len(objects) == 1 and objects[0][0].tag == 'ImageBlock':
|
||||
self.image_page(input_node, objects[0][0], output_parent)
|
||||
else:
|
||||
canvases = [input_node]
|
||||
for x in input_node.itersiblings():
|
||||
if x.tag == 'Canvas':
|
||||
oid = x.get('objid', None)
|
||||
if oid is not None:
|
||||
canvases.append(x)
|
||||
self.processed.add(oid)
|
||||
else:
|
||||
break
|
||||
|
||||
|
||||
table = etree.Element('table')
|
||||
table.text = '\n\t'
|
||||
for canvas in canvases:
|
||||
oid = canvas.get('objid')
|
||||
tr = table.makeelement('tr')
|
||||
tr.set('id', oid)
|
||||
tr.tail = '\n\t'
|
||||
table.append(tr)
|
||||
for obj, x, y in self.get_objects(canvas):
|
||||
if obj.tag != 'TextBlock':
|
||||
self.log.warn(obj.tag, 'elements in Canvas not supported')
|
||||
continue
|
||||
td = table.makeelement('td')
|
||||
self.text_block.render_block(obj, td)
|
||||
tr.append(td)
|
||||
output_parent.append(table)
|
||||
|
||||
def image_page(self, input_node, block, output_parent):
|
||||
div = etree.Element('div')
|
||||
div.set('id', input_node.get('objid', 'scuzzy'))
|
||||
div.set('class', 'image_page')
|
||||
width = self.styles.to_num(block.get("xsize", None))
|
||||
height = self.styles.to_num(block.get("ysize", None))
|
||||
img = div.makeelement('img')
|
||||
if width is not None:
|
||||
img.set('width', str(int(width)))
|
||||
if height is not None:
|
||||
img.set('height', str(int(height)))
|
||||
ref = block.get('refstream', None)
|
||||
if ref is not None:
|
||||
imstr = self.doc.xpath('//ImageStream[@objid="%s"]'%ref)
|
||||
if imstr:
|
||||
src = imstr[0].get('file', None)
|
||||
if src:
|
||||
img.set('src', src)
|
||||
div.append(img)
|
||||
output_parent.append(div)
|
||||
|
||||
|
||||
def get_objects(self, node):
|
||||
for x in node.xpath('descendant::PutObj[@refobj and @x1 and @y1]'):
|
||||
objs = node.xpath('//*[@objid="%s"]'%x.get('refobj'))
|
||||
x, y = map(self.styles.to_num, (x.get('x1'), x.get('y1')))
|
||||
if objs and x is not None and y is not None:
|
||||
yield objs[0], int(x), int(y)
|
||||
|
||||
|
||||
class MediaType(etree.XSLTExtension):
|
||||
def execute(self, context, self_node, input_node, output_parent):
|
||||
name = input_node.get('file', None)
|
||||
typ = guess_type(name)[0]
|
||||
if not typ:
|
||||
typ = 'application/octet-stream'
|
||||
output_parent.text = typ
|
||||
|
||||
class ImageBlock(etree.XSLTExtension):
|
||||
|
||||
def __init__(self, canvas):
|
||||
etree.XSLTExtension.__init__(self)
|
||||
self.canvas = canvas
|
||||
|
||||
def execute(self, context, self_node, input_node, output_parent):
|
||||
self.canvas.image_page(input_node, input_node, output_parent)
|
||||
|
||||
|
||||
class RuledLine(etree.XSLTExtension):
|
||||
|
||||
def execute(self, context, self_node, input_node, output_parent):
|
||||
hr = etree.Element('hr')
|
||||
output_parent.append(hr)
|
||||
|
||||
|
||||
class TextBlock(etree.XSLTExtension):
|
||||
|
||||
def __init__(self, styles, char_button_map, plot_map, log):
|
||||
etree.XSLTExtension.__init__(self)
|
||||
self.styles = styles
|
||||
self.log = log
|
||||
self.char_button_map = char_button_map
|
||||
self.plot_map = plot_map
|
||||
|
||||
def execute(self, context, self_node, input_node, output_parent):
|
||||
input_node = deepcopy(input_node)
|
||||
div = etree.Element('div')
|
||||
self.render_block(input_node, div)
|
||||
output_parent.append(div)
|
||||
|
||||
def render_block(self, node, root):
|
||||
ts = node.get('textstyle', None)
|
||||
classes = []
|
||||
bs = node.get('blockstyle')
|
||||
if bs in self.styles.block_style_map:
|
||||
classes.append('bs%d'%self.styles.block_style_map[bs])
|
||||
if ts in self.styles.text_style_map:
|
||||
classes.append('ts%d'%self.styles.text_style_map[ts])
|
||||
if classes:
|
||||
root.set('class', ' '.join(classes))
|
||||
objid = node.get('objid', None)
|
||||
if objid:
|
||||
root.set('id', objid)
|
||||
root.text = node.text
|
||||
self.root = root
|
||||
self.parent = root
|
||||
self.add_text_to = (self.parent, 'text')
|
||||
for child in node:
|
||||
self.process_child(child)
|
||||
|
||||
def add_text(self, text):
|
||||
if text:
|
||||
if getattr(self.add_text_to[0], self.add_text_to[1]) is None:
|
||||
setattr(self.add_text_to[0], self.add_text_to[1], '')
|
||||
setattr(self.add_text_to[0], self.add_text_to[1],
|
||||
getattr(self.add_text_to[0], self.add_text_to[1])+ text)
|
||||
|
||||
def process_container(self, child, tgt):
|
||||
idx = self.styles.get_text_styles(child)
|
||||
if idx is not None:
|
||||
tgt.set('class', 'ts%d'%idx)
|
||||
self.parent.append(tgt)
|
||||
orig_parent = self.parent
|
||||
self.parent = tgt
|
||||
self.add_text_to = (self.parent, 'text')
|
||||
self.add_text(child.text)
|
||||
for gchild in child:
|
||||
self.process_child(gchild)
|
||||
self.parent = orig_parent
|
||||
self.add_text_to = (tgt, 'tail')
|
||||
self.add_text(child.tail)
|
||||
|
||||
def process_child(self, child):
|
||||
if child.tag == 'CR':
|
||||
if self.parent == self.root:
|
||||
self.parent = self.root.makeelement('p')
|
||||
self.root.append(self.parent)
|
||||
self.add_text_to = (self.parent, 'text')
|
||||
else:
|
||||
br = self.parent.makeelement('br')
|
||||
self.parent.append(br)
|
||||
self.add_text_to = (br, 'tail')
|
||||
self.add_text(child.tail)
|
||||
elif child.tag in ('P', 'Span', 'EmpLine', 'NoBR'):
|
||||
span = self.root.makeelement('span')
|
||||
if child.tag == 'EmpLine':
|
||||
td = 'underline' if child.get('emplineposition', 'before') == 'before' else 'overline'
|
||||
span.set('style', 'text-decoration: '+td)
|
||||
self.process_container(child, span)
|
||||
elif child.tag == 'Sup':
|
||||
sup = self.root.makeelement('sup')
|
||||
self.process_container(child, sup)
|
||||
elif child.tag == 'Sub':
|
||||
sub = self.root.makeelement('sub')
|
||||
self.process_container(child, sub)
|
||||
elif child.tag == 'Italic':
|
||||
sup = self.root.makeelement('i')
|
||||
self.process_container(child, sup)
|
||||
elif child.tag == 'CharButton':
|
||||
a = self.root.makeelement('a')
|
||||
oid = child.get('refobj', None)
|
||||
if oid in self.char_button_map:
|
||||
a.set('href', self.char_button_map[oid])
|
||||
self.process_container(child, a)
|
||||
elif child.tag == 'Plot':
|
||||
xsize = self.styles.to_num(child.get('xsize', None), 166./720)
|
||||
ysize = self.styles.to_num(child.get('ysize', None), 166./720)
|
||||
img = self.root.makeelement('img')
|
||||
if xsize is not None:
|
||||
img.set('width', str(int(xsize)))
|
||||
if ysize is not None:
|
||||
img.set('height', str(int(ysize)))
|
||||
ro = child.get('refobj', None)
|
||||
if ro in self.plot_map:
|
||||
img.set('src', self.plot_map[ro])
|
||||
self.parent.append(img)
|
||||
self.add_text_to = (img, 'tail')
|
||||
self.add_text(child.tail)
|
||||
else:
|
||||
self.log.warn('Unhandled Text element:', child.tag)
|
||||
|
||||
|
||||
class Styles(etree.XSLTExtension):
|
||||
|
||||
def __init__(self):
|
||||
etree.XSLTExtension.__init__(self)
|
||||
self.text_styles, self.block_styles = [], []
|
||||
self.text_style_map, self.block_style_map = {}, {}
|
||||
self.CSS = textwrap.dedent('''
|
||||
.image_page { text-align:center }
|
||||
''')
|
||||
|
||||
def write(self, name='styles.css'):
|
||||
|
||||
def join(style):
|
||||
ans = ['%s : %s;'%(k, v) for k, v in style.items()]
|
||||
if ans:
|
||||
ans[-1] = ans[-1][:-1]
|
||||
return '\n\t'.join(ans)
|
||||
|
||||
with open(name, 'wb') as f:
|
||||
f.write(self.CSS)
|
||||
for (w, sel) in [(self.text_styles, 'ts'), (self.block_styles,
|
||||
'bs')]:
|
||||
for i, s in enumerate(w):
|
||||
if not s:
|
||||
continue
|
||||
rsel = '.%s%d'%(sel, i)
|
||||
s = join(s)
|
||||
f.write(rsel + ' {\n\t' + s + '\n}\n\n')
|
||||
|
||||
|
||||
|
||||
def execute(self, context, self_node, input_node, output_parent):
|
||||
if input_node.tag == 'TextStyle':
|
||||
idx = self.get_text_styles(input_node)
|
||||
if idx is not None:
|
||||
self.text_style_map[input_node.get('objid')] = idx
|
||||
else:
|
||||
idx = self.get_block_styles(input_node)
|
||||
self.block_style_map[input_node.get('objid')] = idx
|
||||
|
||||
def px_to_pt(self, px):
|
||||
try:
|
||||
px = float(px)
|
||||
return px * 72./166.
|
||||
except:
|
||||
return None
|
||||
|
||||
def color(self, val):
|
||||
try:
|
||||
val = int(val, 16)
|
||||
r, g, b, a = val & 0xFF, (val>>8)&0xFF, (val>>16)&0xFF, (val>>24)&0xFF
|
||||
if a == 255:
|
||||
return None
|
||||
if a == 0:
|
||||
return 'rgb(%d,%d,%d)'%(r,g,b)
|
||||
return 'rgba(%d,%d,%d,%f)'%(r,g,b,1.-a/255.)
|
||||
except:
|
||||
return None
|
||||
|
||||
def get_block_styles(self, node):
|
||||
ans = {}
|
||||
sm = self.px_to_pt(node.get('sidemargin', None))
|
||||
if sm is not None:
|
||||
ans['margin-left'] = ans['margin-right'] = '%fpt'%sm
|
||||
ts = self.px_to_pt(node.get('topskip', None))
|
||||
if ts is not None:
|
||||
ans['margin-top'] = '%fpt'%ts
|
||||
fs = self.px_to_pt(node.get('footskip', None))
|
||||
if fs is not None:
|
||||
ans['margin-bottom'] = '%fpt'%fs
|
||||
fw = self.px_to_pt(node.get('framewidth', None))
|
||||
if fw is not None:
|
||||
ans['border-width'] = '%fpt'%fw
|
||||
ans['border-style'] = 'solid'
|
||||
fc = self.color(node.get('framecolor', None))
|
||||
if fc is not None:
|
||||
ans['border-color'] = fc
|
||||
bc = self.color(node.get('bgcolor', None))
|
||||
if bc is not None:
|
||||
ans['background-color'] = bc
|
||||
if ans not in self.block_styles:
|
||||
self.block_styles.append(ans)
|
||||
return self.block_styles.index(ans)
|
||||
|
||||
def to_num(self, val, factor=1.):
|
||||
try:
|
||||
return float(val)*factor
|
||||
except:
|
||||
return None
|
||||
|
||||
def get_text_styles(self, node):
|
||||
ans = {}
|
||||
fs = self.to_num(node.get('fontsize', None), 0.1)
|
||||
if fs is not None:
|
||||
ans['font-size'] = '%fpt'%fs
|
||||
fw = self.to_num(node.get('fontweight', None))
|
||||
if fw is not None:
|
||||
ans['font-weight'] = ('bold' if fw >= 700 else 'normal')
|
||||
#fn = getattr(obj, 'fontfacename', None)
|
||||
#if fn is not None:
|
||||
# fn = cls.FONT_MAP[fn]
|
||||
# item('font-family: %s;'%fn)
|
||||
fg = self.color(node.get('textcolor', None))
|
||||
if fg is not None:
|
||||
ans['color'] = fg
|
||||
bg = self.color(node.get('textbgcolor', None))
|
||||
if bg is not None:
|
||||
ans['background-color'] = bg
|
||||
al = node.get('align', None)
|
||||
if al is not None:
|
||||
all = dict(head='left', center='center', foot='right')
|
||||
ans['text-align'] = all.get(al, 'left')
|
||||
#lh = self.to_num(node.get('linespace', None), 0.1)
|
||||
#if lh is not None:
|
||||
# ans['line-height'] = '%fpt'%lh
|
||||
pi = self.to_num(node.get('parindent', None), 0.1)
|
||||
if pi is not None:
|
||||
ans['text-indent'] = '%fpt'%pi
|
||||
if not ans:
|
||||
return None
|
||||
if ans not in self.text_styles:
|
||||
self.text_styles.append(ans)
|
||||
return self.text_styles.index(ans)
|
||||
|
||||
|
||||
|
||||
class LRFInput(InputFormatPlugin):
|
||||
|
||||
name = 'LRF Input'
|
||||
author = 'Kovid Goyal'
|
||||
description = 'Convert LRF files to HTML'
|
||||
file_types = set(['lrf'])
|
||||
|
||||
def convert(self, stream, options, file_ext, log,
|
||||
accelerators):
|
||||
self.log = log
|
||||
self.log('Generating XML')
|
||||
from calibre.ebooks.lrf.lrfparser import LRFDocument
|
||||
d = LRFDocument(stream)
|
||||
d.parse()
|
||||
xml = d.to_xml(write_files=True)
|
||||
parser = etree.XMLParser(recover=True, no_network=True)
|
||||
doc = etree.fromstring(xml, parser=parser)
|
||||
char_button_map = {}
|
||||
for x in doc.xpath('//CharButton[@refobj]'):
|
||||
ro = x.get('refobj')
|
||||
jump_button = doc.xpath('//*[@objid="%s"]'%ro)
|
||||
if jump_button:
|
||||
jump_to = jump_button[0].xpath('descendant::JumpTo[@refpage and @refobj]')
|
||||
if jump_to:
|
||||
char_button_map[ro] = '%s.xhtml#%s'%(jump_to[0].get('refpage'),
|
||||
jump_to[0].get('refobj'))
|
||||
plot_map = {}
|
||||
for x in doc.xpath('//Plot[@refobj]'):
|
||||
ro = x.get('refobj')
|
||||
image = doc.xpath('//Image[@objid="%s" and @refstream]'%ro)
|
||||
if image:
|
||||
imgstr = doc.xpath('//ImageStream[@objid="%s" and @file]'%
|
||||
image[0].get('refstream'))
|
||||
if imgstr:
|
||||
plot_map[ro] = imgstr[0].get('file')
|
||||
|
||||
self.log('Converting XML to HTML...')
|
||||
styledoc = etree.fromstring(P('templates/lrf.xsl', data=True))
|
||||
media_type = MediaType()
|
||||
styles = Styles()
|
||||
text_block = TextBlock(styles, char_button_map, plot_map, log)
|
||||
canvas = Canvas(doc, styles, text_block, log)
|
||||
image_block = ImageBlock(canvas)
|
||||
ruled_line = RuledLine()
|
||||
extensions = {
|
||||
('calibre', 'media-type') : media_type,
|
||||
('calibre', 'text-block') : text_block,
|
||||
('calibre', 'ruled-line') : ruled_line,
|
||||
('calibre', 'styles') : styles,
|
||||
('calibre', 'canvas') : canvas,
|
||||
('calibre', 'image-block'): image_block,
|
||||
}
|
||||
transform = etree.XSLT(styledoc, extensions=extensions)
|
||||
result = transform(doc)
|
||||
with open('content.opf', 'wb') as f:
|
||||
f.write(result)
|
||||
styles.write()
|
||||
return os.path.abspath('content.opf')
|
||||
|
||||
|
@ -165,13 +165,16 @@ class BookHeader(object):
|
||||
if not isinstance(self.title, unicode):
|
||||
self.title = self.title.decode(self.codec, 'replace')
|
||||
if self.exth_flag & 0x40:
|
||||
self.exth = EXTHHeader(raw[16 + self.length:], self.codec, self.title)
|
||||
self.exth.mi.uid = self.unique_id
|
||||
try:
|
||||
self.exth.mi.language = mobi2iana(langid, sublangid)
|
||||
self.exth = EXTHHeader(raw[16 + self.length:], self.codec, self.title)
|
||||
self.exth.mi.uid = self.unique_id
|
||||
try:
|
||||
self.exth.mi.language = mobi2iana(langid, sublangid)
|
||||
except:
|
||||
self.log.exception('Unknown language code')
|
||||
except:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
self.log.exception('Invalid EXTH header')
|
||||
self.exth_flag = 0
|
||||
|
||||
|
||||
class MetadataHeader(BookHeader):
|
||||
@ -501,13 +504,23 @@ class MobiReader(object):
|
||||
height = attrib.pop('height').strip()
|
||||
if height and '<' not in height and '>' not in height and \
|
||||
re.search(r'\d+', height):
|
||||
styles.append('margin-top: %s' % self.ensure_unit(height))
|
||||
if tag.tag in ('table', 'td', 'tr'):
|
||||
pass
|
||||
elif tag.tag == 'img':
|
||||
tag.set('height', height)
|
||||
else:
|
||||
styles.append('margin-top: %s' % self.ensure_unit(height))
|
||||
if attrib.has_key('width'):
|
||||
width = attrib.pop('width').strip()
|
||||
if width and re.search(r'\d+', width):
|
||||
styles.append('text-indent: %s' % self.ensure_unit(width))
|
||||
if width.startswith('-'):
|
||||
styles.append('margin-left: %s' % self.ensure_unit(width[1:]))
|
||||
if tag.tag in ('table', 'td', 'tr'):
|
||||
pass
|
||||
elif tag.tag == 'img':
|
||||
tag.set('width', width)
|
||||
else:
|
||||
styles.append('text-indent: %s' % self.ensure_unit(width))
|
||||
if width.startswith('-'):
|
||||
styles.append('margin-left: %s' % self.ensure_unit(width[1:]))
|
||||
if attrib.has_key('align'):
|
||||
align = attrib.pop('align').strip()
|
||||
if align:
|
||||
|
@ -34,6 +34,11 @@ class Extract(ODF2XHTML):
|
||||
with CurrentDir(odir):
|
||||
print 'Extracting ODT file...'
|
||||
html = self.odf2xhtml(stream)
|
||||
# A blanket img specification like this causes problems
|
||||
# with EPUB output as the contaiing element often has
|
||||
# an absolute height and width set that is larger than
|
||||
# the available screen real estate
|
||||
html = html.replace('img { width: 100%; height: 100%; }', '')
|
||||
with open('index.xhtml', 'wb') as f:
|
||||
f.write(html.encode('utf-8'))
|
||||
zf = ZipFile(stream, 'r')
|
||||
|
@ -759,13 +759,15 @@ class Manifest(object):
|
||||
% (self.id, self.href, self.media_type)
|
||||
|
||||
def _parse_xml(self, data):
|
||||
parser = etree.XMLParser(recover=True)
|
||||
try:
|
||||
return etree.fromstring(data)
|
||||
return etree.fromstring(data, parser=parser)
|
||||
except etree.XMLSyntaxError, err:
|
||||
if getattr(err, 'code', 0) == 26 or str(err).startswith('Entity'):
|
||||
data = xml_to_unicode(data, strip_encoding_pats=True,
|
||||
resolve_entities=True)[0]
|
||||
return etree.fromstring(data)
|
||||
raise
|
||||
|
||||
def _parse_xhtml(self, data):
|
||||
self.oeb.log.debug('Parsing', self.href, '...')
|
||||
@ -843,6 +845,7 @@ class Manifest(object):
|
||||
if not namespace(data.tag):
|
||||
data.attrib['xmlns'] = XHTML_NS
|
||||
data = etree.tostring(data, encoding=unicode)
|
||||
|
||||
try:
|
||||
data = etree.fromstring(data)
|
||||
except:
|
||||
|
@ -132,8 +132,8 @@ class Stylizer(object):
|
||||
stylesheet.namespaces['h'] = XHTML_NS
|
||||
stylesheets.append(stylesheet)
|
||||
elif elem.tag == XHTML('link') and elem.get('href') \
|
||||
and elem.get('rel', 'stylesheet') == 'stylesheet' \
|
||||
and elem.get('type', CSS_MIME) in OEB_STYLES:
|
||||
and elem.get('rel', 'stylesheet').lower() == 'stylesheet' \
|
||||
and elem.get('type', CSS_MIME).lower() in OEB_STYLES:
|
||||
href = urlnormalize(elem.attrib['href'])
|
||||
path = item.abshref(href)
|
||||
sitem = oeb.manifest.hrefs.get(path, None)
|
||||
|
@ -362,12 +362,13 @@ class FlowSplitter(object):
|
||||
self.log.debug('\t\tSplitting...')
|
||||
root = tree.getroot()
|
||||
# Split large <pre> tags
|
||||
for pre in list(root.xpath('//pre')):
|
||||
for pre in list(XPath('//h:pre')(root)):
|
||||
text = u''.join(pre.xpath('descendant::text()'))
|
||||
pre.text = text
|
||||
for child in list(pre.iterchildren()):
|
||||
pre.remove(child)
|
||||
if len(pre.text) > self.max_flow_size*0.5:
|
||||
self.log.debug('\t\tSplitting large <pre> tag')
|
||||
frags = self.split_text(pre.text, root, int(0.2*self.max_flow_size))
|
||||
new_pres = []
|
||||
for frag in frags:
|
||||
|
@ -2,12 +2,41 @@ from __future__ import with_statement
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
|
||||
import os, glob, re
|
||||
import os, glob, re, textwrap
|
||||
|
||||
from lxml import etree
|
||||
|
||||
from calibre.customize.conversion import InputFormatPlugin
|
||||
|
||||
class InlineClass(etree.XSLTExtension):
|
||||
|
||||
FMTS = ('italics', 'bold', 'underlined', 'strike-through', 'small-caps')
|
||||
|
||||
def __init__(self, log):
|
||||
etree.XSLTExtension.__init__(self)
|
||||
self.log = log
|
||||
self.font_sizes = []
|
||||
self.colors = []
|
||||
|
||||
def execute(self, context, self_node, input_node, output_parent):
|
||||
classes = ['none']
|
||||
for x in self.FMTS:
|
||||
if input_node.get(x, None) == 'true':
|
||||
classes.append(x)
|
||||
fs = input_node.get('font-size', False)
|
||||
if fs:
|
||||
if fs not in self.font_sizes:
|
||||
self.font_sizes.append(fs)
|
||||
classes.append('fs%d'%self.font_sizes.index(fs))
|
||||
fc = input_node.get('font-color', False)
|
||||
if fc:
|
||||
if fc not in self.colors:
|
||||
self.colors.append(fc)
|
||||
classes.append('col%d'%self.colors.index(fc))
|
||||
|
||||
output_parent.text = ' '.join(classes)
|
||||
|
||||
|
||||
class RTFInput(InputFormatPlugin):
|
||||
|
||||
name = 'RTF Input'
|
||||
@ -21,15 +50,15 @@ class RTFInput(InputFormatPlugin):
|
||||
parser = ParseRtf(
|
||||
in_file = stream,
|
||||
out_file = ofile,
|
||||
# Convert symbol fonts to unicode equivelents. Default
|
||||
# Convert symbol fonts to unicode equivalents. Default
|
||||
# is 1
|
||||
convert_symbol = 1,
|
||||
|
||||
# Convert Zapf fonts to unicode equivelents. Default
|
||||
# Convert Zapf fonts to unicode equivalents. Default
|
||||
# is 1.
|
||||
convert_zapf = 1,
|
||||
|
||||
# Convert Wingding fonts to unicode equivelents.
|
||||
# Convert Wingding fonts to unicode equivalents.
|
||||
# Default is 1.
|
||||
convert_wingdings = 1,
|
||||
|
||||
@ -63,6 +92,7 @@ class RTFInput(InputFormatPlugin):
|
||||
|
||||
def extract_images(self, picts):
|
||||
self.log('Extracting images...')
|
||||
|
||||
count = 0
|
||||
raw = open(picts, 'rb').read()
|
||||
starts = []
|
||||
@ -82,21 +112,66 @@ class RTFInput(InputFormatPlugin):
|
||||
if len(enc) % 2 == 1:
|
||||
enc = enc[:-1]
|
||||
data = enc.decode('hex')
|
||||
ext = '.jpg'
|
||||
if 'EMF' in data[:200]:
|
||||
ext = '.wmf'
|
||||
elif 'PNG' in data[:200]:
|
||||
ext = '.png'
|
||||
count += 1
|
||||
name = (('%4d'%count).replace(' ', '0'))+ext
|
||||
name = (('%4d'%count).replace(' ', '0'))+'.wmf'
|
||||
open(name, 'wb').write(data)
|
||||
imap[count] = name
|
||||
#open(name+'.hex', 'wb').write(enc)
|
||||
return self.convert_images(imap)
|
||||
|
||||
def convert_images(self, imap):
|
||||
from calibre.utils.PythonMagickWand import ImageMagick
|
||||
with ImageMagick():
|
||||
for count, val in imap.items():
|
||||
try:
|
||||
imap[count] = self.convert_image(val)
|
||||
except:
|
||||
self.log.exception('Failed to convert', val)
|
||||
return imap
|
||||
|
||||
def convert_image(self, name):
|
||||
import calibre.utils.PythonMagickWand as p
|
||||
img = p.NewMagickWand()
|
||||
if img < 0:
|
||||
raise RuntimeError('Cannot create wand.')
|
||||
if not p.MagickReadImage(img, name):
|
||||
self.log.warn('Failed to read image:', name)
|
||||
name = name.replace('.wmf', '.jpg')
|
||||
p.MagickWriteImage(img, name)
|
||||
|
||||
return name
|
||||
|
||||
|
||||
def write_inline_css(self, ic):
|
||||
font_size_classes = ['span.fs%d { font-size: %spt }'%(i, x) for i, x in
|
||||
enumerate(ic.font_sizes)]
|
||||
color_classes = ['span.col%d { color: %s }'%(i, x) for i, x in
|
||||
enumerate(ic.colors)]
|
||||
css = textwrap.dedent('''
|
||||
span.none {
|
||||
text-decoration: none; font-weight: normal;
|
||||
font-style: normal; font-variant: normal
|
||||
}
|
||||
|
||||
span.italics { font-style: italic }
|
||||
|
||||
span.bold { font-weight: bold }
|
||||
|
||||
span.small-caps { font-variant: small-caps }
|
||||
|
||||
span.underlined { text-decoration: underline }
|
||||
|
||||
span.strike-through { text-decoration: line-through }
|
||||
|
||||
''')
|
||||
css += '\n'+'\n'.join(font_size_classes)
|
||||
css += '\n' +'\n'.join(color_classes)
|
||||
with open('styles.css', 'ab') as f:
|
||||
f.write(css)
|
||||
|
||||
|
||||
def convert(self, stream, options, file_ext, log,
|
||||
accelerators):
|
||||
from calibre.ebooks.rtf.xsl import xhtml
|
||||
from calibre.ebooks.metadata.meta import get_metadata
|
||||
from calibre.ebooks.metadata.opf2 import OPFCreator
|
||||
from calibre.ebooks.rtf2xml.ParseRtf import RtfInvalidCodeException
|
||||
@ -124,15 +199,18 @@ class RTFInput(InputFormatPlugin):
|
||||
if name is not None:
|
||||
pict.set('num', name)
|
||||
self.log('Converting XML to HTML...')
|
||||
styledoc = etree.fromstring(xhtml)
|
||||
inline_class = InlineClass(self.log)
|
||||
styledoc = etree.fromstring(P('templates/rtf.xsl', data=True))
|
||||
|
||||
transform = etree.XSLT(styledoc)
|
||||
extensions = { ('calibre', 'inline-class') : inline_class }
|
||||
transform = etree.XSLT(styledoc, extensions=extensions)
|
||||
result = transform(doc)
|
||||
html = 'index.xhtml'
|
||||
with open(html, 'wb') as f:
|
||||
res = transform.tostring(result)
|
||||
res = res[:100].replace('xmlns:html', 'xmlns') + res[100:]
|
||||
f.write(res)
|
||||
self.write_inline_css(inline_class)
|
||||
stream.seek(0)
|
||||
mi = get_metadata(stream, 'rtf')
|
||||
if not mi.title:
|
||||
|
@ -43,21 +43,26 @@ class Pict:
|
||||
self.__out_file = out_file
|
||||
# this is left over
|
||||
self.__no_ask = 1
|
||||
|
||||
def __initiate_pict_dict(self):
|
||||
self.__pict_dict = {
|
||||
'ob<nu<open-brack' : self.__open_br_func,
|
||||
'cb<nu<clos-brack' : self.__close_br_func,
|
||||
'tx<nu<__________' : self.__text_func,
|
||||
}
|
||||
|
||||
def __open_br_func(self, line):
|
||||
return "{\n"
|
||||
|
||||
def __close_br_func(self, line):
|
||||
return "}\n"
|
||||
|
||||
def __text_func(self, line):
|
||||
#tx<nu<__________<true text
|
||||
return line[17:]
|
||||
|
||||
def __make_dir(self):
|
||||
""" Make a dirctory to put the image data in"""
|
||||
""" Make a directory to put the image data in"""
|
||||
base_name = os.path.basename(getattr(self.__orig_file, 'name',
|
||||
self.__orig_file))
|
||||
base_name = os.path.splitext(base_name)[0]
|
||||
@ -97,6 +102,7 @@ class Pict:
|
||||
pass
|
||||
if self.__run_level > 1:
|
||||
sys.stderr.write('Files removed.\n')
|
||||
|
||||
def __create_pict_file(self):
|
||||
"""Create a file for all the pict data to be written to.
|
||||
"""
|
||||
@ -104,6 +110,7 @@ class Pict:
|
||||
write_pic_obj = open(self.__pict_file, 'w')
|
||||
write_pic_obj.close()
|
||||
self.__write_pic_obj = open(self.__pict_file, 'a')
|
||||
|
||||
def __in_pict_func(self, line):
|
||||
if self.__cb_count == self.__pict_br_count:
|
||||
self.__in_pict = 0
|
||||
@ -115,6 +122,7 @@ class Pict:
|
||||
line = action(line)
|
||||
self.__write_pic_obj.write(line)
|
||||
return 0
|
||||
|
||||
def __default(self, line, write_obj):
|
||||
"""Determine if each token marks the beginning of pict data.
|
||||
If it does, create a new file to write data to (if that file
|
||||
@ -142,6 +150,7 @@ class Pict:
|
||||
self.__write_pic_obj.write("{\\pict\n")
|
||||
return 0
|
||||
return 1
|
||||
|
||||
def __print_rtf_header(self):
|
||||
"""Print to pict file the necessary RTF data for the file to be
|
||||
recognized as an RTF file.
|
||||
@ -150,6 +159,7 @@ class Pict:
|
||||
self.__write_pic_obj.write("{\\fonttbl\\f0\\null;} \n")
|
||||
self.__write_pic_obj.write("{\\colortbl\\red255\\green255\\blue255;} \n")
|
||||
self.__write_pic_obj.write("\\pard \n")
|
||||
|
||||
def process_pict(self):
|
||||
self.__make_dir()
|
||||
read_obj = open(self.__file)
|
||||
|
@ -19,9 +19,11 @@ class PluginWidget(Widget, Ui_Form):
|
||||
Widget.__init__(self, parent, 'comic_input',
|
||||
['colors', 'dont_normalize', 'keep_aspect_ratio', 'right2left',
|
||||
'despeckle', 'no_sort', 'no_process', 'landscape',
|
||||
'dont_sharpen', 'disable_trim', 'wide']
|
||||
'dont_sharpen', 'disable_trim', 'wide', 'output_format']
|
||||
)
|
||||
self.db, self.book_id = db, book_id
|
||||
for x in get_option('output_format').option.choices:
|
||||
self.opt_output_format.addItem(x)
|
||||
self.initialize_options(get_option, get_help, db, book_id)
|
||||
self.opt_no_process.toggle()
|
||||
self.opt_no_process.toggle()
|
||||
|
@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>599</width>
|
||||
<height>305</height>
|
||||
<height>343</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -100,7 +100,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="0">
|
||||
<item row="12" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
@ -120,6 +120,19 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>&Output format:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>opt_output_format</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<widget class="QComboBox" name="opt_output_format"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
@ -263,8 +276,8 @@
|
||||
<y>15</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>52</x>
|
||||
<y>225</y>
|
||||
<x>56</x>
|
||||
<y>248</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
@ -300,5 +313,21 @@
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>opt_no_process</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>opt_output_format</receiver>
|
||||
<slot>setDisabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>237</x>
|
||||
<y>12</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>370</x>
|
||||
<y>308</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
|
@ -14,16 +14,16 @@ from calibre.gui2 import choose_images, error_dialog
|
||||
from calibre.gui2.convert.metadata_ui import Ui_Form
|
||||
from calibre.ebooks.metadata import authors_to_string, string_to_authors, \
|
||||
MetaInformation
|
||||
from calibre.ebooks.metadata.opf2 import OPFCreator
|
||||
from calibre.ebooks.metadata.opf2 import metadata_to_opf
|
||||
from calibre.ptempfile import PersistentTemporaryFile
|
||||
from calibre.gui2.convert import Widget
|
||||
|
||||
def create_opf_file(db, book_id):
|
||||
mi = db.get_metadata(book_id, index_is_id=True)
|
||||
mi.application_id = uuid.uuid4()
|
||||
opf = OPFCreator(os.getcwdu(), mi)
|
||||
raw = metadata_to_opf(mi)
|
||||
opf_file = PersistentTemporaryFile('.opf')
|
||||
opf.render(opf_file)
|
||||
opf_file.write(raw)
|
||||
opf_file.close()
|
||||
return mi, opf_file
|
||||
|
||||
|
@ -23,6 +23,7 @@ from calibre.gui2.convert.debug import DebugWidget
|
||||
|
||||
|
||||
from calibre.ebooks.conversion.plumber import Plumber, supported_input_formats
|
||||
from calibre.ebooks.conversion.config import delete_specifics
|
||||
from calibre.customize.ui import available_output_formats
|
||||
from calibre.customize.conversion import OptionRecommendation
|
||||
from calibre.utils.config import prefs
|
||||
@ -115,9 +116,10 @@ class Config(ResizableDialog, Ui_Dialog):
|
||||
def __init__(self, parent, db, book_id,
|
||||
preferred_input_format=None, preferred_output_format=None):
|
||||
ResizableDialog.__init__(self, parent)
|
||||
self.setup_input_output_formats(db, book_id, preferred_input_format,
|
||||
preferred_output_format)
|
||||
self.db, self.book_id = db, book_id
|
||||
|
||||
self.setup_input_output_formats(self.db, self.book_id, preferred_input_format,
|
||||
preferred_output_format)
|
||||
self.setup_pipeline()
|
||||
|
||||
self.connect(self.input_formats, SIGNAL('currentIndexChanged(QString)'),
|
||||
@ -130,8 +132,14 @@ class Config(ResizableDialog, Ui_Dialog):
|
||||
self.show_pane)
|
||||
self.connect(self.groups, SIGNAL('entered(QModelIndex)'),
|
||||
self.show_group_help)
|
||||
rb = self.buttonBox.button(self.buttonBox.RestoreDefaults)
|
||||
self.connect(rb, SIGNAL('clicked()'), self.restore_defaults)
|
||||
self.groups.setMouseTracking(True)
|
||||
|
||||
def restore_defaults(self):
|
||||
delete_specifics(self.db, self.book_id)
|
||||
self.setup_pipeline()
|
||||
|
||||
@property
|
||||
def input_format(self):
|
||||
return unicode(self.input_formats.currentText()).lower()
|
||||
|
@ -108,8 +108,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>471</height>
|
||||
<width>810</width>
|
||||
<height>492</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
@ -138,7 +138,7 @@
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::RestoreDefaults</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -207,6 +207,9 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
||||
self.series.setEditText(mi.series)
|
||||
if mi.series_index is not None:
|
||||
self.series_index.setValue(float(mi.series_index))
|
||||
if mi.comments and mi.comments.strip():
|
||||
self.comments.setText(mi.comments)
|
||||
|
||||
|
||||
def set_cover(self):
|
||||
mi, ext = self.get_selected_format_metadata()
|
||||
@ -330,6 +333,8 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
||||
if not ext:
|
||||
ext = ''
|
||||
size = self.db.sizeof_format(row, ext)
|
||||
if size is None:
|
||||
continue
|
||||
Format(self.formats, ext, size)
|
||||
|
||||
|
||||
@ -545,6 +550,26 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
||||
if self.formats_changed:
|
||||
self.sync_formats()
|
||||
title = unicode(self.title.text())
|
||||
self.db.set_title(self.id, title, notify=False)
|
||||
au = unicode(self.authors.text())
|
||||
if au:
|
||||
self.db.set_authors(self.id, string_to_authors(au), notify=False)
|
||||
aus = unicode(self.author_sort.text())
|
||||
if aus:
|
||||
self.db.set_author_sort(self.id, aus, notify=False)
|
||||
self.db.set_isbn(self.id,
|
||||
re.sub(r'[^0-9a-zA-Z]', '', unicode(self.isbn.text())), notify=False)
|
||||
self.db.set_rating(self.id, 2*self.rating.value(), notify=False)
|
||||
self.db.set_publisher(self.id, qstring_to_unicode(self.publisher.currentText()), notify=False)
|
||||
self.db.set_tags(self.id, qstring_to_unicode(self.tags.text()).split(','), notify=False)
|
||||
self.db.set_series(self.id, qstring_to_unicode(self.series.currentText()), notify=False)
|
||||
self.db.set_series_index(self.id, self.series_index.value(), notify=False)
|
||||
self.db.set_comment(self.id, qstring_to_unicode(self.comments.toPlainText()), notify=False)
|
||||
d = self.pubdate.date()
|
||||
self.db.set_pubdate(self.id, datetime(d.year(), d.month(), d.day()))
|
||||
|
||||
if self.cover_changed and self.cover_data is not None:
|
||||
self.db.set_cover(self.id, self.cover_data)
|
||||
except IOError, err:
|
||||
if err.errno == 13: # Permission denied
|
||||
fname = err.filename if err.filename else 'file'
|
||||
@ -552,26 +577,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
||||
_('Could not open %s. Is it being used by another'
|
||||
' program?')%fname, show=True)
|
||||
raise
|
||||
self.db.set_title(self.id, title, notify=False)
|
||||
au = unicode(self.authors.text())
|
||||
if au:
|
||||
self.db.set_authors(self.id, string_to_authors(au), notify=False)
|
||||
aus = qstring_to_unicode(self.author_sort.text())
|
||||
if aus:
|
||||
self.db.set_author_sort(self.id, aus, notify=False)
|
||||
self.db.set_isbn(self.id,
|
||||
re.sub(r'[^0-9a-zA-Z]', '', unicode(self.isbn.text())), notify=False)
|
||||
self.db.set_rating(self.id, 2*self.rating.value(), notify=False)
|
||||
self.db.set_publisher(self.id, qstring_to_unicode(self.publisher.currentText()), notify=False)
|
||||
self.db.set_tags(self.id, qstring_to_unicode(self.tags.text()).split(','), notify=False)
|
||||
self.db.set_series(self.id, qstring_to_unicode(self.series.currentText()), notify=False)
|
||||
self.db.set_series_index(self.id, self.series_index.value(), notify=False)
|
||||
self.db.set_comment(self.id, qstring_to_unicode(self.comments.toPlainText()), notify=False)
|
||||
d = self.pubdate.date()
|
||||
self.db.set_pubdate(self.id, datetime(d.year(), d.month(), d.day()))
|
||||
|
||||
if self.cover_changed and self.cover_data is not None:
|
||||
self.db.set_cover(self.id, self.cover_data)
|
||||
QDialog.accept(self)
|
||||
if callable(self.accepted_callback):
|
||||
self.accepted_callback(self.id)
|
||||
|
@ -15,7 +15,7 @@ from PyQt4.Qt import Qt, SIGNAL, QObject, QCoreApplication, QUrl, QTimer, \
|
||||
from PyQt4.QtSvg import QSvgRenderer
|
||||
|
||||
from calibre import prints, patheq
|
||||
from calibre.constants import __version__, __appname__, \
|
||||
from calibre.constants import __version__, __appname__, isfrozen, islinux, \
|
||||
iswindows, isosx, filesystem_encoding
|
||||
from calibre.utils.filenames import ascii_filename
|
||||
from calibre.ptempfile import PersistentTemporaryFile
|
||||
@ -1290,7 +1290,15 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
||||
self.job_manager.launch_gui_app(viewer,
|
||||
kwargs=dict(args=args))
|
||||
else:
|
||||
paths = os.environ.get('LD_LIBRARY_PATH',
|
||||
'').split(os.pathsep)
|
||||
paths = [x for x in paths if x]
|
||||
if isfrozen and islinux and paths:
|
||||
npaths = [x for x in paths if x != sys.frozen_path]
|
||||
os.environ['LD_LIBRARY_PATH'] = os.pathsep.join(npaths)
|
||||
QDesktopServices.openUrl(QUrl.fromLocalFile(name))#launch(name)
|
||||
if isfrozen and islinux and paths:
|
||||
os.environ['LD_LIBRARY_PATH'] = os.pathsep.join(paths)
|
||||
time.sleep(2) # User feedback
|
||||
finally:
|
||||
self.unsetCursor()
|
||||
|
@ -1081,6 +1081,10 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE;
|
||||
return cPickle.loads(str(data))
|
||||
return None
|
||||
|
||||
def delete_conversion_options(self, id, format):
|
||||
self.conn.execute('DELETE FROM conversion_options WHERE book=? AND format=?',
|
||||
(id, format.upper()))
|
||||
|
||||
|
||||
def add_format(self, index, ext, stream, index_is_id=False):
|
||||
'''
|
||||
|
@ -413,6 +413,8 @@ class LibraryDatabase2(LibraryDatabase):
|
||||
self.library_path = os.path.abspath(library_path)
|
||||
self.row_factory = row_factory
|
||||
self.dbpath = os.path.join(library_path, 'metadata.db')
|
||||
self.dbpath = os.environ.get('CALIBRE_OVERRIDE_DATABASE_PATH',
|
||||
self.dbpath)
|
||||
if isinstance(self.dbpath, unicode):
|
||||
self.dbpath = self.dbpath.encode(filesystem_encoding)
|
||||
self.connect()
|
||||
|
@ -366,6 +366,21 @@ class LibraryServer(object):
|
||||
return base.intersection(epub.union(pdb))
|
||||
|
||||
def stanza_sortby_subcategory(self, updated, sortby, offset):
|
||||
pat = re.compile(r'\(.*\)')
|
||||
|
||||
def clean_author(x):
|
||||
return pat.sub('', x).strip()
|
||||
|
||||
def author_cmp(x, y):
|
||||
x = x if ',' in x else clean_author(x).rpartition(' ')[-1]
|
||||
y = y if ',' in y else clean_author(y).rpartition(' ')[-1]
|
||||
return cmp(x.lower(), y.lower())
|
||||
|
||||
def get_author(x):
|
||||
pref, ___, suff = clean_author(x).rpartition(' ')
|
||||
return suff + (', '+pref) if pref else suff
|
||||
|
||||
|
||||
what, subtitle = sortby[2:], ''
|
||||
if sortby == 'byseries':
|
||||
data = self.db.all_series()
|
||||
@ -379,13 +394,15 @@ class LibraryServer(object):
|
||||
data = self.db.all_tags2()
|
||||
data = [(x[0], x[1], len(self.get_matches('tags', x[1]))) for x in data]
|
||||
subtitle = 'Books by tag'
|
||||
fcmp = author_cmp if sortby == 'byauthor' else cmp
|
||||
data = [x for x in data if x[2] > 0]
|
||||
data.sort(cmp=lambda x, y: cmp(x[1], y[1]))
|
||||
data.sort(cmp=lambda x, y: fcmp(x[1], y[1]))
|
||||
next_offset = offset + self.max_stanza_items
|
||||
rdata = data[offset:next_offset]
|
||||
if next_offset >= len(data):
|
||||
next_offset = -1
|
||||
entries = [self.STANZA_SUBCATALOG_ENTRY.generate(title=title, id=id,
|
||||
gt = get_author if sortby == 'byauthor' else lambda x: x
|
||||
entries = [self.STANZA_SUBCATALOG_ENTRY.generate(title=gt(title), id=id,
|
||||
what=what, updated=updated, count=c).render('xml').decode('utf-8') for id,
|
||||
title, c in rdata]
|
||||
next_link = ''
|
||||
|
@ -256,7 +256,13 @@ def setup_udev_rules(group_file, reload, fatal_errors):
|
||||
sys.stdout.flush()
|
||||
groups = open(group_file, 'rb').read()
|
||||
group = 'plugdev' if 'plugdev' in groups else 'usb'
|
||||
udev = open_file('/etc/udev/rules.d/95-calibre.rules')
|
||||
old_udev = '/etc/udev/rules.d/95-calibre.rules'
|
||||
if os.path.exists(old_udev):
|
||||
os.remove(old_udev)
|
||||
if os.path.exists('/lib/udev/rules.d'):
|
||||
udev = open_file('/lib/udev/rules.d/95-calibre.rules')
|
||||
else:
|
||||
udev = open_file(old_udev)
|
||||
manifest.append(udev.name)
|
||||
udev.write('''# Sony Reader PRS-500\n'''
|
||||
'''BUS=="usb", SYSFS{idProduct}=="029b", SYSFS{idVendor}=="054c", MODE="660", GROUP="%s"\n'''%(group,)
|
||||
|
@ -20,7 +20,7 @@ What formats does |app| support conversion to/from?
|
||||
|app| supports the conversion of many input formats to many output formats.
|
||||
It can convert every input format in the following list, to every output format.
|
||||
|
||||
*Input Formats:* CBZ, CBR, CBC, EPUB, FB2, HTML, LIT, MOBI, ODT, PDF, PRC**, PDB, PML, RB, RTF, TXT
|
||||
*Input Formats:* CBZ, CBR, CBC, EPUB, FB2, HTML, LIT, LRF, MOBI, ODT, PDF, PRC**, PDB, PML, RB, RTF, TXT
|
||||
*Output Formats:* EPUB, FB2, OEB, LIT, LRF, MOBI, PDB, PML, RB, PDF, TXT
|
||||
|
||||
** PRC is a generic format, |app| supports PRC files with TextRead and MOBIBook headers
|
||||
|
@ -21,6 +21,7 @@ DEPENDENCIES = [
|
||||
('dnspython', '1.6.0', 'dnspython', 'dnspython', 'dnspython', 'dnspython'),
|
||||
('poppler-qt4', '0.10.6', 'poppler-qt4', 'poppler-qt4', 'poppler-qt4', 'poppler-qt4'),
|
||||
('podofo', '0.7', 'podofo', 'podofo', 'podofo', 'podofo'),
|
||||
('libwmf', '0.2.8', 'libwmf', 'libwmf', 'libwmf', 'libwmf'),
|
||||
]
|
||||
|
||||
|
||||
|
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
@ -4,9 +4,9 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: calibre 0.6.12\n"
|
||||
"POT-Creation-Date: 2009-09-13 10:26+MDT\n"
|
||||
"PO-Revision-Date: 2009-09-13 10:26+MDT\n"
|
||||
"Project-Id-Version: calibre 0.6.13\n"
|
||||
"POT-Creation-Date: 2009-09-18 12:45+MDT\n"
|
||||
"PO-Revision-Date: 2009-09-18 12:45+MDT\n"
|
||||
"Last-Translator: Automatically generated\n"
|
||||
"Language-Team: LANGUAGE\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@ -26,7 +26,7 @@ msgstr ""
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/prs505/books.py:199
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/usbms/device.py:703
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/usbms/device.py:706
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:403
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:410
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/fb2/input.py:65
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/fb2/input.py:67
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/html/input.py:318
|
||||
@ -60,13 +60,13 @@ msgstr ""
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:79
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:121
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:154
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:575
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:762
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/odt/input.py:44
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/odt/input.py:46
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:883
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:888
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:944
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:588
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:775
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/odt/input.py:49
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/odt/input.py:51
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:886
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:891
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:947
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/reader.py:135
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/reader.py:137
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/transforms/jacket.py:105
|
||||
@ -92,8 +92,8 @@ msgstr ""
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/split.py:82
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/writer.py:28
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/writer.py:29
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/rtf/input.py:139
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/rtf/input.py:141
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/rtf/input.py:217
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/rtf/input.py:219
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:261
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:268
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/add.py:111
|
||||
@ -109,7 +109,7 @@ msgstr ""
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf.py:48
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:106
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:139
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:397
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:402
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:41
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:42
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/library.py:391
|
||||
@ -119,15 +119,15 @@ msgstr ""
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:211
|
||||
#: /home/kovid/work/calibre/src/calibre/library/cli.py:277
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database.py:917
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:652
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:664
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1059
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1096
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1426
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:654
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:666
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1061
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1098
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1428
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1537
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server.py:476
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server.py:548
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1430
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1539
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server.py:493
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server.py:565
|
||||
#: /home/kovid/work/calibre/src/calibre/utils/localization.py:103
|
||||
#: /home/kovid/work/calibre/src/calibre/utils/podofo/__init__.py:45
|
||||
#: /home/kovid/work/calibre/src/calibre/utils/podofo/__init__.py:63
|
||||
@ -525,9 +525,9 @@ msgstr ""
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/usbms/device.py:686
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:434
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:83
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1003
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1007
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1330
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1005
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1009
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1332
|
||||
msgid "News"
|
||||
msgstr ""
|
||||
|
||||
@ -586,51 +586,55 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:274
|
||||
msgid "Number of colors for grayscale image conversion. Default: %default"
|
||||
msgid "Number of colors for grayscale image conversion. Default: %default. Values of less than 256 may result in blurred text on your device if you are creating your comics in EPUB format."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:276
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:278
|
||||
msgid "Disable normalize (improve contrast) color range for pictures. Default: False"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:279
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:281
|
||||
msgid "Maintain picture aspect ratio. Default is to fill the screen."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:281
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:283
|
||||
msgid "Disable sharpening."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:283
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:285
|
||||
msgid "Disable trimming of comic pages. For some comics, trimming might remove content as well as borders."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:286
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:288
|
||||
msgid "Don't split landscape images into two portrait images"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:288
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:290
|
||||
msgid "Keep aspect ratio and scale image using screen height as image width for viewing in landscape mode."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:291
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:293
|
||||
msgid "Used for right-to-left publications like manga. Causes landscape pages to be split into portrait pages from right to left."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:295
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:297
|
||||
msgid "Enable Despeckle. Reduces speckle noise. May greatly increase processing time."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:298
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:300
|
||||
msgid "Don't sort the files found in the comic alphabetically by name. Instead use the order they were added to the comic."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:302
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:304
|
||||
msgid "The format that images in the created ebook are converted to. You can experiment to see which format gives you optimal size and look on your device."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:308
|
||||
msgid "Apply no processing to the image"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:427
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:438
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:434
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:445
|
||||
msgid "Page"
|
||||
msgstr ""
|
||||
|
||||
@ -1434,7 +1438,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/opf2.py:1055
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1307
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1310
|
||||
msgid "Cover"
|
||||
msgstr ""
|
||||
|
||||
@ -1463,70 +1467,70 @@ msgstr ""
|
||||
msgid "All articles"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1308
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1311
|
||||
msgid "Title Page"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1309
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1312
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/transforms/htmltoc.py:15
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:51
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main_ui.py:168
|
||||
msgid "Table of Contents"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1310
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1313
|
||||
msgid "Index"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1311
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1314
|
||||
msgid "Glossary"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1312
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1315
|
||||
msgid "Acknowledgements"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1313
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1316
|
||||
msgid "Bibliography"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1314
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1317
|
||||
msgid "Colophon"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1315
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1318
|
||||
msgid "Copyright"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1316
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1319
|
||||
msgid "Dedication"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1317
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1320
|
||||
msgid "Epigraph"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1318
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1321
|
||||
msgid "Foreword"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1319
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1322
|
||||
msgid "List of Illustrations"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1320
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1323
|
||||
msgid "List of Tables"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1321
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1324
|
||||
msgid "Notes"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1322
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1325
|
||||
msgid "Preface"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1323
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1326
|
||||
msgid "Main Text"
|
||||
msgstr ""
|
||||
|
||||
@ -1814,7 +1818,7 @@ msgstr ""
|
||||
msgid "Specify the character encoding of the output document. The default is cp1252."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/rtf/input.py:108
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/rtf/input.py:183
|
||||
msgid "This RTF file has a feature calibre does not support. Convert it to HTML first and then try it."
|
||||
msgstr ""
|
||||
|
||||
@ -2001,7 +2005,7 @@ msgid "Bulk Convert"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/bulk.py:73
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/single.py:177
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/single.py:184
|
||||
msgid "Options specific to the output format."
|
||||
msgstr ""
|
||||
|
||||
@ -2033,7 +2037,7 @@ msgstr ""
|
||||
msgid "input"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:76
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:84
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/debug_ui.py:45
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/epub_output_ui.py:41
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/fb2_input_ui.py:28
|
||||
@ -2061,60 +2065,65 @@ msgstr ""
|
||||
msgid "Form"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:77
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:85
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:94
|
||||
msgid "&Number of Colors:"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:78
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:86
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:96
|
||||
msgid "Disable &normalize"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:79
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:87
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:97
|
||||
msgid "Keep &aspect ratio"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:80
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:88
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:98
|
||||
msgid "Disable &Sharpening"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:81
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:89
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:104
|
||||
msgid "Disable &Trimming"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:82
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:90
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:103
|
||||
msgid "&Wide"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:83
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:91
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:99
|
||||
msgid "&Landscape"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:84
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:92
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:101
|
||||
msgid "&Right to left"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:85
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:93
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:100
|
||||
msgid "Don't so&rt"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:86
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:94
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:102
|
||||
msgid "De&speckle"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:87
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:95
|
||||
msgid "&Disable comic processing"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:96
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/single_ui.py:107
|
||||
msgid "&Output format:"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/debug.py:19
|
||||
msgid "Debug"
|
||||
msgstr ""
|
||||
@ -2571,7 +2580,7 @@ msgid "RB Output"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/regex_builder.py:76
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1313
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1321
|
||||
msgid "Choose the format to view"
|
||||
msgstr ""
|
||||
|
||||
@ -2603,11 +2612,11 @@ msgstr ""
|
||||
msgid "Regex:"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/single.py:163
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/single.py:170
|
||||
msgid "Convert"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/single.py:188
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/single.py:195
|
||||
msgid "Options specific to the input format."
|
||||
msgstr ""
|
||||
|
||||
@ -2622,10 +2631,6 @@ msgstr ""
|
||||
msgid "&Input format:"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/single_ui.py:107
|
||||
msgid "&Output format:"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/structure_detection.py:17
|
||||
msgid ""
|
||||
"Structure\n"
|
||||
@ -2652,22 +2657,22 @@ msgstr ""
|
||||
msgid "Footer regular expression:"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/structure_detection.py:51
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/structure_detection.py:56
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:72
|
||||
msgid "Invalid regular expression"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/structure_detection.py:52
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/structure_detection.py:57
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:73
|
||||
msgid "Invalid regular expression: %s"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/structure_detection.py:57
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/structure_detection.py:62
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/toc.py:38
|
||||
msgid "Invalid XPath"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/structure_detection.py:58
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/structure_detection.py:63
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/toc.py:39
|
||||
msgid "The XPath expression %s is invalid."
|
||||
msgstr ""
|
||||
@ -3807,67 +3812,67 @@ msgstr ""
|
||||
msgid "Could not read metadata from %s format"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:221
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:227
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:224
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:230
|
||||
msgid "Could not read cover"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:222
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:225
|
||||
msgid "Could not read cover from %s format"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:228
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:231
|
||||
msgid "The cover in the %s format is invalid"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:265
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:268
|
||||
msgid "Abort the editing of all remaining books"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:454
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:459
|
||||
msgid "Downloading cover..."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:466
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:471
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:477
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:476
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:482
|
||||
msgid "Cannot fetch cover"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:467
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:478
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:472
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:483
|
||||
msgid "<b>Could not fetch cover.</b><br/>"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:468
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:473
|
||||
msgid "The download timed out."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:472
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:477
|
||||
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:484
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:489
|
||||
msgid "Bad cover"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:485
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:490
|
||||
msgid "The cover is not a valid picture"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:524
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:529
|
||||
msgid "Cannot fetch metadata"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:525
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:530
|
||||
msgid "You must specify at least one of ISBN, Title, Authors or Publisher"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:551
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:576
|
||||
msgid "Permission denied"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:552
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:577
|
||||
msgid "Could not open %s. Is it being used by another program?"
|
||||
msgstr ""
|
||||
|
||||
@ -4677,7 +4682,7 @@ msgid "Save to disk in a single directory"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:280
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1415
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1423
|
||||
msgid "Save only %s format to disk"
|
||||
msgstr ""
|
||||
|
||||
@ -4717,7 +4722,7 @@ msgid "Calibre Library"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:437
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1558
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1566
|
||||
msgid "Choose a location for your ebook library."
|
||||
msgstr ""
|
||||
|
||||
@ -4891,158 +4896,158 @@ msgstr ""
|
||||
msgid "Cannot convert"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1307
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1326
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1315
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1334
|
||||
msgid "No book selected"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1307
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1357
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1315
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1365
|
||||
msgid "Cannot view"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1325
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1333
|
||||
msgid "Cannot open folder"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1342
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1350
|
||||
msgid "Multiple Books Selected"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1343
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1351
|
||||
msgid "You are attempting to open %d books. Opening too many books at once can be slow and have a negative effect on the responsiveness of your computer. Once started the process cannot be stopped until complete. Do you wish to continue?"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1358
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1366
|
||||
msgid "%s has no available formats."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1399
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1407
|
||||
msgid "Cannot configure"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1400
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1408
|
||||
msgid "Cannot configure while there are running jobs."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1443
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1451
|
||||
msgid "No detailed info available"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1444
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1452
|
||||
msgid "No detailed information is available for books on the device."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1496
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1504
|
||||
msgid "Error talking to device"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1497
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1505
|
||||
msgid "There was a temporary error talking to the device. Please unplug and reconnect the device and or reboot."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1520
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1538
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1528
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1546
|
||||
msgid "Conversion Error"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1521
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1529
|
||||
msgid "<p>Could not convert: %s<p>It is a <a href=\"%s\">DRM</a>ed book. You must first remove the DRM using third party tools."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1539
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1547
|
||||
msgid "<b>Failed</b>"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1567
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1575
|
||||
msgid "Invalid library location"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1568
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1576
|
||||
msgid "Could not access %s. Using %s as the library."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1615
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1623
|
||||
msgid "is the result of the efforts of many volunteers from all over the world. If you find it useful, please consider donating to support its development."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1639
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1647
|
||||
msgid "There are active jobs. Are you sure you want to quit?"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1642
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1650
|
||||
msgid ""
|
||||
" is communicating with the device!<br>\n"
|
||||
" Quitting may cause corruption on the device.<br>\n"
|
||||
" Are you sure you want to quit?"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1646
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1654
|
||||
msgid "WARNING: Active jobs"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1697
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1705
|
||||
msgid "will keep running in the system tray. To close it, choose <b>Quit</b> in the context menu of the system tray."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1716
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1724
|
||||
msgid "<span style=\"color:red; font-weight:bold\">Latest version: <a href=\"%s\">%s</a></span>"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1724
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1732
|
||||
msgid "Update available"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1725
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1733
|
||||
msgid "%s has been updated to version %s. See the <a href=\"http://calibre.kovidgoyal.net/wiki/Changelog\">new features</a>. Visit the download page?"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1743
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1751
|
||||
msgid "Use the library located at the specified path."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1745
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1753
|
||||
msgid "Start minimized to system tray."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1747
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1755
|
||||
msgid "Log debugging information to console"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1749
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1757
|
||||
msgid "Do not check for updates"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1797
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1805
|
||||
msgid "If you are sure it is not running"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1799
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1807
|
||||
msgid "Cannot Start "
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1800
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1808
|
||||
msgid "%s is already running."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1803
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1811
|
||||
msgid "may be running in the system tray, in the"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1805
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1813
|
||||
msgid "upper right region of the screen."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1807
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1815
|
||||
msgid "lower right region of the screen."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1810
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1818
|
||||
msgid "try rebooting your computer."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1812
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1824
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1820
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1832
|
||||
msgid "try deleting the file"
|
||||
msgstr ""
|
||||
|
||||
@ -5229,46 +5234,46 @@ msgid "Publishers"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:34
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:105
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:106
|
||||
msgid "Starting conversion of %d books"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:64
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:183
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:184
|
||||
msgid "Convert book %d of %d (%s)"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:90
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:203
|
||||
msgid "Could not convert some books"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:91
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:204
|
||||
msgid "Could not convert some books"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:92
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:205
|
||||
msgid "Could not convert %d of %d books, because no suitable source format was found."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:122
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:123
|
||||
msgid "Queueing books for bulk conversion"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:182
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:183
|
||||
msgid "Queueing "
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:236
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:237
|
||||
msgid "You must set a username and password for %s"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:241
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:242
|
||||
msgid "Fetch news from "
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:252
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:253
|
||||
msgid "Convert existing"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:253
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:254
|
||||
msgid "The following books have already been converted to %s format. Do you wish to reconvert them?"
|
||||
msgstr ""
|
||||
|
||||
@ -6120,27 +6125,27 @@ msgid ""
|
||||
"For help on an individual command: %%prog command --help\n"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1563
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1565
|
||||
msgid "<p>Migrating old database to ebook library in %s<br><center>"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1592
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1594
|
||||
msgid "Copying <b>%s</b>"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1609
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1611
|
||||
msgid "Compacting database"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1697
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1699
|
||||
msgid "Checking SQL integrity..."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1734
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1736
|
||||
msgid "Checking for missing files."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1758
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1760
|
||||
msgid "Checked id"
|
||||
msgstr ""
|
||||
|
||||
@ -6240,7 +6245,7 @@ msgstr ""
|
||||
msgid "Password to access your calibre library. Username is "
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server.py:628
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server.py:645
|
||||
msgid ""
|
||||
"[options]\n"
|
||||
"\n"
|
||||
@ -6466,7 +6471,7 @@ msgstr ""
|
||||
msgid "Article download failed: %s"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1022
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1024
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/recipe_borba.py:81
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/recipe_glas_srpske.py:77
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/recipe_instapaper.py:59
|
||||
@ -6483,12 +6488,12 @@ msgid "sr-Latn-RS"
|
||||
msgstr ""
|
||||
|
||||
#:
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/recipe_le_monde.py:108
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/recipe_le_monde.py:119
|
||||
msgid "Skipping duplicated article: %s"
|
||||
msgstr ""
|
||||
|
||||
#:
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/recipe_le_monde.py:113
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/recipe_le_monde.py:126
|
||||
msgid "Skipping filtered article: %s"
|
||||
msgstr ""
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
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
@ -84,9 +84,12 @@ elif iswindows:
|
||||
_lib = os.path.join(os.path.dirname(sys.executable), 'CORE_RL_wand_.dll') \
|
||||
if isfrozen else 'CORE_RL_wand_'
|
||||
else:
|
||||
_lib = util.find_library('MagickWand')
|
||||
if _lib is None:
|
||||
_lib = util.find_library('Wand')
|
||||
if isfrozen:
|
||||
_lib = os.path.join(sys.frozen_path, 'libMagickWand.so')
|
||||
else:
|
||||
_lib = util.find_library('MagickWand')
|
||||
if _lib is None:
|
||||
_lib = util.find_library('Wand')
|
||||
|
||||
_magick = None
|
||||
_magick_error = None
|
||||
|
@ -12,12 +12,47 @@ BASH completion for calibre commands that are too complex for simple
|
||||
completion.
|
||||
'''
|
||||
|
||||
import sys, os, shlex, glob, re
|
||||
from functools import partial
|
||||
import sys, os, shlex, glob, re, cPickle
|
||||
|
||||
def prints(*args, **kwargs):
|
||||
'''
|
||||
Print unicode arguments safely by encoding them to preferred_encoding
|
||||
Has the same signature as the print function from Python 3, except for the
|
||||
additional keyword argument safe_encode, which if set to True will cause the
|
||||
function to use repr when encoding fails.
|
||||
'''
|
||||
file = kwargs.get('file', sys.stdout)
|
||||
sep = kwargs.get('sep', ' ')
|
||||
end = kwargs.get('end', '\n')
|
||||
enc = 'utf-8'
|
||||
safe_encode = kwargs.get('safe_encode', False)
|
||||
for i, arg in enumerate(args):
|
||||
if isinstance(arg, unicode):
|
||||
try:
|
||||
arg = arg.encode(enc)
|
||||
except UnicodeEncodeError:
|
||||
if not safe_encode:
|
||||
raise
|
||||
arg = repr(arg)
|
||||
if not isinstance(arg, str):
|
||||
try:
|
||||
arg = str(arg)
|
||||
except ValueError:
|
||||
arg = unicode(arg)
|
||||
if isinstance(arg, unicode):
|
||||
try:
|
||||
arg = arg.encode(enc)
|
||||
except UnicodeEncodeError:
|
||||
if not safe_encode:
|
||||
raise
|
||||
arg = repr(arg)
|
||||
|
||||
file.write(arg)
|
||||
if i != len(args)-1:
|
||||
file.write(sep)
|
||||
file.write(end)
|
||||
|
||||
from calibre import prints
|
||||
|
||||
debug = partial(prints, file=sys.stderr)
|
||||
|
||||
def split(src):
|
||||
try:
|
||||
@ -47,10 +82,10 @@ def get_opts_from_parser(parser, prefix):
|
||||
if x.startswith(prefix):
|
||||
yield x
|
||||
for o in parser.option_list:
|
||||
for x in do_opt(o): yield x
|
||||
for x in do_opt(o): yield x+' '
|
||||
for g in parser.option_groups:
|
||||
for o in g.option_list:
|
||||
for x in do_opt(o): yield x
|
||||
for x in do_opt(o): yield x+' '
|
||||
|
||||
def send(ans):
|
||||
pat = re.compile('([^0-9a-zA-Z_./-])')
|
||||
@ -74,6 +109,8 @@ class EbookConvert(object):
|
||||
self.words = words
|
||||
self.prefix = prefix
|
||||
self.previous = words[-2 if prefix else -1]
|
||||
self.cache = cPickle.load(open(os.path.join(sys.resources_location,
|
||||
'ebook-convert-complete.pickle'), 'rb'))
|
||||
self.complete(wc)
|
||||
|
||||
def complete(self, wc):
|
||||
@ -82,41 +119,42 @@ class EbookConvert(object):
|
||||
elif wc == 3:
|
||||
self.complete_output()
|
||||
else:
|
||||
from calibre.ebooks.conversion.cli import create_option_parser
|
||||
from calibre.utils.logging import Log
|
||||
log = Log()
|
||||
log.outputs = []
|
||||
ans = []
|
||||
if not self.prefix or self.prefix.startswith('-'):
|
||||
try:
|
||||
parser, _ = create_option_parser(self.words[:3], log)
|
||||
ans += list(get_opts_from_parser(parser, self.prefix))
|
||||
except:
|
||||
pass
|
||||
q = list(self.words[1:3])
|
||||
q = [os.path.splitext(x)[0 if x.startswith('.') else 1].partition('.')[-1].lower() for x in q]
|
||||
if not q[1]:
|
||||
q[1] = 'oeb'
|
||||
q = tuple(q)
|
||||
if q in self.cache:
|
||||
ans = [x for x in self.cache[q] if x.startswith(self.prefix)]
|
||||
else:
|
||||
from calibre.ebooks.conversion.cli import create_option_parser
|
||||
from calibre.utils.logging import Log
|
||||
log = Log()
|
||||
log.outputs = []
|
||||
ans = []
|
||||
if not self.prefix or self.prefix.startswith('-'):
|
||||
try:
|
||||
parser, _ = create_option_parser(self.words[:3], log)
|
||||
ans += list(get_opts_from_parser(parser, self.prefix))
|
||||
except:
|
||||
pass
|
||||
if self.previous.startswith('-'):
|
||||
ans += list(files_and_dirs(self.prefix, None))
|
||||
send(ans)
|
||||
|
||||
def complete_input(self):
|
||||
from calibre.ebooks.conversion.plumber import supported_input_formats
|
||||
ans = list(files_and_dirs(self.prefix, supported_input_formats()))
|
||||
from calibre.web.feeds.recipes import recipes
|
||||
ans += [t.title+'.recipe ' for t in recipes if
|
||||
(t.title+'.recipe').startswith(self.prefix)]
|
||||
ans = list(files_and_dirs(self.prefix, self.cache['input_fmts']))
|
||||
ans += [t for t in self.cache['input_recipes'] if
|
||||
t.startswith(self.prefix)]
|
||||
send(ans)
|
||||
|
||||
def complete_output(self):
|
||||
from calibre.customize.ui import available_output_formats
|
||||
fmts = available_output_formats()
|
||||
fmts = self.cache['output']
|
||||
ans = list(files_and_dirs(self.prefix, fmts))
|
||||
ans += ['.'+x+' ' for x in fmts if ('.'+x).startswith(self.prefix)]
|
||||
send(ans)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def main(args=sys.argv):
|
||||
comp_line, pos = os.environ['COMP_LINE'], int(os.environ['COMP_POINT'])
|
||||
module = split(comp_line)[0].split(os.sep)[-1]
|
||||
|
@ -1019,6 +1019,8 @@ class BasicNewsRecipe(Recipe):
|
||||
title, url = None, obj
|
||||
else:
|
||||
title, url = obj
|
||||
if url.startswith('feed://'):
|
||||
url = 'http'+url[4:]
|
||||
self.report_progress(0, _('Fetching feed')+' %s...'%(title if title else url))
|
||||
try:
|
||||
with closing(self.browser.open(url)) as f:
|
||||
|
@ -57,7 +57,7 @@ recipe_modules = ['recipe_' + r for r in (
|
||||
'monitor', 'republika', 'beta', 'beta_en', 'glasjavnosti',
|
||||
'esquire', 'livemint', 'thedgesingapore', 'darknet', 'rga',
|
||||
'intelligencer', 'theoldfoodie', 'hln_be', 'honvedelem',
|
||||
'the_new_republic', 'philly',
|
||||
'the_new_republic', 'philly', 'salon', 'tweakers',
|
||||
)]
|
||||
|
||||
|
||||
|
@ -10,8 +10,8 @@ from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class DerStandardRecipe(BasicNewsRecipe):
|
||||
title = u'derStandard'
|
||||
__author__ = 'Gerhard Aigner'
|
||||
description = u'Nachrichten aus Österreich'
|
||||
__author__ = 'Gerhard Aigner and Sujata Raman'
|
||||
description = u'Nachrichten aus ??sterreich'
|
||||
publisher ='derStandard.at'
|
||||
category = 'news, politics, nachrichten, Austria'
|
||||
use_embedded_content = False
|
||||
@ -21,18 +21,15 @@ class DerStandardRecipe(BasicNewsRecipe):
|
||||
encoding = 'utf-8'
|
||||
language = 'de'
|
||||
|
||||
recursions = 0
|
||||
oldest_article = 1
|
||||
max_articles_per_feed = 100
|
||||
|
||||
html2lrf_options = [
|
||||
'--comment' , description
|
||||
, '--category' , category
|
||||
, '--publisher', publisher
|
||||
]
|
||||
|
||||
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"'
|
||||
|
||||
extra_css = '''
|
||||
.artikelBody{font-family:Arial,Helvetica,sans-serif;}
|
||||
.artikelLeft{font-family:Arial,Helvetica,sans-serif;font-size:x-small;}
|
||||
h4{color:#404450;font-size:x-small;}
|
||||
h6{color:#404450; font-size:x-small;}
|
||||
'''
|
||||
feeds = [(u'International', u'http://derstandard.at/?page=rss&ressort=internationalpolitik'),
|
||||
(u'Inland', u'http://derstandard.at/?page=rss&ressort=innenpolitik'),
|
||||
(u'Wirtschaft', u'http://derstandard.at/?page=rss&ressort=investor'),
|
||||
@ -43,22 +40,34 @@ class DerStandardRecipe(BasicNewsRecipe):
|
||||
(u'Kultur', u'http://derstandard.at/?page=rss&ressort=kultur'),
|
||||
(u'Wissenschaft', u'http://derstandard.at/?page=rss&ressort=wissenschaft'),
|
||||
(u'Gesundheit', u'http://derstandard.at/?page=rss&ressort=gesundheit'),
|
||||
(u'Bildung', u'http://derstandard.at/?page=rss&ressort=subildung')]
|
||||
remove_tags = [dict(name='div'), dict(name='a'), dict(name='link'), dict(name='meta'),
|
||||
dict(name='form',attrs={'name':'sitesearch'}), dict(name='hr')]
|
||||
(u'Bildung', u'http://derstandard.at/?page=rss&ressort=subildung')
|
||||
]
|
||||
|
||||
keep_only_tags = [
|
||||
dict(name='div', attrs={'class':["artikel","artikelLeft","artikelBody"]}) ,
|
||||
]
|
||||
|
||||
remove_tags = [
|
||||
dict(name='link'), dict(name='meta'),dict(name='iframe'),dict(name='style'),
|
||||
dict(name='form',attrs={'name':'sitesearch'}), dict(name='hr'),
|
||||
dict(name='div', attrs={'class':["diashow"]})]
|
||||
preprocess_regexps = [
|
||||
(re.compile(r'\[[\d]*\]', re.DOTALL|re.IGNORECASE), lambda match: ''),
|
||||
(re.compile(r'bgcolor="#\w{3,6}"', re.DOTALL|re.IGNORECASE), lambda match: '')
|
||||
]
|
||||
|
||||
def print_version(self, url):
|
||||
return url.replace('?id=', 'txt/?id=')
|
||||
filter_regexps = [r'/r[1-9]*']
|
||||
|
||||
def get_article_url(self, article):
|
||||
'''if the article links to a index page (ressort) or a picture gallery
|
||||
(ansichtssache), don't add it'''
|
||||
if (article.link.count('ressort') > 0 or article.title.lower().count('ansichtssache') > 0):
|
||||
if ( article.link.count('ressort') > 0 or article.title.lower().count('ansichtssache') > 0 ):
|
||||
return None
|
||||
matchObj = re.search( re.compile(r'/r'+'[1-9]*',flags=0), article.link,flags=0)
|
||||
|
||||
if matchObj:
|
||||
return None
|
||||
|
||||
return article.link
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
@ -66,4 +75,7 @@ class DerStandardRecipe(BasicNewsRecipe):
|
||||
soup.html['lang'] = self.lang
|
||||
mtag = '<meta http-equiv="Content-Type" content="text/html; charset=' + self.encoding + '">'
|
||||
soup.head.insert(0,mtag)
|
||||
|
||||
for t in soup.findAll(['ul', 'li']):
|
||||
t.name = 'div'
|
||||
return soup
|
@ -8,7 +8,7 @@ Fetch FTD.
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
|
||||
class FTheiseDe(BasicNewsRecipe):
|
||||
class FTDe(BasicNewsRecipe):
|
||||
|
||||
title = 'FTD'
|
||||
description = 'Financial Times Deutschland'
|
||||
@ -16,24 +16,47 @@ class FTheiseDe(BasicNewsRecipe):
|
||||
use_embedded_content = False
|
||||
timefmt = ' [%d %b %Y]'
|
||||
language = 'de'
|
||||
|
||||
max_articles_per_feed = 40
|
||||
no_stylesheets = True
|
||||
|
||||
remove_tags = [dict(id='navi_top'),
|
||||
dict(id='topbanner'),
|
||||
dict(id='seitenkopf'),
|
||||
dict(id='BoxA-0-0-0'),
|
||||
dict(id='footer'),
|
||||
dict(id='rating_open'),
|
||||
dict(id='ADS_Top'),
|
||||
dict(id='spinner'),
|
||||
dict(id='ftd-contentad'),
|
||||
dict(id='nava-50009007-1-0'),
|
||||
dict(id='navli-50009007-1-0'),
|
||||
dict(id='starRating'),
|
||||
dict(id='saveRating'),
|
||||
dict(id='yLayer'),
|
||||
dict(id='yTip'),
|
||||
dict(id='ftdCookieStorage'),
|
||||
dict(id='ADS_Middle1'),
|
||||
#dict(id='IDMS_ajax_chart_price_information_table'),
|
||||
dict(id='ivwimg'),
|
||||
dict(name='span', attrs={'class':'rsaquo'}),
|
||||
dict(name='p', attrs={'class':'zwischenhead'}),
|
||||
dict(name='ul', attrs={'class':'list'}),
|
||||
dict(name='ul', attrs={'class':'nav'}),
|
||||
dict(name='p', attrs={'class':'articleOptionHead'}),
|
||||
dict(name='p', attrs={'class':'articleOptionFoot'}),
|
||||
dict(name='div', attrs={'class':'chartBox'}),
|
||||
dict(name='div', attrs={'class':'ratingOpt starRatingContainer articleOptionFootFrame'}),
|
||||
dict(name='div', attrs={'class':'box boxArticleBasic boxComments boxTransparent'}),
|
||||
dict(name='div', attrs={'class':'box boxNavTabs '}),
|
||||
dict(name='span', attrs={'class':'vote_455857'}),
|
||||
dict(name='div', attrs={'class':'relatedhalb'}),
|
||||
dict(name='div', attrs={'class':'box boxListScrollOutline'}),
|
||||
dict(name='div', attrs={'class':'tagCloud'}),
|
||||
dict(name='div', attrs={'class':'box boxArticleBasic boxNavTabsOutline'}),
|
||||
dict(name='div', attrs={'class':'ftdHpNav'}),
|
||||
dict(name='div', attrs={'class':'ftdHead'}),
|
||||
dict(name='div', attrs={'class':'ftdTicker'}),
|
||||
dict(name='div', attrs={'class':'ftdBreadcrumb'}),
|
||||
dict(name='div', attrs={'class':'bpoll'}),
|
||||
dict(name='div', attrs={'class':'pollokknopf'}),
|
||||
dict(name='div', attrs={'class':'videohint'}),
|
||||
@ -43,9 +66,24 @@ class FTheiseDe(BasicNewsRecipe):
|
||||
dict(name='div', attrs={'class':'abspielen'}),
|
||||
dict(name='div', attrs={'class':'wertungoben'}),
|
||||
dict(name='div', attrs={'class':'artikelfuss'}),
|
||||
dict(name='a', attrs={'class':'rating'}),
|
||||
dict(name='div', attrs={'class':'articleOptionFootFrame'}),
|
||||
dict(name='div', attrs={'class':'artikelsplitfaq'})]
|
||||
remove_tags_after = [dict(name='div', attrs={'class':'artikelfuss'})]
|
||||
remove_tags_after = [dict(name='a', attrs={'class':'more'})]
|
||||
|
||||
feeds = [ ('FTD', 'http://www.ftd.de/static/ticker/ftd-topnews.rdf') ]
|
||||
feeds = [ ('Finanzen', 'http://www.ftd.de/rss2/finanzen/maerkte'),
|
||||
('Meinungshungrige', 'http://www.ftd.de/rss2/meinungshungrige'),
|
||||
('Unternehmen', 'http://www.ftd.de/rss2/unternehmen'),
|
||||
('Politik', 'http://www.ftd.de/rss2/politik'),
|
||||
('Karriere_Management', 'http://www.ftd.de/rss2/karriere-management'),
|
||||
('IT_Medien', 'http://www.ftd.de/rss2/it-medien'),
|
||||
('Wissen', 'http://www.ftd.de/rss2/wissen'),
|
||||
('Sport', 'http://www.ftd.de/rss2/sport'),
|
||||
('Auto', 'http://www.ftd.de/rss2/auto'),
|
||||
('Lifestyle', 'http://www.ftd.de/rss2/lifestyle')
|
||||
|
||||
]
|
||||
|
||||
|
||||
def print_version(self, url):
|
||||
return url + '?mode=print'
|
||||
|
@ -7,13 +7,12 @@ lemonde.fr
|
||||
'''
|
||||
|
||||
import re
|
||||
#from datetime import date
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
|
||||
class LeMonde(BasicNewsRecipe):
|
||||
title = 'LeMonde.fr'
|
||||
__author__ = 'Mathieu Godlewski <mathieu at godlewski.fr>'
|
||||
__author__ = 'Mathieu Godlewski and Sujata Raman'
|
||||
description = 'Global news in french'
|
||||
oldest_article = 3
|
||||
language = 'fr'
|
||||
@ -23,24 +22,27 @@ class LeMonde(BasicNewsRecipe):
|
||||
remove_javascript = True
|
||||
|
||||
|
||||
#cover_url='http://abonnes.lemonde.fr/titresdumonde/'+date.today().strftime("%y%m%d")+'/1.jpg'
|
||||
# cover_url='http://abonnes.lemonde.fr/titresdumonde/'+date.today().strftime("%y%m%d")+'/1.jpg'
|
||||
|
||||
|
||||
extra_css = '''
|
||||
.dateline{color:#666666;font-family:verdana,sans-serif;font-size:xx-small;}
|
||||
.dateline{color:#666666;font-family:verdana,sans-serif;font-size:x-small;}
|
||||
.author{font-family:verdana,sans-serif;font-size:x-small;color:#222222;}
|
||||
.articleImage{color:#666666;font-family:verdana,sans-serif;font-size:x-small;}
|
||||
.mainText{font-family:Georgia,serif;color:#222222;}
|
||||
.LM_articleText{font-family:Georgia,serif;}
|
||||
.LM_articleText{font-family:Arial,Helvetica,sans-serif;}
|
||||
.LM_titleZone{font-family:Arial,Helvetica,sans-serif;}
|
||||
.mainContent{font-family:Georgia,serif;}
|
||||
.mainTitle{font-family:Georgia,serif;}
|
||||
.LM_content{font-family:Georgia,serif;}
|
||||
.LM_caption{font-family:Georgia,serif;font-size:-small;}
|
||||
.LM_imageSource{font-family:Arial,Helvetica,sans-serif;font-size:x-small;color:#666666;}
|
||||
h1{font-family:Arial,Helvetica,sans-serif;font-size:medium;color:#000000;}
|
||||
.post{font-family:Arial,Helvetica,sans-serif;}
|
||||
.mainTitle{font-family:Georgia,serif;}
|
||||
.content{font-family:Georgia,serif;}
|
||||
.LM_caption{font-family:Georgia,serif;font-size:xx-small;}
|
||||
.LM_imageSource{font-family:Arial,Helvetica,sans-serif;font-size:xx-small;color:#666666;}
|
||||
h1{font-family:Georgia,serif;font-size:medium;color:#000000;}
|
||||
.entry{font-family:Georgia,Times New Roman,Times,serif;}
|
||||
.mainTitle{font-family:Georgia,Times New Roman,Times,serif;}
|
||||
h2{font-family:Georgia,Times New Roman,Times,serif;font-size:large;}
|
||||
small{{font-family:Arial,Helvetica,sans-serif;font-size:xx-small;}
|
||||
.entry{font-family:Georgia,serif;}
|
||||
h2{font-family:Arial,Helvetica,sans-serif;font-size:large;}
|
||||
small{font-family:Arial,Helvetica,sans-serif; color:#ED1B23;}
|
||||
'''
|
||||
|
||||
feeds = [
|
||||
@ -71,11 +73,10 @@ class LeMonde(BasicNewsRecipe):
|
||||
dict(name='iframe', attrs={}),
|
||||
dict(name='table', attrs={'id':["toolBox"]}),
|
||||
dict(name='table', attrs={'class':["bottomToolBox"]}),
|
||||
dict(name='div', attrs={'class':["pageNavigation","fenetreBoxesContainer","breakingNews","LM_toolsBottom","LM_comments","LM_tools","pave_meme_sujet_hidden","boxMemeSujet"]}),
|
||||
dict(name='div', attrs={'class':["pageNavigation","LM_pagination","fenetreBoxesContainer","breakingNews","LM_toolsBottom","LM_comments","LM_tools","pave_meme_sujet_hidden","boxMemeSujet"]}),
|
||||
dict(name='div', attrs={'id':["miniUne","LM_sideBar"]}),
|
||||
]
|
||||
|
||||
|
||||
preprocess_regexps = [ (re.compile(i[0], re.IGNORECASE|re.DOTALL), i[1]) for i in
|
||||
[
|
||||
(r'<html.*(<div class="post".*?>.*?</div>.*?<div class="entry">.*?</div>).*You can start editing here.*</html>', lambda match : '<html><body>'+match.group(1)+'</body></html>'),
|
||||
@ -101,6 +102,16 @@ class LeMonde(BasicNewsRecipe):
|
||||
# Used to filter duplicated articles
|
||||
articles_list = []
|
||||
|
||||
def get_cover_url(self):
|
||||
cover_url = None
|
||||
soup = self.index_to_soup('http://www.lemonde.fr/web/monde_pdf/0,33-0,1-0,0.html')
|
||||
link_item = soup.find('div',attrs={'class':'pg-gch'})
|
||||
|
||||
if link_item and link_item.img:
|
||||
cover_url = link_item.img['src']
|
||||
|
||||
return cover_url
|
||||
|
||||
def get_article_url(self, article):
|
||||
url=article.get('link', None)
|
||||
url=url[0:url.find("#")]
|
||||
@ -109,8 +120,13 @@ class LeMonde(BasicNewsRecipe):
|
||||
return False
|
||||
if self.is_article_wanted(url):
|
||||
self.articles_list.append(url)
|
||||
return url
|
||||
if '/portfolio/' in url or '/video/' in url:
|
||||
url = None
|
||||
return url
|
||||
self.log_debug(_('Skipping filtered article: %s')%url)
|
||||
url = article.get('guid', None)
|
||||
|
||||
|
||||
return False
|
||||
|
||||
|
||||
@ -122,4 +138,15 @@ class LeMonde(BasicNewsRecipe):
|
||||
return False
|
||||
return False
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
|
||||
for item in soup.findAll(style=True):
|
||||
del item['style']
|
||||
|
||||
for item in soup.findAll(face=True):
|
||||
del item['face']
|
||||
for tag in soup.findAll(name=['ul','li']):
|
||||
tag.name = 'div'
|
||||
|
||||
return soup
|
||||
|
||||
|
41
src/calibre/web/feeds/recipes/recipe_salon.py
Normal file
41
src/calibre/web/feeds/recipes/recipe_salon.py
Normal file
@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||
from __future__ import with_statement
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class Salon_com(BasicNewsRecipe):
|
||||
title = 'Salon.com'
|
||||
__author__ = 'cix3'
|
||||
description = 'Salon.com - Breaking news, opinion, politics, entertainment, sports and culture.'
|
||||
timefmt = ' [%b %d, %Y]'
|
||||
language = 'en'
|
||||
|
||||
oldest_article = 7
|
||||
max_articles_per_feed = 100
|
||||
|
||||
remove_tags = [dict(name='div', attrs={'class':['ad_content', 'clearfix']}), dict(name='hr'), dict(name='img')]
|
||||
|
||||
remove_tags_before = dict(name='h2')
|
||||
|
||||
feeds = [
|
||||
('All News & Politics', 'http://feeds.salon.com/salon/news'),
|
||||
('War Room', 'http://feeds.salon.com/salon/war_room'),
|
||||
('All Arts & Entertainment', 'http://feeds.salon.com/salon/ent'),
|
||||
('I Like to Watch', 'http://feeds.salon.com/salon/iltw'),
|
||||
('Book Reviews', 'http://feeds.salon.com/salon/books'),
|
||||
('All Life stories', 'http://feeds.salon.com/salon/mwt'),
|
||||
('Broadsheet', 'http://feeds.salon.com/salon/broadsheet'),
|
||||
('All Opinion', 'http://feeds.salon.com/salon/opinion'),
|
||||
('All Sports', 'http://feeds.salon.com/salon/sports'),
|
||||
('All Tech & Business', 'http://feeds.salon.com/salon/tech'),
|
||||
('Ask the Pilot', 'http://feeds.salon.com/salon/ask_the_pilot'),
|
||||
('How the World Works', 'http://feeds.salon.com/salon/htww')
|
||||
]
|
||||
|
||||
def print_version(self, url):
|
||||
return url.replace('/index.html', '/print.html')
|
@ -7,7 +7,6 @@ spiegel.de
|
||||
'''
|
||||
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
from calibre.ebooks.BeautifulSoup import Tag
|
||||
|
||||
class Spiegel_ger(BasicNewsRecipe):
|
||||
title = 'Spiegel Online - German'
|
||||
@ -17,49 +16,31 @@ class Spiegel_ger(BasicNewsRecipe):
|
||||
category = 'SPIEGEL ONLINE, DER SPIEGEL, Nachrichten, News,Dienste, RSS, RSS, Feedreader, Newsfeed, iGoogle, Netvibes, Widget'
|
||||
oldest_article = 7
|
||||
max_articles_per_feed = 100
|
||||
language = 'de'
|
||||
|
||||
language = 'de'
|
||||
lang = 'de-DE'
|
||||
no_stylesheets = True
|
||||
use_embedded_content = False
|
||||
encoding = 'cp1252'
|
||||
|
||||
html2lrf_options = [
|
||||
'--comment', description
|
||||
, '--category', category
|
||||
, '--publisher', publisher
|
||||
]
|
||||
conversion_options = {
|
||||
'comment' : description
|
||||
, 'tags' : category
|
||||
, 'publisher' : publisher
|
||||
, 'language' : lang
|
||||
}
|
||||
|
||||
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"'
|
||||
|
||||
keep_only_tags = [dict(name='div', attrs={'id':'spMainContent'})]
|
||||
keep_only_tags = [dict(name='div', attrs={'id':'spArticleContent'})]
|
||||
|
||||
remove_tags = [dict(name=['object','link','base'])]
|
||||
remove_tags = [dict(name=['object','link','base','iframe'])]
|
||||
|
||||
remove_tags_after = dict(name='div', attrs={'id':'spArticleBody'})
|
||||
|
||||
feeds = [(u'Spiegel Online', u'http://www.spiegel.de/schlagzeilen/index.rss')]
|
||||
|
||||
def print_version(self, url):
|
||||
main, sep, rest = url.rpartition(',')
|
||||
rmt = url.rpartition('#')[0]
|
||||
main, sep, rest = rmt.rpartition(',')
|
||||
rmain, rsep, rrest = main.rpartition(',')
|
||||
return rmain + ',druck-' + rrest + ',' + rest
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
mlang = Tag(soup,'meta',[("http-equiv","Content-Language"),("content",self.lang)])
|
||||
mcharset = Tag(soup,'meta',[("http-equiv","Content-Type"),("content","text/html; charset=UTF-8")])
|
||||
soup.head.insert(0,mlang)
|
||||
soup.head.insert(1,mcharset)
|
||||
for item in soup.findAll(style=True):
|
||||
del item['style']
|
||||
htmltag = soup.find('html')
|
||||
if not htmltag:
|
||||
thtml = Tag(soup,'html',[("lang",self.lang),("xml:lang",self.lang),("dir","ltr")])
|
||||
soup.insert(0,thtml)
|
||||
thead = soup.head
|
||||
tbody = soup.body
|
||||
thead.extract()
|
||||
tbody.extract()
|
||||
soup.html.insert(0,tbody)
|
||||
soup.html.insert(0,thead)
|
||||
return soup
|
||||
purl = rmain + ',druck-' + rrest + ',' + rest
|
||||
return purl
|
||||
|
44
src/calibre/web/feeds/recipes/recipe_tweakers.py
Normal file
44
src/calibre/web/feeds/recipes/recipe_tweakers.py
Normal file
@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||
from __future__ import with_statement
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import re
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class Tweakers(BasicNewsRecipe):
|
||||
title = u'Tweakers.net'
|
||||
__author__ = 'Kovid Goyal'
|
||||
language = 'nl'
|
||||
oldest_article = 4
|
||||
max_articles_per_feed = 40
|
||||
|
||||
keep_only_tags = [dict(name='div', attrs={'class':'columnwrapper news'})]
|
||||
|
||||
remove_tags = [dict(name='div', attrs={'class':'reacties'}),
|
||||
{'id' : ['utracker']},
|
||||
{'class' : ['sidebar']},
|
||||
{'class' : re.compile('nextPrevious')},
|
||||
]
|
||||
no_stylesheets=True
|
||||
|
||||
feeds = [(u'Tweakers.net', u'http://tweakers.net/feeds/nieuws.xml')]
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
for a in soup.findAll('a', href=True, rel=True):
|
||||
if a['rel'].startswith('imageview'):
|
||||
a['src'] = a['href']
|
||||
del a['href']
|
||||
a.name = 'img'
|
||||
for x in a.findAll(True):
|
||||
x.extract()
|
||||
return soup
|
||||
|
||||
def postprocess_html(self, soup, first):
|
||||
for base in soup.findAll('base'):
|
||||
base.extract()
|
||||
return soup
|
||||
|
@ -19,10 +19,12 @@ class ZeitDe(BasicNewsRecipe):
|
||||
timefmt = ' [%d %b %Y]'
|
||||
max_articles_per_feed = 40
|
||||
no_stylesheets = True
|
||||
encoding = 'latin1'
|
||||
encoding = 'utf8'
|
||||
|
||||
remove_tags = [{'class': 'adwrap'}]
|
||||
keep_only_tags = [{'name': 'div', 'class': 'content'}]
|
||||
|
||||
feeds = [ ('Kurznachrichten', 'http://newsfeed.zeit.de/news/index'),
|
||||
feeds = [ ('Kurznachrichten', 'http://newsfeed.zeit.de/index'),
|
||||
('Politik', 'http://newsfeed.zeit.de/politik/index'),
|
||||
('Wirtschaft', 'http://newsfeed.zeit.de/wirtschaft/index'),
|
||||
('Meinung', 'http://newsfeed.zeit.de/meinung/index'),
|
||||
@ -32,5 +34,5 @@ class ZeitDe(BasicNewsRecipe):
|
||||
]
|
||||
|
||||
def print_version(self,url):
|
||||
return url.replace('http://www.zeit.de/', 'http://images.zeit.de/text/').replace('?from=rss', '')
|
||||
return url.replace('http://www.zeit.de/', 'http://mobil.zeit.de/')
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user