mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Sync to trunk.
This commit is contained in:
commit
c5fbaf44f7
@ -60,6 +60,9 @@ def freeze():
|
||||
'/usr/lib/libgcrypt.so.11',
|
||||
'/usr/lib/libgpg-error.so.0',
|
||||
'/usr/lib/libphonon.so.4',
|
||||
'/usr/lib/libssl.so.0.9.8',
|
||||
'/usr/lib/libcrypto.so.0.9.8',
|
||||
'/lib/libreadline.so.6',
|
||||
]
|
||||
|
||||
binary_includes += [os.path.join(QTDIR, 'lib%s.so.4'%x) for x in QTDLLS]
|
||||
|
@ -4,6 +4,7 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
''' Create an OSX installer '''
|
||||
|
||||
import sys, re, os, shutil, subprocess, stat, glob, zipfile, plistlib
|
||||
sys.path = sys.path[1:]
|
||||
l = {}
|
||||
exec open('setup.py').read() in l
|
||||
VERSION = l['VERSION']
|
||||
@ -210,7 +211,6 @@ os.execv(python, args)
|
||||
|stat.S_IWUSR|stat.S_IROTH|stat.S_IRGRP)
|
||||
|
||||
|
||||
self.add_plugins()
|
||||
print 'Adding fontconfig'
|
||||
for f in glob.glob(os.path.expanduser('~/fontconfig-bundled/*')):
|
||||
dest = os.path.join(frameworks_dir, os.path.basename(f))
|
||||
@ -222,6 +222,8 @@ os.execv(python, args)
|
||||
shutil.rmtree(dst)
|
||||
shutil.copytree('/usr/local/etc/fonts', dst, symlinks=False)
|
||||
|
||||
self.add_plugins()
|
||||
|
||||
print
|
||||
print 'Adding IPython'
|
||||
dst = os.path.join(resource_dir, 'lib', 'python2.6', 'IPython')
|
||||
|
138
installer/osx/py2app/launcher.c
Normal file
138
installer/osx/py2app/launcher.c
Normal file
@ -0,0 +1,138 @@
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <Python.h>
|
||||
|
||||
static const char *ERR_UNKNOWNPYTHONEXCEPTION = "An uncaught exception was raised during execution of the main script, but its class or name could not be determined";
|
||||
|
||||
static int
|
||||
report_error(const char *msg) {
|
||||
fprintf(stderr, msg);
|
||||
fprintf(stderr, "\n");
|
||||
fflush(stderr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// These variable must be filled in before compiling
|
||||
static const char *ENV_VARS[] = { /*ENV_VARS*/ NULL };
|
||||
static const char *ENV_VAR_VALS[] = { /*ENV_VAR_VALS*/ NULL};
|
||||
static char PROGRAM[] = "**PROGRAM**";
|
||||
static const char MODULE[] = "**MODULE**";
|
||||
|
||||
#define EXE "@executable_path/.."
|
||||
|
||||
static void
|
||||
set_env_vars(const char* exe_path, const char* rpath) {
|
||||
int i = 0;
|
||||
char buf[3*PATH_MAX];
|
||||
const char *env_var, *val;
|
||||
|
||||
while(1) {
|
||||
env_var = ENV_VARS[i];
|
||||
if (env_var == NULL) break;
|
||||
val = ENV_VAR_VALS[i++];
|
||||
if (strstr(val, EXE) == val && strlen(val) >= strlen(EXE)+1) {
|
||||
strncpy(buf, exe_path, 3*PATH_MAX-150);
|
||||
strncpy(buf+strlen(exe_path), val+strlen(EXE), 150);
|
||||
setenv(env_var, buf, 1);
|
||||
} else
|
||||
setenv(env_var, val, 1);
|
||||
}
|
||||
setenv("CALIBRE_LAUNCH_MODULE", MODULE, 1);
|
||||
setenv("RESOURCEPATH", rpath, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char * const *argv, char * const *envp) {
|
||||
char *pathPtr = NULL;
|
||||
char buf[3*PATH_MAX];
|
||||
int ret, i;
|
||||
|
||||
|
||||
uint32_t buf_size = PATH_MAX+1;
|
||||
char *ebuf = calloc(buf_size, sizeof(char));
|
||||
ret = _NSGetExecutablePath(ebuf, &buf_size);
|
||||
if (ret == -1) {
|
||||
free(ebuf);
|
||||
ebuf = calloc(buf_size, sizeof(char));
|
||||
if (_NSGetExecutablePath(ebuf, &buf_size) != 0)
|
||||
return report_error("Failed to find real path of executable.");
|
||||
}
|
||||
pathPtr = realpath(ebuf, buf);
|
||||
if (pathPtr == NULL) {
|
||||
return report_error(strerror(errno));
|
||||
}
|
||||
char *t;
|
||||
for (i = 0; i < 3; i++) {
|
||||
t = rindex(pathPtr, '/');
|
||||
if (t == NULL) return report_error("Failed to determine bundle path.");
|
||||
*t = '\0';
|
||||
}
|
||||
|
||||
|
||||
|
||||
char rpath[PATH_MAX+1];
|
||||
strncpy(rpath, pathPtr, strlen(pathPtr));
|
||||
strncat(rpath, "/Contents/Resources", 50);
|
||||
char exe_path[PATH_MAX+1];
|
||||
strncpy(exe_path, pathPtr, strlen(pathPtr));
|
||||
strncat(exe_path, "/Contents", 50);
|
||||
|
||||
set_env_vars(exe_path, rpath);
|
||||
|
||||
char main_script[PATH_MAX+1];
|
||||
strncpy(main_script, rpath, strlen(rpath));
|
||||
strncat(main_script, "/launcher.py", 20);
|
||||
|
||||
Py_SetProgramName(PROGRAM);
|
||||
|
||||
Py_Initialize();
|
||||
|
||||
char **argv_new = calloc(argc+1, sizeof(char *));
|
||||
argv_new[argc] = NULL;
|
||||
argv_new[0] = main_script;
|
||||
memcpy(&argv_new[1], &argv[1], (argc - 1) * sizeof(char *));
|
||||
PySys_SetArgv(argc, argv_new);
|
||||
|
||||
FILE *main_script_file = fopen(main_script, "r");
|
||||
int rval = PyRun_SimpleFileEx(main_script_file, main_script, 1);
|
||||
|
||||
while (rval != 0) {
|
||||
PyObject *exc, *exceptionClassName, *v, *exceptionName;
|
||||
exc = PySys_GetObject("last_type");
|
||||
|
||||
if ( !exc ) {
|
||||
rval = report_error(ERR_UNKNOWNPYTHONEXCEPTION);
|
||||
break;
|
||||
}
|
||||
|
||||
exceptionClassName = PyObject_GetAttrString(exc, "__name__");
|
||||
if (!exceptionClassName) {
|
||||
rval = report_error(ERR_UNKNOWNPYTHONEXCEPTION);
|
||||
break;
|
||||
}
|
||||
|
||||
v = PySys_GetObject("last_value");
|
||||
exceptionName = (v ? PyObject_Str(v) : NULL);
|
||||
|
||||
char *class = PyString_AsString(exceptionClassName);
|
||||
char *exception = "";
|
||||
Py_DecRef(exceptionClassName);
|
||||
if (exceptionName) {
|
||||
exception = PyString_AsString(exceptionName);
|
||||
Py_DecRef(exceptionName);
|
||||
}
|
||||
char msg[2000];
|
||||
strncpy(msg, "An unexpected error occurred: ", 100);
|
||||
strncpy(msg, class, 500);
|
||||
strncpy(msg, " : ", 3);
|
||||
strncpy(msg, exception, 500);
|
||||
rval = report_error(msg);
|
||||
break;
|
||||
|
||||
}
|
||||
Py_Finalize();
|
||||
return rval;
|
||||
}
|
@ -35,22 +35,24 @@ _recipes_pil_prescript(['Hdf5StubImagePlugin', 'FitsStubImagePlugin', 'SunImageP
|
||||
|
||||
def _run():
|
||||
global __file__
|
||||
import os, sys, site
|
||||
sys.frozen = 'macosx_app'
|
||||
import os, sys
|
||||
base = os.environ['RESOURCEPATH']
|
||||
|
||||
sys.frozen = 'macosx_app'
|
||||
sys.frameworks_dir = os.path.join(os.path.dirname(base), 'Frameworks')
|
||||
sys.new_app_bundle = True
|
||||
site.addsitedir(base)
|
||||
site.addsitedir(os.path.join(base, 'Python', 'site-packages'))
|
||||
sys.site_packages = os.path.join(base, 'Python', 'site-packages')
|
||||
sys.binaries_path = os.path.join(os.path.dirname(base), 'MacOS')
|
||||
sys.console_binaries_path = os.path.join(os.path.dirname(base),
|
||||
'console.app', 'Contents', 'MacOS')
|
||||
|
||||
exe = os.environ.get('CALIBRE_LAUNCH_MODULE', 'calibre.gui2.main')
|
||||
exe = os.path.join(base, 'Python', 'site-packages', *exe.split('.'))
|
||||
exe += '.py'
|
||||
sys.argv[0] = __file__ = exe
|
||||
argv = os.environ.get('CALIBRE_LAUNCH_ARGV', None)
|
||||
if argv is not None:
|
||||
import cPickle
|
||||
argv = cPickle.loads(argv)
|
||||
sys.argv[1:] = argv
|
||||
for arg in list(sys.argv[1:]):
|
||||
if arg.startswith('-psn'):
|
||||
sys.argv.remove(arg)
|
||||
execfile(exe, globals(), globals())
|
||||
|
||||
_run()
|
||||
|
@ -1,33 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
|
||||
import os, sys, cPickle
|
||||
|
||||
ENV = {}##ENV##
|
||||
MODULE = ''##MODULE##
|
||||
|
||||
path = os.path.abspath(os.path.realpath(__file__))
|
||||
dirpath = os.path.dirname(path)
|
||||
name = os.path.basename(path)
|
||||
base_dir = os.path.dirname(os.path.dirname(dirpath))
|
||||
resources_dir = os.path.join(base_dir, 'Resources')
|
||||
frameworks_dir = os.path.join(base_dir, 'Frameworks')
|
||||
exe_dir = os.path.join(base_dir, 'MacOS')
|
||||
base_name = os.path.splitext(name)[0]
|
||||
python = os.path.join(base_dir, 'MacOS', 'Python')
|
||||
|
||||
for key, val in ENV.items():
|
||||
if val.startswith('@exec'):
|
||||
ENV[key] = os.path.normpath(val.replace('@executable_path', exe_dir))
|
||||
ENV['CALIBRE_LAUNCH_MODULE'] = MODULE
|
||||
ENV['CALIBRE_LAUNCH_ARGV'] = cPickle.dumps(sys.argv[1:], -1)
|
||||
ENV['RESOURCEPATH'] = resources_dir
|
||||
os.environ.update(ENV)
|
||||
launcher = os.path.join(resources_dir, 'launcher.py')
|
||||
args = ['-OO', launcher]
|
||||
os.execv(python, args)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -20,17 +20,50 @@ main_functions = l['main_functions']
|
||||
main_modules = l['main_modules']
|
||||
LICENSE = open('LICENSE', 'rb').read()
|
||||
ENV = dict(
|
||||
FC_CONFIG_DIR='@executable_path/../Resources/fonts',
|
||||
MAGICK_HOME='@executable_path/../Frameworks/ImageMagick',
|
||||
PYTHONDONTWRITEBYTECODE='1',
|
||||
PYTHONIOENCODING='utf-8:replace',
|
||||
PYTHONPATH='@executable_path/../Resources/Python/site-packages',
|
||||
PYTHONHOME='@executable_path/../Resources/Python',
|
||||
FC_CONFIG_DIR='@executable_path/../Resources/fonts',
|
||||
MAGICK_HOME='@executable_path/../Frameworks/ImageMagick',
|
||||
QT_PLUGIN_PATH='@executable_path/../MacOS',
|
||||
PYTHONDONTWRITEBYTECODE='1',
|
||||
PYTHONIOENCODING='utf-8:replace',
|
||||
PYTHONOPTIMIZE='2',
|
||||
QT_PLUGIN_PATH='@executable_path'
|
||||
)
|
||||
|
||||
SW = os.environ.get('SW')
|
||||
SW = os.environ.get('SW', '/sw')
|
||||
|
||||
def compile_launchers(contents_dir, xprograms):
|
||||
gcc = os.environ.get('CC', 'gcc')
|
||||
base = os.path.dirname(__file__)
|
||||
src = open(join(base, 'launcher.c'), 'rb').read()
|
||||
env, env_vals = [], []
|
||||
for key, val in ENV.items():
|
||||
env.append('"%s"'% key)
|
||||
env_vals.append('"%s"'% val)
|
||||
env = ', '.join(env)+', '
|
||||
env_vals = ', '.join(env_vals)+', '
|
||||
src = src.replace('/*ENV_VARS*/', env)
|
||||
src = src.replace('/*ENV_VAR_VALS*/', env_vals)
|
||||
programs = []
|
||||
for program, module in xprograms.items():
|
||||
print '\tCompiling', program
|
||||
out = join(contents_dir, 'MacOS', program)
|
||||
programs.append(out)
|
||||
psrc = src.replace('**PROGRAM**', program)
|
||||
psrc = psrc.replace('**MODULE**', module)
|
||||
fsrc = '/tmp/%s.c'%program
|
||||
with open(fsrc, 'wb') as f:
|
||||
f.write(psrc)
|
||||
cmd = [gcc, '-Wall', '-arch', 'x86_64',
|
||||
'-I%s/python/Python.framework/Headers'%SW,
|
||||
fsrc, '-o', out, '-F%s/python'%SW,
|
||||
'-framework', 'Python', '-framework', 'CoreFoundation',
|
||||
'-headerpad_max_install_names']
|
||||
print ' '.join(cmd)
|
||||
sys.stdout.flush()
|
||||
subprocess.check_call(cmd)
|
||||
return programs
|
||||
|
||||
|
||||
def flipwritable(fn, mode=None):
|
||||
"""
|
||||
@ -43,6 +76,15 @@ def flipwritable(fn, mode=None):
|
||||
os.chmod(fn, stat.S_IWRITE | old_mode)
|
||||
return old_mode
|
||||
|
||||
def thin(path):
|
||||
try:
|
||||
subprocess.check_call(['lipo', path, '-verify_arch', 'ppc64'])
|
||||
print '\tThinning', path
|
||||
except:
|
||||
return
|
||||
else:
|
||||
subprocess.check_call(['lipo', path, '-thin', 'x86_64', '-output', path])
|
||||
|
||||
STRIPCMD = ['/usr/bin/strip', '-x', '-S', '-']
|
||||
def strip_files(files, argv_max=(256 * 1024)):
|
||||
"""
|
||||
@ -120,8 +162,8 @@ class Py2App(object):
|
||||
|
||||
self.copy_launcher_and_site()
|
||||
self.create_exe()
|
||||
self.thin_to_x86_64()
|
||||
self.strip_files()
|
||||
self.create_launchers()
|
||||
|
||||
ret = self.makedmg(self.build_dir, APPNAME+'-'+VERSION+'-x86_64')
|
||||
sys.stdout.flush()
|
||||
@ -134,23 +176,17 @@ class Py2App(object):
|
||||
return ret
|
||||
|
||||
@flush
|
||||
def create_launchers(self):
|
||||
print '\nCreating launchers'
|
||||
all_names = basenames['console'] + basenames['gui']
|
||||
all_modules = main_modules['console'] + main_modules['gui']
|
||||
launcher = join(os.path.dirname(__file__), 'loader.py')
|
||||
launcher = open(launcher, 'rb').read()
|
||||
launcher = launcher.replace('{}##ENV##', repr(ENV))
|
||||
os.mkdir(join(self.resources_dir, 'loaders'))
|
||||
for basename, module in zip(all_names, all_modules):
|
||||
py_file = join('src', *module.split('.'))+'.py'
|
||||
shutil.copy2(py_file, join(self.resources_dir, 'Python',
|
||||
'site-packages', *module.split('.'))+'.py')
|
||||
raw = launcher.replace("''##MODULE##", repr(module))
|
||||
path = join(self.resources_dir, 'loaders', basename)
|
||||
open(path, 'wb').write(raw)
|
||||
os.chmod(path, stat.S_IXUSR|stat.S_IXGRP|stat.S_IXOTH|stat.S_IREAD\
|
||||
|stat.S_IWUSR|stat.S_IROTH|stat.S_IRGRP)
|
||||
def thin_to_x86_64(self):
|
||||
print '\nThinning to x86_64'
|
||||
for y in (self.frameworks_dir, join(self.resources_dir, 'Python')):
|
||||
for x in os.walk(y):
|
||||
for f in x[-1]:
|
||||
f = join(x[0], f)
|
||||
if not os.path.isfile(f): continue
|
||||
for t in ('.so', '.dylib', '/Python'):
|
||||
if f.endswith(t):
|
||||
thin(f)
|
||||
break
|
||||
|
||||
@flush
|
||||
def strip_files(self):
|
||||
@ -159,13 +195,19 @@ class Py2App(object):
|
||||
|
||||
@flush
|
||||
def create_exe(self):
|
||||
print '\nCreating executable'
|
||||
gcc = os.environ.get('CC', 'gcc')
|
||||
base = os.path.dirname(__file__)
|
||||
out = join(self.contents_dir, 'MacOS', 'calibre')
|
||||
subprocess.check_call([gcc, '-Wall', '-arch', 'x86_64', join(base,
|
||||
'main.c'), '-o', out])
|
||||
self.to_strip.append(out)
|
||||
print '\nCreating launchers'
|
||||
programs = {}
|
||||
for program, module in zip(basenames['console'],
|
||||
main_modules['console'])+zip(basenames['gui'],
|
||||
main_modules['gui']):
|
||||
programs[program] = module
|
||||
programs = compile_launchers(self.contents_dir, programs)
|
||||
for out in programs:
|
||||
self.fix_dependencies_in_lib(out)
|
||||
for module in main_modules['console'] + main_modules['gui']:
|
||||
base = join(*module.split('.'))+'.py'
|
||||
shutil.copy2(join('src', base),
|
||||
join(self.resources_dir, 'Python', 'site-packages', base))
|
||||
|
||||
@flush
|
||||
def set_id(self, path_to_lib, new_id):
|
||||
@ -226,10 +268,6 @@ class Py2App(object):
|
||||
shutil.copy2(join(curr, 'Python'), currd)
|
||||
self.set_id(join(currd, 'Python'),
|
||||
self.FID+'/Python.framework/Versions/%s/Python'%basename(curr))
|
||||
python = '%s/python/Python.framework/Versions/%s/Resources/Python.app/Contents/MacOS/Python'\
|
||||
% (SW, self.version_info)
|
||||
shutil.copy2(python, join(self.contents_dir, 'MacOS'))
|
||||
self.fix_dependencies_in_lib(join(self.contents_dir, 'MacOS', 'Python'))
|
||||
|
||||
@flush
|
||||
def add_qt_frameworks(self):
|
||||
@ -272,10 +310,16 @@ class Py2App(object):
|
||||
for f in glob.glob('src/calibre/plugins/*.so'):
|
||||
shutil.copy2(f, dest)
|
||||
self.fix_dependencies_in_lib(join(dest, basename(f)))
|
||||
if 'podofo' in f:
|
||||
self.change_dep('libpodofo.0.6.99.dylib',
|
||||
self.FID+'/'+'libpodofo.0.6.99.dylib', join(dest, basename(f)))
|
||||
|
||||
|
||||
@flush
|
||||
def create_plist(self):
|
||||
env = dict(**ENV)
|
||||
env['CALIBRE_LAUNCHED_FROM_BUNDLE']='1';
|
||||
|
||||
pl = dict(
|
||||
CFBundleDevelopmentRegion='English',
|
||||
CFBundleDisplayName=APPNAME,
|
||||
@ -286,7 +330,6 @@ class Py2App(object):
|
||||
CFBundleSignature='????',
|
||||
CFBundleExecutable='calibre',
|
||||
LSMinimumSystemVersion='10.5.2',
|
||||
PyRuntimeLocations=[self.FID+'/Python.framework/Versions/%s/Python'%self.version_info],
|
||||
LSRequiresNativeExecution=True,
|
||||
NSAppleScriptEnabled=False,
|
||||
NSHumanReadableCopyright='Copyright 2008, Kovid Goyal',
|
||||
@ -294,7 +337,7 @@ class Py2App(object):
|
||||
'application. Visit http://calibre.kovidgoyal.net for details.'),
|
||||
CFBundleIconFile='library.icns',
|
||||
LSMultipleInstancesProhibited=True,
|
||||
LSEnvironment=ENV
|
||||
LSEnvironment=env
|
||||
)
|
||||
plistlib.writePlist(pl, join(self.contents_dir, 'Info.plist'))
|
||||
|
||||
@ -374,7 +417,7 @@ class Py2App(object):
|
||||
|
||||
@flush
|
||||
def add_misc_libraries(self):
|
||||
for x in ('usb', 'unrar'):
|
||||
for x in ('usb', 'unrar', 'readline.6.0'):
|
||||
print '\nAdding', x
|
||||
x = 'lib%s.dylib'%x
|
||||
shutil.copy2(join(SW, 'lib', x), self.frameworks_dir)
|
||||
@ -551,9 +594,16 @@ class Py2App(object):
|
||||
print '\nInstaller size: %.2fMB\n'%size
|
||||
return dmg
|
||||
|
||||
def test_exe():
|
||||
build_dir = abspath(join('build', APPNAME+'.app'))
|
||||
py2app = Py2App(build_dir)
|
||||
py2app.create_exe()
|
||||
return 0
|
||||
|
||||
|
||||
def main():
|
||||
if 'test_exe' in sys.argv:
|
||||
return test_exe()
|
||||
build_dir = abspath(join('build', APPNAME+'.app'))
|
||||
if os.path.exists(build_dir):
|
||||
shutil.rmtree(build_dir)
|
||||
|
29
setup.py
29
setup.py
@ -73,22 +73,29 @@ if __name__ == '__main__':
|
||||
upload_to_pypi, stage3, stage2, stage1, upload, \
|
||||
upload_rss, betas, build_linux32, build_linux64, \
|
||||
build_osx64
|
||||
resources.SCRIPTS = list(basenames['console']+basenames['gui'])
|
||||
resources.SCRIPTS = {}
|
||||
for x in ('console', 'gui'):
|
||||
for name in basenames[x]:
|
||||
resources.SCRIPTS[name] = x
|
||||
|
||||
list(basenames['console']+basenames['gui'])
|
||||
|
||||
entry_points['console_scripts'].append(
|
||||
'calibre_postinstall = calibre.linux:post_install')
|
||||
optional = []
|
||||
def qmake_query(arg=''):
|
||||
return subprocess.Popen([QMAKE, '-query', arg],
|
||||
stdout=subprocess.PIPE).stdout.read()
|
||||
cmd = [QMAKE, '-query']
|
||||
if arg:
|
||||
cmd += [arg]
|
||||
return subprocess.Popen(cmd, stdout=subprocess.PIPE).stdout.read()
|
||||
qt_inc = qt_lib = None
|
||||
qt_inc = qmake_query('QT_INSTALL_HEADERS').splitlines()[0]
|
||||
qt_inc = qt_inc if qt_inc not in ('', '**Unknown**') and os.path.isdir(qt_inc) else None
|
||||
qt_lib = qmake_query('QT_INSTALL_LIBS').splitlines()[0]
|
||||
qt_lib = qt_lib if qt_lib not in ('', '**Unknown**') and os.path.isdir(qt_lib) else None
|
||||
if qt_lib is None or qt_inc is None:
|
||||
print 'WARNING: Could not find QT librariers and headers.',
|
||||
print 'Is qmake in your PATH?'
|
||||
print '\n\nWARNING: Could not find QT librariers and headers.',
|
||||
print 'Is qmake in your PATH?\n\n'
|
||||
|
||||
|
||||
if iswindows:
|
||||
@ -121,9 +128,9 @@ if __name__ == '__main__':
|
||||
poppler_lib), qt_lib],
|
||||
include_dirs=[poppler_inc, qt_inc]))
|
||||
else:
|
||||
print 'WARNING: Poppler not found on your system. Various PDF related',
|
||||
print '\n\nWARNING: Poppler not found on your system. Various PDF related',
|
||||
print 'functionality will not work. Use the POPPLER_INC_DIR and',
|
||||
print 'POPPLER_LIB_DIR environment variables.'
|
||||
print 'POPPLER_LIB_DIR environment variables.\n\n'
|
||||
|
||||
podofo_inc = '/usr/include/podofo' if islinux else \
|
||||
'C:\\podofo\\include\\podofo' if iswindows else \
|
||||
@ -138,9 +145,9 @@ if __name__ == '__main__':
|
||||
library_dirs=[os.environ.get('PODOFO_LIB_DIR', podofo_lib)],
|
||||
include_dirs=[podofo_inc]))
|
||||
else:
|
||||
print 'WARNING: PoDoFo not found on your system. Various PDF related',
|
||||
print '\n\nWARNING: PoDoFo not found on your system. Various PDF related',
|
||||
print 'functionality will not work. Use the PODOFO_INC_DIR and',
|
||||
print 'PODOFO_LIB_DIR environment variables.'
|
||||
print 'PODOFO_LIB_DIR environment variables.\n\n'
|
||||
|
||||
fc_inc = '/usr/include/fontconfig' if islinux else \
|
||||
r'C:\cygwin\home\kovid\fontconfig\include\fontconfig' if iswindows else \
|
||||
@ -152,8 +159,8 @@ if __name__ == '__main__':
|
||||
fc_inc = os.environ.get('FC_INC_DIR', fc_inc)
|
||||
fc_lib = os.environ.get('FC_LIB_DIR', fc_lib)
|
||||
if not os.path.exists(os.path.join(fc_inc, 'fontconfig.h')):
|
||||
print 'ERROR: fontconfig not found on your system.',
|
||||
print 'Use the FC_INC_DIR and FC_LIB_DIR environment variables.'
|
||||
print '\n\nERROR: fontconfig not found on your system.',
|
||||
print 'Use the FC_INC_DIR and FC_LIB_DIR environment variables.\n\n'
|
||||
raise SystemExit(1)
|
||||
ext_modules = optional + [
|
||||
|
||||
|
@ -2,7 +2,7 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
__appname__ = 'calibre'
|
||||
__version__ = '0.6.10'
|
||||
__version__ = '0.6.11'
|
||||
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
|
||||
|
||||
import re
|
||||
|
@ -6,7 +6,7 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
Embedded console for debugging.
|
||||
'''
|
||||
|
||||
import sys, os, re
|
||||
import sys, os, re, shutil
|
||||
from calibre.utils.config import OptionParser
|
||||
from calibre.constants import iswindows, isosx
|
||||
from calibre.libunzip import update
|
||||
@ -45,6 +45,9 @@ def update_zipfile(zipfile, mod, path):
|
||||
name = mod.replace('.', '/') + os.path.splitext(path)[-1]
|
||||
update(zipfile, [pat], [path], [name])
|
||||
|
||||
def update_site_packages(sp, mod, path):
|
||||
dest = os.path.join(sp, *mod.split('.'))+'.py'
|
||||
shutil.copy2(path, dest)
|
||||
|
||||
def update_module(mod, path):
|
||||
if not hasattr(sys, 'frozen'):
|
||||
@ -52,6 +55,8 @@ def update_module(mod, path):
|
||||
zp = None
|
||||
if iswindows:
|
||||
zp = os.path.join(os.path.dirname(sys.executable), 'library.zip')
|
||||
elif getattr(sys, 'new_app_bundle', False):
|
||||
update_site_packages(sys.site_packages, mod, path)
|
||||
elif isosx:
|
||||
zp = os.path.join(os.path.dirname(getattr(sys, 'frameworks_dir')),
|
||||
'Resources', 'lib',
|
||||
|
@ -38,7 +38,7 @@ class PRS505(CLI, Device):
|
||||
WINDOWS_CARD_A_MEM = re.compile(r'PRS-505/\S+:MS')
|
||||
WINDOWS_CARD_B_MEM = re.compile(r'PRS-505/\S+:SD')
|
||||
|
||||
OSX_MAIN_MEM = re.compile(r'Sony PRS-(505|300)/[^:]+ Media')
|
||||
OSX_MAIN_MEM = re.compile(r'Sony PRS-(((505|300)/[^:]+)|(300)) Media')
|
||||
OSX_CARD_A_MEM = re.compile(r'Sony PRS-505/[^:]+:MS Media')
|
||||
OSX_CARD_B_MEM = re.compile(r'Sony PRS-505/[^:]+:SD Media')
|
||||
|
||||
@ -55,6 +55,7 @@ class PRS505(CLI, Device):
|
||||
EBOOK_DIR_MAIN = 'database/media/books'
|
||||
|
||||
def open(self):
|
||||
self.report_progress = lambda x, y: x
|
||||
Device.open(self)
|
||||
|
||||
def write_cache(prefix):
|
||||
|
@ -21,12 +21,12 @@ class PRS700(PRS505):
|
||||
|
||||
BCD = [0x31a]
|
||||
|
||||
WINDOWS_MAIN_MEM = re.compile('PRS-[67]00')
|
||||
WINDOWS_CARD_A_MEM = re.compile(r'PRS-[67]00/\S+:MS')
|
||||
WINDOWS_CARD_B_MEM = re.compile(r'PRS-[67]00/\S+:SD')
|
||||
WINDOWS_MAIN_MEM = re.compile('PRS-((700/)|(600&))')
|
||||
WINDOWS_CARD_A_MEM = re.compile(r'PRS-((700/\S+:)|(600_))MS')
|
||||
WINDOWS_CARD_B_MEM = re.compile(r'PRS-((700/\S+:)|(600_))SD')
|
||||
|
||||
OSX_MAIN_MEM = re.compile(r'Sony PRS-[67]00/[^:]+ Media')
|
||||
OSX_CARD_A_MEM = re.compile(r'Sony PRS-[67]00/[^:]+:MS Media')
|
||||
OSX_CARD_B_MEM = re.compile(r'Sony PRS-[67]00/[^:]+:SD Media')
|
||||
OSX_MAIN_MEM = re.compile(r'Sony PRS-((700/[^:]+)|(600)) Media')
|
||||
OSX_CARD_A_MEM = re.compile(r'Sony PRS-((700/[^:]+:)|(600 ))MS Media')
|
||||
OSX_CARD_B_MEM = re.compile(r'Sony PRS-((700/[^:]+:)|(600 ))SD Media')
|
||||
|
||||
|
||||
|
@ -814,7 +814,6 @@ OptionRecommendation(name='language',
|
||||
out_dir = os.path.join(self.opts.debug_pipeline, 'processed')
|
||||
self.dump_oeb(self.oeb, out_dir)
|
||||
self.log('Processed HTML written to:', out_dir)
|
||||
return
|
||||
|
||||
self.log.info('Creating %s...'%self.output_plugin.name)
|
||||
our = CompositeProgressReporter(0.67, 1., self.ui_reporter)
|
||||
|
@ -127,6 +127,7 @@ class Stylizer(object):
|
||||
if elem.tag == XHTML('style') and elem.text \
|
||||
and elem.get('type', CSS_MIME) in OEB_STYLES:
|
||||
text = XHTML_CSS_NAMESPACE + elem.text
|
||||
text = oeb.css_preprocessor(text)
|
||||
stylesheet = parser.parseString(text, href=cssname)
|
||||
stylesheet.namespaces['h'] = XHTML_NS
|
||||
stylesheets.append(stylesheet)
|
||||
|
@ -23,7 +23,8 @@ class TXTInput(InputFormatPlugin):
|
||||
'With this option it will assume that every line represents '
|
||||
'a paragraph instead.')),
|
||||
OptionRecommendation(name='markdown', recommended_value=False,
|
||||
help=_('Run the text input though the markdown processor.')),
|
||||
help=_('Run the text input through the markdown pre-processor. To '
|
||||
'learn more about markdown see')+' http://daringfireball.net/projects/markdown/'),
|
||||
])
|
||||
|
||||
def convert(self, stream, options, file_ext, log,
|
||||
|
@ -464,9 +464,16 @@ class ConfigDialog(QDialog, Ui_Dialog):
|
||||
def create_symlinks(self):
|
||||
from calibre.utils.osx_symlinks import create_symlinks
|
||||
loc, paths = create_symlinks()
|
||||
info_dialog(self, _('Command line tools installed'),
|
||||
_('Command line tools installed in')+' '+loc,
|
||||
if loc is None:
|
||||
error_dialog(self, _('Error'),
|
||||
_('Failed to install command line tools.'),
|
||||
det_msg=paths, show=True)
|
||||
else:
|
||||
info_dialog(self, _('Command line tools installed'),
|
||||
'<p>'+_('Command line tools installed in')+' '+loc+
|
||||
'<br>'+ _('If you move calibre.app, you have to re-install '
|
||||
'the command line tools.'),
|
||||
det_msg='\n'.join(paths), show=True)
|
||||
|
||||
def setup_conversion_options(self):
|
||||
self.conversion_options = ConfigTabs(self)
|
||||
|
@ -699,10 +699,7 @@
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_12">
|
||||
<item>
|
||||
<widget class="QToolButton" name="compact_button">
|
||||
<property name="toolTip">
|
||||
<string>Free unused diskspace from the database</string>
|
||||
</property>
|
||||
<widget class="QPushButton" name="compact_button">
|
||||
<property name="text">
|
||||
<string>&Check database integrity</string>
|
||||
</property>
|
||||
|
@ -122,21 +122,49 @@ class TagsModel(QStandardItemModel):
|
||||
self._data[category], self.cmap[r], self.bold_font, self.icon_map))
|
||||
#self.reset()
|
||||
|
||||
def reset_all_states(self):
|
||||
changed_indices = []
|
||||
for category in self._data.values():
|
||||
Category = self.find_category(category)
|
||||
for tag in category:
|
||||
if tag.state != 0:
|
||||
tag.state = 0
|
||||
if Category is not None:
|
||||
Tag = self.find_tag(tag, Category)
|
||||
if Tag is not None:
|
||||
changed_indices.append(Tag.index())
|
||||
for idx in changed_indices:
|
||||
if idx.isValid():
|
||||
self.emit(SIGNAL('dataChanged(QModelIndex,QModelIndex)'),
|
||||
idx, idx)
|
||||
|
||||
def clear_state(self):
|
||||
for category in self._data.values():
|
||||
for tag in category:
|
||||
tag.state = 0
|
||||
self.refresh()
|
||||
self.reset_all_states()
|
||||
|
||||
def find_category(self, name):
|
||||
root = self.invisibleRootItem()
|
||||
for i in range(root.rowCount()):
|
||||
child = root.child(i)
|
||||
if getattr(child, 'category', None) == name:
|
||||
return child
|
||||
|
||||
def find_tag(self, tag, category):
|
||||
for i in range(category.rowCount()):
|
||||
child = category.child(i)
|
||||
if getattr(child, 'tag', None) == tag:
|
||||
return child
|
||||
|
||||
|
||||
def reinit(self, *args, **kwargs):
|
||||
if self.ignore_next_search == 0:
|
||||
for category in self._data.values():
|
||||
for tag in category:
|
||||
tag.state = 0
|
||||
self.reset()
|
||||
self.reset_all_states()
|
||||
else:
|
||||
self.ignore_next_search -= 1
|
||||
|
||||
|
||||
def toggle(self, index):
|
||||
if index.parent().isValid():
|
||||
category = self.row_map[index.parent().row()]
|
||||
|
@ -42,8 +42,8 @@ def convert_single_ebook(parent, db, book_ids, auto_conversion=False, out_format
|
||||
result = d.exec_()
|
||||
|
||||
if result == QDialog.Accepted:
|
||||
if not convert_existing(parent, db, [book_id], d.output_format):
|
||||
continue
|
||||
#if not convert_existing(parent, db, [book_id], d.output_format):
|
||||
# continue
|
||||
|
||||
mi = db.get_metadata(book_id, True)
|
||||
in_file = db.format_abspath(book_id, d.input_format, True)
|
||||
@ -198,7 +198,10 @@ def convert_existing(parent, db, book_ids, output_format):
|
||||
already_converted_ids.append(book_id)
|
||||
already_converted_titles.append(db.get_metadata(book_id, True).title)
|
||||
|
||||
if not question_dialog(parent, _('Convert existing'), _('The following books have already been converted to %s format. Do you wish to reconvert them?' % output_format), '\n'.join(already_converted_titles)):
|
||||
if not question_dialog(parent, _('Convert existing'),
|
||||
_('The following books have already been converted to %s format. '
|
||||
'Do you wish to reconvert them?') % output_format,
|
||||
'\n'.join(already_converted_titles)):
|
||||
book_ids = [x for x in book_ids if x not in already_converted_ids]
|
||||
|
||||
return book_ids
|
||||
|
@ -114,6 +114,24 @@ class LibraryServer(object):
|
||||
</entry>
|
||||
'''))
|
||||
|
||||
STANZA_TAG_ENTRY=MarkupTemplate(textwrap.dedent('''\
|
||||
<entry xmlns:py="http://genshi.edgewall.org/">
|
||||
<title>${tags}</title>
|
||||
<id>urn:calibre:${record[FM['id']]}</id>
|
||||
<updated>${timestamp}</updated>
|
||||
<link type="application/atom+xml" href="/stanza/?tagid=${record[FM['id']]}" />
|
||||
</entry>
|
||||
'''))
|
||||
|
||||
STANZA_SERIES_ENTRY=MarkupTemplate(textwrap.dedent('''\
|
||||
<entry xmlns:py="http://genshi.edgewall.org/">
|
||||
<title>${series}</title>
|
||||
<id>urn:calibre:${record[FM['id']]}</id>
|
||||
<updated>${timestamp}</updated>
|
||||
<link type="application/atom+xml" href="/stanza/?seriesid=${record[FM['id']]}" />
|
||||
</entry>
|
||||
'''))
|
||||
|
||||
STANZA = MarkupTemplate(textwrap.dedent('''\
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:py="http://genshi.edgewall.org/">
|
||||
@ -166,6 +184,18 @@ class LibraryServer(object):
|
||||
<updated>${updated.strftime('%Y-%m-%dT%H:%M:%S+00:00')}</updated>
|
||||
<link type="application/atom+xml" href="/stanza/?sortby=bynewest" />
|
||||
</entry>
|
||||
<entry>
|
||||
<title>By Tag</title>
|
||||
<id>urn:uuid:824921e8-db8a-4e61-7d38-f1ce41502853</id>
|
||||
<updated>${updated.strftime('%Y-%m-%dT%H:%M:%S+00:00')}</updated>
|
||||
<link type="application/atom+xml" href="/stanza/?sortby=bytag" />
|
||||
</entry>
|
||||
<entry>
|
||||
<title>By Series</title>
|
||||
<id>urn:uuid:512a5e50-a88f-f6b8-82aa-8f129c719f61</id>
|
||||
<updated>${updated.strftime('%Y-%m-%dT%H:%M:%S+00:00')}</updated>
|
||||
<link type="application/atom+xml" href="/stanza/?sortby=byseries" />
|
||||
</entry>
|
||||
</feed>
|
||||
'''))
|
||||
|
||||
@ -339,30 +369,46 @@ class LibraryServer(object):
|
||||
|
||||
|
||||
@expose
|
||||
def stanza(self, search=None, sortby=None, authorid=None):
|
||||
def stanza(self, search=None, sortby=None, authorid=None, tagid=None, seriesid=None):
|
||||
'Feeds to read calibre books on a ipod with stanza.'
|
||||
books = []
|
||||
updated = self.db.last_modified()
|
||||
cherrypy.response.headers['Last-Modified'] = self.last_modified(updated)
|
||||
cherrypy.response.headers['Content-Type'] = 'text/xml'
|
||||
if not sortby and not search and not authorid:
|
||||
if not sortby and not search and not authorid and not tagid and not seriesid:
|
||||
return self.STANZA_MAIN.generate(subtitle='', data=books, FM=FIELD_MAP,
|
||||
updated=updated, id='urn:calibre:main').render('xml')
|
||||
if authorid:
|
||||
authorid=int(authorid)
|
||||
au = self.db.authors(authorid, index_is_id=True)
|
||||
ids = self.db.data.get_matches('authors', au)
|
||||
elif tagid:
|
||||
tagid=int(tagid)
|
||||
ta = self.db.tags(tagid, index_is_id=True)
|
||||
ids = self.db.data.get_matches('tags', ta)
|
||||
elif seriesid:
|
||||
seriesid=int(seriesid)
|
||||
se = self.db.series(seriesid, index_is_id=True)
|
||||
ids = self.db.data.get_matches('series', se)
|
||||
else:
|
||||
ids = self.db.data.parse(search) if search and search.strip() else self.db.data.universal_set()
|
||||
record_list = list(iter(self.db))
|
||||
if sortby == "byauthor":
|
||||
record_list.sort(lambda x, y: cmp(x[FIELD_MAP['author_sort']], y[FIELD_MAP['author_sort']]))
|
||||
elif sortby == "bytitle" or authorid:
|
||||
elif sortby == "bytag":
|
||||
record_list.sort(lambda x, y: cmp(x[FIELD_MAP['tags']], y[FIELD_MAP['tags']]))
|
||||
elif sortby == "byseries":
|
||||
record_list.sort(lambda x, y: cmp(x[FIELD_MAP['series']], y[FIELD_MAP['series']]))
|
||||
elif sortby == "bytitle" or authorid or tagid:
|
||||
record_list.sort(lambda x, y: cmp(title_sort(x[FIELD_MAP['title']]),
|
||||
title_sort(y[FIELD_MAP['title']])))
|
||||
elif seriesid:
|
||||
record_list.sort(lambda x, y: cmp(x[FIELD_MAP['series_index']], y[FIELD_MAP['series_index']]))
|
||||
else:
|
||||
record_list = reversed(record_list)
|
||||
author_list=[]
|
||||
tag_list=[]
|
||||
series_list=[]
|
||||
for record in record_list:
|
||||
if record[0] not in ids: continue
|
||||
r = record[FIELD_MAP['formats']]
|
||||
@ -401,6 +447,30 @@ class LibraryServer(object):
|
||||
fmt=fmt,
|
||||
timestamp=strftime('%Y-%m-%dT%H:%M:%S+00:00', record[5]),
|
||||
).render('xml').decode('utf8'))
|
||||
elif sortby == "bytag":
|
||||
if tags and tags not in tag_list:
|
||||
tag_list.append(tags)
|
||||
books.append(self.STANZA_TAG_ENTRY.generate(
|
||||
tags=tags,
|
||||
record=record, FM=FIELD_MAP,
|
||||
port=self.opts.port,
|
||||
extra=''.join(extra),
|
||||
mimetype=mimetype,
|
||||
fmt=fmt,
|
||||
timestamp=strftime('%Y-%m-%dT%H:%M:%S+00:00', record[5]),
|
||||
).render('xml').decode('utf8'))
|
||||
elif sortby == "byseries":
|
||||
if series and series not in series_list:
|
||||
series_list.append(series)
|
||||
books.append(self.STANZA_SERIES_ENTRY.generate(
|
||||
series=series,
|
||||
record=record, FM=FIELD_MAP,
|
||||
port=self.opts.port,
|
||||
extra=''.join(extra),
|
||||
mimetype=mimetype,
|
||||
fmt=fmt,
|
||||
timestamp=strftime('%Y-%m-%dT%H:%M:%S+00:00', record[5]),
|
||||
).render('xml').decode('utf8'))
|
||||
else:
|
||||
books.append(self.STANZA_ENTRY.generate(
|
||||
authors=authors,
|
||||
@ -415,6 +485,7 @@ class LibraryServer(object):
|
||||
return self.STANZA.generate(subtitle='', data=books, FM=FIELD_MAP,
|
||||
updated=updated, id='urn:calibre:main').render('xml')
|
||||
|
||||
|
||||
@expose
|
||||
def library(self, start='0', num='50', sort=None, search=None,
|
||||
_=None, order='ascending'):
|
||||
@ -465,7 +536,8 @@ class LibraryServer(object):
|
||||
cherrypy.request.headers.get('Stanza-Device-Name', 919) != 919 or \
|
||||
cherrypy.request.headers.get('Want-OPDS-Catalog', 919) != 919 or \
|
||||
ua.startswith('Stanza')
|
||||
return self.stanza(search=kwargs.get('search', None), sortby=kwargs.get('sortby',None), authorid=kwargs.get('authorid',None)) if want_opds else self.static('index.html')
|
||||
return self.stanza(search=kwargs.get('search', None), sortby=kwargs.get('sortby',None), authorid=kwargs.get('authorid',None),
|
||||
tagid=kwargs.get('tagid',None), seriesid=kwargs.get('seriesid',None)) if want_opds else self.static('index.html')
|
||||
|
||||
|
||||
@expose
|
||||
|
@ -22,7 +22,7 @@
|
||||
</div>
|
||||
|
||||
<div id="count_bar">
|
||||
<span id="left"><img src="/static/first.png" alt="Show first set of books" title="Show first set of books"/> <img src="/static/previous.png" alt="Show previous set of books" title="Show previous set of books"/> </span><span id="count"> </span> <span id="right"><img src="/static/next.png" alt="Show first set of books" title="Show first set of books"/> <img src="/static/last.png" alt="Show previous set of books" title="Show previous set of books" /></span>
|
||||
<span id="left"><img src="/static/first.png" alt="Show first set of books" title="Show first set of books"/> <img src="/static/previous.png" alt="Show previous set of books" title="Show previous set of books"/> </span><span id="count"> </span> <span id="right"><img src="/static/next.png" alt="Show next set of books" title="Show next set of books"/> <img src="/static/last.png" alt="Show last set of books" title="Show last set of books" /></span>
|
||||
</div>
|
||||
|
||||
<div id="main">
|
||||
|
@ -78,7 +78,7 @@ Device Integration
|
||||
|
||||
What devices does |app| support?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
At the moment |app| has full support for the SONY PRS 500/505/700, Cybook Gen 3/Opus, Amazon Kindle 1/2/DX, Netronix EB600, Ectaco Jetbook, BeBook/BeBook Mini, Irex Illiad/DR1000, Adroid phones and the iPhone. In addition, using the :guilabel:`Save to disk` function you can use it with any ebook reader that exports itself as a USB disk.
|
||||
At the moment |app| has full support for the SONY PRS 300/500/505/600/700, Cybook Gen 3/Opus, Amazon Kindle 1/2/DX, Netronix EB600, Ectaco Jetbook, BeBook/BeBook Mini, Irex Illiad/DR1000, Adroid phones and the iPhone. In addition, using the :guilabel:`Save to disk` function you can use it with any ebook reader that exports itself as a USB disk.
|
||||
|
||||
I used |app| to transfer some books to my reader, and now the SONY software hangs every time I connect the reader?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
@ -180,7 +180,7 @@ else:
|
||||
data = dict(version = version, name='osx',
|
||||
installer_name='OS X universal dmg',
|
||||
title='Download %s for OS X'%(__appname__),
|
||||
compatibility='%s works on OS X Tiger and Leopard, but not Snow Leopard.'%(__appname__,),
|
||||
compatibility='%s works on OS X Tiger and Leopard, but not Snow Leopard (It might work on Snow Leopard if run with Rosetta).'%(__appname__,),
|
||||
path=MOBILEREAD+file, app=__appname__,
|
||||
note=Markup(\
|
||||
u'''
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -4,9 +4,9 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: calibre 0.6.10\n"
|
||||
"POT-Creation-Date: 2009-09-01 21:13+MDT\n"
|
||||
"PO-Revision-Date: 2009-09-01 21:13+MDT\n"
|
||||
"Project-Id-Version: calibre 0.6.11\n"
|
||||
"POT-Creation-Date: 2009-09-04 15:35+MDT\n"
|
||||
"PO-Revision-Date: 2009-09-04 15:35+MDT\n"
|
||||
"Last-Translator: Automatically generated\n"
|
||||
"Language-Team: LANGUAGE\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@ -75,8 +75,8 @@ msgstr ""
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdb/input.py:33
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdb/palmdoc/writer.py:29
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdb/ztxt/writer.py:27
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/crop.py:81
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/crop.py:82
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/crop.py:83
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/decrypt.py:75
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/decrypt.py:76
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/encrypt.py:61
|
||||
@ -127,8 +127,8 @@ msgstr ""
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1423
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1425
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:1534
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server.py:373
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server.py:446
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server.py:419
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server.py:517
|
||||
#: /home/kovid/work/calibre/src/calibre/utils/podofo/__init__.py:45
|
||||
#: /home/kovid/work/calibre/src/calibre/utils/podofo/__init__.py:63
|
||||
#: /home/kovid/work/calibre/src/calibre/utils/podofo/__init__.py:77
|
||||
@ -392,8 +392,8 @@ msgstr ""
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/cybookg3/driver.py:76
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/jetbook/driver.py:76
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/jetbook/driver.py:78
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:129
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:131
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:130
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:132
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:99
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:101
|
||||
msgid "Transferring books to device..."
|
||||
@ -441,10 +441,10 @@ msgid "Communicate with the Sony PRS-500 eBook reader."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/prs505/books.py:150
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:92
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:95
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:98
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:109
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:93
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:96
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:99
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:110
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:49
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:52
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:55
|
||||
@ -463,14 +463,14 @@ msgstr ""
|
||||
msgid "Kovid Goyal and John Schember"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:162
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:169
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:163
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:170
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:119
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:134
|
||||
msgid "Removing books from device..."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:197
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:198
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:149
|
||||
msgid "Sending metadata to device..."
|
||||
msgstr ""
|
||||
@ -920,7 +920,7 @@ msgstr ""
|
||||
msgid "Running transforms on ebook..."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:822
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:821
|
||||
msgid "Creating"
|
||||
msgstr ""
|
||||
|
||||
@ -940,10 +940,10 @@ msgstr ""
|
||||
msgid "Normally, if the input file has no cover and you don't specify one, a default cover is generated with the title, authors, etc. This option disables the generation of this cover."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/fb2/fb2ml.py:123
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/fb2/fb2ml.py:122
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pml/pmlml.py:111
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/rb/rbml.py:98
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/txt/txtml.py:70
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/txt/txtml.py:72
|
||||
msgid "Table of Contents:"
|
||||
msgstr ""
|
||||
|
||||
@ -1623,14 +1623,14 @@ msgid ""
|
||||
"Manipulate a PDF.\n"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/crop.py:28
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/crop.py:29
|
||||
msgid ""
|
||||
"[options] file.pdf\n"
|
||||
"\n"
|
||||
"Crop a PDF file.\n"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/crop.py:37
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/crop.py:38
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/decrypt.py:34
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/encrypt.py:32
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/merge.py:36
|
||||
@ -1640,31 +1640,31 @@ msgstr ""
|
||||
msgid "Path to output file. By default a file is created in the current directory."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/crop.py:40
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/crop.py:41
|
||||
msgid "Number of pixels to crop from the left most x (default is %s)"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/crop.py:43
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/crop.py:44
|
||||
msgid "Number of pixels to crop from the left most y (default is %s)"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/crop.py:46
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/crop.py:47
|
||||
msgid "Number of pixels to crop from the right most x (default is %s)"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/crop.py:49
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/crop.py:50
|
||||
msgid "Number of pixels to crop from the right most y (default is %s)"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/crop.py:52
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/crop.py:53
|
||||
msgid "A file generated by ghostscript which allows each page to be individually cropped `gs -dSAFER -dNOPAUSE -dBATCH -sDEVICE=bbox file.pdf 2> bounding`"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/crop.py:72
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/crop.py:73
|
||||
msgid "Crop Options:"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/crop.py:72
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/crop.py:73
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/decrypt.py:62
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/encrypt.py:52
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/merge.py:56
|
||||
@ -1810,7 +1810,7 @@ msgid "This RTF file has a feature calibre does not support. Convert it to HTML
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/txt/input.py:26
|
||||
msgid "Run the text input though the markdown processor."
|
||||
msgid "Run the text input through the markdown pre-processor. To learn more about markdown see"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/txt/output.py:24
|
||||
@ -1821,6 +1821,15 @@ msgstr ""
|
||||
msgid "Specify the character encoding of the output document. The default is utf-8. Note: This option is not honored by all formats."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/txt/output.py:38
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/txt_output_ui.py:44
|
||||
msgid "Do not add a blank line between paragraphs."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/txt/output.py:41
|
||||
msgid "Add a tab at the beginning of each paragraph."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:28
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:505
|
||||
msgid "Frequently used directories"
|
||||
@ -2021,8 +2030,8 @@ msgstr ""
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/rb_output_ui.py:28
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/structure_detection_ui.py:67
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/toc_ui.py:61
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/txt_input_ui.py:28
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/txt_output_ui.py:35
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/txt_input_ui.py:35
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/txt_output_ui.py:41
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/xpath_edit_ui.py:41
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/xpath_wizard_ui.py:67
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget_ui.py:59
|
||||
@ -2124,7 +2133,7 @@ msgstr ""
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:509
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:525
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:526
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:557
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:556
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:343
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:348
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:362
|
||||
@ -2192,7 +2201,7 @@ msgstr ""
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/fb2_output_ui.py:29
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdb_output_ui.py:37
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/rb_output_ui.py:29
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/txt_output_ui.py:37
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/txt_output_ui.py:43
|
||||
msgid "&Inline TOC"
|
||||
msgstr ""
|
||||
|
||||
@ -2498,7 +2507,7 @@ msgid "PDB Input"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdb_input_ui.py:29
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/txt_input_ui.py:29
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/txt_input_ui.py:36
|
||||
msgid "Treat each &line as a paragraph"
|
||||
msgstr ""
|
||||
|
||||
@ -2686,14 +2695,26 @@ msgstr ""
|
||||
msgid "TXT Input"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/txt_input_ui.py:37
|
||||
msgid "Process using markdown"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/txt_input_ui.py:38
|
||||
msgid "<p>Markdown is a simple markup language for text files, that allows for advanced formatting. To learn more visit <a href=\"http://daringfireball.net/projects/markdown\">markdown</a>."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/txt_output.py:16
|
||||
msgid "TXT Output"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/txt_output_ui.py:36
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/txt_output_ui.py:42
|
||||
msgid "&Line ending style:"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/txt_output_ui.py:45
|
||||
msgid "Add a tab at the beginning of each paragraph"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/xpath_edit_ui.py:42
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:62
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:63
|
||||
@ -3099,117 +3120,126 @@ msgstr ""
|
||||
msgid "new email address"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:467
|
||||
msgid "Command line tools installed"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:468
|
||||
msgid "Command line tools installed in"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:518
|
||||
msgid "No valid plugin path"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:519
|
||||
msgid "%s is not a valid plugin path"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:522
|
||||
msgid "Choose plugin"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:534
|
||||
msgid "Plugin cannot be disabled"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:535
|
||||
msgid "The plugin: %s cannot be disabled"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:544
|
||||
msgid "Plugin not customizable"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:545
|
||||
msgid "Plugin: %s does not need customization"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:569
|
||||
msgid "Customize %s"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:579
|
||||
msgid "Cannot remove builtin plugin"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:580
|
||||
msgid " cannot be removed. It is a builtin plugin. Try disabling it instead."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:613
|
||||
msgid "Error log:"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:620
|
||||
msgid "Access log:"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:645
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:574
|
||||
msgid "Failed to start content server"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:669
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:471
|
||||
msgid "Select location for books"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:686
|
||||
msgid "Invalid size"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:687
|
||||
msgid "The size %s is invalid. must be of the form widthxheight"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:731
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:736
|
||||
msgid "Invalid database location"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:732
|
||||
msgid "Invalid database location "
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:733
|
||||
msgid "<br>Must be a directory."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:737
|
||||
msgid "Invalid database location.<br>Cannot write to "
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:775
|
||||
msgid "Checking database integrity"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:794
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:801
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:142
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1005
|
||||
#: /home/kovid/work/calibre/src/calibre/utils/ipc/job.py:52
|
||||
msgid "Error"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:795
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:469
|
||||
msgid "Failed to install command line tools."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:472
|
||||
msgid "Command line tools installed"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:473
|
||||
msgid "Command line tools installed in"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:474
|
||||
msgid "If you move calibre.app, you have to re-install the command line tools."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:525
|
||||
msgid "No valid plugin path"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:526
|
||||
msgid "%s is not a valid plugin path"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:529
|
||||
msgid "Choose plugin"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:541
|
||||
msgid "Plugin cannot be disabled"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:542
|
||||
msgid "The plugin: %s cannot be disabled"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:551
|
||||
msgid "Plugin not customizable"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:552
|
||||
msgid "Plugin: %s does not need customization"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:576
|
||||
msgid "Customize %s"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:586
|
||||
msgid "Cannot remove builtin plugin"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:587
|
||||
msgid " cannot be removed. It is a builtin plugin. Try disabling it instead."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:620
|
||||
msgid "Error log:"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:627
|
||||
msgid "Access log:"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:652
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:574
|
||||
msgid "Failed to start content server"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:676
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:471
|
||||
msgid "Select location for books"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:693
|
||||
msgid "Invalid size"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:694
|
||||
msgid "The size %s is invalid. must be of the form widthxheight"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:738
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:743
|
||||
msgid "Invalid database location"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:739
|
||||
msgid "Invalid database location "
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:740
|
||||
msgid "<br>Must be a directory."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:744
|
||||
msgid "Invalid database location.<br>Cannot write to "
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:782
|
||||
msgid "Checking database integrity"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:802
|
||||
msgid "Failed to check database integrity"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:800
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:807
|
||||
msgid "Some inconsistencies found"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:801
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:808
|
||||
msgid "The following books had formats listed in the database that are not actually available. The entries for the formats have been removed. You should check them manually. This can happen if you manipulate the files in the library folder directly."
|
||||
msgstr ""
|
||||
|
||||
@ -3444,109 +3474,105 @@ msgid "calibre can send your books to you (or your reader) by email"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:533
|
||||
msgid "Free unused diskspace from the database"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:534
|
||||
msgid "&Check database integrity"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:535
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:534
|
||||
msgid "&Install command line tools"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:536
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:535
|
||||
msgid "calibre contains a network server that allows you to access your book collection using a browser from anywhere in the world. Any changes to the settings will only take effect after a server restart."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:537
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:536
|
||||
msgid "Server &port:"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:538
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:537
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/password_ui.py:58
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:178
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/send_email_ui.py:117
|
||||
msgid "&Username:"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:539
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:538
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/password_ui.py:59
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:179
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/send_email_ui.py:119
|
||||
msgid "&Password:"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:540
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:539
|
||||
msgid "If you leave the password blank, anyone will be able to access your book collection using the web interface."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:541
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:540
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/password_ui.py:60
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:180
|
||||
msgid "&Show password"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:542
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:541
|
||||
msgid "The maximum size (widthxheight) for displayed covers. Larger covers are resized. "
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:543
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:542
|
||||
msgid "Max. &cover size:"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:544
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:543
|
||||
msgid "&Start Server"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:545
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:544
|
||||
msgid "St&op Server"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:546
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:545
|
||||
msgid "&Test Server"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:547
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:546
|
||||
msgid "Run server &automatically on startup"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:548
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:547
|
||||
msgid "View &server logs"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:549
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:548
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/stanza_ui.py:46
|
||||
msgid ""
|
||||
"<p>Remember to leave calibre running as the server only runs as long as calibre is running.\n"
|
||||
"<p>Stanza should see your calibre collection automatically. If not, try adding the URL http://myhostname:8080 as a new catalog in the Stanza reader on your iPhone. Here myhostname should be the fully qualified hostname or the IP address of the computer calibre is running on."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:551
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:550
|
||||
msgid "Here you can customize the behavior of Calibre by controlling what plugins it uses."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:552
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:551
|
||||
msgid "Enable/&Disable plugin"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:553
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:552
|
||||
msgid "&Customize plugin"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:554
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:553
|
||||
msgid "&Remove plugin"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:555
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:554
|
||||
msgid "Add new plugin"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:556
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:555
|
||||
msgid "Plugin &file:"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:558
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:557
|
||||
msgid "&Add"
|
||||
msgstr ""
|
||||
|
||||
@ -5135,33 +5161,41 @@ msgid "Publishers"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:30
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:94
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:97
|
||||
msgid "Starting conversion of %d books"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:53
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:133
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:56
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:137
|
||||
msgid "Convert book %d of %d (%s)"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:79
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:150
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:82
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:154
|
||||
msgid "Could not convert some books"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:80
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:151
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:83
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:155
|
||||
msgid "Could not convert %d of %d books, because no suitable source format was found."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:182
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:186
|
||||
msgid "You must set a username and password for %s"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:187
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:191
|
||||
msgid "Fetch news from "
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:201
|
||||
msgid "Convert existing"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:202
|
||||
msgid "The following books have already been converted to %s format. Do you wish to reconvert them?"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/bookmarkmanager.py:43
|
||||
msgid "Edit bookmark"
|
||||
msgstr ""
|
||||
@ -6126,11 +6160,11 @@ msgstr ""
|
||||
msgid "Requested formats not available"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server.py:203
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server.py:233
|
||||
msgid "Password to access your calibre library. Username is "
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server.py:526
|
||||
#: /home/kovid/work/calibre/src/calibre/library/server.py:598
|
||||
msgid ""
|
||||
"[options]\n"
|
||||
"\n"
|
||||
@ -6308,19 +6342,19 @@ msgstr ""
|
||||
msgid "Downloading cover from %s"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:930
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:932
|
||||
msgid "Untitled Article"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1001
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1003
|
||||
msgid "Article downloaded: %s"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1012
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1014
|
||||
msgid "Article download failed: %s"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1027
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1029
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/recipe_borba.py:80
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/recipe_glas_srpske.py:76
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/recipe_instapaper.py:59
|
||||
@ -6509,10 +6543,10 @@ msgstr ""
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/recipe_stackoverflow.py:18
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/recipe_starbulletin.py:19
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/recipe_straitstimes.py:22
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/recipe_telegraph_uk.py:18
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/recipe_telegraph_uk.py:17
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/recipe_teleread.py:17
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/recipe_the_age.py:19
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/recipe_the_budget_fashionista.py:25
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/recipe_the_budget_fashionista.py:23
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/recipe_the_nation.py:17
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/recipe_the_oz.py:16
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/recipe_the_register.py:6
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -63,6 +63,8 @@ def shorten_components_to(length, components):
|
||||
if not r:
|
||||
r = x.strip()[0] if x.strip() else 'x'
|
||||
ans.append(r)
|
||||
if len(os.sep.join(ans)) > length:
|
||||
return shorten_components_to(length, ans)
|
||||
return ans
|
||||
|
||||
def find_executable_in_path(name, path=None):
|
||||
|
@ -16,6 +16,8 @@ if iswindows:
|
||||
import win32process
|
||||
_windows_null_file = open(os.devnull, 'wb')
|
||||
|
||||
isnewosx = isosx and getattr(sys, 'new_app_bundle', False)
|
||||
|
||||
class Worker(object):
|
||||
'''
|
||||
Platform independent object for launching child processes. All processes
|
||||
@ -45,6 +47,9 @@ class Worker(object):
|
||||
return os.path.join(os.path.dirname(sys.executable),
|
||||
'calibre-parallel.exe' if isfrozen else \
|
||||
'Scripts\\calibre-parallel.exe')
|
||||
if isnewosx:
|
||||
return os.path.join(sys.console_binaries_path, 'calibre-parallel')
|
||||
|
||||
if isosx:
|
||||
if not isfrozen: return 'calibre-parallel'
|
||||
contents = os.path.join(self.osx_contents_dir,
|
||||
@ -56,6 +61,9 @@ class Worker(object):
|
||||
|
||||
@property
|
||||
def gui_executable(self):
|
||||
if isnewosx:
|
||||
return os.path.join(sys.binaries_path, 'calibre-parallel')
|
||||
|
||||
if isfrozen and isosx:
|
||||
return os.path.join(self.osx_contents_dir,
|
||||
'MacOS', self.osx_interpreter)
|
||||
@ -98,7 +106,7 @@ class Worker(object):
|
||||
def __init__(self, env, gui=False):
|
||||
self._env = {}
|
||||
self.gui = gui
|
||||
if isosx and isfrozen:
|
||||
if isosx and isfrozen and not isnewosx:
|
||||
contents = os.path.join(self.osx_contents_dir, 'console.app', 'Contents')
|
||||
resources = os.path.join(contents, 'Resources')
|
||||
fd = os.path.join(contents, 'Frameworks')
|
||||
@ -133,7 +141,7 @@ class Worker(object):
|
||||
if priority is None:
|
||||
priority = prefs['worker_process_priority']
|
||||
cmd = [exe]
|
||||
if isosx:
|
||||
if isosx and not isnewosx:
|
||||
cmd += ['-c', self.osx_prefix + 'from calibre.utils.ipc.worker import main; main()']
|
||||
args = {
|
||||
'env' : env,
|
||||
|
@ -6,14 +6,18 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
AUTHTOOL="""#!%s
|
||||
import sys, os
|
||||
|
||||
AUTHTOOL="""#!/usr/bin/python
|
||||
import os
|
||||
scripts = %s
|
||||
links = %s
|
||||
os.setuid(0)
|
||||
for s, l in zip(scripts, links):
|
||||
if os.path.lexists(l):
|
||||
try:
|
||||
os.remove(l)
|
||||
except:
|
||||
pass
|
||||
print 'Creating link:', l, '->', s
|
||||
omask = os.umask(022)
|
||||
os.symlink(s, l)
|
||||
@ -23,15 +27,31 @@ for s, l in zip(scripts, links):
|
||||
DEST_PATH = '/usr/bin'
|
||||
|
||||
def create_symlinks():
|
||||
import os, tempfile, traceback, sys
|
||||
from Authorization import Authorization, kAuthorizationFlagDestroyRights
|
||||
return create_symlinks_new() if getattr(sys, 'new_app_bundle', False) else create_symlinks_old()
|
||||
|
||||
def create_symlinks_new():
|
||||
from calibre.resources import scripts
|
||||
|
||||
links = [os.path.join(DEST_PATH, i) for i in scripts]
|
||||
scripts = [os.path.join(
|
||||
sys.binaries_path if scripts[i] == 'gui' else sys.console_binaries_path, i) for i in scripts]
|
||||
|
||||
return do_it(scripts, links)
|
||||
|
||||
|
||||
def create_symlinks_old():
|
||||
from calibre.resources import scripts
|
||||
|
||||
resources_path = os.environ['RESOURCEPATH']
|
||||
links = [os.path.join(DEST_PATH, i) for i in scripts]
|
||||
scripts = [os.path.join(resources_path, 'loaders', i) for i in scripts]
|
||||
|
||||
return do_it(scripts, links)
|
||||
|
||||
def do_it(scripts, links):
|
||||
import os, tempfile, traceback
|
||||
from Authorization import Authorization, kAuthorizationFlagDestroyRights
|
||||
r1, r2 = DEST_PATH, links
|
||||
bad = False
|
||||
for s, l in zip(scripts, links):
|
||||
if os.path.exists(l) and os.path.exists(os.path.realpath(l)):
|
||||
@ -39,19 +59,28 @@ def create_symlinks():
|
||||
bad = True
|
||||
break
|
||||
if bad:
|
||||
ph, pp = os.environ.get('PYTHONHOME', None), os.environ.get('PYTHONPATH', None)
|
||||
auth = Authorization(destroyflags=(kAuthorizationFlagDestroyRights,))
|
||||
fd, name = tempfile.mkstemp('.py')
|
||||
os.write(fd, AUTHTOOL % (sys.executable, repr(scripts), repr(links)))
|
||||
os.write(fd, AUTHTOOL % (repr(scripts), repr(links)))
|
||||
os.close(fd)
|
||||
os.chmod(name, 0700)
|
||||
try:
|
||||
pipe = auth.executeWithPrivileges(sys.executable, name)
|
||||
if pp:
|
||||
del os.environ['PYTHONPATH']
|
||||
if ph:
|
||||
del os.environ['PYTHONHOME']
|
||||
pipe = auth.executeWithPrivileges(name)
|
||||
sys.stdout.write(pipe.read())
|
||||
pipe.close()
|
||||
except:
|
||||
traceback.print_exc()
|
||||
r1, r2 = None, traceback.format_exc()
|
||||
finally:
|
||||
os.unlink(name)
|
||||
if pp:
|
||||
os.environ['PYTHONPATH'] = pp
|
||||
if ph:
|
||||
os.environ['PYTHONHOME'] = ph
|
||||
|
||||
return DEST_PATH, links
|
||||
return r1, r2
|
||||
|
||||
|
@ -61,7 +61,9 @@ class Economist(BasicNewsRecipe):
|
||||
continue
|
||||
a = tag.find('a', href=True)
|
||||
if a is not None:
|
||||
url=a['href'].replace('displaystory', 'PrinterFriendly')
|
||||
url=a['href'].replace('displaystory', 'PrinterFriendly').strip()
|
||||
if url.startswith('Printer'):
|
||||
url = '/'+url
|
||||
if url.startswith('/'):
|
||||
url = 'http://www.economist.com' + url
|
||||
try:
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>'
|
||||
__copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
|
||||
'''
|
||||
latimes.com
|
||||
'''
|
||||
@ -10,20 +10,56 @@ from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class LATimes(BasicNewsRecipe):
|
||||
title = u'The Los Angeles Times'
|
||||
__author__ = u'Darko Miletic'
|
||||
__author__ = u'Darko Miletic and Sujata Raman'
|
||||
description = u'News from Los Angeles'
|
||||
oldest_article = 7
|
||||
max_articles_per_feed = 100
|
||||
language = _('English')
|
||||
no_stylesheets = True
|
||||
use_embedded_content = False
|
||||
encoding = 'utf-8'
|
||||
lang = 'en-US'
|
||||
|
||||
keep_only_tags = [ dict(name='div', attrs={'id':'center' }) ]
|
||||
remove_tags_after = [ dict(name='div', attrs={'id':'socialnet'}) ]
|
||||
remove_tags = [
|
||||
dict(name='div' , attrs={'id':'wrapper_vid' })
|
||||
,dict(name='div' , attrs={'id':'article_related'})
|
||||
,dict(name='div' , attrs={'id':'socialnet' })
|
||||
conversion_options = {
|
||||
'comment' : description
|
||||
, 'language' : lang
|
||||
}
|
||||
|
||||
extra_css = '''
|
||||
h1{font-family :Georgia,"Times New Roman",Times,serif; font-size:large; }
|
||||
h2{font-family :Georgia,"Times New Roman",Times,serif; font-size:x-small;}
|
||||
.story{font-family :Georgia,"Times New Roman",Times,serif; font-size: x-small;}
|
||||
.entry-body{font-family :Georgia,"Times New Roman",Times,serif; font-size: x-small;}
|
||||
.entry-more{font-family :Georgia,"Times New Roman",Times,serif; font-size: x-small;}
|
||||
.credit{color:#666666; font-family :Georgia,"Times New Roman",Times,serif; font-size: xx-small;}
|
||||
.small{color:#666666; font-family :Georgia,"Times New Roman",Times,serif; font-size: xx-small;}
|
||||
.byline{font-family :Georgia,"Times New Roman",Times,serif; font-size: xx-small;}
|
||||
.date{font-family :Georgia,"Times New Roman",Times,serif; font-size: xx-small;color:#930000; font-style:italic;}
|
||||
.time{font-family :Georgia,"Times New Roman",Times,serif; font-size: xx-small;color:#930000; font-style:italic;}
|
||||
.copyright{font-family :Georgia,"Times New Roman",Times,serif; font-size: xx-small;color:#930000; }
|
||||
.subhead{font-family :Georgia,"Times New Roman",Times,serif; font-size:x-small;}
|
||||
'''
|
||||
|
||||
|
||||
keep_only_tags = [dict(name='div', attrs={'class':["story" ,"entry"] })]
|
||||
remove_tags = [ dict(name='div', attrs={'class':['articlerail',"sphereTools","tools","toppaginate","entry-footer-left","entry-footer-right"]}),
|
||||
dict(name='div', attrs={'id':["moduleArticleToolsContainer",]}),
|
||||
dict(name='ul', attrs={'class':["article-nav clearfix",]}),
|
||||
dict(name='p', attrs={'class':["entry-footer",]}),
|
||||
dict(name=['iframe'])
|
||||
]
|
||||
|
||||
feeds = [(u'News', u'http://feeds.latimes.com/latimes/news')]
|
||||
feeds = [(u'News', u'http://feeds.latimes.com/latimes/news')
|
||||
,(u'Local','http://feeds.latimes.com/latimes/news/local')
|
||||
,(u'Most Emailed','http://feeds.latimes.com/MostEmailed')
|
||||
,(u'California Politics','http://feeds.latimes.com/latimes/news/local/politics/cal/')
|
||||
,('OrangeCounty','http://feeds.latimes.com/latimes/news/local/orange/')
|
||||
,('National','http://feeds.latimes.com/latimes/news/nationworld/nation')
|
||||
,('Politics','http://feeds.latimes.com/latimes/news/politics/')
|
||||
,('Business','http://feeds.latimes.com/latimes/business')
|
||||
,('Sports','http://feeds.latimes.com/latimes/sports/')
|
||||
,('Entertainment','http://feeds.latimes.com/latimes/entertainment/')
|
||||
]
|
||||
|
||||
def get_article_url(self, article):
|
||||
return article.get('feedburner_origlink')
|
||||
|
@ -89,6 +89,17 @@ class Newsweek(BasicNewsRecipe):
|
||||
return cmp(tx, ty)
|
||||
return sorted(ans, cmp=fcmp)
|
||||
|
||||
def ensure_html(self, soup):
|
||||
root = soup.find(name=True)
|
||||
if root.name == 'html': return soup
|
||||
nsoup = BeautifulSoup('<html><head></head><body/></html>')
|
||||
nroot = nsoup.find(name='body')
|
||||
for x in soup.contents:
|
||||
if getattr(x, 'name', False):
|
||||
x.extract()
|
||||
nroot.insert(len(nroot), x)
|
||||
return nsoup
|
||||
|
||||
def postprocess_html(self, soup, first_fetch):
|
||||
if not first_fetch:
|
||||
h1 = soup.find(id='headline')
|
||||
@ -99,7 +110,7 @@ class Newsweek(BasicNewsRecipe):
|
||||
div.extract()
|
||||
divs = list(soup.findAll('div', 'pagination'))
|
||||
if not divs:
|
||||
return soup
|
||||
return self.ensure_html(soup)
|
||||
for div in divs[1:]: div.extract()
|
||||
all_a = divs[0].findAll('a', href=True)
|
||||
divs[0]['style']="display:none"
|
||||
@ -109,7 +120,7 @@ class Newsweek(BasicNewsRecipe):
|
||||
for a in soup.findAll('a', href=test):
|
||||
if a not in all_a:
|
||||
del a['href']
|
||||
return soup
|
||||
return self.ensure_html(soup)
|
||||
|
||||
def get_current_issue(self):
|
||||
soup = self.index_to_soup('http://www.newsweek.com')
|
||||
|
@ -1,5 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>'
|
||||
'''
|
||||
@ -18,11 +17,21 @@ class TelegraphUK(BasicNewsRecipe):
|
||||
language = _('English')
|
||||
use_embedded_content = False
|
||||
|
||||
extra_css = '''
|
||||
h1{font-family :Arial,Helvetica,sans-serif; font-size:large; }
|
||||
h2{font-family :Arial,Helvetica,sans-serif; font-size:x-small; color:#444444}
|
||||
.story{font-family :Arial,Helvetica,sans-serif; font-size: x-small;}
|
||||
.byline{color:#666666; font-family :Arial,Helvetica,sans-serif; font-size: xx-small;}
|
||||
a{color:#234B7B; }
|
||||
.imageExtras{color:#666666; font-family :Arial,Helvetica,sans-serif; font-size: xx-small;}
|
||||
'''
|
||||
|
||||
keep_only_tags = [
|
||||
dict(name='div', attrs={'class':'storyHead'})
|
||||
,dict(name='div', attrs={'class':'story' })
|
||||
#,dict(name='div', attrs={'class':['slideshowHD gutterUnder',"twoThirds gutter","caption" ] })
|
||||
]
|
||||
remove_tags = [dict(name='div', attrs={'class':'slideshow'})]
|
||||
remove_tags = [dict(name='div', attrs={'class':['related_links_inline',"imgindex","next","prev","gutterUnder"]})]
|
||||
|
||||
feeds = [
|
||||
(u'UK News' , u'http://www.telegraph.co.uk/news/uknews/rss' )
|
||||
@ -36,3 +45,14 @@ class TelegraphUK(BasicNewsRecipe):
|
||||
,(u'Comment' , u'http://www.telegraph.co.uk/comment/rss' )
|
||||
,(u'How about that?', u'http://www.telegraph.co.uk/news/newstopics/howaboutthat/rss' )
|
||||
]
|
||||
|
||||
def get_article_url(self, article):
|
||||
|
||||
url = article.get('guid', None)
|
||||
|
||||
if 'picture-galleries' in url or 'pictures' in url or 'picturegalleries' in url :
|
||||
url = None
|
||||
|
||||
return url
|
||||
|
||||
|
||||
|
@ -6,9 +6,7 @@ __copyright__ = '2009, Darko Miletic <darko.miletic at gmail.com>'
|
||||
www.thebudgetfashionista.com
|
||||
'''
|
||||
|
||||
import re
|
||||
from calibre.web.feeds.recipes import BasicNewsRecipe
|
||||
from calibre.ebooks.BeautifulSoup import Tag
|
||||
|
||||
class TheBudgetFashionista(BasicNewsRecipe):
|
||||
title = 'The Budget Fashionista'
|
||||
@ -24,40 +22,22 @@ class TheBudgetFashionista(BasicNewsRecipe):
|
||||
lang = 'en-US'
|
||||
language = _('English')
|
||||
|
||||
preprocess_regexps = [(re.compile(r"</head>{0,1}", re.DOTALL|re.IGNORECASE),lambda match: '')]
|
||||
conversion_options = {
|
||||
'comment' : description
|
||||
, 'tags' : category
|
||||
, 'publisher' : publisher
|
||||
, 'language' : lang
|
||||
}
|
||||
|
||||
html2lrf_options = [
|
||||
'--comment', description
|
||||
, '--category', category
|
||||
, '--publisher', publisher
|
||||
]
|
||||
|
||||
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"'
|
||||
|
||||
keep_only_tags = [dict(name='div', attrs={'id':'singlepost'})]
|
||||
remove_tags_after = dict(name='div', attrs={'id':'postnav'})
|
||||
remove_tags = [
|
||||
dict(name=['object','link','script','iframe','form'])
|
||||
,dict(name='div', attrs={'id':'postnav'})
|
||||
]
|
||||
keep_only_tags = [dict(name='div', attrs={'class':'columnLeft'})]
|
||||
remove_tags_after = dict(name='div', attrs={'class':'postDetails'})
|
||||
remove_tags = [dict(name=['object','link','script','iframe','form','login-button'])]
|
||||
|
||||
feeds = [(u'Articles', u'http://www.thebudgetfashionista.com/feeds/atom/')]
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
for item in soup.findAll(style=True):
|
||||
del item['style']
|
||||
return soup
|
||||
for it in soup.findAll('img'):
|
||||
if it.parent.name == 'a':
|
||||
it.parent.name = 'div'
|
||||
return soup;
|
||||
|
||||
def postprocess_html(self, soup, x):
|
||||
body = soup.find('body')
|
||||
post = soup.find('div', attrs={'id':'singlepost'})
|
||||
if post and body:
|
||||
post.extract()
|
||||
body.extract()
|
||||
soup.html.append(body)
|
||||
body.insert(1,post)
|
||||
mlang = Tag(soup,'meta',[("http-equiv","Content-Language"),("content",self.lang)])
|
||||
mcharset = Tag(soup,'meta',[("http-equiv","Content-Type"),("content","text/html; charset=utf-8")])
|
||||
soup.head.insert(0,mlang)
|
||||
soup.head.insert(1,mcharset)
|
||||
return self.adeify_images(soup)
|
||||
|
Loading…
x
Reference in New Issue
Block a user