mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Pull from trunk
This commit is contained in:
commit
b8a5d12234
@ -2,7 +2,7 @@
|
|||||||
<?eclipse-pydev version="1.0"?>
|
<?eclipse-pydev version="1.0"?>
|
||||||
|
|
||||||
<pydev_project>
|
<pydev_project>
|
||||||
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.6</pydev_property>
|
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.5</pydev_property>
|
||||||
<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
|
<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
|
||||||
<path>/calibre-pluginize/src</path>
|
<path>/calibre-pluginize/src</path>
|
||||||
</pydev_pathproperty>
|
</pydev_pathproperty>
|
||||||
|
@ -38,6 +38,10 @@ def freeze():
|
|||||||
'/usr/lib/libxml2.so.2',
|
'/usr/lib/libxml2.so.2',
|
||||||
'/usr/lib/libxslt.so.1',
|
'/usr/lib/libxslt.so.1',
|
||||||
'/usr/lib/libxslt.so.1',
|
'/usr/lib/libxslt.so.1',
|
||||||
|
'/usr/lib/libgthread-2.0.so.0',
|
||||||
|
'/usr/lib/libglib-2.0.so.0',
|
||||||
|
'/usr/lib/gcc/i686-pc-linux-gnu/4.3.3/libstdc++.so.6',
|
||||||
|
'/usr/lib/libpng12.so.0',
|
||||||
'/usr/lib/libexslt.so.0',
|
'/usr/lib/libexslt.so.0',
|
||||||
'/usr/lib/libMagickWand.so',
|
'/usr/lib/libMagickWand.so',
|
||||||
'/usr/lib/libMagickCore.so',
|
'/usr/lib/libMagickCore.so',
|
||||||
|
@ -28,33 +28,12 @@ for icon in ICONS:
|
|||||||
raise Exception('No icon at '+icon)
|
raise Exception('No icon at '+icon)
|
||||||
|
|
||||||
VERSION = re.sub('[a-z]\d+', '', VERSION)
|
VERSION = re.sub('[a-z]\d+', '', VERSION)
|
||||||
|
WINVER = VERSION+'.0'
|
||||||
|
|
||||||
PY2EXE_DIR = os.path.join(BASE_DIR, 'build','py2exe')
|
PY2EXE_DIR = os.path.join(BASE_DIR, 'build','py2exe')
|
||||||
|
|
||||||
class BuildEXE(py2exe.build_exe.py2exe):
|
class BuildEXE(py2exe.build_exe.py2exe):
|
||||||
manifest_resource_id = 0
|
|
||||||
|
|
||||||
MANIFEST_TEMPLATE = '''
|
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
||||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
|
||||||
<assemblyIdentity version="%(version)s"
|
|
||||||
processorArchitecture="x86"
|
|
||||||
name="net.kovidgoyal.%(prog)s"
|
|
||||||
type="win32"
|
|
||||||
/>
|
|
||||||
<description>Ebook management application</description>
|
|
||||||
<!-- Identify the application security requirements. -->
|
|
||||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
|
||||||
<security>
|
|
||||||
<requestedPrivileges>
|
|
||||||
<requestedExecutionLevel
|
|
||||||
level="asInvoker"
|
|
||||||
uiAccess="false"/>
|
|
||||||
</requestedPrivileges>
|
|
||||||
</security>
|
|
||||||
</trustInfo>
|
|
||||||
</assembly>
|
|
||||||
'''
|
|
||||||
def run(self):
|
def run(self):
|
||||||
py2exe.build_exe.py2exe.run(self)
|
py2exe.build_exe.py2exe.run(self)
|
||||||
print 'Adding plugins...'
|
print 'Adding plugins...'
|
||||||
@ -129,38 +108,34 @@ class BuildEXE(py2exe.build_exe.py2exe):
|
|||||||
shutil.copyfile(f, os.path.join(PY2EXE_DIR, os.path.basename(f)))
|
shutil.copyfile(f, os.path.join(PY2EXE_DIR, os.path.basename(f)))
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
def exe_factory(dest_base, script, icon_resources=None):
|
||||||
def manifest(cls, prog):
|
exe = {
|
||||||
cls.manifest_resource_id += 1
|
'dest_base' : dest_base,
|
||||||
return (24, cls.manifest_resource_id,
|
'script' : script,
|
||||||
cls.MANIFEST_TEMPLATE % dict(prog=prog, version=(VERSION+'.0')))
|
'name' : dest_base,
|
||||||
|
'version' : WINVER,
|
||||||
|
'description' : 'calibre - E-book library management',
|
||||||
|
'author' : 'Kovid Goyal',
|
||||||
|
'copyright' : '(c) Kovid Goyal, 2008',
|
||||||
|
'company' : 'kovidgoyal.net',
|
||||||
|
}
|
||||||
|
if icon_resources is not None:
|
||||||
|
exe['icon_resources'] = icon_resources
|
||||||
|
return exe
|
||||||
|
|
||||||
def main(args=sys.argv):
|
def main(args=sys.argv):
|
||||||
sys.argv[1:2] = ['py2exe']
|
sys.argv[1:2] = ['py2exe']
|
||||||
if os.path.exists(PY2EXE_DIR):
|
if os.path.exists(PY2EXE_DIR):
|
||||||
shutil.rmtree(PY2EXE_DIR)
|
shutil.rmtree(PY2EXE_DIR)
|
||||||
|
|
||||||
console = [dict(dest_base=basenames['console'][i], script=scripts['console'][i])
|
console = [exe_factory(basenames['console'][i], scripts['console'][i])
|
||||||
for i in range(len(scripts['console']))]
|
for i in range(len(scripts['console']))]
|
||||||
setup(
|
setup(
|
||||||
cmdclass = {'py2exe': BuildEXE},
|
cmdclass = {'py2exe': BuildEXE},
|
||||||
windows = [
|
windows = [
|
||||||
{'script' : scripts['gui'][0],
|
exe_factory(APPNAME, scripts['gui'][0], [(1, ICONS[0])]),
|
||||||
'dest_base' : APPNAME,
|
exe_factory('lrfviewer', scripts['gui'][1], [(1, ICONS[1])]),
|
||||||
'icon_resources' : [(1, ICONS[0])],
|
exe_factory('ebook-viewer', scripts['gui'][2], [(1, ICONS[1])]),
|
||||||
#'other_resources' : [BuildEXE.manifest(APPNAME)],
|
|
||||||
},
|
|
||||||
{'script' : scripts['gui'][1],
|
|
||||||
'dest_base' : 'lrfviewer',
|
|
||||||
'icon_resources' : [(1, ICONS[1])],
|
|
||||||
#'other_resources' : [BuildEXE.manifest('lrfviewer')],
|
|
||||||
},
|
|
||||||
{'script' : scripts['gui'][2],
|
|
||||||
'dest_base' : 'ebook-viewer',
|
|
||||||
'icon_resources' : [(1, ICONS[1])],
|
|
||||||
#'other_resources' : [BuildEXE.manifest('ebook-viewer')],
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
console = console,
|
console = console,
|
||||||
options = { 'py2exe' : {'compressed': 1,
|
options = { 'py2exe' : {'compressed': 1,
|
||||||
|
372
setup.py
372
setup.py
@ -47,350 +47,15 @@ main_functions = {
|
|||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
from setuptools import setup, find_packages
|
from setuptools import setup, find_packages
|
||||||
from setuptools.command.build_py import build_py as _build_py, convert_path
|
|
||||||
from distutils.command.build import build as _build
|
|
||||||
from distutils.core import Command as _Command
|
|
||||||
from pyqtdistutils import PyQtExtension, build_ext, Extension
|
from pyqtdistutils import PyQtExtension, build_ext, Extension
|
||||||
import subprocess, glob
|
from upload import sdist, pot, build, build_py, manual, \
|
||||||
|
resources, clean, gui, translations, update, \
|
||||||
|
tag_release, upload_demo, build_linux, build_windows, \
|
||||||
|
build_osx, upload_installers, upload_user_manual, \
|
||||||
|
upload_to_pypi, stage3, stage2, stage1, upload
|
||||||
|
|
||||||
def newer(targets, sources):
|
entry_points['console_scripts'].append(
|
||||||
'''
|
'calibre_postinstall = calibre.linux:post_install')
|
||||||
Return True is sources is newer that targets or if targets
|
|
||||||
does not exist.
|
|
||||||
'''
|
|
||||||
for f in targets:
|
|
||||||
if not os.path.exists(f):
|
|
||||||
return True
|
|
||||||
ttimes = map(lambda x: os.stat(x).st_mtime, targets)
|
|
||||||
stimes = map(lambda x: os.stat(x).st_mtime, sources)
|
|
||||||
newest_source, oldest_target = max(stimes), min(ttimes)
|
|
||||||
return newest_source > oldest_target
|
|
||||||
|
|
||||||
class build_py(_build_py):
|
|
||||||
|
|
||||||
def find_data_files(self, package, src_dir):
|
|
||||||
"""
|
|
||||||
Return filenames for package's data files in 'src_dir'
|
|
||||||
Modified to treat data file specs as paths not globs
|
|
||||||
"""
|
|
||||||
globs = (self.package_data.get('', [])
|
|
||||||
+ self.package_data.get(package, []))
|
|
||||||
files = self.manifest_files.get(package, [])[:]
|
|
||||||
for pattern in globs:
|
|
||||||
# Each pattern has to be converted to a platform-specific path
|
|
||||||
pattern = os.path.join(src_dir, convert_path(pattern))
|
|
||||||
next = glob.glob(pattern)
|
|
||||||
files.extend(next if next else [pattern])
|
|
||||||
|
|
||||||
return self.exclude_data_files(package, src_dir, files)
|
|
||||||
|
|
||||||
|
|
||||||
class Command(_Command):
|
|
||||||
user_options = []
|
|
||||||
def initialize_options(self): pass
|
|
||||||
def finalize_options(self): pass
|
|
||||||
|
|
||||||
class sdist(Command):
|
|
||||||
|
|
||||||
description = "create a source distribution using bzr"
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
name = 'dist/calibre-%s.tar.gz'%VERSION
|
|
||||||
subprocess.check_call(('bzr export '+name).split())
|
|
||||||
self.distribution.dist_files.append(('sdist', '', name))
|
|
||||||
|
|
||||||
class pot(Command):
|
|
||||||
description = '''Create the .pot template for all translatable strings'''
|
|
||||||
|
|
||||||
PATH = os.path.join('src', APPNAME, 'translations')
|
|
||||||
|
|
||||||
def source_files(self):
|
|
||||||
ans = []
|
|
||||||
for root, dirs, files in os.walk(os.path.dirname(self.PATH)):
|
|
||||||
for name in files:
|
|
||||||
if name.endswith('.py'):
|
|
||||||
ans.append(os.path.abspath(os.path.join(root, name)))
|
|
||||||
return ans
|
|
||||||
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
sys.path.insert(0, os.path.abspath(self.PATH))
|
|
||||||
try:
|
|
||||||
from pygettext import main as pygettext
|
|
||||||
files = self.source_files()
|
|
||||||
buf = cStringIO.StringIO()
|
|
||||||
print 'Creating translations template'
|
|
||||||
tempdir = tempfile.mkdtemp()
|
|
||||||
pygettext(buf, ['-k', '__', '-p', tempdir]+files)
|
|
||||||
src = buf.getvalue()
|
|
||||||
pot = os.path.join(tempdir, 'calibre.pot')
|
|
||||||
f = open(pot, 'wb')
|
|
||||||
f.write(src)
|
|
||||||
f.close()
|
|
||||||
print 'Translations template:', pot
|
|
||||||
return pot
|
|
||||||
finally:
|
|
||||||
sys.path.remove(os.path.abspath(self.PATH))
|
|
||||||
|
|
||||||
class manual(Command):
|
|
||||||
description='''Build the User Manual '''
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
cwd = os.path.abspath(os.getcwd())
|
|
||||||
os.chdir(os.path.join('src', 'calibre', 'manual'))
|
|
||||||
try:
|
|
||||||
for d in ('.build', 'cli'):
|
|
||||||
if os.path.exists(d):
|
|
||||||
shutil.rmtree(d)
|
|
||||||
os.makedirs(d)
|
|
||||||
if not os.path.exists('.build'+os.sep+'html'):
|
|
||||||
os.makedirs('.build'+os.sep+'html')
|
|
||||||
subprocess.check_call(['sphinx-build', '-b', 'custom', '-d',
|
|
||||||
'.build/doctrees', '.', '.build/html'])
|
|
||||||
finally:
|
|
||||||
os.chdir(cwd)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def clean(cls):
|
|
||||||
path = os.path.join('src', 'calibre', 'manual', '.build')
|
|
||||||
if os.path.exists(path):
|
|
||||||
shutil.rmtree(path)
|
|
||||||
|
|
||||||
class resources(Command):
|
|
||||||
description='''Compile various resource files used in calibre. '''
|
|
||||||
|
|
||||||
RESOURCES = dict(
|
|
||||||
opf_template = 'ebooks/metadata/opf.xml',
|
|
||||||
ncx_template = 'ebooks/metadata/ncx.xml',
|
|
||||||
fb2_xsl = 'ebooks/lrf/fb2/fb2.xsl',
|
|
||||||
metadata_sqlite = 'library/metadata_sqlite.sql',
|
|
||||||
jquery = 'gui2/viewer/jquery.js',
|
|
||||||
jquery_scrollTo = 'gui2/viewer/jquery_scrollTo.js',
|
|
||||||
html_css = 'ebooks/oeb/html.css',
|
|
||||||
)
|
|
||||||
|
|
||||||
DEST = os.path.join('src', APPNAME, 'resources.py')
|
|
||||||
|
|
||||||
def get_qt_translations(self):
|
|
||||||
data = {}
|
|
||||||
translations_found = False
|
|
||||||
for TPATH in ('/usr/share/qt4/translations', '/usr/lib/qt4/translations'):
|
|
||||||
if os.path.exists(TPATH):
|
|
||||||
files = glob.glob(TPATH + '/qt_??.qm')
|
|
||||||
for f in files:
|
|
||||||
key = os.path.basename(f).partition('.')[0]
|
|
||||||
data[key] = f
|
|
||||||
translations_found = True
|
|
||||||
break
|
|
||||||
if not translations_found:
|
|
||||||
print 'WARNING: Could not find Qt transations'
|
|
||||||
return data
|
|
||||||
|
|
||||||
def get_static_resources(self):
|
|
||||||
sdir = os.path.join('src', 'calibre', 'library', 'static')
|
|
||||||
resources, max = {}, 0
|
|
||||||
for f in os.listdir(sdir):
|
|
||||||
resources[f] = open(os.path.join(sdir, f), 'rb').read()
|
|
||||||
mtime = os.stat(os.path.join(sdir, f)).st_mtime
|
|
||||||
max = mtime if mtime > max else max
|
|
||||||
return resources, max
|
|
||||||
|
|
||||||
def get_recipes(self):
|
|
||||||
sdir = os.path.join('src', 'calibre', 'web', 'feeds', 'recipes')
|
|
||||||
resources, max = {}, 0
|
|
||||||
for f in os.listdir(sdir):
|
|
||||||
if f.endswith('.py') and f != '__init__.py':
|
|
||||||
resources[f.replace('.py', '')] = open(os.path.join(sdir, f), 'rb').read()
|
|
||||||
mtime = os.stat(os.path.join(sdir, f)).st_mtime
|
|
||||||
max = mtime if mtime > max else max
|
|
||||||
return resources, max
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
data, dest, RESOURCES = {}, self.DEST, self.RESOURCES
|
|
||||||
for key in RESOURCES:
|
|
||||||
path = RESOURCES[key]
|
|
||||||
if not os.path.isabs(path):
|
|
||||||
RESOURCES[key] = os.path.join('src', APPNAME, path)
|
|
||||||
translations = self.get_qt_translations()
|
|
||||||
RESOURCES.update(translations)
|
|
||||||
static, smax = self.get_static_resources()
|
|
||||||
recipes, rmax = self.get_recipes()
|
|
||||||
amax = max(rmax, smax)
|
|
||||||
if newer([dest], RESOURCES.values()) or os.stat(dest).st_mtime < amax:
|
|
||||||
print 'Compiling resources...'
|
|
||||||
with open(dest, 'wb') as f:
|
|
||||||
for key in RESOURCES:
|
|
||||||
data = open(RESOURCES[key], 'rb').read()
|
|
||||||
f.write(key + ' = ' + repr(data)+'\n\n')
|
|
||||||
f.write('server_resources = %s\n\n'%repr(static))
|
|
||||||
f.write('recipes = %s\n\n'%repr(recipes))
|
|
||||||
f.write('build_time = "%s"\n\n'%time.strftime('%d %m %Y %H%M%S'))
|
|
||||||
else:
|
|
||||||
print 'Resources are up to date'
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def clean(cls):
|
|
||||||
path = cls.DEST
|
|
||||||
for path in glob.glob(path+'*'):
|
|
||||||
if os.path.exists(path):
|
|
||||||
os.remove(path)
|
|
||||||
|
|
||||||
class translations(Command):
|
|
||||||
description='''Compile the translations'''
|
|
||||||
PATH = os.path.join('src', APPNAME, 'translations')
|
|
||||||
DEST = os.path.join(PATH, 'compiled.py')
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
sys.path.insert(0, os.path.abspath(self.PATH))
|
|
||||||
try:
|
|
||||||
files = glob.glob(os.path.join(self.PATH, '*.po'))
|
|
||||||
if newer([self.DEST], files):
|
|
||||||
from msgfmt import main as msgfmt
|
|
||||||
translations = {}
|
|
||||||
print 'Compiling translations...'
|
|
||||||
for po in files:
|
|
||||||
lang = os.path.basename(po).partition('.')[0]
|
|
||||||
buf = cStringIO.StringIO()
|
|
||||||
print 'Compiling', lang
|
|
||||||
msgfmt(buf, [po])
|
|
||||||
translations[lang] = buf.getvalue()
|
|
||||||
open(self.DEST, 'wb').write('translations = '+repr(translations))
|
|
||||||
else:
|
|
||||||
print 'Translations up to date'
|
|
||||||
finally:
|
|
||||||
sys.path.remove(os.path.abspath(self.PATH))
|
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def clean(cls):
|
|
||||||
path = cls.DEST
|
|
||||||
if os.path.exists(path):
|
|
||||||
os.remove(path)
|
|
||||||
|
|
||||||
|
|
||||||
class gui(Command):
|
|
||||||
description='''Compile all GUI forms and images'''
|
|
||||||
PATH = os.path.join('src', APPNAME, 'gui2')
|
|
||||||
IMAGES_DEST = os.path.join(PATH, 'images_rc.py')
|
|
||||||
QRC = os.path.join(PATH, 'images.qrc')
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def find_forms(cls):
|
|
||||||
forms = []
|
|
||||||
for root, dirs, files in os.walk(cls.PATH):
|
|
||||||
for name in files:
|
|
||||||
if name.endswith('.ui'):
|
|
||||||
forms.append(os.path.abspath(os.path.join(root, name)))
|
|
||||||
|
|
||||||
return forms
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def form_to_compiled_form(cls, form):
|
|
||||||
return form.rpartition('.')[0]+'_ui.py'
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
self.build_forms()
|
|
||||||
self.build_images()
|
|
||||||
|
|
||||||
def build_images(self):
|
|
||||||
cwd, images = os.getcwd(), os.path.basename(self.IMAGES_DEST)
|
|
||||||
try:
|
|
||||||
os.chdir(self.PATH)
|
|
||||||
sources, files = [], []
|
|
||||||
for root, dirs, files in os.walk('images'):
|
|
||||||
for name in files:
|
|
||||||
sources.append(os.path.join(root, name))
|
|
||||||
if newer([images], sources):
|
|
||||||
print 'Compiling images...'
|
|
||||||
for s in sources:
|
|
||||||
alias = ' alias="library"' if s.endswith('images'+os.sep+'library.png') else ''
|
|
||||||
files.append('<file%s>%s</file>'%(alias, s))
|
|
||||||
manifest = '<RCC>\n<qresource prefix="/">\n%s\n</qresource>\n</RCC>'%'\n'.join(files)
|
|
||||||
with open('images.qrc', 'wb') as f:
|
|
||||||
f.write(manifest)
|
|
||||||
subprocess.check_call(['pyrcc4', '-o', images, 'images.qrc'])
|
|
||||||
else:
|
|
||||||
print 'Images are up to date'
|
|
||||||
finally:
|
|
||||||
os.chdir(cwd)
|
|
||||||
|
|
||||||
|
|
||||||
def build_forms(self):
|
|
||||||
from PyQt4.uic import compileUi
|
|
||||||
forms = self.find_forms()
|
|
||||||
for form in forms:
|
|
||||||
compiled_form = self.form_to_compiled_form(form)
|
|
||||||
if not os.path.exists(compiled_form) or os.stat(form).st_mtime > os.stat(compiled_form).st_mtime:
|
|
||||||
print 'Compiling form', form
|
|
||||||
buf = cStringIO.StringIO()
|
|
||||||
compileUi(form, buf)
|
|
||||||
dat = buf.getvalue()
|
|
||||||
dat = dat.replace('__appname__', APPNAME)
|
|
||||||
dat = dat.replace('import images_rc', 'from calibre.gui2 import images_rc')
|
|
||||||
dat = dat.replace('from library import', 'from calibre.gui2.library import')
|
|
||||||
dat = dat.replace('from widgets import', 'from calibre.gui2.widgets import')
|
|
||||||
dat = re.compile(r'QtGui.QApplication.translate\(.+?,\s+"(.+?)(?<!\\)",.+?\)', re.DOTALL).sub(r'_("\1")', dat)
|
|
||||||
|
|
||||||
# Workaround bug in Qt 4.4 on Windows
|
|
||||||
if form.endswith('dialogs%sconfig.ui'%os.sep) or form.endswith('dialogs%slrf_single.ui'%os.sep):
|
|
||||||
print 'Implementing Workaround for buggy pyuic in form', form
|
|
||||||
dat = re.sub(r'= QtGui\.QTextEdit\(self\..*?\)', '= QtGui.QTextEdit()', dat)
|
|
||||||
dat = re.sub(r'= QtGui\.QListWidget\(self\..*?\)', '= QtGui.QListWidget()', dat)
|
|
||||||
|
|
||||||
if form.endswith('viewer%smain.ui'%os.sep):
|
|
||||||
print 'Promoting WebView'
|
|
||||||
dat = dat.replace('self.view = QtWebKit.QWebView(', 'self.view = DocumentView(')
|
|
||||||
dat += '\n\nfrom calibre.gui2.viewer.documentview import DocumentView'
|
|
||||||
|
|
||||||
open(compiled_form, 'wb').write(dat)
|
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def clean(cls):
|
|
||||||
forms = cls.find_forms()
|
|
||||||
for form in forms:
|
|
||||||
c = cls.form_to_compiled_form(form)
|
|
||||||
if os.path.exists(c):
|
|
||||||
os.remove(c)
|
|
||||||
for x in (cls.IMAGES_DEST, cls.QRC):
|
|
||||||
if os.path.exists(x):
|
|
||||||
os.remove(x)
|
|
||||||
|
|
||||||
class clean(Command):
|
|
||||||
description='''Delete all computer generated files in the source tree'''
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
print 'Cleaning...'
|
|
||||||
manual.clean()
|
|
||||||
gui.clean()
|
|
||||||
translations.clean()
|
|
||||||
resources.clean()
|
|
||||||
|
|
||||||
for f in glob.glob(os.path.join('src', 'calibre', 'plugins', '*')):
|
|
||||||
os.remove(f)
|
|
||||||
for root, dirs, files in os.walk('.'):
|
|
||||||
for name in files:
|
|
||||||
for t in ('.pyc', '.pyo', '~'):
|
|
||||||
if name.endswith(t):
|
|
||||||
os.remove(os.path.join(root, name))
|
|
||||||
break
|
|
||||||
|
|
||||||
for dir in ('build', 'dist', os.path.join('src', 'calibre.egg-info')):
|
|
||||||
shutil.rmtree(dir, ignore_errors=True)
|
|
||||||
|
|
||||||
class build(_build):
|
|
||||||
|
|
||||||
sub_commands = [
|
|
||||||
('resources', lambda self : 'CALIBRE_BUILDBOT' not in os.environ.keys()),
|
|
||||||
('translations', lambda self : 'CALIBRE_BUILDBOT' not in os.environ.keys()),
|
|
||||||
('gui', lambda self : 'CALIBRE_BUILDBOT' not in os.environ.keys()),
|
|
||||||
('build_ext', lambda self: True),
|
|
||||||
('build_py', lambda self: True),
|
|
||||||
('build_clib', _build.has_c_libraries),
|
|
||||||
('build_scripts', _build.has_scripts),
|
|
||||||
]
|
|
||||||
|
|
||||||
entry_points['console_scripts'].append('calibre_postinstall = calibre.linux:post_install')
|
|
||||||
ext_modules = [
|
ext_modules = [
|
||||||
Extension('calibre.plugins.lzx',
|
Extension('calibre.plugins.lzx',
|
||||||
sources=['src/calibre/utils/lzx/lzxmodule.c',
|
sources=['src/calibre/utils/lzx/lzxmodule.c',
|
||||||
@ -430,7 +95,9 @@ if __name__ == '__main__':
|
|||||||
plugins = ['plugins/%s.so'%(x.name.rpartition('.')[-1]) for x in ext_modules]
|
plugins = ['plugins/%s.so'%(x.name.rpartition('.')[-1]) for x in ext_modules]
|
||||||
else:
|
else:
|
||||||
plugins = ['plugins/%s.pyd'%(x.name.rpartition('.')[-1]) for x in ext_modules] + \
|
plugins = ['plugins/%s.pyd'%(x.name.rpartition('.')[-1]) for x in ext_modules] + \
|
||||||
['plugins/%s.pyd.manifest'%(x.name.rpartition('.')[-1]) for x in ext_modules if 'pictureflow' not in x.name]
|
['plugins/%s.pyd.manifest'%(x.name.rpartition('.')[-1]) \
|
||||||
|
for x in ext_modules if 'pictureflow' not in x.name]
|
||||||
|
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name = APPNAME,
|
name = APPNAME,
|
||||||
@ -451,7 +118,11 @@ if __name__ == '__main__':
|
|||||||
''',
|
''',
|
||||||
long_description =
|
long_description =
|
||||||
'''
|
'''
|
||||||
%s is an e-book library manager. It can view, convert and catalog e-books in most of the major e-book formats. It can also talk to a few e-book reader devices. It can go out to the internet and fetch metadata for your books. It can download newspapers and convert them into e-books for convenient reading. It is cross platform, running on Linux, Windows and OS X.
|
%s is an e-book library manager. It can view, convert and catalog e-books \
|
||||||
|
in most of the major e-book formats. It can also talk to e-book reader \
|
||||||
|
devices. It can go out to the internet and fetch metadata for your books. \
|
||||||
|
It can download newspapers and convert them into e-books for convenient \
|
||||||
|
reading. It is cross platform, running on Linux, Windows and OS X.
|
||||||
|
|
||||||
For screenshots: https://%s.kovidgoyal.net/wiki/Screenshots
|
For screenshots: https://%s.kovidgoyal.net/wiki/Screenshots
|
||||||
|
|
||||||
@ -490,6 +161,19 @@ if __name__ == '__main__':
|
|||||||
'gui' : gui,
|
'gui' : gui,
|
||||||
'clean' : clean,
|
'clean' : clean,
|
||||||
'sdist' : sdist,
|
'sdist' : sdist,
|
||||||
|
'update' : update,
|
||||||
|
'tag_release' : tag_release,
|
||||||
|
'upload_demo' : upload_demo,
|
||||||
|
'build_linux' : build_linux,
|
||||||
|
'build_windows' : build_windows,
|
||||||
|
'build_osx' : build_osx,
|
||||||
|
'upload_installers': upload_installers,
|
||||||
|
'upload_user_manual': upload_user_manual,
|
||||||
|
'upload_to_pypi': upload_to_pypi,
|
||||||
|
'stage3' : stage3,
|
||||||
|
'stage2' : stage2,
|
||||||
|
'stage1' : stage1,
|
||||||
|
'publish' : upload,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -29,7 +29,8 @@ mimetypes.add_type('application/adobe-page-template+xml', '.xpgt')
|
|||||||
mimetypes.add_type('application/x-font-opentype', '.otf')
|
mimetypes.add_type('application/x-font-opentype', '.otf')
|
||||||
mimetypes.add_type('application/x-font-truetype', '.ttf')
|
mimetypes.add_type('application/x-font-truetype', '.ttf')
|
||||||
mimetypes.add_type('application/oebps-package+xml', '.opf')
|
mimetypes.add_type('application/oebps-package+xml', '.opf')
|
||||||
|
import cssutils
|
||||||
|
cssutils.log.setLevel(logging.WARN)
|
||||||
|
|
||||||
def to_unicode(raw, encoding='utf-8', errors='strict'):
|
def to_unicode(raw, encoding='utf-8', errors='strict'):
|
||||||
if isinstance(raw, unicode):
|
if isinstance(raw, unicode):
|
||||||
@ -71,7 +72,7 @@ def sanitize_file_name(name, substitute='_', as_unicode=False):
|
|||||||
one = re.sub(r'^\.+$', '_', one)
|
one = re.sub(r'^\.+$', '_', one)
|
||||||
if as_unicode:
|
if as_unicode:
|
||||||
one = one.decode(filesystem_encoding)
|
one = one.decode(filesystem_encoding)
|
||||||
return one
|
return one.replace('..', '_')
|
||||||
|
|
||||||
|
|
||||||
def prints(*args, **kwargs):
|
def prints(*args, **kwargs):
|
||||||
@ -401,8 +402,10 @@ def walk(dir):
|
|||||||
for f in record[-1]:
|
for f in record[-1]:
|
||||||
yield os.path.join(record[0], f)
|
yield os.path.join(record[0], f)
|
||||||
|
|
||||||
def strftime(fmt, t=time.localtime()):
|
def strftime(fmt, t=None):
|
||||||
''' A version of strtime that returns unicode strings. '''
|
''' A version of strtime that returns unicode strings. '''
|
||||||
|
if t is None:
|
||||||
|
t = time.localtime()
|
||||||
if iswindows:
|
if iswindows:
|
||||||
if isinstance(fmt, unicode):
|
if isinstance(fmt, unicode):
|
||||||
fmt = fmt.encode('mbcs')
|
fmt = fmt.encode('mbcs')
|
||||||
|
@ -2,7 +2,7 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
__appname__ = 'calibre'
|
__appname__ = 'calibre'
|
||||||
__version__ = '0.4.136'
|
__version__ = '0.4.138'
|
||||||
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
|
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
|
||||||
'''
|
'''
|
||||||
Various run time constants.
|
Various run time constants.
|
||||||
|
@ -132,7 +132,7 @@ class HTMLMetadataReader(MetadataReaderPlugin):
|
|||||||
class MOBIMetadataReader(MetadataReaderPlugin):
|
class MOBIMetadataReader(MetadataReaderPlugin):
|
||||||
|
|
||||||
name = 'Read MOBI metadata'
|
name = 'Read MOBI metadata'
|
||||||
file_types = set(['mobi', 'prc'])
|
file_types = set(['mobi', 'prc', '.azw'])
|
||||||
description = _('Read metadata from %s files')%'MOBI'
|
description = _('Read metadata from %s files')%'MOBI'
|
||||||
|
|
||||||
def get_metadata(self, stream, ftype):
|
def get_metadata(self, stream, ftype):
|
||||||
|
@ -186,7 +186,10 @@ class BookList(_BookList):
|
|||||||
node = self.document.createElement(self.prefix + "text")
|
node = self.document.createElement(self.prefix + "text")
|
||||||
mime = MIME_MAP[name.rpartition('.')[-1].lower()]
|
mime = MIME_MAP[name.rpartition('.')[-1].lower()]
|
||||||
cid = self.max_id()+1
|
cid = self.max_id()+1
|
||||||
sourceid = str(self[0].sourceid) if len(self) else "1"
|
try:
|
||||||
|
sourceid = str(self[0].sourceid) if len(self) else '1'
|
||||||
|
except:
|
||||||
|
sourceid = '1'
|
||||||
attrs = {
|
attrs = {
|
||||||
"title" : info["title"],
|
"title" : info["title"],
|
||||||
'titleSorter' : sortable_title(info['title']),
|
'titleSorter' : sortable_title(info['title']),
|
||||||
|
@ -32,7 +32,7 @@ class PRS505(Device):
|
|||||||
BCD = [0x229] #: Needed to disambiguate 505 and 700 on linux
|
BCD = [0x229] #: Needed to disambiguate 505 and 700 on linux
|
||||||
PRODUCT_NAME = 'PRS-505'
|
PRODUCT_NAME = 'PRS-505'
|
||||||
VENDOR_NAME = 'SONY'
|
VENDOR_NAME = 'SONY'
|
||||||
FORMATS = ['lrf', 'epub', 'lrx', 'rtf', 'pdf', 'txt']
|
FORMATS = ['epub', 'lrf', 'lrx', 'rtf', 'pdf', 'txt']
|
||||||
|
|
||||||
MEDIA_XML = 'database/cache/media.xml'
|
MEDIA_XML = 'database/cache/media.xml'
|
||||||
CACHE_XML = 'Sony Reader/database/cache.xml'
|
CACHE_XML = 'Sony Reader/database/cache.xml'
|
||||||
|
@ -124,6 +124,7 @@ MAP = {
|
|||||||
'lit' : lit2opf,
|
'lit' : lit2opf,
|
||||||
'mobi' : mobi2opf,
|
'mobi' : mobi2opf,
|
||||||
'prc' : mobi2opf,
|
'prc' : mobi2opf,
|
||||||
|
'azw' : mobi2opf,
|
||||||
'fb2' : fb22opf,
|
'fb2' : fb22opf,
|
||||||
'rtf' : rtf2opf,
|
'rtf' : rtf2opf,
|
||||||
'txt' : txt2opf,
|
'txt' : txt2opf,
|
||||||
@ -131,7 +132,8 @@ MAP = {
|
|||||||
'epub' : epub2opf,
|
'epub' : epub2opf,
|
||||||
'odt' : odt2epub,
|
'odt' : odt2epub,
|
||||||
}
|
}
|
||||||
SOURCE_FORMATS = ['lit', 'mobi', 'prc', 'fb2', 'odt', 'rtf', 'txt', 'pdf', 'rar', 'zip', 'oebzip', 'htm', 'html', 'epub']
|
SOURCE_FORMATS = ['lit', 'mobi', 'prc', 'azw', 'fb2', 'odt', 'rtf',
|
||||||
|
'txt', 'pdf', 'rar', 'zip', 'oebzip', 'htm', 'html', 'epub']
|
||||||
|
|
||||||
def unarchive(path, tdir):
|
def unarchive(path, tdir):
|
||||||
extract(path, tdir)
|
extract(path, tdir)
|
||||||
|
@ -310,6 +310,8 @@ def create_cover_image(src, dest, screen_size, rescale_cover=True):
|
|||||||
def process_title_page(mi, filelist, htmlfilemap, opts, tdir):
|
def process_title_page(mi, filelist, htmlfilemap, opts, tdir):
|
||||||
old_title_page = None
|
old_title_page = None
|
||||||
f = lambda x : os.path.normcase(os.path.normpath(x))
|
f = lambda x : os.path.normcase(os.path.normpath(x))
|
||||||
|
if not isinstance(mi.cover, basestring):
|
||||||
|
mi.cover = None
|
||||||
if mi.cover:
|
if mi.cover:
|
||||||
if f(filelist[0].path) == f(mi.cover):
|
if f(filelist[0].path) == f(mi.cover):
|
||||||
old_title_page = htmlfilemap[filelist[0].path]
|
old_title_page = htmlfilemap[filelist[0].path]
|
||||||
|
@ -332,6 +332,8 @@ class PreProcessor(object):
|
|||||||
(re.compile(r'&(\S+?);'), convert_entities),
|
(re.compile(r'&(\S+?);'), convert_entities),
|
||||||
# Remove the <![if/endif tags inserted by everybody's darling, MS Word
|
# Remove the <![if/endif tags inserted by everybody's darling, MS Word
|
||||||
(re.compile(r'(?i)<{0,1}!\[(end){0,1}if[^>]*>'), lambda match: ''),
|
(re.compile(r'(?i)<{0,1}!\[(end){0,1}if[^>]*>'), lambda match: ''),
|
||||||
|
# Strip all comments since Adobe DE is petrified of them
|
||||||
|
(re.compile(r'<!--[^>]*>'), lambda match : ''),
|
||||||
]
|
]
|
||||||
|
|
||||||
# Fix pdftohtml markup
|
# Fix pdftohtml markup
|
||||||
@ -491,9 +493,25 @@ class Parser(PreProcessor, LoggingInterface):
|
|||||||
self.root.insert(0, head)
|
self.root.insert(0, head)
|
||||||
|
|
||||||
self.head = head
|
self.head = head
|
||||||
|
try:
|
||||||
self.body = self.root.body
|
self.body = self.root.body
|
||||||
|
except:
|
||||||
|
import traceback
|
||||||
|
err = traceback.format_exc()
|
||||||
|
self.root = fromstring(u'<html><head/><body><p>This page was too '
|
||||||
|
'severely malformed for calibre to handle. '
|
||||||
|
'It has been replaced by this error message.'
|
||||||
|
'</p><pre>%s</pre></body></html>'%err)
|
||||||
|
self.head = self.root.xpath('./head')[0]
|
||||||
|
self.body = self.root.body
|
||||||
|
invalid_counter = 0
|
||||||
for a in self.root.xpath('//a[@name]'):
|
for a in self.root.xpath('//a[@name]'):
|
||||||
|
try:
|
||||||
a.set('id', a.get('name'))
|
a.set('id', a.get('name'))
|
||||||
|
except:
|
||||||
|
invalid_counter += 1
|
||||||
|
for x in ('id', 'name'):
|
||||||
|
a.set(x, 'calibre_invalid_id_%d'%invalid_counter)
|
||||||
if not self.head.xpath('./title'):
|
if not self.head.xpath('./title'):
|
||||||
title = etree.SubElement(self.head, 'title')
|
title = etree.SubElement(self.head, 'title')
|
||||||
title.text = _('Unknown')
|
title.text = _('Unknown')
|
||||||
|
@ -780,7 +780,7 @@ class LitReader(object):
|
|||||||
if u != 0:
|
if u != 0:
|
||||||
raise LitError("Reset table entry greater than 32 bits")
|
raise LitError("Reset table entry greater than 32 bits")
|
||||||
if size >= len(content):
|
if size >= len(content):
|
||||||
raise LitError("Reset table entry out of bounds")
|
self._warn("LZX reset table entry out of bounds")
|
||||||
if bytes_remaining >= window_bytes:
|
if bytes_remaining >= window_bytes:
|
||||||
lzx.reset()
|
lzx.reset()
|
||||||
try:
|
try:
|
||||||
|
@ -29,6 +29,7 @@ preferred_source_formats = [
|
|||||||
'XHTM',
|
'XHTM',
|
||||||
'XHTML',
|
'XHTML',
|
||||||
'PRC',
|
'PRC',
|
||||||
|
'AZW',
|
||||||
'RTF',
|
'RTF',
|
||||||
'PDF',
|
'PDF',
|
||||||
'TXT',
|
'TXT',
|
||||||
|
@ -154,7 +154,7 @@ def process_file(path, options, logger=None):
|
|||||||
convertor = txt2lrf
|
convertor = txt2lrf
|
||||||
elif 'epub' == ext:
|
elif 'epub' == ext:
|
||||||
convertor = epub2lrf
|
convertor = epub2lrf
|
||||||
elif ext in ['mobi', 'prc']:
|
elif ext in ['mobi', 'prc', 'azw']:
|
||||||
convertor = mobi2lrf
|
convertor = mobi2lrf
|
||||||
elif ext == 'fb2':
|
elif ext == 'fb2':
|
||||||
convertor = fb22lrf
|
convertor = fb22lrf
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,6 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<?python
|
<?python
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
import re
|
||||||
?>
|
?>
|
||||||
<ncx version="2005-1"
|
<ncx version="2005-1"
|
||||||
xml:lang="en"
|
xml:lang="en"
|
||||||
@ -19,7 +20,7 @@ from uuid import uuid4
|
|||||||
<py:def function="navpoint(np, level)">
|
<py:def function="navpoint(np, level)">
|
||||||
${'%*s'%(4*level,'')}<navPoint id="${str(uuid4())}" playOrder="${str(np.play_order)}">
|
${'%*s'%(4*level,'')}<navPoint id="${str(uuid4())}" playOrder="${str(np.play_order)}">
|
||||||
${'%*s'%(4*level,'')}<navLabel>
|
${'%*s'%(4*level,'')}<navLabel>
|
||||||
${'%*s'%(4*level,'')}<text>${np.text}</text>
|
${'%*s'%(4*level,'')}<text>${re.sub(r'\s+', ' ', np.text)}</text>
|
||||||
${'%*s'%(4*level,'')}</navLabel>
|
${'%*s'%(4*level,'')}</navLabel>
|
||||||
${'%*s'%(4*level,'')}<content src="${unicode(np.href)+(('#' + unicode(np.fragment)) if np.fragment else '')}" />
|
${'%*s'%(4*level,'')}<content src="${unicode(np.href)+(('#' + unicode(np.fragment)) if np.fragment else '')}" />
|
||||||
<py:for each="np2 in np">${navpoint(np2, level+1)}</py:for>
|
<py:for each="np2 in np">${navpoint(np2, level+1)}</py:for>
|
||||||
|
@ -186,6 +186,8 @@ class MobiReader(object):
|
|||||||
self.processed_html = self.processed_html.decode(self.book_header.codec, 'ignore')
|
self.processed_html = self.processed_html.decode(self.book_header.codec, 'ignore')
|
||||||
for pat in ENCODING_PATS:
|
for pat in ENCODING_PATS:
|
||||||
self.processed_html = pat.sub('', self.processed_html)
|
self.processed_html = pat.sub('', self.processed_html)
|
||||||
|
self.processed_html = re.sub(r'&(\S+?);', entity_to_unicode,
|
||||||
|
self.processed_html)
|
||||||
self.extract_images(processed_records, output_dir)
|
self.extract_images(processed_records, output_dir)
|
||||||
self.replace_page_breaks()
|
self.replace_page_breaks()
|
||||||
self.cleanup_html()
|
self.cleanup_html()
|
||||||
@ -247,9 +249,6 @@ class MobiReader(object):
|
|||||||
self.processed_html = '<html><p>'+self.processed_html.replace('\n\n', '<p>')+'</html>'
|
self.processed_html = '<html><p>'+self.processed_html.replace('\n\n', '<p>')+'</html>'
|
||||||
self.processed_html = self.processed_html.replace('\r\n', '\n')
|
self.processed_html = self.processed_html.replace('\r\n', '\n')
|
||||||
self.processed_html = self.processed_html.replace('> <', '>\n<')
|
self.processed_html = self.processed_html.replace('> <', '>\n<')
|
||||||
for t, c in [('b', 'bold'), ('i', 'italic')]:
|
|
||||||
self.processed_html = re.sub(r'(?i)<%s>'%t, r'<span class="%s">'%c, self.processed_html)
|
|
||||||
self.processed_html = re.sub(r'(?i)</%s>'%t, r'</span>', self.processed_html)
|
|
||||||
|
|
||||||
def upshift_markup(self, root):
|
def upshift_markup(self, root):
|
||||||
if self.verbose:
|
if self.verbose:
|
||||||
@ -290,35 +289,44 @@ class MobiReader(object):
|
|||||||
align = attrib.pop('align').strip()
|
align = attrib.pop('align').strip()
|
||||||
if align:
|
if align:
|
||||||
styles.append('text-align: %s' % align)
|
styles.append('text-align: %s' % align)
|
||||||
if mobi_version == 1 and tag.tag == 'hr':
|
if tag.tag == 'hr':
|
||||||
|
if mobi_version == 1:
|
||||||
tag.tag = 'div'
|
tag.tag = 'div'
|
||||||
styles.append('page-break-before: always')
|
styles.append('page-break-before: always')
|
||||||
styles.append('display: block')
|
styles.append('display: block')
|
||||||
styles.append('margin: 0')
|
styles.append('margin: 0')
|
||||||
if styles:
|
elif tag.tag == 'i':
|
||||||
attrib['style'] = '; '.join(styles)
|
tag.tag = 'span'
|
||||||
|
tag.attrib['class'] = 'italic'
|
||||||
if tag.tag.lower() == 'font':
|
elif tag.tag == 'b':
|
||||||
|
tag.tag = 'span'
|
||||||
|
tag.attrib['class'] = 'bold'
|
||||||
|
elif tag.tag == 'font':
|
||||||
sz = tag.get('size', '').lower()
|
sz = tag.get('size', '').lower()
|
||||||
try:
|
try:
|
||||||
float(sz)
|
float(sz)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
if sz in size_map.keys():
|
if sz in size_map.keys():
|
||||||
attrib['size'] = size_map[sz]
|
attrib['size'] = size_map[sz]
|
||||||
|
elif tag.tag == 'img':
|
||||||
|
recindex = None
|
||||||
|
for attr in self.IMAGE_ATTRS:
|
||||||
|
recindex = attrib.pop(attr, None) or recindex
|
||||||
|
if recindex is not None:
|
||||||
|
attrib['src'] = 'images/%s.jpg' % recindex
|
||||||
|
elif tag.tag == 'pre':
|
||||||
|
if not tag.text:
|
||||||
|
tag.tag = 'div'
|
||||||
|
if styles:
|
||||||
|
attrib['style'] = '; '.join(styles)
|
||||||
if 'filepos-id' in attrib:
|
if 'filepos-id' in attrib:
|
||||||
attrib['id'] = attrib.pop('filepos-id')
|
attrib['id'] = attrib.pop('filepos-id')
|
||||||
if 'filepos' in attrib:
|
if 'filepos' in attrib:
|
||||||
filepos = attrib.pop('filepos')
|
filepos = attrib.pop('filepos')
|
||||||
try:
|
try:
|
||||||
attrib['href'] = "#filepos%d" % int(filepos)
|
attrib['href'] = "#filepos%d" % int(filepos)
|
||||||
except:
|
except ValueError:
|
||||||
attrib['href'] = filepos
|
pass
|
||||||
if tag.tag == 'img':
|
|
||||||
recindex = None
|
|
||||||
for attr in self.IMAGE_ATTRS:
|
|
||||||
recindex = attrib.pop(attr, None) or recindex
|
|
||||||
if recindex is not None:
|
|
||||||
attrib['src'] = 'images/%s.jpg' % recindex
|
|
||||||
|
|
||||||
def create_opf(self, htmlfile, guide=None):
|
def create_opf(self, htmlfile, guide=None):
|
||||||
mi = self.book_header.exth.mi
|
mi = self.book_header.exth.mi
|
||||||
@ -328,7 +336,7 @@ class MobiReader(object):
|
|||||||
manifest = [(htmlfile, 'text/x-oeb1-document')]
|
manifest = [(htmlfile, 'text/x-oeb1-document')]
|
||||||
bp = os.path.dirname(htmlfile)
|
bp = os.path.dirname(htmlfile)
|
||||||
for i in getattr(self, 'image_names', []):
|
for i in getattr(self, 'image_names', []):
|
||||||
manifest.append((os.path.join(bp, 'images/', i), 'image/jpg'))
|
manifest.append((os.path.join(bp, 'images/', i), 'image/jpeg'))
|
||||||
|
|
||||||
opf.create_manifest(manifest)
|
opf.create_manifest(manifest)
|
||||||
opf.create_spine([os.path.basename(htmlfile)])
|
opf.create_spine([os.path.basename(htmlfile)])
|
||||||
@ -452,6 +460,7 @@ class MobiReader(object):
|
|||||||
pos = end
|
pos = end
|
||||||
self.processed_html += self.mobi_html[pos:]
|
self.processed_html += self.mobi_html[pos:]
|
||||||
|
|
||||||
|
|
||||||
def extract_images(self, processed_records, output_dir):
|
def extract_images(self, processed_records, output_dir):
|
||||||
if self.verbose:
|
if self.verbose:
|
||||||
print 'Extracting images...'
|
print 'Extracting images...'
|
||||||
|
@ -416,7 +416,11 @@ class MobiWriter(object):
|
|||||||
coverid = metadata.cover[0] if metadata.cover else None
|
coverid = metadata.cover[0] if metadata.cover else None
|
||||||
for _, href in images:
|
for _, href in images:
|
||||||
item = self._oeb.manifest.hrefs[href]
|
item = self._oeb.manifest.hrefs[href]
|
||||||
|
try:
|
||||||
data = rescale_image(item.data, self._imagemax)
|
data = rescale_image(item.data, self._imagemax)
|
||||||
|
except IOError:
|
||||||
|
self._oeb.logger.warn('Bad image file %r' % item.href)
|
||||||
|
continue
|
||||||
self._records.append(data)
|
self._records.append(data)
|
||||||
|
|
||||||
def _generate_record0(self):
|
def _generate_record0(self):
|
||||||
@ -486,9 +490,11 @@ class MobiWriter(object):
|
|||||||
index = self._images[href] - 1
|
index = self._images[href] - 1
|
||||||
exth.write(pack('>III', 0xc9, 0x0c, index))
|
exth.write(pack('>III', 0xc9, 0x0c, index))
|
||||||
exth.write(pack('>III', 0xcb, 0x0c, 0))
|
exth.write(pack('>III', 0xcb, 0x0c, 0))
|
||||||
index = self._add_thumbnail(item) - 1
|
nrecs += 2
|
||||||
exth.write(pack('>III', 0xca, 0x0c, index))
|
index = self._add_thumbnail(item)
|
||||||
nrecs += 3
|
if index is not None:
|
||||||
|
exth.write(pack('>III', 0xca, 0x0c, index - 1))
|
||||||
|
nrecs += 1
|
||||||
exth = exth.getvalue()
|
exth = exth.getvalue()
|
||||||
trail = len(exth) % 4
|
trail = len(exth) % 4
|
||||||
pad = '\0' * (4 - trail) # Always pad w/ at least 1 byte
|
pad = '\0' * (4 - trail) # Always pad w/ at least 1 byte
|
||||||
@ -496,7 +502,11 @@ class MobiWriter(object):
|
|||||||
return ''.join(exth)
|
return ''.join(exth)
|
||||||
|
|
||||||
def _add_thumbnail(self, item):
|
def _add_thumbnail(self, item):
|
||||||
|
try:
|
||||||
data = rescale_image(item.data, MAX_THUMB_SIZE, MAX_THUMB_DIMEN)
|
data = rescale_image(item.data, MAX_THUMB_SIZE, MAX_THUMB_DIMEN)
|
||||||
|
except IOError:
|
||||||
|
self._oeb.logger.warn('Bad image file %r' % item.href)
|
||||||
|
return None
|
||||||
manifest = self._oeb.manifest
|
manifest = self._oeb.manifest
|
||||||
id, href = manifest.generate('thumbnail', 'thumbnail.jpeg')
|
id, href = manifest.generate('thumbnail', 'thumbnail.jpeg')
|
||||||
manifest.add(id, href, 'image/jpeg', data=data)
|
manifest.add(id, href, 'image/jpeg', data=data)
|
||||||
|
@ -8,24 +8,20 @@ from __future__ import with_statement
|
|||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2008, Marshall T. Vandegrift <llasram@gmail.com>'
|
__copyright__ = '2008, Marshall T. Vandegrift <llasram@gmail.com>'
|
||||||
|
|
||||||
import sys
|
|
||||||
import os
|
import os
|
||||||
import locale
|
|
||||||
import codecs
|
|
||||||
import itertools
|
import itertools
|
||||||
import types
|
|
||||||
import re
|
import re
|
||||||
import copy
|
import copy
|
||||||
from itertools import izip
|
|
||||||
from weakref import WeakKeyDictionary
|
from weakref import WeakKeyDictionary
|
||||||
from xml.dom import SyntaxErr as CSSSyntaxError
|
from xml.dom import SyntaxErr as CSSSyntaxError
|
||||||
import cssutils
|
import cssutils
|
||||||
from cssutils.css import CSSStyleRule, CSSPageRule, CSSStyleDeclaration, \
|
from cssutils.css import CSSStyleRule, CSSPageRule, CSSStyleDeclaration, \
|
||||||
CSSValueList, cssproperties
|
CSSValueList, cssproperties
|
||||||
|
from cssutils.profiles import profiles as cssprofiles
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from lxml.cssselect import css_to_xpath, ExpressionError
|
from lxml.cssselect import css_to_xpath, ExpressionError
|
||||||
from calibre.ebooks.oeb.base import XHTML, XHTML_NS, CSS_MIME, OEB_STYLES
|
from calibre.ebooks.oeb.base import XHTML, XHTML_NS, CSS_MIME, OEB_STYLES
|
||||||
from calibre.ebooks.oeb.base import XPNSMAP, xpath, barename, urlnormalize
|
from calibre.ebooks.oeb.base import XPNSMAP, xpath, urlnormalize
|
||||||
from calibre.ebooks.oeb.profile import PROFILES
|
from calibre.ebooks.oeb.profile import PROFILES
|
||||||
from calibre.resources import html_css
|
from calibre.resources import html_css
|
||||||
|
|
||||||
@ -163,7 +159,7 @@ class Stylizer(object):
|
|||||||
for _, _, cssdict, text, _ in rules:
|
for _, _, cssdict, text, _ in rules:
|
||||||
try:
|
try:
|
||||||
selector = CSSSelector(text)
|
selector = CSSSelector(text)
|
||||||
except ExpressionError, e:
|
except ExpressionError:
|
||||||
continue
|
continue
|
||||||
for elem in selector(tree):
|
for elem in selector(tree):
|
||||||
self.style(elem)._update_cssdict(cssdict)
|
self.style(elem)._update_cssdict(cssdict)
|
||||||
@ -246,7 +242,7 @@ class Stylizer(object):
|
|||||||
primitives.reverse()
|
primitives.reverse()
|
||||||
value = primitives.pop()
|
value = primitives.pop()
|
||||||
for key in composition:
|
for key in composition:
|
||||||
if cssproperties.cssvalues[key](value):
|
if cssprofiles.validate(key, value):
|
||||||
style[key] = value
|
style[key] = value
|
||||||
if not primitives: break
|
if not primitives: break
|
||||||
value = primitives.pop()
|
value = primitives.pop()
|
||||||
|
@ -6,13 +6,9 @@ from __future__ import with_statement
|
|||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2008, Marshall T. Vandegrift <llasram@gmail.com>'
|
__copyright__ = '2008, Marshall T. Vandegrift <llasram@gmail.com>'
|
||||||
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
from urlparse import urldefrag
|
from urlparse import urldefrag
|
||||||
from lxml import etree
|
from calibre.ebooks.oeb.base import CSS_MIME, OEB_DOCS
|
||||||
import cssutils
|
|
||||||
from calibre.ebooks.oeb.base import XPNSMAP, CSS_MIME, OEB_DOCS
|
|
||||||
from calibre.ebooks.oeb.base import LINK_SELECTORS, CSSURL_RE
|
from calibre.ebooks.oeb.base import LINK_SELECTORS, CSSURL_RE
|
||||||
from calibre.ebooks.oeb.base import urlnormalize
|
from calibre.ebooks.oeb.base import urlnormalize
|
||||||
|
|
||||||
|
@ -113,6 +113,10 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
|||||||
def set_cover(self):
|
def set_cover(self):
|
||||||
row = self.formats.currentRow()
|
row = self.formats.currentRow()
|
||||||
fmt = self.formats.item(row)
|
fmt = self.formats.item(row)
|
||||||
|
if fmt is None:
|
||||||
|
error_dialog(self, _('No format selected'),
|
||||||
|
_('No format selected')).exec_()
|
||||||
|
return
|
||||||
ext = fmt.ext.lower()
|
ext = fmt.ext.lower()
|
||||||
if fmt.path is None:
|
if fmt.path is None:
|
||||||
stream = self.db.format(self.row, ext, as_file=True)
|
stream = self.db.format(self.row, ext, as_file=True)
|
||||||
@ -265,7 +269,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
|||||||
def cover_dropped(self):
|
def cover_dropped(self):
|
||||||
self.cover_changed = True
|
self.cover_changed = True
|
||||||
|
|
||||||
def initialize_series_and_publisher(self):
|
def initialize_series(self):
|
||||||
all_series = self.db.all_series()
|
all_series = self.db.all_series()
|
||||||
all_series.sort(cmp=lambda x, y : cmp(x[1], y[1]))
|
all_series.sort(cmp=lambda x, y : cmp(x[1], y[1]))
|
||||||
series_id = self.db.series_id(self.row)
|
series_id = self.db.series_id(self.row)
|
||||||
@ -289,6 +293,8 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
|||||||
l.invalidate()
|
l.invalidate()
|
||||||
l.activate()
|
l.activate()
|
||||||
|
|
||||||
|
def initialize_series_and_publisher(self):
|
||||||
|
self.initialize_series()
|
||||||
all_publishers = self.db.all_publishers()
|
all_publishers = self.db.all_publishers()
|
||||||
all_publishers.sort(cmp=lambda x, y : cmp(x[1], y[1]))
|
all_publishers.sort(cmp=lambda x, y : cmp(x[1], y[1]))
|
||||||
publisher_id = self.db.publisher_id(self.row)
|
publisher_id = self.db.publisher_id(self.row)
|
||||||
|
BIN
src/calibre/gui2/images/news/chicago_breaking_news.png
Normal file
BIN
src/calibre/gui2/images/news/chicago_breaking_news.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 704 B |
BIN
src/calibre/gui2/images/news/linuxdevices.png
Normal file
BIN
src/calibre/gui2/images/news/linuxdevices.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 535 B |
BIN
src/calibre/gui2/images/news/pressonline.png
Normal file
BIN
src/calibre/gui2/images/news/pressonline.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
@ -216,12 +216,9 @@ class BooksModel(QAbstractTableModel):
|
|||||||
|
|
||||||
|
|
||||||
def delete_books(self, indices):
|
def delete_books(self, indices):
|
||||||
ids = [ self.id(i) for i in indices ]
|
ids = map(self.id, indices)
|
||||||
for id in ids:
|
for id in ids:
|
||||||
row = self.db.index(id)
|
self.db.delete_book(id, notify=False)
|
||||||
self.beginRemoveRows(QModelIndex(), row, row)
|
|
||||||
self.db.delete_book(id)
|
|
||||||
self.endRemoveRows()
|
|
||||||
self.count_changed()
|
self.count_changed()
|
||||||
self.clear_caches()
|
self.clear_caches()
|
||||||
self.reset()
|
self.reset()
|
||||||
@ -414,8 +411,11 @@ class BooksModel(QAbstractTableModel):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_preferred_formats(self, rows, formats, paths=False, set_metadata=False):
|
def get_preferred_formats(self, rows, formats, paths=False,
|
||||||
|
set_metadata=False, specific_format=None):
|
||||||
ans = []
|
ans = []
|
||||||
|
if specific_format is not None:
|
||||||
|
formats = [specific_format.lower()]
|
||||||
for row in (row.row() for row in rows):
|
for row in (row.row() for row in rows):
|
||||||
format = None
|
format = None
|
||||||
fmts = self.db.formats(row)
|
fmts = self.db.formats(row)
|
||||||
|
@ -156,6 +156,9 @@ class Main(MainWindow, Ui_MainWindow):
|
|||||||
sm.addAction(QIcon(':/images/sd.svg'), _('Send to storage card'))
|
sm.addAction(QIcon(':/images/sd.svg'), _('Send to storage card'))
|
||||||
sm.addAction(QIcon(':/images/reader.svg'), _('Send to main memory')+' '+_('and delete from library'))
|
sm.addAction(QIcon(':/images/reader.svg'), _('Send to main memory')+' '+_('and delete from library'))
|
||||||
sm.addAction(QIcon(':/images/sd.svg'), _('Send to storage card')+' '+_('and delete from library'))
|
sm.addAction(QIcon(':/images/sd.svg'), _('Send to storage card')+' '+_('and delete from library'))
|
||||||
|
sm.addAction(self.action_send_specific_format_to_device)
|
||||||
|
self.connect(self.action_send_specific_format_to_device,
|
||||||
|
SIGNAL('triggered()'), self.send_specific_format_to_device)
|
||||||
sm.addSeparator()
|
sm.addSeparator()
|
||||||
sm.addAction(_('Send to storage card by default'))
|
sm.addAction(_('Send to storage card by default'))
|
||||||
sm.actions()[-1].setCheckable(True)
|
sm.actions()[-1].setCheckable(True)
|
||||||
@ -330,11 +333,16 @@ class Main(MainWindow, Ui_MainWindow):
|
|||||||
self.cover_flow.setVisible(False)
|
self.cover_flow.setVisible(False)
|
||||||
if not config['separate_cover_flow']:
|
if not config['separate_cover_flow']:
|
||||||
self.library.layout().addWidget(self.cover_flow)
|
self.library.layout().addWidget(self.cover_flow)
|
||||||
self.connect(self.cover_flow, SIGNAL('currentChanged(int)'), self.sync_cf_to_listview)
|
self.connect(self.cover_flow, SIGNAL('currentChanged(int)'),
|
||||||
self.connect(self.cover_flow, SIGNAL('itemActivated(int)'), self.show_book_info)
|
self.sync_cf_to_listview)
|
||||||
self.connect(self.status_bar.cover_flow_button, SIGNAL('toggled(bool)'), self.toggle_cover_flow)
|
self.connect(self.cover_flow, SIGNAL('itemActivated(int)'),
|
||||||
self.connect(self.cover_flow, SIGNAL('stop()'), self.status_bar.cover_flow_button.toggle)
|
self.show_book_info)
|
||||||
QObject.connect(self.library_view.selectionModel(), SIGNAL('currentRowChanged(QModelIndex, QModelIndex)'),
|
self.connect(self.status_bar.cover_flow_button,
|
||||||
|
SIGNAL('toggled(bool)'), self.toggle_cover_flow)
|
||||||
|
self.connect(self.cover_flow, SIGNAL('stop()'),
|
||||||
|
self.status_bar.cover_flow_button.toggle)
|
||||||
|
QObject.connect(self.library_view.selectionModel(),
|
||||||
|
SIGNAL('currentRowChanged(QModelIndex, QModelIndex)'),
|
||||||
self.sync_cf_to_listview)
|
self.sync_cf_to_listview)
|
||||||
self.db_images = DatabaseImages(self.library_view.model())
|
self.db_images = DatabaseImages(self.library_view.model())
|
||||||
self.cover_flow.setImages(self.db_images)
|
self.cover_flow.setImages(self.db_images)
|
||||||
@ -482,7 +490,8 @@ class Main(MainWindow, Ui_MainWindow):
|
|||||||
if not hasattr(index, 'row') and self.library_view.currentIndex().row() != index:
|
if not hasattr(index, 'row') and self.library_view.currentIndex().row() != index:
|
||||||
index = self.library_view.model().index(index, 0)
|
index = self.library_view.model().index(index, 0)
|
||||||
self.library_view.setCurrentIndex(index)
|
self.library_view.setCurrentIndex(index)
|
||||||
if hasattr(index, 'row') and self.cover_flow.isVisible() and self.cover_flow.currentSlide() != index.row():
|
if hasattr(index, 'row') and self.cover_flow.isVisible() and \
|
||||||
|
self.cover_flow.currentSlide() != index.row():
|
||||||
self.cover_flow.setCurrentSlide(index.row())
|
self.cover_flow.setCurrentSlide(index.row())
|
||||||
|
|
||||||
def another_instance_wants_to_talk(self, msg):
|
def another_instance_wants_to_talk(self, msg):
|
||||||
@ -709,6 +718,7 @@ class Main(MainWindow, Ui_MainWindow):
|
|||||||
t.process_duplicates()
|
t.process_duplicates()
|
||||||
if t.number_of_books_added > 0:
|
if t.number_of_books_added > 0:
|
||||||
self.library_view.model().books_added(t.number_of_books_added)
|
self.library_view.model().books_added(t.number_of_books_added)
|
||||||
|
self.db_images.reset()
|
||||||
|
|
||||||
def upload_books(self, files, names, metadata, on_card=False, memory=None):
|
def upload_books(self, files, names, metadata, on_card=False, memory=None):
|
||||||
'''
|
'''
|
||||||
@ -886,8 +896,16 @@ class Main(MainWindow, Ui_MainWindow):
|
|||||||
self.upload_books(files, names, metadata, on_card=on_card, memory=[[f.name for f in files], remove])
|
self.upload_books(files, names, metadata, on_card=on_card, memory=[[f.name for f in files], remove])
|
||||||
self.status_bar.showMessage(_('Sending news to device.'), 5000)
|
self.status_bar.showMessage(_('Sending news to device.'), 5000)
|
||||||
|
|
||||||
|
def send_specific_format_to_device(self):
|
||||||
|
d = ChooseFormatDialog(self, _('Choose format to send to device'),
|
||||||
|
self.device_manager.device_class.FORMATS)
|
||||||
|
d.exec_()
|
||||||
|
fmt = d.format().lower()
|
||||||
|
on_card = config['send_to_storage_card_by_default']
|
||||||
|
self.sync_to_device(on_card, False, specific_format=fmt)
|
||||||
|
|
||||||
def sync_to_device(self, on_card, delete_from_library):
|
|
||||||
|
def sync_to_device(self, on_card, delete_from_library, specific_format=None):
|
||||||
rows = self.library_view.selectionModel().selectedRows()
|
rows = self.library_view.selectionModel().selectedRows()
|
||||||
if not self.device_manager or not rows or len(rows) == 0:
|
if not self.device_manager or not rows or len(rows) == 0:
|
||||||
return
|
return
|
||||||
@ -900,7 +918,8 @@ class Main(MainWindow, Ui_MainWindow):
|
|||||||
metadata = iter(metadata)
|
metadata = iter(metadata)
|
||||||
_files = self.library_view.model().get_preferred_formats(rows,
|
_files = self.library_view.model().get_preferred_formats(rows,
|
||||||
self.device_manager.device_class.FORMATS,
|
self.device_manager.device_class.FORMATS,
|
||||||
paths=True, set_metadata=True)
|
paths=True, set_metadata=True,
|
||||||
|
specific_format=specific_format)
|
||||||
files = [getattr(f, 'name', None) for f in _files]
|
files = [getattr(f, 'name', None) for f in _files]
|
||||||
bad, good, gf, names, remove_ids = [], [], [], [], []
|
bad, good, gf, names, remove_ids = [], [], [], [], []
|
||||||
for f in files:
|
for f in files:
|
||||||
@ -1336,10 +1355,13 @@ class Main(MainWindow, Ui_MainWindow):
|
|||||||
'''
|
'''
|
||||||
Handle exceptions in threaded device jobs.
|
Handle exceptions in threaded device jobs.
|
||||||
'''
|
'''
|
||||||
if 'Could not read 32 bytes on the control bus.' in str(job.exception):
|
try:
|
||||||
|
if 'Could not read 32 bytes on the control bus.' in unicode(job.exception):
|
||||||
error_dialog(self, _('Error talking to device'),
|
error_dialog(self, _('Error talking to device'),
|
||||||
_('There was a temporary error talking to the device. Please unplug and reconnect the device and or reboot.')).show()
|
_('There was a temporary error talking to the device. Please unplug and reconnect the device and or reboot.')).show()
|
||||||
return
|
return
|
||||||
|
except:
|
||||||
|
pass
|
||||||
try:
|
try:
|
||||||
print >>sys.stderr, job.console_text()
|
print >>sys.stderr, job.console_text()
|
||||||
except:
|
except:
|
||||||
|
@ -656,6 +656,15 @@
|
|||||||
<string>Books with the same tags</string>
|
<string>Books with the same tags</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="action_send_specific_format_to_device" >
|
||||||
|
<property name="icon" >
|
||||||
|
<iconset resource="images.qrc" >
|
||||||
|
<normaloff>:/images/book.svg</normaloff>:/images/book.svg</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text" >
|
||||||
|
<string>Send specific format to device</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
|
@ -19,7 +19,8 @@ from calibre.library import title_sort
|
|||||||
from calibre.library.database import LibraryDatabase
|
from calibre.library.database import LibraryDatabase
|
||||||
from calibre.library.sqlite import connect, IntegrityError
|
from calibre.library.sqlite import connect, IntegrityError
|
||||||
from calibre.utils.search_query_parser import SearchQueryParser
|
from calibre.utils.search_query_parser import SearchQueryParser
|
||||||
from calibre.ebooks.metadata import string_to_authors, authors_to_string, MetaInformation
|
from calibre.ebooks.metadata import string_to_authors, authors_to_string, \
|
||||||
|
MetaInformation, authors_to_sort_string
|
||||||
from calibre.ebooks.metadata.meta import get_metadata, set_metadata, \
|
from calibre.ebooks.metadata.meta import get_metadata, set_metadata, \
|
||||||
metadata_from_formats
|
metadata_from_formats
|
||||||
from calibre.ebooks.metadata.opf2 import OPFCreator
|
from calibre.ebooks.metadata.opf2 import OPFCreator
|
||||||
@ -728,7 +729,7 @@ class LibraryDatabase2(LibraryDatabase):
|
|||||||
if notify:
|
if notify:
|
||||||
self.notify('metadata', [id])
|
self.notify('metadata', [id])
|
||||||
|
|
||||||
def delete_book(self, id):
|
def delete_book(self, id, notify=True):
|
||||||
'''
|
'''
|
||||||
Removes book from the result cache and the underlying database.
|
Removes book from the result cache and the underlying database.
|
||||||
'''
|
'''
|
||||||
@ -743,6 +744,7 @@ class LibraryDatabase2(LibraryDatabase):
|
|||||||
self.conn.commit()
|
self.conn.commit()
|
||||||
self.clean()
|
self.clean()
|
||||||
self.data.books_deleted([id])
|
self.data.books_deleted([id])
|
||||||
|
if notify:
|
||||||
self.notify('delete', [id])
|
self.notify('delete', [id])
|
||||||
|
|
||||||
def remove_format(self, index, format, index_is_id=False, notify=True):
|
def remove_format(self, index, format, index_is_id=False, notify=True):
|
||||||
@ -1197,11 +1199,17 @@ class LibraryDatabase2(LibraryDatabase):
|
|||||||
|
|
||||||
def import_book(self, mi, formats, notify=True):
|
def import_book(self, mi, formats, notify=True):
|
||||||
series_index = 1 if mi.series_index is None else mi.series_index
|
series_index = 1 if mi.series_index is None else mi.series_index
|
||||||
|
if not mi.title:
|
||||||
|
mi.title = _('Unknown')
|
||||||
if not mi.authors:
|
if not mi.authors:
|
||||||
mi.authors = [_('Unknown')]
|
mi.authors = [_('Unknown')]
|
||||||
aus = mi.author_sort if mi.author_sort else ', '.join(mi.authors)
|
aus = mi.author_sort if mi.author_sort else authors_to_sort_string(mi.authors)
|
||||||
|
if isinstance(aus, str):
|
||||||
|
aus = aus.decode(preferred_encoding, 'replace')
|
||||||
|
title = mi.title if isinstance(mi.title, unicode) else \
|
||||||
|
mi.title.decode(preferred_encoding, 'replace')
|
||||||
obj = self.conn.execute('INSERT INTO books(title, uri, series_index, author_sort) VALUES (?, ?, ?, ?)',
|
obj = self.conn.execute('INSERT INTO books(title, uri, series_index, author_sort) VALUES (?, ?, ?, ?)',
|
||||||
(mi.title, None, series_index, aus))
|
(title, None, series_index, aus))
|
||||||
id = obj.lastrowid
|
id = obj.lastrowid
|
||||||
self.data.books_added([id], self.conn)
|
self.data.books_added([id], self.conn)
|
||||||
self.set_path(id, True)
|
self.set_path(id, True)
|
||||||
@ -1210,8 +1218,7 @@ class LibraryDatabase2(LibraryDatabase):
|
|||||||
ext = os.path.splitext(path)[1][1:].lower()
|
ext = os.path.splitext(path)[1][1:].lower()
|
||||||
if ext == 'opf':
|
if ext == 'opf':
|
||||||
continue
|
continue
|
||||||
stream = open(path, 'rb')
|
self.add_format_with_hooks(id, ext, path, index_is_id=True)
|
||||||
self.add_format(id, ext, stream, index_is_id=True)
|
|
||||||
self.conn.commit()
|
self.conn.commit()
|
||||||
self.data.refresh_ids(self.conn, [id]) # Needed to update format list and size
|
self.data.refresh_ids(self.conn, [id]) # Needed to update format list and size
|
||||||
if notify:
|
if notify:
|
||||||
|
@ -12,11 +12,50 @@ from sqlite3 import IntegrityError
|
|||||||
from threading import Thread
|
from threading import Thread
|
||||||
from Queue import Queue
|
from Queue import Queue
|
||||||
from threading import RLock
|
from threading import RLock
|
||||||
|
from datetime import tzinfo, datetime, timedelta
|
||||||
|
|
||||||
from calibre.ebooks.metadata import title_sort
|
from calibre.ebooks.metadata import title_sort
|
||||||
|
|
||||||
global_lock = RLock()
|
global_lock = RLock()
|
||||||
|
|
||||||
|
def convert_timestamp(val):
|
||||||
|
datepart, timepart = val.split(' ')
|
||||||
|
tz, mult = None, 1
|
||||||
|
x = timepart.split('+')
|
||||||
|
if len(x) > 1:
|
||||||
|
timepart, tz = x
|
||||||
|
else:
|
||||||
|
x = timepart.split('-')
|
||||||
|
if len(x) > 1:
|
||||||
|
timepart, tz = x
|
||||||
|
mult = -1
|
||||||
|
|
||||||
|
year, month, day = map(int, datepart.split("-"))
|
||||||
|
timepart_full = timepart.split(".")
|
||||||
|
hours, minutes, seconds = map(int, timepart_full[0].split(":"))
|
||||||
|
if len(timepart_full) == 2:
|
||||||
|
microseconds = int(timepart_full[1])
|
||||||
|
else:
|
||||||
|
microseconds = 0
|
||||||
|
if tz is not None:
|
||||||
|
h, m = map(int, tz.split(':'))
|
||||||
|
delta = timedelta(minutes=mult*(60*h + m))
|
||||||
|
tz = type('CustomTZ', (tzinfo,), {'utcoffset':lambda self, dt:delta,
|
||||||
|
'dst':lambda self,dt:timedelta(0)})()
|
||||||
|
|
||||||
|
val = datetime(year, month, day, hours, minutes, seconds, microseconds,
|
||||||
|
tzinfo=tz)
|
||||||
|
if tz is not None:
|
||||||
|
val = datetime(*(val.utctimetuple()[:6]))
|
||||||
|
return val
|
||||||
|
|
||||||
|
def adapt_datetime(dt):
|
||||||
|
dt = datetime(*(dt.utctimetuple()[:6]))
|
||||||
|
return dt.isoformat(' ')
|
||||||
|
|
||||||
|
sqlite.register_adapter(datetime, adapt_datetime)
|
||||||
|
sqlite.register_converter('timestamp', convert_timestamp)
|
||||||
|
|
||||||
class Concatenate(object):
|
class Concatenate(object):
|
||||||
'''String concatenation aggregator for sqlite'''
|
'''String concatenation aggregator for sqlite'''
|
||||||
def __init__(self, sep=','):
|
def __init__(self, sep=','):
|
||||||
|
@ -480,6 +480,7 @@ VIEWER = '''\
|
|||||||
Version=%s
|
Version=%s
|
||||||
Type=Application
|
Type=Application
|
||||||
Name=LRF Viewer
|
Name=LRF Viewer
|
||||||
|
GenericName=Viewer for LRF files
|
||||||
Comment=Viewer for LRF files (SONY ebook format files)
|
Comment=Viewer for LRF files (SONY ebook format files)
|
||||||
TryExec=lrfviewer
|
TryExec=lrfviewer
|
||||||
Exec=lrfviewer %%F
|
Exec=lrfviewer %%F
|
||||||
@ -492,8 +493,9 @@ EVIEWER = '''\
|
|||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Version=%s
|
Version=%s
|
||||||
Type=Application
|
Type=Application
|
||||||
Name=Ebook Viewer
|
Name=E-book Viewer
|
||||||
Comment=Viewer for Ebooks
|
GenericName=Viewer for E-books
|
||||||
|
Comment=Viewer for E-books
|
||||||
TryExec=ebook-viewer
|
TryExec=ebook-viewer
|
||||||
Exec=ebook-viewer %%F
|
Exec=ebook-viewer %%F
|
||||||
Icon=calibre-viewer
|
Icon=calibre-viewer
|
||||||
@ -506,7 +508,8 @@ GUI = '''\
|
|||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Version=%s
|
Version=%s
|
||||||
Type=Application
|
Type=Application
|
||||||
Name=calibre - Ebook library management
|
Name=calibre
|
||||||
|
GenericName=E-book library management
|
||||||
Comment=E-book library management
|
Comment=E-book library management
|
||||||
TryExec=calibre
|
TryExec=calibre
|
||||||
Exec=calibre
|
Exec=calibre
|
||||||
|
@ -28,7 +28,7 @@ What formats does |app| support conversion to/from?
|
|||||||
| | | | | |
|
| | | | | |
|
||||||
| | LIT | ✔ | ✔ | ✔ |
|
| | LIT | ✔ | ✔ | ✔ |
|
||||||
| | | | | |
|
| | | | | |
|
||||||
| | PRC | ✔ | ✔ | ✔ |
|
| | PRC** | ✔ | ✔ | ✔ |
|
||||||
| | | | | |
|
| | | | | |
|
||||||
| | EPUB | ✔ | ✔ | ✔ |
|
| | EPUB | ✔ | ✔ | ✔ |
|
||||||
| | | | | |
|
| | | | | |
|
||||||
@ -49,6 +49,7 @@ What formats does |app| support conversion to/from?
|
|||||||
| | LRS | | ✔ | |
|
| | LRS | | ✔ | |
|
||||||
+-------------------+--------+------------------+-----------------------+-----------------------+
|
+-------------------+--------+------------------+-----------------------+-----------------------+
|
||||||
|
|
||||||
|
** PRC is a generic format, |app| supports PRC files with TextRead and MOBIBook headers
|
||||||
|
|
||||||
|
|
||||||
What are the best source formats to convert?
|
What are the best source formats to convert?
|
||||||
@ -146,7 +147,7 @@ When you first run |app|, it will ask you for a folder in which to store your bo
|
|||||||
Why doesn't |app| let me store books in my own directory structure?
|
Why doesn't |app| let me store books in my own directory structure?
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
The whole point if |app|'s library management features is that they provide an interface for locating books that is *much* more efficient than any possible directory scheme you could come up with for your collection. Indeed, once you become comfortable using |app|'s interface to find, sort and browse your collection, you wont ever feel the need to hunt through the files on your disk to find a book again. By managing books in its own directory struture of Author -> Title -> Book files, |app| is able to achieve a high level of reliability and standardization.
|
The whole point of |app|'s library management features is that they provide an interface for locating books that is *much* more efficient than any possible directory scheme you could come up with for your collection. Indeed, once you become comfortable using |app|'s interface to find, sort and browse your collection, you wont ever feel the need to hunt through the files on your disk to find a book again. By managing books in its own directory struture of Author -> Title -> Book files, |app| is able to achieve a high level of reliability and standardization.
|
||||||
|
|
||||||
Why doesn't |app| have a column for foo?
|
Why doesn't |app| have a column for foo?
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
12
src/calibre/manual/templates/layout.html
Normal file
12
src/calibre/manual/templates/layout.html
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{% extends "!layout.html" %}
|
||||||
|
{% block sidebarlogo %}
|
||||||
|
{{ super() }}
|
||||||
|
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
|
||||||
|
<input type="hidden" name="cmd" value="_s-xclick" />
|
||||||
|
<input type="hidden" name="hosted_button_id" value="3028915" />
|
||||||
|
<input type="image" src="https://www.paypal.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="Donate to support calibre development" style="border:0pt" />
|
||||||
|
<img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1"/>
|
||||||
|
</form>
|
||||||
|
<hr/>
|
||||||
|
{% endblock %}
|
||||||
|
|
@ -197,6 +197,7 @@ class Server(object):
|
|||||||
def calculate_month_trend(self, days=31):
|
def calculate_month_trend(self, days=31):
|
||||||
stats = self.get_slice(date.today()-timedelta(days=days-1), date.today())
|
stats = self.get_slice(date.today()-timedelta(days=days-1), date.today())
|
||||||
fig = plt.figure(2, (12, 4), 96)#, facecolor, edgecolor, frameon, FigureClass)
|
fig = plt.figure(2, (12, 4), 96)#, facecolor, edgecolor, frameon, FigureClass)
|
||||||
|
fig.clear()
|
||||||
ax = fig.add_subplot(111)
|
ax = fig.add_subplot(111)
|
||||||
x = list(range(days-1, -1, -1))
|
x = list(range(days-1, -1, -1))
|
||||||
y = stats.daily_totals
|
y = stats.daily_totals
|
||||||
@ -235,6 +236,7 @@ Donors per day: %(dpd).2f
|
|||||||
y = [m.total for m in _months]
|
y = [m.total for m in _months]
|
||||||
ml = mdates.MonthLocator() # every month
|
ml = mdates.MonthLocator() # every month
|
||||||
fig = plt.figure(1, (8, 4), 96)#, facecolor, edgecolor, frameon, FigureClass)
|
fig = plt.figure(1, (8, 4), 96)#, facecolor, edgecolor, frameon, FigureClass)
|
||||||
|
fig.clear()
|
||||||
ax = fig.add_subplot(111)
|
ax = fig.add_subplot(111)
|
||||||
average = sum(y)/len(y)
|
average = sum(y)/len(y)
|
||||||
ax.bar(x, y, align='center', width=20, color='g')
|
ax.bar(x, y, align='center', width=20, color='g')
|
||||||
|
@ -1,28 +1,9 @@
|
|||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
import re
|
|
||||||
from pkg_resources import resource_filename
|
|
||||||
|
|
||||||
from trac.core import Component, implements
|
|
||||||
from trac.web.chrome import INavigationContributor, ITemplateProvider, add_stylesheet
|
|
||||||
from trac.web.main import IRequestHandler
|
|
||||||
from trac.util import Markup
|
|
||||||
|
|
||||||
|
|
||||||
__appname__ = 'calibre'
|
__appname__ = 'calibre'
|
||||||
DOWNLOAD_DIR = '/var/www/calibre.kovidgoyal.net/htdocs/downloads'
|
import re, textwrap
|
||||||
MOBILEREAD = 'https://dev.mobileread.com/dist/kovid/calibre/'
|
|
||||||
|
|
||||||
class OS(dict):
|
DEPENDENCIES = [
|
||||||
"""Dictionary with a default value for unknown keys."""
|
|
||||||
def __init__(self, dict):
|
|
||||||
self.update(dict)
|
|
||||||
if not dict.has_key('img'):
|
|
||||||
self['img'] = self['name']
|
|
||||||
|
|
||||||
class Distribution(object):
|
|
||||||
|
|
||||||
DEPENDENCIES = [
|
|
||||||
#(Generic, version, gentoo, ubuntu, fedora)
|
#(Generic, version, gentoo, ubuntu, fedora)
|
||||||
('python', '2.5', None, None, None),
|
('python', '2.5', None, None, None),
|
||||||
('setuptools', '0.6c5', 'setuptools', 'python-setuptools', 'python-setuptools-devel'),
|
('setuptools', '0.6c5', 'setuptools', 'python-setuptools', 'python-setuptools-devel'),
|
||||||
@ -30,7 +11,7 @@ class Distribution(object):
|
|||||||
('libusb', '0.1.12', None, None, None),
|
('libusb', '0.1.12', None, None, None),
|
||||||
('Qt', '4.4.0', 'qt', 'libqt4-core libqt4-gui', 'qt4'),
|
('Qt', '4.4.0', 'qt', 'libqt4-core libqt4-gui', 'qt4'),
|
||||||
('PyQt', '4.4.2', 'PyQt4', 'python-qt4', 'PyQt4'),
|
('PyQt', '4.4.2', 'PyQt4', 'python-qt4', 'PyQt4'),
|
||||||
('mechanize for python', '0.1.11', 'dev-python/mechanize', 'python-mechanize', 'python-mechanize'),
|
('python-mechanize', '0.1.11', 'dev-python/mechanize', 'python-mechanize', 'python-mechanize'),
|
||||||
('ImageMagick', '6.3.5', 'imagemagick', 'imagemagick', 'ImageMagick'),
|
('ImageMagick', '6.3.5', 'imagemagick', 'imagemagick', 'ImageMagick'),
|
||||||
('xdg-utils', '1.0.2', 'xdg-utils', 'xdg-utils', 'xdg-utils'),
|
('xdg-utils', '1.0.2', 'xdg-utils', 'xdg-utils', 'xdg-utils'),
|
||||||
('dbus-python', '0.82.2', 'dbus-python', 'python-dbus', 'dbus-python'),
|
('dbus-python', '0.82.2', 'dbus-python', 'python-dbus', 'dbus-python'),
|
||||||
@ -40,54 +21,62 @@ class Distribution(object):
|
|||||||
('help2man', '1.36.4', 'help2man', 'help2man', 'help2man'),
|
('help2man', '1.36.4', 'help2man', 'help2man', 'help2man'),
|
||||||
]
|
]
|
||||||
|
|
||||||
DISTRO_MAP = {'gentoo':2, 'ubuntu':3, 'fedora':4, 'debian':3}
|
|
||||||
|
|
||||||
INSTALLERS = ('emerge -avn', 'apt-get install', 'yum install')
|
class CoolDistro:
|
||||||
AS_ROOT = (True, False, True)
|
|
||||||
|
|
||||||
TITLEMAP = {'gentoo':'Gentoo', 'ubuntu':'Ubuntu Intrepid Ibex',
|
def __init__(self, name, title, prefix=''):
|
||||||
'fedora':'Fedora 10', 'debian':'Debian sid', 'generic': 'Install from source'}
|
self.title = title
|
||||||
|
url = prefix + '/chrome/dl/images/%s_logo.png'
|
||||||
|
self.img = url%name
|
||||||
|
|
||||||
MANUAL_MAP = {
|
def get_linux_data(version='1.0.0'):
|
||||||
'fedora' : '''<li>You have to upgrade Qt to at least 4.4.0 and PyQt to at least 4.4.2</li>''',
|
data = {'version':version, 'app':__appname__}
|
||||||
}
|
data['title'] = 'Download calibre for linux'
|
||||||
|
data['supported'] = []
|
||||||
|
for name, title in [
|
||||||
|
('ubuntu', 'Ubuntu Jaunty Jackalope'),
|
||||||
|
('debian', 'Debian Sid'),
|
||||||
|
('exherbo', 'Exherbo'),
|
||||||
|
]:
|
||||||
|
data['supported'].append(CoolDistro(name, title,
|
||||||
|
prefix='http://calibre.kovidgoyal.net'))
|
||||||
|
data['dependencies'] = DEPENDENCIES
|
||||||
|
return data
|
||||||
|
|
||||||
def __init__(self, os):
|
if __name__ == '__main__':
|
||||||
self.os = os
|
import os
|
||||||
self.img = os
|
from calibre.utils.genshi.template import MarkupTemplate
|
||||||
self.title = self.TITLEMAP[os]
|
import cherrypy
|
||||||
self.app = __appname__
|
class Test:
|
||||||
self.is_generic = os == 'generic'
|
def index(self):
|
||||||
offset = 0
|
raw = open(os.path.dirname(os.path.abspath(__file__))+'/templates/linux.html').read()
|
||||||
if not self.is_generic:
|
return MarkupTemplate(raw).generate(**get_linux_data()).render('xhtml')
|
||||||
index = self.DISTRO_MAP[self.os]
|
index.exposed = True
|
||||||
if os == 'debian':
|
t = Test()
|
||||||
self.as_root = True
|
t.index()
|
||||||
else: self.as_root = self.AS_ROOT[index-2]
|
cherrypy.quickstart(t)
|
||||||
prefix = ''
|
else:
|
||||||
if not self.as_root: prefix = 'sudo '
|
from pkg_resources import resource_filename
|
||||||
cmd = prefix + self.INSTALLERS[index-2]
|
|
||||||
pre = ' \\\n '.ljust(len(cmd)+4)
|
from trac.core import Component, implements
|
||||||
for dep in self.DEPENDENCIES:
|
from trac.web.chrome import INavigationContributor, ITemplateProvider, add_stylesheet
|
||||||
if len(cmd) > 70+offset:
|
from trac.web.main import IRequestHandler
|
||||||
offset += 70
|
from trac.util import Markup
|
||||||
cmd += pre
|
|
||||||
cmd += ' '
|
|
||||||
if dep[index]: cmd += dep[index]
|
|
||||||
self.command = cmd.strip()
|
|
||||||
easy_install = 'easy_install'
|
|
||||||
if os == 'debian':
|
|
||||||
easy_install = 'easy_install-2.5'
|
|
||||||
self.command += '\n'+prefix+easy_install+' -U calibre \n'+prefix+'calibre_postinstall'
|
|
||||||
try:
|
|
||||||
self.manual = Markup(self.MANUAL_MAP[os])
|
|
||||||
except KeyError:
|
|
||||||
self.manual = None
|
|
||||||
else:
|
|
||||||
self.img = 'linux'
|
|
||||||
|
|
||||||
|
|
||||||
class Download(Component):
|
|
||||||
|
DOWNLOAD_DIR = '/var/www/calibre.kovidgoyal.net/htdocs/downloads'
|
||||||
|
MOBILEREAD = 'https://dev.mobileread.com/dist/kovid/calibre/'
|
||||||
|
|
||||||
|
class OS(dict):
|
||||||
|
"""Dictionary with a default value for unknown keys."""
|
||||||
|
def __init__(self, dict):
|
||||||
|
self.update(dict)
|
||||||
|
if not dict.has_key('img'):
|
||||||
|
self['img'] = self['name']
|
||||||
|
|
||||||
|
|
||||||
|
class Download(Component):
|
||||||
implements(INavigationContributor, IRequestHandler, ITemplateProvider)
|
implements(INavigationContributor, IRequestHandler, ITemplateProvider)
|
||||||
|
|
||||||
request_pat = re.compile(r'\/download$|\/download_\S+')
|
request_pat = re.compile(r'\/download$|\/download_\S+')
|
||||||
@ -125,16 +114,6 @@ class Download(Component):
|
|||||||
return self.osx(req)
|
return self.osx(req)
|
||||||
elif os == 'linux':
|
elif os == 'linux':
|
||||||
return self.linux(req)
|
return self.linux(req)
|
||||||
elif 'binary' in os:
|
|
||||||
return self.linux_binary(req)
|
|
||||||
else:
|
|
||||||
return self.linux_distro(req, os)
|
|
||||||
|
|
||||||
def linux_distro(self, req, os):
|
|
||||||
version = self.version_from_filename()
|
|
||||||
distro = Distribution(os)
|
|
||||||
data = dict(distro=distro,title=distro.title, version=version)
|
|
||||||
return 'distro.html', data, None
|
|
||||||
|
|
||||||
def top_level(self, req):
|
def top_level(self, req):
|
||||||
operating_systems = [
|
operating_systems = [
|
||||||
@ -162,37 +141,33 @@ class Download(Component):
|
|||||||
compatibility='%s works on Windows XP and Windows Vista.'%(__appname__,),
|
compatibility='%s works on Windows XP and Windows Vista.'%(__appname__,),
|
||||||
path=MOBILEREAD+file, app=__appname__,
|
path=MOBILEREAD+file, app=__appname__,
|
||||||
note=Markup(\
|
note=Markup(\
|
||||||
'''
|
'''
|
||||||
<p>If you are using the <b>SONY PRS-500</b> and %(appname)s does not detect your reader, read on:</p>
|
<p>If you are using the <b>SONY PRS-500</b> and %(appname)s does not detect your reader, read on:</p>
|
||||||
<blockquote>
|
<blockquote>
|
||||||
<p>
|
<p>
|
||||||
If you are using 64-bit windows, you're out of luck.
|
If you are using 64-bit windows, you're out of luck.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
There may be a conflict with the USB driver from SONY. In windows, you cannot install two drivers
|
There may be a conflict with the USB driver from SONY. In windows, you cannot install two drivers
|
||||||
for one device. In order to resolve the conflict:
|
for one device. In order to resolve the conflict:
|
||||||
<ol>
|
<ol>
|
||||||
<li>Start Device Manager by clicking Start->Run, typing devmgmt.msc and pressing enter.</li>
|
<li>Start Device Manager by clicking Start->Run, typing devmgmt.msc and pressing enter.</li>
|
||||||
<li>Uninstall all PRS500 related drivers. You will find them in two locations:
|
<li>Uninstall all PRS500 related drivers. You will find them in two locations:
|
||||||
<ul>
|
<ul>
|
||||||
<li>Under "Libusb-Win32"</li>
|
<li>Under "Libusb-Win32"</li>
|
||||||
<li>Under "Universal Serial ..." (... depends on the version of windows)</li>
|
<li>Under "Universal Serial ..." (... depends on the version of windows)</li>
|
||||||
</ul>
|
</ul>
|
||||||
You can uninstall a driver by right clicking on it and selecting uninstall.
|
You can uninstall a driver by right clicking on it and selecting uninstall.
|
||||||
</li>
|
</li>
|
||||||
<li>Once the drivers have been uninstalled, find the file prs500.inf (it will be in the
|
<li>Once the drivers have been uninstalled, find the file prs500.inf (it will be in the
|
||||||
driver folder in the folder in which you installed %(appname)s. Right click on it and
|
driver folder in the folder in which you installed %(appname)s. Right click on it and
|
||||||
select Install.</li>
|
select Install.</li>
|
||||||
</ol>
|
</ol>
|
||||||
</p>
|
</p>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
'''%dict(appname=__appname__)))
|
'''%dict(appname=__appname__)))
|
||||||
return 'binary.html', data, None
|
return 'binary.html', data, None
|
||||||
|
|
||||||
def linux_binary(self, req):
|
|
||||||
version = self.version_from_filename()
|
|
||||||
return 'pyinstaller.html', {'app':__appname__, 'version':version}, None
|
|
||||||
|
|
||||||
def osx(self, req):
|
def osx(self, req):
|
||||||
version = self.version_from_filename()
|
version = self.version_from_filename()
|
||||||
file = 'calibre-%s.dmg'%(version,)
|
file = 'calibre-%s.dmg'%(version,)
|
||||||
@ -202,35 +177,26 @@ select Install.</li>
|
|||||||
compatibility='%s works on OS X Tiger and above.'%(__appname__,),
|
compatibility='%s works on OS X Tiger and above.'%(__appname__,),
|
||||||
path=MOBILEREAD+file, app=__appname__,
|
path=MOBILEREAD+file, app=__appname__,
|
||||||
note=Markup(\
|
note=Markup(\
|
||||||
'''
|
'''
|
||||||
<ol>
|
<ol>
|
||||||
<li>Before trying to use the command line tools, you must run the app at least once. This will ask you for you password and then setup the symbolic links for the command line tools.</li>
|
<li>Before trying to use the command line tools, you must run the app at least once. This will ask you for you password and then setup the symbolic links for the command line tools.</li>
|
||||||
<li>The app cannot be run from within the dmg. You must drag it to a folder on your filesystem (The Desktop, Applications, wherever).</li>
|
<li>The app cannot be run from within the dmg. You must drag it to a folder on your filesystem (The Desktop, Applications, wherever).</li>
|
||||||
<li>In order for localization of the user interface in your language, select your language in the configuration dialog (by clicking the hammer icon next to the search bar) and select your language.</li>
|
<li>In order for localization of the user interface in your language, select your language in the configuration dialog (by clicking the hammer icon next to the search bar) and select your language.</li>
|
||||||
</ol>
|
</ol>
|
||||||
'''))
|
'''))
|
||||||
return 'binary.html', data, None
|
return 'binary.html', data, None
|
||||||
|
|
||||||
def linux(self, req):
|
def linux(self, req):
|
||||||
operating_systems = [
|
data = get_linux_data(version=self.version_from_filename())
|
||||||
OS({'name' : 'binary', 'title': 'Binary Installer'}),
|
return 'linux.html', data, None
|
||||||
OS({'name' : 'gentoo', 'title': 'Gentoo'}),
|
|
||||||
OS({'name' : 'ubuntu', 'title': 'Ubuntu'}),
|
|
||||||
OS({'name' : 'fedora', 'title': 'Fedora'}),
|
|
||||||
OS({'name' : 'debian', 'title': 'Debian'}),
|
|
||||||
OS({'name' : 'generic','title': 'Install from source', 'img':'linux'}),
|
|
||||||
]
|
|
||||||
data = dict(title='Choose linux distribution', width=100,
|
|
||||||
operating_systems=operating_systems, font_size='x-large', top_level=False)
|
|
||||||
return 'download.html', data, None
|
|
||||||
|
|
||||||
|
|
||||||
LINUX_INSTALLER = r'''
|
LINUX_INSTALLER = textwrap.dedent(r'''
|
||||||
import sys, os, shutil, tarfile, subprocess, tempfile, urllib2, re, stat
|
import sys, os, shutil, tarfile, subprocess, tempfile, urllib2, re, stat
|
||||||
|
|
||||||
MOBILEREAD='https://dev.mobileread.com/dist/kovid/calibre/'
|
MOBILEREAD='https://dev.mobileread.com/dist/kovid/calibre/'
|
||||||
|
|
||||||
class TerminalController:
|
class TerminalController:
|
||||||
BOL = '' #: Move the cursor to the beginning of the line
|
BOL = '' #: Move the cursor to the beginning of the line
|
||||||
UP = '' #: Move the cursor up one line
|
UP = '' #: Move the cursor up one line
|
||||||
DOWN = '' #: Move the cursor down one line
|
DOWN = '' #: Move the cursor down one line
|
||||||
@ -329,7 +295,7 @@ class TerminalController:
|
|||||||
if s == '$$': return s
|
if s == '$$': return s
|
||||||
else: return getattr(self, s[2:-1])
|
else: return getattr(self, s[2:-1])
|
||||||
|
|
||||||
class ProgressBar:
|
class ProgressBar:
|
||||||
BAR = '%3d%% ${GREEN}[${BOLD}%s%s${NORMAL}${GREEN}]${NORMAL}\n'
|
BAR = '%3d%% ${GREEN}[${BOLD}%s%s${NORMAL}${GREEN}]${NORMAL}\n'
|
||||||
HEADER = '${BOLD}${CYAN}%s${NORMAL}\n\n'
|
HEADER = '${BOLD}${CYAN}%s${NORMAL}\n\n'
|
||||||
|
|
||||||
@ -364,7 +330,7 @@ class ProgressBar:
|
|||||||
self.term.UP + self.term.CLEAR_EOL)
|
self.term.UP + self.term.CLEAR_EOL)
|
||||||
self.cleared = 1
|
self.cleared = 1
|
||||||
|
|
||||||
def download_tarball():
|
def download_tarball():
|
||||||
try:
|
try:
|
||||||
pb = ProgressBar(TerminalController(sys.stdout), 'Downloading calibre...')
|
pb = ProgressBar(TerminalController(sys.stdout), 'Downloading calibre...')
|
||||||
except ValueError:
|
except ValueError:
|
||||||
@ -389,7 +355,7 @@ def download_tarball():
|
|||||||
f.seek(0)
|
f.seek(0)
|
||||||
return f
|
return f
|
||||||
|
|
||||||
def extract_tarball(tar, destdir):
|
def extract_tarball(tar, destdir):
|
||||||
print 'Extracting application files...'
|
print 'Extracting application files...'
|
||||||
if hasattr(tar, 'read'):
|
if hasattr(tar, 'read'):
|
||||||
try:
|
try:
|
||||||
@ -399,7 +365,7 @@ def extract_tarball(tar, destdir):
|
|||||||
else:
|
else:
|
||||||
tarfile.open(tar, 'r').extractall(destdir)
|
tarfile.open(tar, 'r').extractall(destdir)
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
defdir = '/opt/calibre'
|
defdir = '/opt/calibre'
|
||||||
destdir = raw_input('Enter the installation directory for calibre (Its contents will be deleted!)[%s]: '%defdir).strip()
|
destdir = raw_input('Enter the installation directory for calibre (Its contents will be deleted!)[%s]: '%defdir).strip()
|
||||||
if not destdir:
|
if not destdir:
|
||||||
@ -416,4 +382,5 @@ def main():
|
|||||||
pi = os.path.join(destdir, 'calibre_postinstall')
|
pi = os.path.join(destdir, 'calibre_postinstall')
|
||||||
subprocess.call(pi, shell=True)
|
subprocess.call(pi, shell=True)
|
||||||
return 0
|
return 0
|
||||||
'''
|
''')
|
||||||
|
|
||||||
|
BIN
src/calibre/trac/plugins/htdocs/images/exherbo_logo.png
Normal file
BIN
src/calibre/trac/plugins/htdocs/images/exherbo_logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 42 KiB |
@ -1,68 +0,0 @@
|
|||||||
<!DOCTYPE html
|
|
||||||
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
|
||||||
xmlns:py="http://genshi.edgewall.org/"
|
|
||||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
|
||||||
<xi:include href="layout.html" />
|
|
||||||
<head>
|
|
||||||
<title>$title</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div id="ctxtnav" class="nav"></div>
|
|
||||||
|
|
||||||
<div id="content" class="download">
|
|
||||||
<h1><img src="${href.chrome('/dl/images/%s_logo.png'%(distro.img,))}" valign="middle" width="60" height="80"/> $title</h1>
|
|
||||||
See the <a href="/wiki/Changelog">Changelog</a> for the changes in the latest version. <span py:if="not distro.is_generic"><b>Note:</b> As of 0.4.80 this install
|
|
||||||
will not work on 64-bit CPUs. Try the precompiled binary available <a href="/download_binary">here</a> instead.</span>
|
|
||||||
<div py:if="not distro.is_generic">
|
|
||||||
First verify that you have a sufficiently new installation of python
|
|
||||||
<pre class="wiki">python --version</pre> should return at least 2.5.1<br />
|
|
||||||
<p py:if="distro.os == 'gentoo'">
|
|
||||||
Make sure your python is compiled with the sqlite USE flag.
|
|
||||||
</p>
|
|
||||||
<br />
|
|
||||||
Run the following commands in a terminal <span py:if="distro.as_root">as root</span>
|
|
||||||
<pre class="wiki">${distro.command}</pre>
|
|
||||||
<div py:if="distro.manual">
|
|
||||||
<h2>Manual steps</h2>
|
|
||||||
<ul>
|
|
||||||
${distro.manual}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div py:if="distro.is_generic">
|
|
||||||
<ol>
|
|
||||||
<li>Make sure that your system has <code>python >= 2.5</code></li>
|
|
||||||
<li>Install the various dependencies listed below: Make sure that any python packages are installed into python2.5 (e.g. setuptools, python-imaging, PyQt4, etc). You will also have to install the development versions of the packages (these packages usually have -dev added to their names).</li>
|
|
||||||
<li>Run the following commands in a terminal:
|
|
||||||
<pre class="wiki">
|
|
||||||
wget -O- http://calibre.kovidgoyal.net/downloads/calibre-${version}.tar.gz | tar xvz
|
|
||||||
cd calibre*
|
|
||||||
python setup.py build && sudo python setup.py install
|
|
||||||
</pre></li>
|
|
||||||
</ol>
|
|
||||||
<h2>Dependencies</h2>
|
|
||||||
<table border="1" cellpadding="10">
|
|
||||||
<tr><th style="font-weight:bold">Name</th><th style="font-weight:bold">Minimum version</th></tr>
|
|
||||||
<tr py:for="dep in distro.DEPENDENCIES">
|
|
||||||
<td>${dep[0]}</td><td>${dep[1]}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>HAL</td><td>0.5.10</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
While you wait for the installation to complete, please consider donating to support the development of ${distro.app}.
|
|
||||||
<div>
|
|
||||||
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
|
|
||||||
<input type="hidden" name="cmd" value="_s-xclick" />
|
|
||||||
<input type="hidden" name="hosted_button_id" value="3029289" />
|
|
||||||
<input type="image" src="https://www.paypal.com/en_US/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="Donate to support calibre development" />
|
|
||||||
<img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1" />
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
155
src/calibre/trac/plugins/templates/linux.html
Normal file
155
src/calibre/trac/plugins/templates/linux.html
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
<!DOCTYPE html
|
||||||
|
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||||
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||||
|
xmlns:py="http://genshi.edgewall.org/"
|
||||||
|
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||||
|
<xi:include href="layout.html" />
|
||||||
|
<head>
|
||||||
|
<title>${title}</title>
|
||||||
|
<style type="text/css">
|
||||||
|
table tr th.distro_type {
|
||||||
|
font-family: monospace;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: larger;
|
||||||
|
vertical-align:middle;
|
||||||
|
text-align: center;
|
||||||
|
border-bottom: solid 1pt black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
margin-left:2em;
|
||||||
|
border-left: solid 1pt black;
|
||||||
|
}
|
||||||
|
|
||||||
|
table#install_info {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-width: 1pt;
|
||||||
|
border-style: solid;
|
||||||
|
table-layout: fixed;
|
||||||
|
width: 95%;
|
||||||
|
background: #F7F7F0 none repeat scroll 0 0;
|
||||||
|
}
|
||||||
|
table#dependencies {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-width: 0pt;
|
||||||
|
font-family:monospace;
|
||||||
|
}
|
||||||
|
.tdata {vertical-align: top;}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="ctxtnav" class="nav"></div>
|
||||||
|
<div id="content" class="download">
|
||||||
|
<h1>${title}</h1>
|
||||||
|
<p>
|
||||||
|
The latest release of ${app} is ${version}. See the
|
||||||
|
<a href="/wiki/Changelog">Changelog</a> for a list of new features.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
${app} is available in the software repositories of the following
|
||||||
|
linux distributions:
|
||||||
|
<table id="install_info">
|
||||||
|
<col width="150" /><col width="*" />
|
||||||
|
<tr>
|
||||||
|
<th class="left distro_type">Supported<br/>distributions</th>
|
||||||
|
<th class="right distro_type">Unsupported distributions</th>
|
||||||
|
</tr>
|
||||||
|
<tr class="tdata">
|
||||||
|
<td class="left" style="overflow-y:scroll">
|
||||||
|
<div py:for="distro in supported"
|
||||||
|
style="text-align:center;margin-top:2ex;">
|
||||||
|
<div>
|
||||||
|
<img width="64px" height="64px"
|
||||||
|
src="${distro.img}" alt="${distro.title}" />
|
||||||
|
</div>
|
||||||
|
${distro.title}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="right">
|
||||||
|
<div style="margin-left:2em">
|
||||||
|
<h3>Binary install</h3>
|
||||||
|
<p>
|
||||||
|
${app} has a binary installer that has been
|
||||||
|
tested on a number of distributions on both
|
||||||
|
32-bit and 64-bit x86 machines. To install,
|
||||||
|
copy paste the following command into a terminal
|
||||||
|
and press Enter:
|
||||||
|
</p>
|
||||||
|
<pre class="wiki">
|
||||||
|
sudo python -c "import urllib2; exec urllib2.urlopen('http://calibre.kovidgoyal.net/download_linux_binary_installer').read(); main()"
|
||||||
|
</pre>
|
||||||
|
<h4>Note</h4>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
When running the command line utilities,
|
||||||
|
they will segfault after completion. This can
|
||||||
|
be ignored.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
You must have help2man and xdg-utils installed
|
||||||
|
on your system before running the installer.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
On a 64bit machine, you must have 32-bit versions
|
||||||
|
of common libraries like X11, freetype, fontconfig,
|
||||||
|
expat and their varios dependencies installed.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<h3>Source install</h3>
|
||||||
|
<p>
|
||||||
|
<ol>
|
||||||
|
<li>
|
||||||
|
Make sure your system has python ≥ ${dependencies[0][1]}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Install the various dependencies listed below
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Run the following commands in a terminal:
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
<pre class="wiki">
|
||||||
|
wget -O- http://calibre.kovidgoyal.net/downloads/${app}-${version}.tar.gz | tar xvz
|
||||||
|
cd calibre*
|
||||||
|
python setup.py build && sudo python setup.py install
|
||||||
|
</pre>
|
||||||
|
Note that if your distribution does not have a
|
||||||
|
correctly compiled libunrar.so, ${app} will not
|
||||||
|
support rar files.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
While you wait for the download to complete, please consider
|
||||||
|
donating to support the development of ${app}.
|
||||||
|
</p>
|
||||||
|
<div>
|
||||||
|
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
|
||||||
|
<input type="hidden" name="cmd" value="_s-xclick" />
|
||||||
|
<input type="image" src="https://www.paypal.com/en_US/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!" />
|
||||||
|
<img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1" />
|
||||||
|
<input type="hidden" name="encrypted" value="-----BEGIN PKCS7-----MIIHbwYJKoZIhvcNAQcEoIIHYDCCB1wCAQExggEwMIIBLAIBADCBlDCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwDQYJKoZIhvcNAQEBBQAEgYBn7jneGiSLVO8rcDrBtOUXL+HftY+CiC47hTntwICio6qqpLKezIryyG8tKcjY58Rcocur/kDwljEutIafVG7XRA7BJL9eZdHAZsZdX04f4dApzkWwR9w6GQhj0kwmO2ZNE878UcgGZBve4qQKWM8bf2pMY7vJwCNoo6ozpIi3VTELMAkGBSsOAwIaBQAwgewGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQIBTALt7s1gJmAgcjEAwUMRYeIdIOE/yi0Y5vrVKBFxOUCbqTx/lu3Rk4EHsODZXLHT+BDA5WSWYO3AXfv2Lmlv1kJ7jWrjUVirYoQ5M4qdIhY9DtvPioIMMRoTJmYM9JKH8n2TWcjJ1XIzIuDP4zn8/Ya9hap3RHOrj2RBj89g7iSuFRsjoA0PYZgtWAKwR7g3LLpjRachn041JO55BEd3YWUgorNQeo3WEHgowLFfTWgFFePkm8OoWA1klWkYp4S07IhX5NaRc8OegkdshpkiIHGAKCCA4cwggODMIIC7KADAgECAgEAMA0GCSqGSIb3DQEBBQUAMIGOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQDFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbTAeFw0wNDAyMTMxMDEzMTVaFw0zNTAyMTMxMDEzMTVaMIGOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQDFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwUdO3fxEzEtcnI7ZKZL412XvZPugoni7i7D7prCe0AtaHTc97CYgm7NsAtJyxNLixmhLV8pyIEaiHXWAh8fPKW+R017+EmXrr9EaquPmsVvTywAAE1PMNOKqo2kl4Gxiz9zZqIajOm1fZGWcGS0f5JQ2kBqNbvbg2/Za+GJ/qwUCAwEAAaOB7jCB6zAdBgNVHQ4EFgQUlp98u8ZvF71ZP1LXChvsENZklGswgbsGA1UdIwSBszCBsIAUlp98u8ZvF71ZP1LXChvsENZklGuhgZSkgZEwgY4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFsIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAgV86VpqAWuXvX6Oro4qJ1tYVIT5DgWpE692Ag422H7yRIr/9j/iKG4Thia/Oflx4TdL+IFJBAyPK9v6zZNZtBgPBynXb048hsP16l2vi0k5Q2JKiPDsEfBhGI+HnxLXEaUWAcVfCsQFvd2A1sxRr67ip5y2wwBelUecP3AjJ+YcxggGaMIIBlgIBATCBlDCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwCQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTA4MDQzMDE1MzkyMlowIwYJKoZIhvcNAQkEMRYEFJSI9/zWx7TUlKPY7kLjnvzB1h6sMA0GCSqGSIb3DQEBAQUABIGAikZNCmQdkWPdfmYnGqOb1f65ViaK0zjHf50azvsigWQLlhHqJ3PgB+jEJH3JU9Pm9M4wgiK23Bg2oIGuIsAfQkYO9mw/HjtDtOQHqXyZZbrM32YGtNWUD4ynakLYnaz7OnPl40aTPD4iDApgsGcj1oMdmw7KA2E9J0l2J9iJXF4=-----END PKCS7-----" />
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<hr/>
|
||||||
|
<h3>Dependencies</h3>
|
||||||
|
${app} has the following dependencies (the listed version is the minimum version)
|
||||||
|
<br/><br/>
|
||||||
|
<table id="dependencies">
|
||||||
|
<tr>
|
||||||
|
<th class="distro_type" style="margin-right:2em">Package</th>
|
||||||
|
<th class="distro_type">Version</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="dependency" py:for="dep in dependencies">
|
||||||
|
<td style="margin-right:2em">${dep[0]}</td><td>${dep[1]}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -1,47 +0,0 @@
|
|||||||
<!DOCTYPE html
|
|
||||||
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
|
||||||
xmlns:py="http://genshi.edgewall.org/"
|
|
||||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
|
||||||
<xi:include href="layout.html" />
|
|
||||||
<head>
|
|
||||||
<title>Download $app for Linux</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div id="ctxtnav" class="nav"></div>
|
|
||||||
|
|
||||||
<div id="content" class="binary">
|
|
||||||
<h1>Download $app for Linux</h1>
|
|
||||||
<p>This binary package is compatible with most recent linux distributions running on Intel 32 bit CPUs. It needs testing on 64 bit CPUs. There have been reports of its working on some 64bit machines. </p>
|
|
||||||
<p>
|
|
||||||
<img width="50" height="50" style="border:1px red solid" src="${href.chrome('/dl/images/binary_logo.png')}" />
|
|
||||||
(Version: $version <a href="/wiki/Changelog">Changelog</a>)
|
|
||||||
</p>
|
|
||||||
<p>To install, copy paste the following command into a terminal and press Enter:
|
|
||||||
</p>
|
|
||||||
<pre class="wiki">sudo python -c "import urllib2; exec urllib2.urlopen('http://calibre.kovidgoyal.net/download_linux_binary_installer').read(); main()"</pre>
|
|
||||||
<p>
|
|
||||||
While you wait for the download to complete, please consider donating to support the development
|
|
||||||
of ${app}.</p>
|
|
||||||
<div>
|
|
||||||
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
|
|
||||||
<input type="hidden" name="cmd" value="_s-xclick" />
|
|
||||||
<input type="image" src="https://www.paypal.com/en_US/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!" />
|
|
||||||
<img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1" />
|
|
||||||
<input type="hidden" name="encrypted" value="-----BEGIN PKCS7-----MIIHbwYJKoZIhvcNAQcEoIIHYDCCB1wCAQExggEwMIIBLAIBADCBlDCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwDQYJKoZIhvcNAQEBBQAEgYBn7jneGiSLVO8rcDrBtOUXL+HftY+CiC47hTntwICio6qqpLKezIryyG8tKcjY58Rcocur/kDwljEutIafVG7XRA7BJL9eZdHAZsZdX04f4dApzkWwR9w6GQhj0kwmO2ZNE878UcgGZBve4qQKWM8bf2pMY7vJwCNoo6ozpIi3VTELMAkGBSsOAwIaBQAwgewGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQIBTALt7s1gJmAgcjEAwUMRYeIdIOE/yi0Y5vrVKBFxOUCbqTx/lu3Rk4EHsODZXLHT+BDA5WSWYO3AXfv2Lmlv1kJ7jWrjUVirYoQ5M4qdIhY9DtvPioIMMRoTJmYM9JKH8n2TWcjJ1XIzIuDP4zn8/Ya9hap3RHOrj2RBj89g7iSuFRsjoA0PYZgtWAKwR7g3LLpjRachn041JO55BEd3YWUgorNQeo3WEHgowLFfTWgFFePkm8OoWA1klWkYp4S07IhX5NaRc8OegkdshpkiIHGAKCCA4cwggODMIIC7KADAgECAgEAMA0GCSqGSIb3DQEBBQUAMIGOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQDFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbTAeFw0wNDAyMTMxMDEzMTVaFw0zNTAyMTMxMDEzMTVaMIGOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQDFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwUdO3fxEzEtcnI7ZKZL412XvZPugoni7i7D7prCe0AtaHTc97CYgm7NsAtJyxNLixmhLV8pyIEaiHXWAh8fPKW+R017+EmXrr9EaquPmsVvTywAAE1PMNOKqo2kl4Gxiz9zZqIajOm1fZGWcGS0f5JQ2kBqNbvbg2/Za+GJ/qwUCAwEAAaOB7jCB6zAdBgNVHQ4EFgQUlp98u8ZvF71ZP1LXChvsENZklGswgbsGA1UdIwSBszCBsIAUlp98u8ZvF71ZP1LXChvsENZklGuhgZSkgZEwgY4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFsIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAgV86VpqAWuXvX6Oro4qJ1tYVIT5DgWpE692Ag422H7yRIr/9j/iKG4Thia/Oflx4TdL+IFJBAyPK9v6zZNZtBgPBynXb048hsP16l2vi0k5Q2JKiPDsEfBhGI+HnxLXEaUWAcVfCsQFvd2A1sxRr67ip5y2wwBelUecP3AjJ+YcxggGaMIIBlgIBATCBlDCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwCQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTA4MDQzMDE1MzkyMlowIwYJKoZIhvcNAQkEMRYEFJSI9/zWx7TUlKPY7kLjnvzB1h6sMA0GCSqGSIb3DQEBAQUABIGAikZNCmQdkWPdfmYnGqOb1f65ViaK0zjHf50azvsigWQLlhHqJ3PgB+jEJH3JU9Pm9M4wgiK23Bg2oIGuIsAfQkYO9mw/HjtDtOQHqXyZZbrM32YGtNWUD4ynakLYnaz7OnPl40aTPD4iDApgsGcj1oMdmw7KA2E9J0l2J9iJXF4=-----END PKCS7-----" />
|
|
||||||
</form>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<h2>Note</h2>
|
|
||||||
<div class="note">
|
|
||||||
<ul>
|
|
||||||
<li>This installer is very new and has only been tested on a couple of systems, so if you encounter
|
|
||||||
problems, please report them.</li>
|
|
||||||
<li>You shoud have help2man and xdg-utils installed on your system.</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
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
@ -6,7 +6,7 @@ __docformat__ = 'restructuredtext en'
|
|||||||
'''
|
'''
|
||||||
Manage application-wide preferences.
|
Manage application-wide preferences.
|
||||||
'''
|
'''
|
||||||
import os, re, cPickle, textwrap
|
import os, re, cPickle, textwrap, traceback
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from optparse import OptionParser as _OptionParser
|
from optparse import OptionParser as _OptionParser
|
||||||
@ -314,7 +314,12 @@ class OptionSet(object):
|
|||||||
if not isinstance(src, unicode):
|
if not isinstance(src, unicode):
|
||||||
src = src.decode('utf-8')
|
src = src.decode('utf-8')
|
||||||
if src is not None:
|
if src is not None:
|
||||||
|
try:
|
||||||
exec src in options
|
exec src in options
|
||||||
|
except:
|
||||||
|
print 'Failed to parse options string:'
|
||||||
|
print repr(src)
|
||||||
|
traceback.print_exc()
|
||||||
opts = OptionValues()
|
opts = OptionValues()
|
||||||
for pref in self.preferences:
|
for pref in self.preferences:
|
||||||
val = options.get(pref.name, pref.default)
|
val = options.get(pref.name, pref.default)
|
||||||
@ -539,7 +544,7 @@ def _prefs():
|
|||||||
help=_('Path to directory in which your library of books is stored'))
|
help=_('Path to directory in which your library of books is stored'))
|
||||||
c.add_opt('language', default=None,
|
c.add_opt('language', default=None,
|
||||||
help=_('The language in which to display the user interface'))
|
help=_('The language in which to display the user interface'))
|
||||||
c.add_opt('output_format', default='LRF',
|
c.add_opt('output_format', default='EPUB',
|
||||||
help=_('The default output format for ebook conversions.'))
|
help=_('The default output format for ebook conversions.'))
|
||||||
c.add_opt('read_file_metadata', default=True,
|
c.add_opt('read_file_metadata', default=True,
|
||||||
help=_('Read metadata from files'))
|
help=_('Read metadata from files'))
|
||||||
|
@ -190,7 +190,7 @@ class BasicNewsRecipe(object, LoggingInterface):
|
|||||||
#: For the format for specifying a tag see :attr:`BasicNewsRecipe.remove_tags`.
|
#: For the format for specifying a tag see :attr:`BasicNewsRecipe.remove_tags`.
|
||||||
#: For example::
|
#: For example::
|
||||||
#:
|
#:
|
||||||
#: remove_tags_before = [dict(id='content')]
|
#: remove_tags_before = dict(id='content')
|
||||||
#:
|
#:
|
||||||
#: will remove all
|
#: will remove all
|
||||||
#: tags before the first element with `id="content"`.
|
#: tags before the first element with `id="content"`.
|
||||||
|
@ -28,7 +28,9 @@ recipe_modules = ['recipe_' + r for r in (
|
|||||||
'la_tercera', 'el_mercurio_chile', 'la_cuarta', 'lanacion_chile', 'la_segunda',
|
'la_tercera', 'el_mercurio_chile', 'la_cuarta', 'lanacion_chile', 'la_segunda',
|
||||||
'jb_online', 'estadao', 'o_globo', 'vijesti', 'elmundo', 'the_oz',
|
'jb_online', 'estadao', 'o_globo', 'vijesti', 'elmundo', 'the_oz',
|
||||||
'honoluluadvertiser', 'starbulletin', 'exiled', 'indy_star', 'dna',
|
'honoluluadvertiser', 'starbulletin', 'exiled', 'indy_star', 'dna',
|
||||||
'pobjeda',
|
'pobjeda', 'chicago_breaking_news', 'glasgow_herald', 'linuxdevices',
|
||||||
|
'hindu', 'cincinnati_enquirer', 'physics_world', 'pressonline',
|
||||||
|
'la_republica', 'physics_today',
|
||||||
)]
|
)]
|
||||||
|
|
||||||
import re, imp, inspect, time, os
|
import re, imp, inspect, time, os
|
||||||
|
@ -1,50 +1,77 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
__license__ = 'GPL v3'
|
|
||||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
|
||||||
__docformat__ = 'restructuredtext en'
|
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
|
||||||
'''
|
'''
|
||||||
arstechnica.com
|
arstechnica.com
|
||||||
'''
|
'''
|
||||||
|
|
||||||
from calibre.web.feeds.news import BasicNewsRecipe
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
class ArsTechnica(BasicNewsRecipe):
|
class ArsTechnica2(BasicNewsRecipe):
|
||||||
title = 'Ars Technica'
|
title = u'Ars Technica'
|
||||||
description = 'The art of technology'
|
|
||||||
oldest_article = 7
|
|
||||||
language = _('English')
|
language = _('English')
|
||||||
no_stylesheets = True
|
__author__ = 'Darko Miletic'
|
||||||
__author__ = 'Michael Warner'
|
description = 'The art of technology'
|
||||||
|
publisher = 'Ars Technica'
|
||||||
|
category = 'news, IT, technology'
|
||||||
|
oldest_article = 2
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
extra_css = """
|
no_stylesheets = True
|
||||||
body {
|
encoding = 'utf8'
|
||||||
font: normal 19px/180% Times, serif;
|
remove_javascript = True
|
||||||
}
|
use_embedded_content = False
|
||||||
|
|
||||||
|
html2lrf_options = [
|
||||||
|
'--comment', description
|
||||||
|
, '--category', category
|
||||||
|
, '--publisher', publisher
|
||||||
|
]
|
||||||
|
|
||||||
|
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"'
|
||||||
|
|
||||||
|
keep_only_tags = [dict(name='div', attrs={'id':['news-item-info','news-item']})]
|
||||||
|
|
||||||
h1, h2, h3, h4 {
|
|
||||||
font: bold 28px/100% Verdana, Arial, Helvetica, sans-serif;
|
|
||||||
margin-top: 19px
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
remove_tags = [
|
remove_tags = [
|
||||||
dict(id="Masthead"),
|
dict(name=['object','link','embed'])
|
||||||
dict(id="Banner"),
|
,dict(name='div', attrs={'class':'related-stories'})
|
||||||
dict(id="Nav"),
|
]
|
||||||
dict(name='div', attrs={'class':'ContentHeader'}),
|
|
||||||
dict(name='img'),
|
|
||||||
dict(name='div', attrs={'class':'Inset RelatedStories'}),
|
feeds = [
|
||||||
dict(name='div', attrs={'class':'Tags'}),
|
(u'Infinite Loop (Apple content)' , u'http://feeds.arstechnica.com/arstechnica/apple/' )
|
||||||
dict(name='div', attrs={'class':'PostOptions flat'}),
|
,(u'Opposable Thumbs (Gaming content)' , u'http://feeds.arstechnica.com/arstechnica/gaming/' )
|
||||||
dict(name='div', attrs={'class':'ContentFooter'}),
|
,(u'Gear and Gadgets' , u'http://feeds.arstechnica.com/arstechnica/gadgets/' )
|
||||||
dict(id="Sidebar"),
|
,(u'Chipster (Hardware content)' , u'http://feeds.arstechnica.com/arstechnica/hardware/' )
|
||||||
dict(id="LatestPosts"),
|
,(u'Uptime (IT content)' , u'http://feeds.arstechnica.com/arstechnica/business/' )
|
||||||
dict(id="Footer")]
|
,(u'Open Ended (Open Source content)' , u'http://feeds.arstechnica.com/arstechnica/open-source/')
|
||||||
feeds = [(u'News and Features', u'http://feeds.arstechnica.com/arstechnica/BAaf'),
|
,(u'One Microsoft Way' , u'http://feeds.arstechnica.com/arstechnica/microsoft/' )
|
||||||
(u'Nobel Intent (Science)', u'http://arstechnica.com/journals/science.rssx'),
|
,(u'Nobel Intent (Science content)' , u'http://feeds.arstechnica.com/arstechnica/science/' )
|
||||||
(u'Infinite Loop (Apple)', u'http://arstechnica.com/journals/apple.rssx'),
|
,(u'Law & Disorder (Tech policy content)' , u'http://feeds.arstechnica.com/arstechnica/tech-policy/')
|
||||||
(u'M-Dollar (Microsoft)', u'http://arstechnica.com/journals/microsoft.rssx'),
|
]
|
||||||
(u'Open Ended (Linux)', u'http://arstechnica.com/journals/linux.rssx'),
|
|
||||||
(u'Opposable Thumbs (Games)', u'http://arstechnica.com/journals/thumbs.rssx'),
|
def append_page(self, soup, appendtag, position):
|
||||||
(u'Kit (Hardware)', u'http://arstechnica.com/journals/hardware.rssx'),
|
pager = soup.find('div',attrs={'id':'pager'})
|
||||||
(u'Journals', u'http://arstechnica.com/journals.rssx')]
|
if pager:
|
||||||
|
for atag in pager.findAll('a',href=True):
|
||||||
|
str = self.tag_to_string(atag)
|
||||||
|
if str.startswith('Next'):
|
||||||
|
soup2 = self.index_to_soup(atag['href'])
|
||||||
|
texttag = soup2.find('div', attrs={'class':'news-item-text'})
|
||||||
|
for it in texttag.findAll(style=True):
|
||||||
|
del it['style']
|
||||||
|
newpos = len(texttag.contents)
|
||||||
|
self.append_page(soup2,texttag,newpos)
|
||||||
|
texttag.extract()
|
||||||
|
pager.extract()
|
||||||
|
appendtag.insert(position,texttag)
|
||||||
|
|
||||||
|
|
||||||
|
def preprocess_html(self, soup):
|
||||||
|
ftag = soup.find('div', attrs={'class':'news-item-byline'})
|
||||||
|
if ftag:
|
||||||
|
ftag.insert(4,'<br /><br />')
|
||||||
|
for item in soup.findAll(style=True):
|
||||||
|
del item['style']
|
||||||
|
self.append_page(soup, soup.body, 3)
|
||||||
|
return soup
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>'
|
__copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
|
||||||
'''
|
'''
|
||||||
b92.net
|
b92.net
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from calibre.web.feeds.news import BasicNewsRecipe
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
class B92(BasicNewsRecipe):
|
class B92(BasicNewsRecipe):
|
||||||
@ -22,19 +21,22 @@ class B92(BasicNewsRecipe):
|
|||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
cover_url = 'http://static.b92.net/images/fp/logo.gif'
|
cover_url = 'http://static.b92.net/images/fp/logo.gif'
|
||||||
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "monospace1";src:url(res:///opt/sony/ebook/FONT/tt0419m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{text-align: left; font-family: serif1, serif} .article_date{font-family: monospace1, monospace} .article_description{font-family: sans1, sans-serif} .navbar{font-family: monospace1, monospace}'
|
language = _('Serbian')
|
||||||
|
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{font-family: serif1, serif} .article_description{font-family: sans1, sans-serif}'
|
||||||
|
|
||||||
|
html2lrf_options = [
|
||||||
|
'--comment' , description
|
||||||
|
, '--category' , category
|
||||||
|
, '--publisher', publisher
|
||||||
|
, '--ignore-tables'
|
||||||
|
]
|
||||||
|
|
||||||
|
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\nlinearize_tables=True'
|
||||||
|
|
||||||
keep_only_tags = [ dict(name='div', attrs={'class':'sama_vest'}) ]
|
keep_only_tags = [ dict(name='div', attrs={'class':'sama_vest'}) ]
|
||||||
|
|
||||||
html2lrf_options = [
|
|
||||||
'--comment', description
|
|
||||||
, '--category', category
|
|
||||||
, '--publisher', publisher
|
|
||||||
]
|
|
||||||
|
|
||||||
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"'
|
|
||||||
|
|
||||||
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
|
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
|
||||||
|
|
||||||
feeds = [
|
feeds = [
|
||||||
(u'Vesti', u'http://www.b92.net/info/rss/vesti.xml')
|
(u'Vesti', u'http://www.b92.net/info/rss/vesti.xml')
|
||||||
,(u'Biz' , u'http://www.b92.net/info/rss/biz.xml' )
|
,(u'Biz' , u'http://www.b92.net/info/rss/biz.xml' )
|
||||||
@ -54,9 +56,10 @@ class B92(BasicNewsRecipe):
|
|||||||
return nurl
|
return nurl
|
||||||
|
|
||||||
def preprocess_html(self, soup):
|
def preprocess_html(self, soup):
|
||||||
soup.html['xml:lang'] = 'sr-Latn'
|
lng = 'sr-Latn-RS'
|
||||||
soup.html['lang'] = 'sr-Latn'
|
soup.html['xml:lang'] = lng
|
||||||
mtag = '<meta http-equiv="Content-Language" content="sr-Latn"/>'
|
soup.html['lang'] = lng
|
||||||
|
mtag = '<meta http-equiv="Content-Language" content="sr-Latn-RS"/>'
|
||||||
soup.head.insert(0,mtag)
|
soup.head.insert(0,mtag)
|
||||||
for item in soup.findAll(style=True):
|
for item in soup.findAll(style=True):
|
||||||
del item['style']
|
del item['style']
|
||||||
@ -64,4 +67,3 @@ class B92(BasicNewsRecipe):
|
|||||||
del item['align']
|
del item['align']
|
||||||
item.insert(0,'<br /><br />')
|
item.insert(0,'<br /><br />')
|
||||||
return soup
|
return soup
|
||||||
language = _('Serbian')
|
|
@ -1,13 +1,12 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>'
|
__copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
|
||||||
'''
|
'''
|
||||||
blic.rs
|
blic.rs
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from calibre.web.feeds.news import BasicNewsRecipe
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
class Blic(BasicNewsRecipe):
|
class Blic(BasicNewsRecipe):
|
||||||
@ -21,15 +20,17 @@ class Blic(BasicNewsRecipe):
|
|||||||
remove_javascript = True
|
remove_javascript = True
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "monospace1";src:url(res:///opt/sony/ebook/FONT/tt0419m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{text-align: left; font-family: serif1, serif} .article_date{font-family: monospace1, monospace} .article_description{font-family: sans1, sans-serif} .navbar{font-family: monospace1, monospace}'
|
language = _('Serbian')
|
||||||
|
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{font-family: serif1, serif} .article_description{font-family: sans1, sans-serif}'
|
||||||
|
|
||||||
html2lrf_options = [
|
html2lrf_options = [
|
||||||
'--comment', description
|
'--comment' , description
|
||||||
, '--category', category
|
, '--category' , category
|
||||||
, '--publisher', publisher
|
, '--publisher', publisher
|
||||||
|
, '--ignore-tables'
|
||||||
]
|
]
|
||||||
|
|
||||||
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"'
|
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\nlinearize_tables=True'
|
||||||
|
|
||||||
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
|
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
|
||||||
|
|
||||||
@ -44,10 +45,9 @@ class Blic(BasicNewsRecipe):
|
|||||||
return u'http://www.blic.rs/_print.php?' + rest_url
|
return u'http://www.blic.rs/_print.php?' + rest_url
|
||||||
|
|
||||||
def preprocess_html(self, soup):
|
def preprocess_html(self, soup):
|
||||||
mtag = '<meta http-equiv="Content-Language" content="sr-Latn"/>'
|
mtag = '<meta http-equiv="Content-Language" content="sr-Latn-RS"/>'
|
||||||
soup.head.insert(0,mtag)
|
soup.head.insert(0,mtag)
|
||||||
for item in soup.findAll(style=True):
|
for item in soup.findAll(style=True):
|
||||||
del item['style']
|
del item['style']
|
||||||
return soup
|
return soup
|
||||||
|
|
||||||
language = _('Serbian')
|
|
@ -0,0 +1,45 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2009, Darko Miletic <darko.miletic at gmail.com>'
|
||||||
|
'''
|
||||||
|
chicagobreakingnews.com
|
||||||
|
'''
|
||||||
|
|
||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
|
class ChicagoBreakingNews(BasicNewsRecipe):
|
||||||
|
title = 'Chicago Breaking News'
|
||||||
|
__author__ = 'Darko Miletic'
|
||||||
|
description = 'Breaking News from Chicago'
|
||||||
|
oldest_article = 1
|
||||||
|
max_articles_per_feed = 100
|
||||||
|
no_stylesheets = True
|
||||||
|
use_embedded_content = True
|
||||||
|
publisher = 'Chicago Breaking News'
|
||||||
|
category = 'news, politics, USA, Chicago'
|
||||||
|
encoding = 'utf8'
|
||||||
|
language = _('English')
|
||||||
|
|
||||||
|
html2lrf_options = [
|
||||||
|
'--comment', description
|
||||||
|
, '--category', category
|
||||||
|
, '--publisher', publisher
|
||||||
|
]
|
||||||
|
|
||||||
|
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"'
|
||||||
|
|
||||||
|
feeds = [(u'Breaking news', u'http://feeds2.feedburner.com/ChicagoBreakingNews/')]
|
||||||
|
|
||||||
|
def preprocess_html(self, soup):
|
||||||
|
links = soup.findAll('a')
|
||||||
|
for item in soup.findAll('a'):
|
||||||
|
if item['href'].find('http://feedads.googleadservices.com') > -1:
|
||||||
|
item.extract()
|
||||||
|
for item in soup.findAll(style=True):
|
||||||
|
del item['style']
|
||||||
|
for item in soup.findAll(color=True):
|
||||||
|
del item['color']
|
||||||
|
for item in soup.findAll(size=True):
|
||||||
|
del item['size']
|
||||||
|
return soup
|
34
src/calibre/web/feeds/recipes/recipe_cincinnati_enquirer.py
Normal file
34
src/calibre/web/feeds/recipes/recipe_cincinnati_enquirer.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2009 Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
|
|
||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
|
class AdvancedUserRecipe1234144423(BasicNewsRecipe):
|
||||||
|
title = u'Cincinnati Enquirer'
|
||||||
|
oldest_article = 7
|
||||||
|
language = _('English')
|
||||||
|
__author__ = 'Joseph Kitzmiller'
|
||||||
|
max_articles_per_feed = 100
|
||||||
|
no_stylesheets = True
|
||||||
|
use_embedded_content = False
|
||||||
|
remove_javascript = True
|
||||||
|
encoding = 'cp1252'
|
||||||
|
extra_css = ' p {font-size: medium; font-weight: normal;} '
|
||||||
|
|
||||||
|
keep_only_tags = [dict(name='div', attrs={'class':'padding'})]
|
||||||
|
|
||||||
|
remove_tags = [
|
||||||
|
dict(name=['object','link','table','embed'])
|
||||||
|
,dict(name='div',attrs={'id':'pluckcomments'})
|
||||||
|
,dict(name='div',attrs={'class':'articleflex-container'})
|
||||||
|
]
|
||||||
|
|
||||||
|
feeds = [(u'Cincinnati Enquirer', u'http://rss.cincinnati.com/apps/pbcs.dll/section?category=rssenq01&mime=xml')]
|
||||||
|
|
||||||
|
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']
|
||||||
|
return soup
|
@ -1,12 +1,11 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>'
|
__copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
|
||||||
'''
|
'''
|
||||||
danas.rs
|
danas.rs
|
||||||
'''
|
'''
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from calibre.web.feeds.news import BasicNewsRecipe
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
class Danas(BasicNewsRecipe):
|
class Danas(BasicNewsRecipe):
|
||||||
@ -20,15 +19,17 @@ class Danas(BasicNewsRecipe):
|
|||||||
no_stylesheets = False
|
no_stylesheets = False
|
||||||
remove_javascript = True
|
remove_javascript = True
|
||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "monospace1";src:url(res:///opt/sony/ebook/FONT/tt0419m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{text-align: left; font-family: serif1, serif} .article_date{font-family: monospace1, monospace} .article_description{font-family: sans1, sans-serif} .navbar{font-family: monospace1, monospace}'
|
language = _('Serbian')
|
||||||
|
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{font-family: serif1, serif} .article_description{font-family: sans1, sans-serif}'
|
||||||
|
|
||||||
html2lrf_options = [
|
html2lrf_options = [
|
||||||
'--comment', description
|
'--comment' , description
|
||||||
, '--category', category
|
, '--category' , category
|
||||||
, '--publisher', publisher
|
, '--publisher', publisher
|
||||||
|
, '--ignore-tables'
|
||||||
]
|
]
|
||||||
|
|
||||||
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"'
|
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\nlinearize_tables=True'
|
||||||
|
|
||||||
|
|
||||||
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
|
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
|
||||||
@ -43,9 +44,8 @@ class Danas(BasicNewsRecipe):
|
|||||||
feeds = [ (u'Vesti', u'http://www.danas.rs/rss/rss.asp')]
|
feeds = [ (u'Vesti', u'http://www.danas.rs/rss/rss.asp')]
|
||||||
|
|
||||||
def preprocess_html(self, soup):
|
def preprocess_html(self, soup):
|
||||||
mtag = '<meta http-equiv="Content-Language" content="sr-Latn"/>'
|
mtag = '<meta http-equiv="Content-Language" content="sr-Latn-RS"/>'
|
||||||
soup.head.insert(0,mtag)
|
soup.head.insert(0,mtag)
|
||||||
for item in soup.findAll(style=True):
|
for item in soup.findAll(style=True):
|
||||||
del item['style']
|
del item['style']
|
||||||
return soup
|
return soup
|
||||||
language = _('Serbian')
|
|
@ -60,8 +60,11 @@ class Economist(BasicNewsRecipe):
|
|||||||
continue
|
continue
|
||||||
a = tag.find('a', href=True)
|
a = tag.find('a', href=True)
|
||||||
if a is not None:
|
if a is not None:
|
||||||
|
url=a['href'].replace('displaystory', 'PrinterFriendly')
|
||||||
|
if url.startswith('/'):
|
||||||
|
url = 'http://www.economist.com' + url
|
||||||
article = dict(title=text,
|
article = dict(title=text,
|
||||||
url='http://www.economist.com'+a['href'].replace('displaystory', 'PrinterFriendly'),
|
url = url,
|
||||||
description='', content='', date='')
|
description='', content='', date='')
|
||||||
feeds[key].append(article)
|
feeds[key].append(article)
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ __copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
|
|||||||
'''
|
'''
|
||||||
elargentino.com
|
elargentino.com
|
||||||
'''
|
'''
|
||||||
|
|
||||||
from calibre.web.feeds.news import BasicNewsRecipe
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
class ElArgentino(BasicNewsRecipe):
|
class ElArgentino(BasicNewsRecipe):
|
||||||
@ -21,6 +20,7 @@ class ElArgentino(BasicNewsRecipe):
|
|||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
encoding = 'utf8'
|
encoding = 'utf8'
|
||||||
cover_url = 'http://www.elargentino.com/TemplateWeb/MediosFooter/tapa_elargentino.png'
|
cover_url = 'http://www.elargentino.com/TemplateWeb/MediosFooter/tapa_elargentino.png'
|
||||||
|
language = _('Spanish')
|
||||||
|
|
||||||
html2lrf_options = [
|
html2lrf_options = [
|
||||||
'--comment', description
|
'--comment', description
|
||||||
@ -59,5 +59,3 @@ class ElArgentino(BasicNewsRecipe):
|
|||||||
for item in soup.findAll(style=True):
|
for item in soup.findAll(style=True):
|
||||||
del item['style']
|
del item['style']
|
||||||
return soup
|
return soup
|
||||||
|
|
||||||
language = _('Spanish')
|
|
34
src/calibre/web/feeds/recipes/recipe_glasgow_herald.py
Normal file
34
src/calibre/web/feeds/recipes/recipe_glasgow_herald.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import re
|
||||||
|
|
||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
|
class GlasgowHerald(BasicNewsRecipe):
|
||||||
|
title = u'Glasgow Herald'
|
||||||
|
oldest_article = 1
|
||||||
|
max_articles_per_feed = 100
|
||||||
|
no_stylesheets = True
|
||||||
|
language = _('English')
|
||||||
|
__author__ = 'McCande'
|
||||||
|
|
||||||
|
preprocess_regexps = [ (re.compile(i[0], re.IGNORECASE | re.DOTALL), i[1]) for i in
|
||||||
|
[
|
||||||
|
(r'<center><h3>', lambda match : '<h3>'),
|
||||||
|
(r'Click here to comment on this story...', lambda match : ''),
|
||||||
|
(r'<h3>Related links</h3>.*?</head>', lambda match : '</head>'),
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
feeds = [
|
||||||
|
(u'News', u'http://www.theherald.co.uk/news/news/rss.xml'),
|
||||||
|
(u'Politics', u'http://www.theherald.co.uk/politics/news/rss.xml'),
|
||||||
|
(u'Features', u'http://www.theherald.co.uk/features/features/rss.xml'),
|
||||||
|
(u'Business', u'http://www.theherald.co.uk/business/news/rss.xml')]
|
||||||
|
|
||||||
|
def print_version(self, url):
|
||||||
|
(beginning,end)=url.split(".var.")
|
||||||
|
num=end[0:7]
|
||||||
|
main="http://www.theherald.co.uk/misc/print.php?artid="+num
|
||||||
|
return main
|
@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>'
|
__copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
|
||||||
'''
|
'''
|
||||||
granma.cubaweb.cu
|
granma.cubaweb.cu
|
||||||
'''
|
'''
|
||||||
@ -21,19 +21,22 @@ class Granma(BasicNewsRecipe):
|
|||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
encoding = 'cp1252'
|
encoding = 'cp1252'
|
||||||
cover_url = 'http://www.granma.cubaweb.cu/imagenes/granweb229d.jpg'
|
cover_url = 'http://www.granma.cubaweb.cu/imagenes/granweb229d.jpg'
|
||||||
|
language = _('Spanish')
|
||||||
remove_javascript = True
|
remove_javascript = True
|
||||||
|
|
||||||
html2lrf_options = [
|
html2lrf_options = [
|
||||||
'--comment', description
|
'--comment' , description
|
||||||
, '--category', category
|
, '--category' , category
|
||||||
, '--publisher', publisher
|
, '--publisher', publisher
|
||||||
, '--ignore-tables'
|
, '--ignore-tables'
|
||||||
]
|
]
|
||||||
|
|
||||||
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"'
|
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\nlinearize_tables=True'
|
||||||
|
|
||||||
keep_only_tags = [dict(name='table', attrs={'height':'466'})]
|
keep_only_tags = [dict(name='table', attrs={'height':'466'})]
|
||||||
|
|
||||||
|
remove_tags = [dict(name=['embed','link','object'])]
|
||||||
|
|
||||||
feeds = [(u'Noticias', u'http://www.granma.cubaweb.cu/noticias.xml' )]
|
feeds = [(u'Noticias', u'http://www.granma.cubaweb.cu/noticias.xml' )]
|
||||||
|
|
||||||
|
|
||||||
@ -49,4 +52,3 @@ class Granma(BasicNewsRecipe):
|
|||||||
del item['style']
|
del item['style']
|
||||||
return soup
|
return soup
|
||||||
|
|
||||||
language = _('Spanish')
|
|
@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>'
|
__copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
|
||||||
'''
|
'''
|
||||||
harpers.org
|
harpers.org
|
||||||
'''
|
'''
|
||||||
@ -12,18 +12,29 @@ class Harpers(BasicNewsRecipe):
|
|||||||
__author__ = u'Darko Miletic'
|
__author__ = u'Darko Miletic'
|
||||||
language = _('English')
|
language = _('English')
|
||||||
description = u"Harper's Magazine: Founded June 1850."
|
description = u"Harper's Magazine: Founded June 1850."
|
||||||
|
publisher = "Harper's Magazine "
|
||||||
|
category = 'news, politics, USA'
|
||||||
oldest_article = 30
|
oldest_article = 30
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
timefmt = ' [%A, %d %B, %Y]'
|
remove_javascript = True
|
||||||
|
|
||||||
|
html2lrf_options = [
|
||||||
|
'--comment', description
|
||||||
|
, '--category', category
|
||||||
|
, '--publisher', publisher
|
||||||
|
]
|
||||||
|
|
||||||
|
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\noverride_css=" p {text-indent: 0em; margin-top: 0em; margin-bottom: 0.5em} img {margin-top: 0em; margin-bottom: 0.4em}"'
|
||||||
|
|
||||||
|
|
||||||
keep_only_tags = [ dict(name='div', attrs={'id':'cached'}) ]
|
keep_only_tags = [ dict(name='div', attrs={'id':'cached'}) ]
|
||||||
remove_tags = [
|
remove_tags = [
|
||||||
dict(name='table', attrs={'class':'rcnt'})
|
dict(name='table', attrs={'class':'rcnt'})
|
||||||
,dict(name='table', attrs={'class':'rcnt topline'})
|
,dict(name='table', attrs={'class':'rcnt topline'})
|
||||||
|
,dict(name=['link','object','embed'])
|
||||||
]
|
]
|
||||||
|
|
||||||
feeds = [
|
feeds = [(u"Harper's Magazine", u'http://www.harpers.org/rss/frontpage-rss20.xml')]
|
||||||
(u"Harper's Magazine", u'http://www.harpers.org/rss/frontpage-rss20.xml')
|
|
||||||
]
|
|
||||||
|
@ -24,6 +24,7 @@ class Harpers_full(BasicNewsRecipe):
|
|||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
simultaneous_downloads = 1
|
simultaneous_downloads = 1
|
||||||
delay = 1
|
delay = 1
|
||||||
|
language = _('English')
|
||||||
needs_subscription = True
|
needs_subscription = True
|
||||||
INDEX = strftime('http://www.harpers.org/archive/%Y/%m')
|
INDEX = strftime('http://www.harpers.org/archive/%Y/%m')
|
||||||
LOGIN = 'http://www.harpers.org'
|
LOGIN = 'http://www.harpers.org'
|
||||||
@ -36,7 +37,7 @@ class Harpers_full(BasicNewsRecipe):
|
|||||||
, '--publisher', publisher
|
, '--publisher', publisher
|
||||||
]
|
]
|
||||||
|
|
||||||
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"'
|
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\noverride_css=" p {text-indent: 0em; margin-top: 0em; margin-bottom: 0.5em} img {margin-top: 0em; margin-bottom: 0.4em}"'
|
||||||
|
|
||||||
keep_only_tags = [ dict(name='div', attrs={'id':'cached'}) ]
|
keep_only_tags = [ dict(name='div', attrs={'id':'cached'}) ]
|
||||||
remove_tags = [
|
remove_tags = [
|
||||||
@ -72,9 +73,3 @@ class Harpers_full(BasicNewsRecipe):
|
|||||||
})
|
})
|
||||||
return [(soup.head.title.string, articles)]
|
return [(soup.head.title.string, articles)]
|
||||||
|
|
||||||
def preprocess_html(self, soup):
|
|
||||||
for item in soup.findAll(style=True):
|
|
||||||
del item['style']
|
|
||||||
return soup
|
|
||||||
|
|
||||||
language = _('English')
|
|
47
src/calibre/web/feeds/recipes/recipe_hindu.py
Normal file
47
src/calibre/web/feeds/recipes/recipe_hindu.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
from __future__ import with_statement
|
||||||
|
__license__ = 'GPL 3'
|
||||||
|
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
|
|
||||||
|
import re
|
||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
|
class TheHindu(BasicNewsRecipe):
|
||||||
|
title = u'The Hindu'
|
||||||
|
language = _('English')
|
||||||
|
oldest_article = 7
|
||||||
|
__author__ = _('Kovid Goyal')
|
||||||
|
max_articles_per_feed = 100
|
||||||
|
|
||||||
|
remove_tags_before = {'name':'font', 'class':'storyhead'}
|
||||||
|
preprocess_regexps = [
|
||||||
|
(re.compile(r'<!-- story ends -->.*', re.DOTALL),
|
||||||
|
lambda match: '</body></html>'),
|
||||||
|
]
|
||||||
|
|
||||||
|
feeds = [
|
||||||
|
(u'Main - Font Page', u'http://www.hindu.com/rss/01hdline.xml'),
|
||||||
|
(u'Main - National', u'http://www.hindu.com/rss/02hdline.xml'),
|
||||||
|
(u'Main - International', u'http://www.hindu.com/rss/03hdline.xml'),
|
||||||
|
(u'Main - Opinion', u'http://www.hindu.com/rss/05hdline.xml'),
|
||||||
|
(u'Main - Business', u'http://www.hindu.com/rss/06hdline.xml'),
|
||||||
|
(u'Main - Sport', u'http://www.hindu.com/rss/07hdline.xml'),
|
||||||
|
(u'Main - Weather / Religion / Crossword / Cartoon',
|
||||||
|
u'http://www.hindu.com/rss/10hdline.xml'),
|
||||||
|
(u'Main - Engagements', u'http://www.hindu.com/rss/26hdline.xml'),
|
||||||
|
(u'Supplement - Literary Review',
|
||||||
|
u'http://www.hindu.com/rss/lrhdline.xml'),
|
||||||
|
(u'Supplement - Sunday Magazine',
|
||||||
|
u'http://www.hindu.com/rss/maghdline.xml'),
|
||||||
|
(u'Supplement - Open Page', u'http://www.hindu.com/rss/ophdline.xml'),
|
||||||
|
(u'Supplement - Business Review',
|
||||||
|
u'http://www.hindu.com/rss/bizhdline.xml'),
|
||||||
|
(u'Supplement - Book Review',
|
||||||
|
u'http://www.hindu.com/rss/brhdline.xml'),
|
||||||
|
(u'Supplement - Science & Technology',
|
||||||
|
u'http://www.hindu.com/rss/setahdline.xml')
|
||||||
|
]
|
||||||
|
|
||||||
|
def postprocess_html(self, soup, first_fetch):
|
||||||
|
for t in soup.findAll(['table', 'tr', 'td']):
|
||||||
|
t.name = 'div'
|
||||||
|
return soup
|
@ -14,21 +14,28 @@ class Infobae(BasicNewsRecipe):
|
|||||||
description = 'Informacion Libre las 24 horas'
|
description = 'Informacion Libre las 24 horas'
|
||||||
publisher = 'Infobae.com'
|
publisher = 'Infobae.com'
|
||||||
category = 'news, politics, Argentina'
|
category = 'news, politics, Argentina'
|
||||||
oldest_article = 2
|
oldest_article = 1
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
|
language = _('Spanish')
|
||||||
encoding = 'iso-8859-1'
|
encoding = 'iso-8859-1'
|
||||||
cover_url = 'http://www.infobae.com/imgs/header/header.gif'
|
cover_url = 'http://www.infobae.com/imgs/header/header.gif'
|
||||||
remove_javascript = True
|
remove_javascript = True
|
||||||
|
|
||||||
html2lrf_options = [
|
html2lrf_options = [
|
||||||
'--comment', description
|
'--comment' , description
|
||||||
, '--category', category
|
, '--category' , category
|
||||||
, '--publisher', publisher
|
, '--publisher', publisher
|
||||||
|
, '--ignore-tables'
|
||||||
]
|
]
|
||||||
|
|
||||||
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"'
|
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\nlinearize_tables=True'
|
||||||
|
|
||||||
|
remove_tags = [
|
||||||
|
dict(name=['embed','link','object'])
|
||||||
|
,dict(name='a', attrs={'onclick':'javascript:window.print()'})
|
||||||
|
]
|
||||||
|
|
||||||
feeds = [
|
feeds = [
|
||||||
(u'Noticias' , u'http://www.infobae.com/adjuntos/html/RSS/hoy.xml' )
|
(u'Noticias' , u'http://www.infobae.com/adjuntos/html/RSS/hoy.xml' )
|
||||||
@ -48,5 +55,3 @@ class Infobae(BasicNewsRecipe):
|
|||||||
for item in soup.findAll(style=True):
|
for item in soup.findAll(style=True):
|
||||||
del item['style']
|
del item['style']
|
||||||
return soup
|
return soup
|
||||||
|
|
||||||
language = _('Spanish')
|
|
@ -1,13 +1,12 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>'
|
__copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
|
||||||
'''
|
'''
|
||||||
jutarnji.hr
|
jutarnji.hr
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from calibre.web.feeds.news import BasicNewsRecipe
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
class Jutarnji(BasicNewsRecipe):
|
class Jutarnji(BasicNewsRecipe):
|
||||||
@ -16,32 +15,32 @@ class Jutarnji(BasicNewsRecipe):
|
|||||||
description = u'Hrvatski portal'
|
description = u'Hrvatski portal'
|
||||||
publisher = 'Jutarnji.hr'
|
publisher = 'Jutarnji.hr'
|
||||||
category = 'news, politics, Croatia'
|
category = 'news, politics, Croatia'
|
||||||
oldest_article = 2
|
oldest_article = 1
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
simultaneous_downloads = 1
|
simultaneous_downloads = 2
|
||||||
delay = 1
|
delay = 1
|
||||||
language = _('Croatian')
|
language = _('Croatian')
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
remove_javascript = True
|
remove_javascript = True
|
||||||
encoding = 'cp1250'
|
encoding = 'cp1250'
|
||||||
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "monospace1";src:url(res:///opt/sony/ebook/FONT/tt0419m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{text-align: left; font-family: serif1, serif} .article_date{font-family: monospace1, monospace} .article_description{font-family: sans1, sans-serif} .navbar{font-family: monospace1, monospace}'
|
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{text-align: justify; font-family: serif1, serif} .article_description{font-family: sans1, sans-serif}'
|
||||||
|
|
||||||
html2lrf_options = [
|
html2lrf_options = [
|
||||||
'--comment', description
|
'--comment' , description
|
||||||
, '--category', category
|
, '--category' , category
|
||||||
, '--publisher', publisher
|
, '--publisher', publisher
|
||||||
|
, '--ignore-tables'
|
||||||
]
|
]
|
||||||
|
|
||||||
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"'
|
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\nlinearize_tables=True'
|
||||||
|
|
||||||
|
|
||||||
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
|
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
|
||||||
|
|
||||||
remove_tags = [
|
remove_tags = [
|
||||||
dict(name='embed')
|
dict(name=['embed','hr','link','object'])
|
||||||
,dict(name='a', attrs={'class':'a11'})
|
,dict(name='a', attrs={'class':'a11'})
|
||||||
,dict(name='hr')
|
|
||||||
]
|
]
|
||||||
|
|
||||||
feeds = [
|
feeds = [
|
||||||
@ -60,9 +59,7 @@ class Jutarnji(BasicNewsRecipe):
|
|||||||
return 'http://www.jutarnji.hr/ispis_clanka.jl?artid=' + rrest
|
return 'http://www.jutarnji.hr/ispis_clanka.jl?artid=' + rrest
|
||||||
|
|
||||||
def preprocess_html(self, soup):
|
def preprocess_html(self, soup):
|
||||||
mtag = '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">'
|
mtag = '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">\n<meta http-equiv="Content-Language" content="hr-HR"/>'
|
||||||
soup.head.insert(0,mtag)
|
|
||||||
mtag = '<meta http-equiv="Content-Language" content="hr"/>'
|
|
||||||
soup.head.insert(0,mtag)
|
soup.head.insert(0,mtag)
|
||||||
for item in soup.findAll(style=True):
|
for item in soup.findAll(style=True):
|
||||||
del item['style']
|
del item['style']
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>'
|
__copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
|
||||||
'''
|
'''
|
||||||
juventudrebelde.cu
|
juventudrebelde.cu
|
||||||
'''
|
'''
|
||||||
from calibre import strftime
|
|
||||||
|
|
||||||
|
from calibre import strftime
|
||||||
from calibre.web.feeds.news import BasicNewsRecipe
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
class Juventudrebelde(BasicNewsRecipe):
|
class Juventudrebelde(BasicNewsRecipe):
|
||||||
@ -20,17 +20,18 @@ class Juventudrebelde(BasicNewsRecipe):
|
|||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
encoding = 'cp1252'
|
encoding = 'cp1252'
|
||||||
|
language = _('Spanish')
|
||||||
cover_url = strftime('http://www.juventudrebelde.cu/UserFiles/File/impreso/iportada-%Y-%m-%d.jpg')
|
cover_url = strftime('http://www.juventudrebelde.cu/UserFiles/File/impreso/iportada-%Y-%m-%d.jpg')
|
||||||
remove_javascript = True
|
remove_javascript = True
|
||||||
|
|
||||||
html2lrf_options = [
|
html2lrf_options = [
|
||||||
'--comment', description
|
'--comment' , description
|
||||||
, '--category', category
|
, '--category' , category
|
||||||
, '--publisher', publisher
|
, '--publisher', publisher
|
||||||
, '--ignore-tables'
|
, '--ignore-tables'
|
||||||
]
|
]
|
||||||
|
|
||||||
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"'
|
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\nlinearize_tables=True'
|
||||||
|
|
||||||
keep_only_tags = [dict(name='div', attrs={'id':'noticia'})]
|
keep_only_tags = [dict(name='div', attrs={'id':'noticia'})]
|
||||||
|
|
||||||
@ -51,4 +52,3 @@ class Juventudrebelde(BasicNewsRecipe):
|
|||||||
del item['style']
|
del item['style']
|
||||||
return soup
|
return soup
|
||||||
|
|
||||||
language = _('Spanish')
|
|
28
src/calibre/web/feeds/recipes/recipe_la_republica.py
Normal file
28
src/calibre/web/feeds/recipes/recipe_la_republica.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
|
class LaRepublica(BasicNewsRecipe):
|
||||||
|
title = u'la Repubblica'
|
||||||
|
oldest_article = 1
|
||||||
|
language = _('Italian')
|
||||||
|
author = 'Darko Miletic'
|
||||||
|
max_articles_per_feed = 100
|
||||||
|
remove_javascript = True
|
||||||
|
no_stylesheets = True
|
||||||
|
|
||||||
|
keep_only_tags = [dict(name='div', attrs={'class':'articolo'})]
|
||||||
|
|
||||||
|
|
||||||
|
remove_tags = [
|
||||||
|
dict(name=['object','link'])
|
||||||
|
,dict(name='span',attrs={'class':'linkindice'})
|
||||||
|
,dict(name='div',attrs={'class':'bottom-mobile'})
|
||||||
|
,dict(name='div',attrs={'id':['rssdiv','blocco']})
|
||||||
|
]
|
||||||
|
|
||||||
|
feeds = [
|
||||||
|
(u'Repubblica homepage', u'http://www.repubblica.it/rss/homepage/rss2.0.xml'),
|
||||||
|
(u'Repubblica Scienze', u'http://www.repubblica.it/rss/scienze/rss2.0.xml'),
|
||||||
|
(u'Repubblica Tecnologia', u'http://www.repubblica.it/rss/tecnologia/rss2.0.xml'),
|
||||||
|
(u'Repubblica Esteri', u'http://www.repubblica.it/rss/esteri/rss2.0.xml')
|
||||||
|
]
|
||||||
|
|
80
src/calibre/web/feeds/recipes/recipe_linuxdevices.py
Normal file
80
src/calibre/web/feeds/recipes/recipe_linuxdevices.py
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
|
|
||||||
|
'''
|
||||||
|
Fetch Linuxdevices.
|
||||||
|
'''
|
||||||
|
|
||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
|
|
||||||
|
class Sueddeutsche(BasicNewsRecipe):
|
||||||
|
|
||||||
|
title = u'Linuxdevices'
|
||||||
|
description = 'News about Linux driven Hardware'
|
||||||
|
__author__ = 'Oliver Niesner'
|
||||||
|
use_embedded_content = False
|
||||||
|
timefmt = ' [%a, %d %b %Y]'
|
||||||
|
language = _('English')
|
||||||
|
max_articles_per_feed = 50
|
||||||
|
no_stylesheets = True
|
||||||
|
encoding = 'latin1'
|
||||||
|
|
||||||
|
remove_tags_after = [dict(id='nointelliTXT')]
|
||||||
|
filter_regexps = [r'ad\.doubleclick\.net']
|
||||||
|
|
||||||
|
|
||||||
|
remove_tags = [dict(name='div', attrs={'class':'bannerSuperBanner'}),
|
||||||
|
dict(name='div', attrs={'class':'bannerSky'}),
|
||||||
|
dict(name='div', attrs={'class':'footerLinks'}),
|
||||||
|
dict(name='div', attrs={'class':'seitenanfang'}),
|
||||||
|
dict(name='td', attrs={'class':'mar5'}),
|
||||||
|
dict(name='td', attrs={'class':'mar5'}),
|
||||||
|
dict(name='table', attrs={'class':'pageAktiv'}),
|
||||||
|
dict(name='table', attrs={'class':'xartable'}),
|
||||||
|
dict(name='table', attrs={'class':'wpnavi'}),
|
||||||
|
dict(name='table', attrs={'class':'bgcontent absatz'}),
|
||||||
|
dict(name='table', attrs={'class':'footer'}),
|
||||||
|
dict(name='table', attrs={'class':'artikelBox'}),
|
||||||
|
dict(name='table', attrs={'class':'kommentare'}),
|
||||||
|
dict(name='table', attrs={'class':'pageBoxBot'}),
|
||||||
|
#dict(name='table', attrs={'with':'100%'}),
|
||||||
|
dict(name='td', attrs={'nowrap':'nowrap'}),
|
||||||
|
dict(name='td', attrs={'valign':'middle'}),
|
||||||
|
dict(name='td', attrs={'align':'left'}),
|
||||||
|
dict(name='td', attrs={'align':'center'}),
|
||||||
|
dict(name='td', attrs={'height':'5'}),
|
||||||
|
dict(name='div', attrs={'class':'artikelBox navigatorBox'}),
|
||||||
|
dict(name='div', attrs={'class':'similar-article-box'}),
|
||||||
|
dict(name='div', attrs={'class':'videoBigHack'}),
|
||||||
|
dict(name='td', attrs={'class':'artikelDruckenRight'}),
|
||||||
|
dict(name='td', attrs={'class':'width="200"'}),
|
||||||
|
dict(name='a', attrs={'href':'/news'}),
|
||||||
|
dict(name='a', attrs={'href':'/'}),
|
||||||
|
dict(name='a', attrs={'href':'/articles'}),
|
||||||
|
dict(name='a', attrs={'href':'/cgi-bin/survey/survey.cgi'}),
|
||||||
|
dict(name='a', attrs={'href':'/cgi-bin/board/UltraBoard.pl'}),
|
||||||
|
dict(name='iframe'),
|
||||||
|
dict(name='form'),
|
||||||
|
#dict(name='tr', attrs={'td':'Click here to learn'}),
|
||||||
|
dict(name='span', attrs={'class':'hidePrint'}),
|
||||||
|
dict(id='headerLBox'),
|
||||||
|
dict(id='nointelliTXT'),
|
||||||
|
dict(id='rechteSpalte'),
|
||||||
|
dict(id='newsticker-list-small'),
|
||||||
|
dict(id='ntop5'),
|
||||||
|
dict(id='ntop5send'),
|
||||||
|
dict(id='ntop5commented'),
|
||||||
|
dict(id='nnav-bgheader'),
|
||||||
|
dict(id='nnav-headerteaser'),
|
||||||
|
dict(id='nnav-head'),
|
||||||
|
dict(id='nnav-top'),
|
||||||
|
dict(id='nnav-logodiv'),
|
||||||
|
dict(id='nnav-logo'),
|
||||||
|
dict(id='nnav-oly'),
|
||||||
|
dict(id='readcomment')]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
feeds = [ (u'Linuxdevices', u'http://www.linuxdevices.com/backend/headlines.rss') ]
|
||||||
|
|
@ -1,13 +1,12 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>'
|
__copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
|
||||||
'''
|
'''
|
||||||
nin.co.yu
|
nin.co.yu
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import re, urllib
|
import re, urllib
|
||||||
|
|
||||||
from calibre.web.feeds.news import BasicNewsRecipe
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
class Nin(BasicNewsRecipe):
|
class Nin(BasicNewsRecipe):
|
||||||
@ -27,15 +26,17 @@ class Nin(BasicNewsRecipe):
|
|||||||
LOGIN = PREFIX + '/?logout=true'
|
LOGIN = PREFIX + '/?logout=true'
|
||||||
remove_javascript = True
|
remove_javascript = True
|
||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "monospace1";src:url(res:///opt/sony/ebook/FONT/tt0419m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{text-align: left; font-family: serif1, serif} .article_date{font-family: monospace1, monospace} .article_description{font-family: sans1, sans-serif} .navbar{font-family: monospace1, monospace}'
|
language = _('Serbian')
|
||||||
|
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{text-align: justify; font-family: serif1, serif} .article_description{font-family: sans1, sans-serif}'
|
||||||
|
|
||||||
html2lrf_options = [
|
html2lrf_options = [
|
||||||
'--comment', description
|
'--comment' , description
|
||||||
, '--category', category
|
, '--category' , category
|
||||||
, '--publisher', publisher
|
, '--publisher', publisher
|
||||||
|
, '--ignore-tables'
|
||||||
]
|
]
|
||||||
|
|
||||||
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"'
|
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\nlinearize_tables=True'
|
||||||
|
|
||||||
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
|
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
|
||||||
|
|
||||||
@ -69,5 +70,3 @@ class Nin(BasicNewsRecipe):
|
|||||||
for item in soup.findAll(style=True):
|
for item in soup.findAll(style=True):
|
||||||
del item['style']
|
del item['style']
|
||||||
return soup
|
return soup
|
||||||
|
|
||||||
language = _('Serbian')
|
|
@ -1,13 +1,12 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>'
|
__copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
|
||||||
'''
|
'''
|
||||||
novosti.rs
|
novosti.rs
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from calibre.web.feeds.news import BasicNewsRecipe
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
class Novosti(BasicNewsRecipe):
|
class Novosti(BasicNewsRecipe):
|
||||||
@ -22,15 +21,17 @@ class Novosti(BasicNewsRecipe):
|
|||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
encoding = 'utf8'
|
encoding = 'utf8'
|
||||||
remove_javascript = True
|
remove_javascript = True
|
||||||
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "monospace1";src:url(res:///opt/sony/ebook/FONT/tt0419m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{text-align: left; font-family: serif1, serif} .article_date{font-family: monospace1, monospace} .article_description{font-family: sans1, sans-serif} .navbar{font-family: monospace1, monospace}'
|
language = _('Serbian')
|
||||||
|
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{font-family: serif1, serif} .article_description{font-family: sans1, sans-serif}'
|
||||||
|
|
||||||
html2lrf_options = [
|
html2lrf_options = [
|
||||||
'--comment', description
|
'--comment' , description
|
||||||
, '--category', category
|
, '--category' , category
|
||||||
, '--publisher', publisher
|
, '--publisher', publisher
|
||||||
|
, '--ignore-tables'
|
||||||
]
|
]
|
||||||
|
|
||||||
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"'
|
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\nlinearize_tables=True'
|
||||||
|
|
||||||
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
|
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
|
||||||
|
|
||||||
@ -40,10 +41,8 @@ class Novosti(BasicNewsRecipe):
|
|||||||
feeds = [(u'Vesti', u'http://www.novosti.rs/php/vesti/rss.php')]
|
feeds = [(u'Vesti', u'http://www.novosti.rs/php/vesti/rss.php')]
|
||||||
|
|
||||||
def preprocess_html(self, soup):
|
def preprocess_html(self, soup):
|
||||||
mtag = '<meta http-equiv="Content-Language" content="sr-Latn"/>'
|
mtag = '<meta http-equiv="Content-Language" content="sr-Latn-RS"/>'
|
||||||
soup.head.insert(0,mtag)
|
soup.head.insert(0,mtag)
|
||||||
for item in soup.findAll(style=True):
|
for item in soup.findAll(style=True):
|
||||||
del item['style']
|
del item['style']
|
||||||
return soup
|
return soup
|
||||||
|
|
||||||
language = _('Serbian')
|
|
@ -1,13 +1,12 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>'
|
__copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
|
||||||
'''
|
'''
|
||||||
nspm.rs
|
nspm.rs
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from calibre.web.feeds.news import BasicNewsRecipe
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
class Nspm(BasicNewsRecipe):
|
class Nspm(BasicNewsRecipe):
|
||||||
@ -16,26 +15,30 @@ class Nspm(BasicNewsRecipe):
|
|||||||
description = 'Casopis za politicku teoriju i drustvena istrazivanja'
|
description = 'Casopis za politicku teoriju i drustvena istrazivanja'
|
||||||
publisher = 'NSPM'
|
publisher = 'NSPM'
|
||||||
category = 'news, politics, Serbia'
|
category = 'news, politics, Serbia'
|
||||||
oldest_article = 7
|
oldest_article = 2
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
INDEX = 'http://www.nspm.rs/?alphabet=l'
|
INDEX = 'http://www.nspm.rs/?alphabet=l'
|
||||||
encoding = 'utf8'
|
encoding = 'utf8'
|
||||||
remove_javascript = True
|
remove_javascript = True
|
||||||
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "monospace1";src:url(res:///opt/sony/ebook/FONT/tt0419m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{text-align: left; font-family: serif1, serif} .article_date{font-family: monospace1, monospace} .article_description{font-family: sans1, sans-serif} .navbar{font-family: monospace1, monospace}'
|
language = _('Serbian')
|
||||||
|
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{text-align: justify; font-family: serif1, serif} .article_description{font-family: sans1, sans-serif}'
|
||||||
|
|
||||||
html2lrf_options = [
|
html2lrf_options = [
|
||||||
'--comment', description
|
'--comment' , description
|
||||||
, '--category', category
|
, '--category' , category
|
||||||
, '--publisher', publisher
|
, '--publisher', publisher
|
||||||
, '--ignore-tables'
|
, '--ignore-tables'
|
||||||
]
|
]
|
||||||
|
|
||||||
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"'
|
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\nlinearize_tables=True'
|
||||||
|
|
||||||
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
|
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
|
||||||
remove_tags = [dict(name='a')]
|
remove_tags = [
|
||||||
|
dict(name=['a','img','link','object','embed'])
|
||||||
|
,dict(name='td', attrs={'class':'buttonheading'})
|
||||||
|
]
|
||||||
|
|
||||||
def get_browser(self):
|
def get_browser(self):
|
||||||
br = BasicNewsRecipe.get_browser()
|
br = BasicNewsRecipe.get_browser()
|
||||||
@ -48,13 +51,12 @@ class Nspm(BasicNewsRecipe):
|
|||||||
return url.replace('.html','/stampa.html')
|
return url.replace('.html','/stampa.html')
|
||||||
|
|
||||||
def preprocess_html(self, soup):
|
def preprocess_html(self, soup):
|
||||||
soup.html['xml:lang'] = 'sr-Latn-RS'
|
lng = 'sr-Latn-RS'
|
||||||
soup.html['lang'] = 'sr-Latn-RS'
|
soup.html['xml:lang'] = lng
|
||||||
|
soup.html['lang'] = lng
|
||||||
ftag = soup.find('meta',attrs={'http-equiv':'Content-Language'})
|
ftag = soup.find('meta',attrs={'http-equiv':'Content-Language'})
|
||||||
if ftag:
|
if ftag:
|
||||||
ftag['content'] = 'sr-Latn-RS'
|
ftag['content'] = lng
|
||||||
for item in soup.findAll(style=True):
|
for item in soup.findAll(style=True):
|
||||||
del item['style']
|
del item['style']
|
||||||
return soup
|
return soup
|
||||||
|
|
||||||
language = _('Serbian')
|
|
@ -1,13 +1,12 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>'
|
__copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
|
||||||
'''
|
'''
|
||||||
pescanik.net
|
pescanik.net
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from calibre.web.feeds.news import BasicNewsRecipe
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
class Pescanik(BasicNewsRecipe):
|
class Pescanik(BasicNewsRecipe):
|
||||||
@ -16,30 +15,32 @@ class Pescanik(BasicNewsRecipe):
|
|||||||
description = 'Pescanik'
|
description = 'Pescanik'
|
||||||
publisher = 'Pescanik'
|
publisher = 'Pescanik'
|
||||||
category = 'news, politics, Serbia'
|
category = 'news, politics, Serbia'
|
||||||
oldest_article = 7
|
oldest_article = 5
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
remove_javascript = True
|
remove_javascript = True
|
||||||
encoding = 'utf8'
|
encoding = 'utf8'
|
||||||
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "monospace1";src:url(res:///opt/sony/ebook/FONT/tt0419m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{text-align: left; font-family: serif1, serif} .article_date{font-family: monospace1, monospace} .article_description{font-family: sans1, sans-serif} .navbar{font-family: monospace1, monospace}'
|
cover_url = "http://pescanik.net/templates/ja_teline/images/logo.png"
|
||||||
|
language = _('Serbian')
|
||||||
|
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{font-family: serif1, serif} .article_description{font-family: sans1, sans-serif}'
|
||||||
|
|
||||||
html2lrf_options = [
|
html2lrf_options = [
|
||||||
'--comment', description
|
'--comment' , description
|
||||||
, '--category', category
|
, '--category' , category
|
||||||
, '--publisher', publisher
|
, '--publisher', publisher
|
||||||
|
, '--ignore-tables'
|
||||||
]
|
]
|
||||||
|
|
||||||
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"'
|
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\nlinearize_tables=True'
|
||||||
|
|
||||||
cover_url = "http://pescanik.net/templates/ja_teline/images/logo.png"
|
|
||||||
|
|
||||||
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
|
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
|
||||||
|
|
||||||
remove_tags = [
|
remove_tags = [
|
||||||
dict(name='td' , attrs={'class':'buttonheading'})
|
dict(name='td' , attrs={'class':'buttonheading'})
|
||||||
,dict(name='span', attrs={'class':'article_seperator'})
|
,dict(name='span', attrs={'class':'article_seperator'})
|
||||||
,dict(name=['object','link'])
|
,dict(name=['object','link','img','h4','ul'])
|
||||||
]
|
]
|
||||||
|
|
||||||
feeds = [(u'Pescanik Online', u'http://pescanik.net/index.php?option=com_rd_rss&id=12')]
|
feeds = [(u'Pescanik Online', u'http://pescanik.net/index.php?option=com_rd_rss&id=12')]
|
||||||
@ -54,5 +55,3 @@ class Pescanik(BasicNewsRecipe):
|
|||||||
for item in soup.findAll(style=True):
|
for item in soup.findAll(style=True):
|
||||||
del item['style']
|
del item['style']
|
||||||
return soup
|
return soup
|
||||||
|
|
||||||
language = _('Serbian')
|
|
39
src/calibre/web/feeds/recipes/recipe_physics_today.py
Normal file
39
src/calibre/web/feeds/recipes/recipe_physics_today.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import re
|
||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
from calibre import strftime
|
||||||
|
|
||||||
|
class Physicstoday(BasicNewsRecipe):
|
||||||
|
title = u'Physicstoday'
|
||||||
|
__author__ = 'Hypernova'
|
||||||
|
description = u'Physics Today magazine'
|
||||||
|
publisher = 'American Institute of Physics'
|
||||||
|
category = 'Physics'
|
||||||
|
language = _('English')
|
||||||
|
cover_url = strftime('http://ptonline.aip.org/journals/doc/PHTOAD-home/jrnls/images/medcover%m_%Y.jpg')
|
||||||
|
oldest_article = 30
|
||||||
|
max_articles_per_feed = 100
|
||||||
|
no_stylesheets = True
|
||||||
|
use_embedded_content = False
|
||||||
|
needs_subscription = True
|
||||||
|
remove_javascript = True
|
||||||
|
remove_tags_before = dict(name='h1')
|
||||||
|
remove_tags = [dict(name='div', attrs={'class':'highslide-footer'})]
|
||||||
|
remove_tags = [dict(name='div', attrs={'class':'highslide-header'})]
|
||||||
|
#remove_tags = [dict(name='a', attrs={'class':'highslide'})]
|
||||||
|
preprocess_regexps = [
|
||||||
|
#(re.compile(r'<!--start PHTOAD_tail.jsp -->.*</body>', re.DOTALL|re.IGNORECASE),
|
||||||
|
(re.compile(r'<!-- END ARTICLE and footer section -->.*</body>', re.DOTALL|re.IGNORECASE),
|
||||||
|
lambda match: '</body>'),
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_browser(self):
|
||||||
|
br = BasicNewsRecipe.get_browser()
|
||||||
|
if self.username is not None and self.password is not None:
|
||||||
|
br.open('http://www.physicstoday.org/pt/sso_login.jsp')
|
||||||
|
br.select_form(name='login')
|
||||||
|
br['username'] = self.username
|
||||||
|
br['password'] = self.password
|
||||||
|
br.submit()
|
||||||
|
return br
|
||||||
|
|
||||||
|
feeds = [(u'All', u'http://www.physicstoday.org/feed.xml')]
|
35
src/calibre/web/feeds/recipes/recipe_physics_world.py
Normal file
35
src/calibre/web/feeds/recipes/recipe_physics_world.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import re
|
||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
|
class PhysicsWorld(BasicNewsRecipe):
|
||||||
|
title = u'Physicsworld'
|
||||||
|
description = 'News from the world of physics'
|
||||||
|
__author__ = 'Hypernova'
|
||||||
|
language = _('English')
|
||||||
|
oldest_article = 7
|
||||||
|
max_articles_per_feed = 100
|
||||||
|
no_stylesheets = True
|
||||||
|
use_embedded_content = False
|
||||||
|
remove_javascript = True
|
||||||
|
needs_subscription = True
|
||||||
|
remove_tags_before = dict(name='h1')
|
||||||
|
remove_tags_after = [dict(name='div', attrs={'id':'shareThis'})]
|
||||||
|
preprocess_regexps = [
|
||||||
|
(re.compile(r'<div id="shareThis">.*</body>', re.DOTALL|re.IGNORECASE),
|
||||||
|
lambda match: '</body>'),
|
||||||
|
]
|
||||||
|
feeds = [
|
||||||
|
(u'Headlines News', u'http://feeds.feedburner.com/PhysicsWorldNews')
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_browser(self):
|
||||||
|
br = BasicNewsRecipe.get_browser(self)
|
||||||
|
if self.username is not None and self.password is not None:
|
||||||
|
br.open('http://physicsworld.com/cws/sign-in')
|
||||||
|
br.select_form(nr=1)
|
||||||
|
br['username'] = self.username
|
||||||
|
br['password'] = self.password
|
||||||
|
br.submit()
|
||||||
|
return br
|
||||||
|
|
||||||
|
|
@ -17,9 +17,6 @@ class Pobjeda(BasicNewsRecipe):
|
|||||||
description = 'News from Montenegro'
|
description = 'News from Montenegro'
|
||||||
publisher = 'Pobjeda a.d.'
|
publisher = 'Pobjeda a.d.'
|
||||||
category = 'news, politics, Montenegro'
|
category = 'news, politics, Montenegro'
|
||||||
language = _('Serbian')
|
|
||||||
oldest_article = 2
|
|
||||||
max_articles_per_feed = 100
|
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
remove_javascript = True
|
remove_javascript = True
|
||||||
encoding = 'utf8'
|
encoding = 'utf8'
|
||||||
@ -30,11 +27,13 @@ class Pobjeda(BasicNewsRecipe):
|
|||||||
|
|
||||||
html2lrf_options = [
|
html2lrf_options = [
|
||||||
'--comment', description
|
'--comment', description
|
||||||
|
, '--base-font-size', '10'
|
||||||
, '--category', category
|
, '--category', category
|
||||||
, '--publisher', publisher
|
, '--publisher', publisher
|
||||||
]
|
]
|
||||||
|
|
||||||
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"'
|
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\noverride_css=" p {text-indent: 0em; margin-top: 0em; margin-bottom: 0.5em} img {margin-top: 0em; margin-bottom: 0.4em}"'
|
||||||
|
|
||||||
|
|
||||||
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
|
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
|
||||||
|
|
||||||
@ -64,8 +63,6 @@ class Pobjeda(BasicNewsRecipe):
|
|||||||
soup.html['lang'] = 'sr-Latn-ME'
|
soup.html['lang'] = 'sr-Latn-ME'
|
||||||
mtag = '<meta http-equiv="Content-Language" content="sr-Latn-ME"/>'
|
mtag = '<meta http-equiv="Content-Language" content="sr-Latn-ME"/>'
|
||||||
soup.head.insert(0,mtag)
|
soup.head.insert(0,mtag)
|
||||||
for item in soup.findAll(style=True):
|
|
||||||
del item['style']
|
|
||||||
return soup
|
return soup
|
||||||
|
|
||||||
def get_cover_url(self):
|
def get_cover_url(self):
|
||||||
@ -87,7 +84,7 @@ class Pobjeda(BasicNewsRecipe):
|
|||||||
for item in soup.findAll('div', attrs={'class':'vijest'}):
|
for item in soup.findAll('div', attrs={'class':'vijest'}):
|
||||||
description = self.tag_to_string(item.h2)
|
description = self.tag_to_string(item.h2)
|
||||||
atag = item.h1.find('a')
|
atag = item.h1.find('a')
|
||||||
if atag:
|
if atag and atag.has_key('href'):
|
||||||
url = self.INDEX + '/' + atag['href']
|
url = self.INDEX + '/' + atag['href']
|
||||||
title = self.tag_to_string(atag)
|
title = self.tag_to_string(atag)
|
||||||
date = strftime(self.timefmt)
|
date = strftime(self.timefmt)
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user