Merge remote-tracking branch 'upstream/master' into pr/1804
3
.gitattributes
vendored
@ -1,7 +1,7 @@
|
||||
# Tell git what files are txt
|
||||
*.py text diff=python
|
||||
*.pyj text diff=python
|
||||
*.recipe text diff=python
|
||||
*.recipe text diff=python linguist-language=python
|
||||
*.coffee text
|
||||
*.js text
|
||||
*.pot text
|
||||
@ -46,6 +46,7 @@ resources/coffee-script.js linguist-vendored=true
|
||||
resources/csscolorparser.js linguist-vendored=true
|
||||
resources/viewer/hyphen* linguist-vendored=true
|
||||
resources/viewer/jquery* linguist-vendored=true
|
||||
resources/stylelint-bundle.min.js linguist-vendored=true
|
||||
src/hunspell linguist-vendored=true
|
||||
|
||||
# Mark generated files
|
||||
|
4
.github/workflows/ci.yml
vendored
@ -9,7 +9,8 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-2019]
|
||||
# windows is disabled because webenging is crashing when compiling rapydscript in CI, try re-enabling after next Qt update
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
@ -67,4 +68,5 @@ jobs:
|
||||
run: |
|
||||
set -xe
|
||||
runuser -u ci -- python setup.py test --under-sanitize
|
||||
echo "Running test_rs"
|
||||
runuser -u ci -- python setup.py test_rs
|
||||
|
89
.gitignore
vendored
@ -6,57 +6,52 @@
|
||||
.bzrignore
|
||||
.build-cache
|
||||
.cache
|
||||
compile_commands.json
|
||||
link_commands.json
|
||||
src/calibre/plugins
|
||||
resources/images.qrc
|
||||
resources/icons.rcc
|
||||
manual/generated
|
||||
manual/locale
|
||||
manual/.doctrees
|
||||
build
|
||||
dist
|
||||
docs
|
||||
resources/localization
|
||||
resources/hyphenation
|
||||
resources/scripts.calibre_msgpack
|
||||
resources/changelog.json
|
||||
resources/ebook-convert-complete.calibre_msgpack
|
||||
resources/builtin_recipes.xml
|
||||
resources/builtin_recipes.zip
|
||||
resources/template-functions.json
|
||||
resources/editor-functions.json
|
||||
resources/user-manual-translation-stats.json
|
||||
resources/editor.js
|
||||
resources/viewer.js
|
||||
resources/viewer.html
|
||||
resources/content-server/index-generated.html
|
||||
resources/content-server/locales.zip
|
||||
resources/mathjax
|
||||
resources/fonts/liberation
|
||||
resources/mozilla-ca-certs.pem
|
||||
resources/user-agent-data.json
|
||||
icons/icns/*.iconset
|
||||
setup/installer/windows/calibre/build.log
|
||||
setup/pyqt_enums
|
||||
tags
|
||||
nbproject/
|
||||
translations/
|
||||
/src/calibre/plugins
|
||||
/resources/images.qrc
|
||||
/resources/icons.rcc
|
||||
/manual/generated
|
||||
/manual/locale
|
||||
/manual/.doctrees
|
||||
/build
|
||||
/dist
|
||||
/docs
|
||||
/resources/localization
|
||||
/resources/hyphenation
|
||||
/resources/scripts.calibre_msgpack
|
||||
/resources/changelog.json
|
||||
/resources/ebook-convert-complete.calibre_msgpack
|
||||
/resources/builtin_recipes.xml
|
||||
/resources/builtin_recipes.zip
|
||||
/resources/template-functions.json
|
||||
/resources/editor-functions.json
|
||||
/resources/user-manual-translation-stats.json
|
||||
/resources/editor.js
|
||||
/resources/viewer.js
|
||||
/resources/viewer.html
|
||||
/resources/content-server/index-generated.html
|
||||
/resources/content-server/locales.zip
|
||||
/resources/mathjax
|
||||
/resources/fonts/liberation
|
||||
/resources/mozilla-ca-certs.pem
|
||||
/resources/user-agent-data.json
|
||||
/icons/icns/*.iconset
|
||||
/setup/installer/windows/calibre/build.log
|
||||
/setup/pyqt_enums
|
||||
/tags
|
||||
/nbproject/
|
||||
/translations/
|
||||
*.mdproj
|
||||
*.pidb
|
||||
*.sln
|
||||
*.userprefs
|
||||
.project
|
||||
.pydevproject
|
||||
.settings/
|
||||
/.project
|
||||
/.pydevproject
|
||||
/.settings/
|
||||
*.DS_Store
|
||||
calibre_plugins/
|
||||
recipes/*.mobi
|
||||
recipes/*.epub
|
||||
recipes/debug
|
||||
/calibre_plugins/
|
||||
/.metadata/
|
||||
.idea
|
||||
/.idea
|
||||
/*env*/
|
||||
cmake-build-*
|
||||
bypy/b
|
||||
bypy/virtual-machines.conf
|
||||
/cmake-build-*
|
||||
/bypy/b
|
||||
/bypy/virtual-machines.conf
|
||||
|
@ -1,5 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPL v3 Copyright: %YEAR%, %USER% <%MAIL%>
|
||||
|
||||
%HERE%
|
@ -1,5 +1,5 @@
|
||||
Files: *
|
||||
Copyright: Copyright (C) 2008-2022 Kovid Goyal <kovid@kovidgoyal.net>
|
||||
Copyright: Copyright (C) 2008-2024 Kovid Goyal <kovid@kovidgoyal.net>
|
||||
License: GPL-3
|
||||
The full text of the GPL is distributed as in
|
||||
/usr/share/common-licenses/GPL-3 on Debian systems.
|
||||
|
1850
Changelog.old.txt
3031
Changelog.txt
@ -45,4 +45,4 @@ calibre binaries and installers for all the platforms calibre supports.
|
||||
|
||||
## calibre package versions in various repositories
|
||||
|
||||
[](https://repology.org/project/calibre/versions)
|
||||
[](https://repology.org/project/calibre/versions)
|
||||
|
@ -26,7 +26,8 @@ page for details). Once the dependencies are installed, run::
|
||||
|
||||
./setup.py bootstrap
|
||||
|
||||
To make the Windows and macOS builds it uses QEMU VMs. Instructions on
|
||||
All building is done inside QEMU VMs. Linux VMs are auto-created as needed,
|
||||
Windows and macOS VMs must be created manually. Instructions on
|
||||
creating the VMs are in the bypy repo under :file:`virtual_machine/README.rst`.
|
||||
Required software for the VMs are listed in :file:`bypy/windows.conf` and
|
||||
:file:`bypy/macos.conf`.
|
||||
@ -34,10 +35,10 @@ Required software for the VMs are listed in :file:`bypy/windows.conf` and
|
||||
Linux
|
||||
-------
|
||||
|
||||
To build the 64bit and 32bit dependencies for calibre, run::
|
||||
To build the Intel and ARM dependencies for calibre, run::
|
||||
|
||||
./setup.py build_dep linux
|
||||
./setup.py build_dep linux 32
|
||||
./setup.py build_dep linux-arm64
|
||||
|
||||
The output (after a very long time) will be in :literal:`bypy/b/linux/[32|64]`
|
||||
|
||||
@ -45,7 +46,7 @@ Now you can build the calibre Linux tarballs with::
|
||||
|
||||
./setup.py linux
|
||||
|
||||
The output will be in :literal:`dist`
|
||||
The output will be in :file:`dist`
|
||||
|
||||
|
||||
macOS
|
||||
@ -62,7 +63,7 @@ Now you can build the calibre ``.dmg`` with::
|
||||
|
||||
./setup.py osx --dont-sign --dont-notarize
|
||||
|
||||
The output will be in :literal:`dist`
|
||||
The output will be in :file:`dist`
|
||||
|
||||
|
||||
Windows
|
||||
@ -74,11 +75,10 @@ Make sure all software mentioned in :file:`bypy/windows.conf` is installed.
|
||||
To build the dependencies for calibre, run::
|
||||
|
||||
./setup.py build_dep windows
|
||||
./setup.py build_dep windows 32
|
||||
|
||||
The output (after a very long time) will be in :literal:`bypy/b/windows/[32|64]`.
|
||||
Now you can build the calibre windows installers with::
|
||||
|
||||
./setup.py win --dont-sign
|
||||
|
||||
The output will be in :literal:`dist`
|
||||
The output will be in :file:`dist`
|
||||
|
@ -2,4 +2,4 @@ image 'https://cloud-images.ubuntu.com/releases/focal/release/ubuntu-20.04-serve
|
||||
|
||||
# Build time deps for Qt. See https://doc.qt.io/qt-6/linux-requirements.html and
|
||||
# https://doc.qt.io/qt-6/qtwebengine-platform-notes.html
|
||||
deps 'flex bison gperf ruby python2 libx11-dev libxext-dev libxfixes-dev libxi-dev libxrender-dev libxcb1-dev libx11-xcb-dev libxcb-glx0-dev libxcb-keysyms1-dev libxcb-image0-dev libxcb-shm0-dev libxcb-icccm4-dev libxcb-sync0-dev libxcb-xfixes0-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-render-util0-dev libxcb-xinerama0-dev libxcb-util-dev xkb-data libglu1-mesa-dev libxkbcommon-dev libinput-dev libxkbcommon-x11-dev libxkbfile-dev libgtk2.0-dev libvulkan-dev libwayland-dev libwayland-egl1-mesa libxcb-xkb-dev libegl1-mesa-dev libxtst-dev libnss3-dev libfreetype6-dev libfontconfig-dev libdrm-dev libxshmfence-dev libcups2-dev'
|
||||
deps 'flex bison gperf ruby python2 libx11-dev libxext-dev libxfixes-dev libxi-dev libxrender-dev libxcb1-dev libx11-xcb-dev libxcb-glx0-dev libxcb-keysyms1-dev libxcb-image0-dev libxcb-shm0-dev libxcb-icccm4-dev libxcb-sync0-dev libxcb-xfixes0-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-render-util0-dev libxcb-xinerama0-dev libxcb-util-dev xkb-data libglu1-mesa-dev libxkbcommon-dev libinput-dev libxkbcommon-x11-dev libxkbfile-dev libgtk2.0-dev libvulkan-dev libwayland-dev libwayland-egl1-mesa libxcb-xkb-dev libegl1-mesa-dev libxtst-dev libnss3-dev libfreetype6-dev libfontconfig-dev libdrm-dev libxshmfence-dev libcups2-dev libxcb-cursor-dev'
|
||||
|
@ -13,13 +13,14 @@ import time
|
||||
from functools import partial
|
||||
|
||||
from bypy.constants import (
|
||||
OUTPUT_DIR, PREFIX, SRC as CALIBRE_DIR, python_major_minor_version
|
||||
LIBDIR, OUTPUT_DIR, PREFIX, SRC as CALIBRE_DIR, python_major_minor_version,
|
||||
)
|
||||
from bypy.freeze import (
|
||||
extract_extension_modules, fix_pycryptodome, freeze_python, path_to_freeze_dir
|
||||
extract_extension_modules, fix_pycryptodome, freeze_python, is_package_dir,
|
||||
path_to_freeze_dir,
|
||||
)
|
||||
from bypy.utils import (
|
||||
create_job, get_dll_path, mkdtemp, parallel_build, py_compile, run, walk
|
||||
create_job, get_dll_path, mkdtemp, parallel_build, py_compile, run, walk,
|
||||
)
|
||||
|
||||
j = os.path.join
|
||||
@ -38,15 +39,15 @@ qt_get_dll_path = partial(get_dll_path, loc=os.path.join(QT_PREFIX, 'lib'))
|
||||
|
||||
def binary_includes():
|
||||
return [
|
||||
j(PREFIX, 'bin', x) for x in ('pdftohtml', 'pdfinfo', 'pdftoppm', 'pdftotext', 'optipng', 'JxrDecApp')] + [
|
||||
j(PREFIX, 'bin', x) for x in ('pdftohtml', 'pdfinfo', 'pdftoppm', 'pdftotext', 'optipng', 'cwebp', 'JxrDecApp')] + [
|
||||
|
||||
j(PREFIX, 'private', 'mozjpeg', 'bin', x) for x in ('jpegtran', 'cjpeg')] + [
|
||||
] + list(map(
|
||||
get_dll_path,
|
||||
('usb-1.0 mtp expat sqlite3 ffi z lzma openjp2 poppler dbus-1 iconv xml2 xslt jpeg png16'
|
||||
' webp webpmux webpdemux exslt ncursesw readline chm hunspell-1.7 hyphen'
|
||||
' webp webpmux webpdemux sharpyuv exslt ncursesw readline chm hunspell-1.7 hyphen'
|
||||
' icudata icui18n icuuc icuio stemmer gcrypt gpg-error uchardet graphite2'
|
||||
' brotlicommon brotlidec brotlienc'
|
||||
' brotlicommon brotlidec brotlienc zstd podofo ssl crypto tiff'
|
||||
' gobject-2.0 glib-2.0 gthread-2.0 gmodule-2.0 gio-2.0 dbus-glib-1').split()
|
||||
)) + [
|
||||
# debian/ubuntu for for some typical stupid reason use libpcre.so.3
|
||||
@ -56,8 +57,8 @@ def binary_includes():
|
||||
# than libc and libpthread we bundle the Ubuntu one here
|
||||
glob.glob('/usr/lib/*/libpcre.so.3')[0],
|
||||
|
||||
get_dll_path('podofo', 3), get_dll_path('bz2', 2), j(PREFIX, 'lib', 'libunrar.so'),
|
||||
get_dll_path('ssl', 2), get_dll_path('crypto', 2), get_dll_path('python' + py_ver, 2),
|
||||
get_dll_path('bz2', 2), j(PREFIX, 'lib', 'libunrar.so'),
|
||||
get_dll_path('python' + py_ver, 2), get_dll_path('jbig', 2),
|
||||
|
||||
# We dont include libstdc++.so as the OpenGL dlls on the target
|
||||
# computer fail to load in the QPA xcb plugin if they were compiled
|
||||
@ -90,8 +91,7 @@ def ignore_in_lib(base, items, ignored_dirs=None):
|
||||
for name in items:
|
||||
path = j(base, name)
|
||||
if os.path.isdir(path):
|
||||
if name in ignored_dirs or not os.path.exists(j(path, '__init__.py')):
|
||||
if name != 'plugins':
|
||||
if name != 'plugins' and (name in ignored_dirs or not is_package_dir(path)):
|
||||
ans.append(name)
|
||||
else:
|
||||
if name.rpartition('.')[-1] not in ('so', 'py'):
|
||||
@ -112,7 +112,7 @@ def import_site_packages(srcdir, dest):
|
||||
src = os.path.abspath(j(srcdir, line))
|
||||
if os.path.exists(src) and os.path.isdir(src):
|
||||
import_site_packages(src, dest)
|
||||
elif os.path.exists(j(f, '__init__.py')):
|
||||
elif is_package_dir(f):
|
||||
shutil.copytree(f, j(dest, x), ignore=ignore_in_lib)
|
||||
|
||||
|
||||
@ -125,6 +125,8 @@ def copy_libs(env):
|
||||
os.chmod(j(
|
||||
dest, os.path.basename(x)),
|
||||
stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH)
|
||||
for x in ('ossl-modules',):
|
||||
shutil.copytree(os.path.join(LIBDIR, x), os.path.join(env.lib_dir, x))
|
||||
|
||||
base = j(QT_PREFIX, 'plugins')
|
||||
dest = j(env.lib_dir, '..', 'plugins')
|
||||
@ -161,7 +163,7 @@ def copy_python(env, ext_dir):
|
||||
elif os.path.isfile(c):
|
||||
shutil.copy2(c, j(dest, x))
|
||||
shutil.copytree(j(env.src_root, 'resources'), j(env.base, 'resources'))
|
||||
for pak in glob.glob(j(QT_PREFIX, 'resources', '*.pak')):
|
||||
for pak in glob.glob(j(QT_PREFIX, 'resources', '*')):
|
||||
shutil.copy2(pak, j(env.base, 'resources'))
|
||||
os.mkdir(j(env.base, 'translations'))
|
||||
shutil.copytree(j(QT_PREFIX, 'translations', 'qtwebengine_locales'), j(env.base, 'translations', 'qtwebengine_locales'))
|
||||
|
@ -26,17 +26,25 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
strncpy(lib, buf, PATHLEN);
|
||||
strncpy(base, dirname(lib), PATHLEN);
|
||||
snprintf(exe, PATHLEN, "%s/bin/%s", base, basename(buf));
|
||||
int ret = snprintf(exe, PATHLEN, "%s/bin/%s", base, basename(buf));
|
||||
if (ret < 0 || ret > (PATHLEN-2)) { fprintf(stderr, "Path to executable too long: %s/bin/%s", base, basename(buf)); return 1; }
|
||||
memset(lib, 0, PATHLEN);
|
||||
snprintf(lib, PATHLEN, "%s/lib", base);
|
||||
ret = snprintf(lib, PATHLEN, "%s/lib", base);
|
||||
if (ret < 0 || ret > (PATHLEN-2)) { fprintf(stderr, "Path to lib too long: %s/lib", base); return 1; }
|
||||
|
||||
SET("CALIBRE_QT_PREFIX", base)
|
||||
|
||||
memset(buf, 0, PATHLEN);
|
||||
ldp = getenv("LD_LIBRARY_PATH");
|
||||
if (ldp == NULL) strncpy(buf, lib, PATHLEN);
|
||||
else snprintf(buf, PATHLEN, "%s:%s", lib, ldp);
|
||||
else {
|
||||
ret = snprintf(buf, PATHLEN, "%s:%s", lib, ldp);
|
||||
if (ret < 0 || ret > (PATHLEN-2)) { fprintf(stderr, "LD_LIBRARY_PATH too long: %s:%s", lib, ldp); return 1; }
|
||||
}
|
||||
SET("LD_LIBRARY_PATH", buf)
|
||||
ret = snprintf(buf, PATHLEN, "%s/ossl-modules", lib);
|
||||
if (ret < 0 || ret > (PATHLEN-2)) { fprintf(stderr, "OPENSSL_MODULES too long: %s/ossl-modules", lib); return 1; }
|
||||
SET("OPENSSL_MODULES", buf)
|
||||
|
||||
argv[0] = exe;
|
||||
if (execv(exe, argv) == -1) {
|
||||
|
@ -1,7 +1,9 @@
|
||||
# Requires installation of XCode 10.3 and Python 3 and
|
||||
# Requires installation of XCode 14.3 and
|
||||
# python3 -m pip install certifi html5lib
|
||||
|
||||
vm_name 'macos-calibre-qt6'
|
||||
vm_name 'macos-calibre'
|
||||
root '/Users/Shared/calibre-build'
|
||||
python '/usr/local/bin/python3'
|
||||
python '/usr/bin/python3'
|
||||
rsync '/usr/local/bin/rsync'
|
||||
deploy_target '11.0'
|
||||
universal 'true'
|
||||
|
@ -20,13 +20,14 @@ from functools import partial, reduce
|
||||
from itertools import repeat
|
||||
|
||||
from bypy.constants import (
|
||||
OUTPUT_DIR, PREFIX, PYTHON, SRC as CALIBRE_DIR, python_major_minor_version
|
||||
OUTPUT_DIR, PREFIX, PYTHON, SRC as CALIBRE_DIR, python_major_minor_version,
|
||||
)
|
||||
from bypy.freeze import (
|
||||
extract_extension_modules, fix_pycryptodome, freeze_python, path_to_freeze_dir
|
||||
extract_extension_modules, fix_pycryptodome, freeze_python, is_package_dir,
|
||||
path_to_freeze_dir,
|
||||
)
|
||||
from bypy.utils import (
|
||||
current_dir, get_arches_in_binary, mkdtemp, py_compile, timeit, walk
|
||||
current_dir, get_arches_in_binary, mkdtemp, py_compile, timeit, walk,
|
||||
)
|
||||
|
||||
abspath, join, basename, dirname = os.path.abspath, os.path.join, os.path.basename, os.path.dirname
|
||||
@ -44,11 +45,14 @@ ENV = dict(
|
||||
FONTCONFIG_PATH='@executable_path/../Resources/fonts',
|
||||
FONTCONFIG_FILE='@executable_path/../Resources/fonts/fonts.conf',
|
||||
SSL_CERT_FILE='@executable_path/../Resources/resources/mozilla-ca-certs.pem',
|
||||
OPENSSL_ENGINES='@executable_path/../Frameworks/engines-3',
|
||||
OPENSSL_MODULES='@executable_path/../Frameworks/ossl-modules',
|
||||
)
|
||||
APPNAME, VERSION = calibre_constants['appname'], calibre_constants['version']
|
||||
basenames, main_modules, main_functions = calibre_constants['basenames'], calibre_constants['modules'], calibre_constants['functions']
|
||||
ARCH_FLAGS = '-arch x86_64 -arch arm64'.split()
|
||||
EXPECTED_ARCHES = {'x86_64', 'arm64'}
|
||||
MINIMUM_SYSTEM_VERSION = '13.0.0'
|
||||
|
||||
|
||||
def compile_launcher_lib(contents_dir, gcc, base, pyver, inc_dir):
|
||||
@ -99,7 +103,7 @@ def compile_launchers(contents_dir, inc_dir, xprograms, pyver):
|
||||
is_gui = 'true' if ptype == 'gui' else 'false'
|
||||
cmd = [gcc] + ARCH_FLAGS + [
|
||||
'-Wall', f'-DPROGRAM=L"{program}"', f'-DMODULE=L"{module}"', f'-DFUNCTION=L"{func}"', f'-DIS_GUI={is_gui}',
|
||||
'-I' + base, src, lib, '-o', out, '-headerpad_max_install_names'
|
||||
'-I' + base, src, lib, '-o', out, '-headerpad_max_install_names',
|
||||
]
|
||||
# print('\t'+' '.join(cmd))
|
||||
sys.stdout.flush()
|
||||
@ -270,12 +274,10 @@ class Freeze:
|
||||
@flush
|
||||
def get_local_dependencies(self, path_to_lib):
|
||||
for x, is_id in self.get_dependencies(path_to_lib):
|
||||
if x.startswith('@rpath/Qt') or x.startswith('@rpath/libexpat'):
|
||||
yield x, x[len('@rpath/'):], is_id
|
||||
elif x in ('libunrar.dylib', 'libstemmer.0.dylib', 'libstemmer.dylib') and not is_id:
|
||||
if x in ('libunrar.dylib', 'libstemmer.0.dylib', 'libstemmer.dylib', 'libjbig.2.1.dylib') and not is_id:
|
||||
yield x, x, is_id
|
||||
else:
|
||||
for y in (PREFIX + '/lib/', PREFIX + '/python/Python.framework/'):
|
||||
for y in ('@rpath/', PREFIX + '/lib/', PREFIX + '/python/Python.framework/'):
|
||||
if x.startswith(y):
|
||||
if y == PREFIX + '/python/Python.framework/':
|
||||
y = PREFIX + '/python/'
|
||||
@ -395,7 +397,7 @@ class Freeze:
|
||||
CFBundlePackageType='APPL',
|
||||
CFBundleSignature='????',
|
||||
CFBundleExecutable='pdftohtml',
|
||||
LSMinimumSystemVersion='10.15.0',
|
||||
LSMinimumSystemVersion=MINIMUM_SYSTEM_VERSION,
|
||||
LSRequiresNativeExecution=True,
|
||||
NSAppleScriptEnabled=False,
|
||||
CFBundleIconFile='',
|
||||
@ -414,9 +416,6 @@ class Freeze:
|
||||
raise SystemExit('No calibre plugins found in: ' + self.ext_dir)
|
||||
for f in plugins:
|
||||
self.fix_dependencies_in_lib(f)
|
||||
if f.endswith('/podofo.so'):
|
||||
self.change_dep('libpodofo.0.9.7.dylib',
|
||||
'@executable_path/../Frameworks/libpodofo.0.9.7.dylib', False, f)
|
||||
|
||||
@flush
|
||||
def create_plist(self):
|
||||
@ -448,7 +447,7 @@ class Freeze:
|
||||
CFBundleExecutable='calibre',
|
||||
CFBundleDocumentTypes=docs,
|
||||
CFBundleURLTypes=url_handlers,
|
||||
LSMinimumSystemVersion='10.15.0',
|
||||
LSMinimumSystemVersion=MINIMUM_SYSTEM_VERSION,
|
||||
LSRequiresNativeExecution=True,
|
||||
NSAppleScriptEnabled=False,
|
||||
NSSupportsAutomaticGraphicsSwitching=True,
|
||||
@ -476,13 +475,13 @@ class Freeze:
|
||||
@flush
|
||||
def add_podofo(self):
|
||||
print('\nAdding PoDoFo')
|
||||
pdf = join(PREFIX, 'lib', 'libpodofo.0.9.7.dylib')
|
||||
pdf = join(PREFIX, 'lib', 'libpodofo.2.dylib')
|
||||
self.install_dylib(pdf)
|
||||
|
||||
@flush
|
||||
def add_poppler(self):
|
||||
print('\nAdding poppler')
|
||||
for x in ('libopenjp2.7.dylib', 'libpoppler.115.dylib',):
|
||||
for x in ('libopenjp2.7.dylib', 'libpoppler.130.dylib',):
|
||||
self.install_dylib(join(PREFIX, 'lib', x))
|
||||
for x in ('pdftohtml', 'pdftoppm', 'pdfinfo', 'pdftotext'):
|
||||
self.install_dylib(
|
||||
@ -491,9 +490,9 @@ class Freeze:
|
||||
@flush
|
||||
def add_imaging_libs(self):
|
||||
print('\nAdding libjpeg, libpng, libwebp, optipng and mozjpeg')
|
||||
for x in ('jpeg.8', 'png16.16', 'webp.7', 'webpmux.3', 'webpdemux.2'):
|
||||
for x in ('jpeg.8', 'png16.16', 'webp.7', 'webpmux.3', 'webpdemux.2', 'sharpyuv.0'):
|
||||
self.install_dylib(join(PREFIX, 'lib', 'lib%s.dylib' % x))
|
||||
for x in 'optipng', 'JxrDecApp':
|
||||
for x in 'optipng', 'JxrDecApp', 'cwebp':
|
||||
self.install_dylib(join(PREFIX, 'bin', x), set_id=False, dest=self.helpers_dir)
|
||||
for x in ('jpegtran', 'cjpeg'):
|
||||
self.install_dylib(
|
||||
@ -527,10 +526,10 @@ class Freeze:
|
||||
def add_misc_libraries(self):
|
||||
for x in (
|
||||
'usb-1.0.0', 'mtp.9', 'chm.0', 'sqlite3.0', 'hunspell-1.7.0',
|
||||
'icudata.70', 'icui18n.70', 'icuio.70', 'icuuc.70', 'hyphen.0', 'uchardet.0',
|
||||
'icudata.73', 'icui18n.73', 'icuio.73', 'icuuc.73', 'hyphen.0', 'uchardet.0',
|
||||
'stemmer.0', 'xslt.1', 'exslt.0', 'xml2.2', 'z.1', 'unrar', 'lzma.5',
|
||||
'brotlicommon.1', 'brotlidec.1', 'brotlienc.1',
|
||||
'crypto.1.1', 'ssl.1.1', 'iconv.2', # 'ltdl.7'
|
||||
'brotlicommon.1', 'brotlidec.1', 'brotlienc.1', 'zstd.1', 'jbig.2.1', 'tiff.6',
|
||||
'crypto.3', 'ssl.3', 'iconv.2', # 'ltdl.7'
|
||||
):
|
||||
print('\nAdding', x)
|
||||
x = 'lib%s.dylib' % x
|
||||
@ -540,6 +539,16 @@ class Freeze:
|
||||
self.set_id(dest, self.FID + '/' + x)
|
||||
self.fix_dependencies_in_lib(dest)
|
||||
|
||||
# OpenSSL modules and engines
|
||||
for x in ('ossl-modules', 'engines-3'):
|
||||
dest = join(self.frameworks_dir, x)
|
||||
shutil.copytree(join(PREFIX, 'lib', x), dest)
|
||||
for dylib in os.listdir(dest):
|
||||
if dylib.endswith('.dylib'):
|
||||
dylib = join(dest, dylib)
|
||||
self.set_id(dylib, self.FID + '/' + x + '/' + os.path.basename(dylib))
|
||||
self.fix_dependencies_in_lib(dylib)
|
||||
|
||||
@flush
|
||||
def add_site_packages(self):
|
||||
print('\nAdding site-packages')
|
||||
@ -587,7 +596,7 @@ class Freeze:
|
||||
def add_packages_from_dir(self, src):
|
||||
for x in os.listdir(src):
|
||||
x = join(src, x)
|
||||
if os.path.isdir(x) and os.path.exists(join(x, '__init__.py')):
|
||||
if os.path.isdir(x) and is_package_dir(x):
|
||||
if self.filter_package(basename(x)):
|
||||
continue
|
||||
self.add_package_dir(x)
|
||||
@ -742,15 +751,24 @@ class Freeze:
|
||||
e = plist['CFBundleDocumentTypes'][0]
|
||||
e['CFBundleTypeExtensions'] = [x.lower() for x in formats]
|
||||
|
||||
def headless_plist(plist):
|
||||
plist['CFBundleDisplayName'] = 'calibre worker process'
|
||||
plist['CFBundleExecutable'] = 'calibre-parallel'
|
||||
plist['CFBundleIdentifier'] = 'com.calibre-ebook.calibre-parallel'
|
||||
plist['LSBackgroundOnly'] = '1'
|
||||
plist.pop('CFBundleDocumentTypes')
|
||||
|
||||
self.create_app_clone('ebook-viewer.app', partial(specialise_plist, 'ebook-viewer', input_formats))
|
||||
self.create_app_clone('ebook-edit.app', partial(specialise_plist, 'ebook-edit', edit_formats),
|
||||
base_dir=join(self.contents_dir, 'ebook-viewer.app', 'Contents'))
|
||||
self.create_app_clone('headless.app', headless_plist,
|
||||
base_dir=join(self.contents_dir, 'ebook-viewer.app', 'Contents', 'ebook-edit.app', 'Contents'))
|
||||
# We need to move the webengine resources into the deepest sub-app
|
||||
# because the sandbox gets set to the nearest enclosing app which
|
||||
# means that WebEngine will fail to access its resources when running
|
||||
# in the sub-apps unless they are present inside the sub app bundle
|
||||
# somewhere
|
||||
base_dest = join(self.contents_dir, 'ebook-viewer.app', 'Contents', 'ebook-edit.app', 'Contents', 'SharedSupport')
|
||||
base_dest = join(self.contents_dir, 'ebook-viewer.app', 'Contents', 'ebook-edit.app', 'Contents', 'headless.app', 'Contents', 'SharedSupport')
|
||||
os.mkdir(base_dest)
|
||||
base_src = os.path.realpath(join(self.frameworks_dir, 'QtWebEngineCore.framework/Resources'))
|
||||
items = [join(base_src, 'qtwebengine_locales')] + glob.glob(join(base_src, '*.pak')) + glob.glob(join(base_src, '*.dat'))
|
||||
@ -810,7 +828,8 @@ def main(args, ext_dir, test_runner):
|
||||
build_dir = abspath(join(mkdtemp('frozen-'), APPNAME + '.app'))
|
||||
inc_dir = abspath(mkdtemp('include'))
|
||||
if args.skip_tests:
|
||||
test_runner = lambda *a: None
|
||||
def test_runner(*a):
|
||||
return None
|
||||
Freeze(build_dir, ext_dir, inc_dir, test_runner, dont_strip=args.dont_strip, sign_installers=args.sign_installers, notarize=args.notarize)
|
||||
|
||||
|
||||
|
@ -1 +1 @@
|
||||
to_vm_excludes '/imgsrc /build /dist /manual /format_docs /translations /.build-cache /tags /Changelog* *.so *.pyd'
|
||||
to_vm_excludes '/imgsrc /build /dist /manual /format_docs /translations /.build-cache /.cache /tags /Changelog* *.so *.pyd'
|
||||
|
@ -1,17 +1,16 @@
|
||||
# Requires installation of Visual Studio 2019 Community Edition, WiX Toolset, Git, Ruby, NodeJS, Python (2 and 3) and Perl
|
||||
# git.exe must be in PATH. Must have ~120GB available disk space and 8GB RAM
|
||||
# Requires installation of Visual Studio 2022 Community Edition, .NET SDK, WiX Toolset, Git, Ruby (without devkit), NodeJS, Python and Perl
|
||||
# git.exe must be in PATH. Must have ~120GB available disk space and 24GB RAM to build Qt WebEngine
|
||||
# Install certifi in python 3 with:
|
||||
# py.exe -m pip install certifi
|
||||
# Note that python2 is needed to build Qt WebEngine
|
||||
# Copy opengl32sw.dll from
|
||||
# https://download.qt.io/development_releases/prebuilt/llvmpipe/windows/
|
||||
# to C:/mesa/32 and C:/mesa/64
|
||||
# to C:/mesa/64
|
||||
|
||||
vm_name 'windows-calibre'
|
||||
root 'C:/r'
|
||||
python 'py.exe'
|
||||
python2 'C:/Python27/python.exe'
|
||||
perl 'C:/Strawberry/perl/bin/perl.exe'
|
||||
ruby 'C:/Ruby30-x64/bin/ruby.exe'
|
||||
nodejs 'C:/nodejs/node.exe'
|
||||
ruby 'C:/Ruby32-x64/bin/ruby.exe'
|
||||
nodejs 'C:/Program Files/nodejs/node.exe'
|
||||
mesa 'C:/mesa'
|
||||
|
@ -128,17 +128,21 @@ def freeze(env, ext_dir, incdir):
|
||||
|
||||
printf('\tAdding misc binary deps')
|
||||
|
||||
def copybin(x):
|
||||
shutil.copy2(x, env.dll_dir)
|
||||
def copybin(x, dest=env.dll_dir):
|
||||
shutil.copy2(x, dest)
|
||||
with contextlib.suppress(FileNotFoundError):
|
||||
shutil.copy2(x + '.manifest', env.dll_dir)
|
||||
shutil.copy2(x + '.manifest', dest)
|
||||
|
||||
bindir = os.path.join(PREFIX, 'bin')
|
||||
for x in ('pdftohtml', 'pdfinfo', 'pdftoppm', 'pdftotext', 'jpegtran-calibre', 'cjpeg-calibre', 'optipng-calibre', 'JXRDecApp-calibre'):
|
||||
for x in ('pdftohtml', 'pdfinfo', 'pdftoppm', 'pdftotext', 'jpegtran-calibre', 'cjpeg-calibre', 'optipng-calibre', 'cwebp-calibre', 'JXRDecApp-calibre'):
|
||||
copybin(os.path.join(bindir, x + '.exe'))
|
||||
for f in glob.glob(os.path.join(bindir, '*.dll')):
|
||||
if re.search(r'(easylzma|icutest)', f.lower()) is None:
|
||||
copybin(f)
|
||||
ossm = os.path.join(env.dll_dir, 'ossl-modules')
|
||||
os.mkdir(ossm)
|
||||
for f in glob.glob(os.path.join(PREFIX, 'lib', 'ossl-modules', '*.dll')):
|
||||
copybin(f, ossm)
|
||||
|
||||
copybin(os.path.join(env.python_base, 'python%s.dll' % env.py_ver.replace('.', '')))
|
||||
copybin(os.path.join(env.python_base, 'python%s.dll' % env.py_ver[0]))
|
||||
@ -315,6 +319,7 @@ def build_portable_installer(env):
|
||||
'Ole32.lib', 'Shlwapi.lib', 'Kernel32.lib', 'Psapi.lib']
|
||||
run(*cmd)
|
||||
os.remove(zf)
|
||||
os.remove(manifest)
|
||||
|
||||
|
||||
def build_portable(env):
|
||||
@ -496,6 +501,7 @@ def build_launchers(env, incdir, debug=False):
|
||||
'/LIBPATH:' + env.obj_dir, '/SUBSYSTEM:' + subsys,
|
||||
'/LIBPATH:%s/libs' % env.python_base, '/RELEASE',
|
||||
'/MANIFEST:EMBED', '/MANIFESTINPUT:' + mf,
|
||||
'/STACK:2097152', # Set stack size to 2MB which is what python expects. Default on windows is 1MB
|
||||
'user32.lib', 'kernel32.lib',
|
||||
'/OUT:' + exe] + u32 + dlflags + [embed_resources(env, exe), dest, lib]
|
||||
run(*cmd)
|
||||
@ -570,7 +576,7 @@ def main():
|
||||
run_tests(os.path.join(env.base, 'calibre-debug.exe'), env.base)
|
||||
if args.sign_installers:
|
||||
sign_executables(env)
|
||||
create_installer(env)
|
||||
create_installer(env, args.compression_level)
|
||||
build_portable(env)
|
||||
build_portable_installer(env)
|
||||
if args.sign_installers:
|
||||
|
@ -1,9 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization">
|
||||
<String Id="AdvancedWelcomeEulaDlgDescriptionPerUser">Click Advanced to change installation settings.</String>
|
||||
<String Id="ProgressTextFileCost">Computing space requirements, this may take up to five minutes...</String>
|
||||
<String Id="ProgressTextCostInitialize">Computing space requirements, this may take up to five minutes...</String>
|
||||
<String Id="ProgressTextCostFinalize">Computing space requirements, this may take up to five minutes...</String>
|
||||
<String Id="WaitForCostingDlgText">Please wait while the installer finishes determining your disk space requirements, this may take up to five minutes...</String>
|
||||
<WixLocalization Culture="en-us" xmlns="http://wixtoolset.org/schemas/v4/wxl">
|
||||
<String Id="AdvancedWelcomeEulaDlgDescriptionPerUser" Value="Click Advanced to change installation settings." />
|
||||
<String Id="ProgressTextFileCost" Value="Computing space requirements, this may take up to five minutes..." />
|
||||
<String Id="ProgressTextCostInitialize" Value="Computing space requirements, this may take up to five minutes..." />
|
||||
<String Id="ProgressTextCostFinalize" Value="Computing space requirements, this may take up to five minutes..." />
|
||||
<String Id="WaitForCostingDlgText" Value="Please wait while the installer finishes determining your disk space requirements, this may take up to five minutes..." />
|
||||
</WixLocalization>
|
||||
|
||||
|
@ -60,6 +60,16 @@ def set_quit():
|
||||
builtins.exit = _sitebuiltins.Quitter('exit', eof)
|
||||
|
||||
|
||||
def workaround_lxml_bug():
|
||||
# Without calling xmlInitParser() import lxml causes a segfault
|
||||
import ctypes
|
||||
x = ctypes.WinDLL('libxml2.dll')
|
||||
x.xmlInitParser()
|
||||
workaround_lxml_bug.libxml2 = x
|
||||
from lxml import etree
|
||||
del etree
|
||||
|
||||
|
||||
def main():
|
||||
sys.meta_path.insert(0, PydImporter())
|
||||
os.add_dll_directory(os.path.abspath(os.path.join(sys.app_dir, 'app', 'bin')))
|
||||
@ -75,6 +85,8 @@ def main():
|
||||
set_helper()
|
||||
set_quit()
|
||||
|
||||
workaround_lxml_bug()
|
||||
|
||||
return run_entry_point()
|
||||
|
||||
|
||||
|
@ -43,6 +43,8 @@ get_app_dirw(void) {
|
||||
static void
|
||||
get_install_locations(void) {
|
||||
get_app_dirw();
|
||||
_snwprintf_s(qt_prefix_dir, MAX_PATH-1, _TRUNCATE, L"%ls\\ossl-modules", interpreter_data.executables_path);
|
||||
_wputenv_s(L"OPENSSL_MODULES", qt_prefix_dir);
|
||||
_snwprintf_s(qt_prefix_dir, MAX_PATH-1, _TRUNCATE, L"%ls\\app", interpreter_data.app_dir);
|
||||
_wputenv_s(L"CALIBRE_QT_PREFIX", qt_prefix_dir);
|
||||
}
|
||||
|
@ -1,13 +1,8 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi' xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"
|
||||
>
|
||||
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util" xmlns:ui="http://wixtoolset.org/schemas/v4/wxs/ui">
|
||||
|
||||
<Product Name='{app}{x64}' Id='*' UpgradeCode='{upgrade_code}' Language='1033' Codepage='1252' Version='{version}' Manufacturer='Kovid Goyal'>
|
||||
<Package Name="{app}{x64}" UpgradeCode="{upgrade_code}" Language="1033" Codepage="1252" Version="{version}" Manufacturer="Kovid Goyal" InstallerVersion="300" Scope="perMachine">
|
||||
|
||||
<Package Id='*' Keywords='Installer' Description="{app} Installer"
|
||||
Comments='{app} is a registered trademark of Kovid Goyal' Manufacturer='Kovid Goyal'
|
||||
InstallerVersion='300' Languages='1033' Compressed='yes'
|
||||
SummaryCodepage='1252' />
|
||||
<SummaryInformation Keywords="Installer" Description="{app} Installer" Manufacturer="Kovid Goyal" />
|
||||
|
||||
<!-- Disable creation of system restore points on calibre installs. Speeds
|
||||
up the install. We dont need system restore since we dont install any
|
||||
@ -24,7 +19,7 @@
|
||||
should always result in a consistent set of files being present in the
|
||||
installation folder, though of course, with Microsoft there are no
|
||||
guarantees of anything. -->
|
||||
<Property Id='REINSTALLMODE' Value='amus'/>
|
||||
<Property Id="REINSTALLMODE" Value="amus" />
|
||||
|
||||
<!-- get the windows build number -->
|
||||
<Property Id="WINDOWSBUILDNUMBER" Secure="yes">
|
||||
@ -32,61 +27,42 @@
|
||||
</Property>
|
||||
|
||||
<Upgrade Id="{upgrade_code}">
|
||||
<UpgradeVersion Maximum="{version}"
|
||||
IncludeMaximum="yes"
|
||||
OnlyDetect="no"
|
||||
Language="1033"
|
||||
MigrateFeatures="yes"
|
||||
Property="OLDPRODUCTFOUND"/>
|
||||
<UpgradeVersion Minimum="{version}"
|
||||
IncludeMinimum="no"
|
||||
OnlyDetect="yes"
|
||||
Language="1033"
|
||||
Property="NEWPRODUCTFOUND"/>
|
||||
<UpgradeVersion Maximum="{version}" IncludeMaximum="yes" OnlyDetect="no" Language="1033" MigrateFeatures="yes" Property="OLDPRODUCTFOUND" />
|
||||
<UpgradeVersion Minimum="{version}" IncludeMinimum="no" OnlyDetect="yes" Language="1033" Property="NEWPRODUCTFOUND" />
|
||||
</Upgrade>
|
||||
<Upgrade Id="BEB2A80D-E902-4DAD-ADF9-8BD2DA42CFE1">
|
||||
<UpgradeVersion Maximum="{version}"
|
||||
IncludeMaximum="yes"
|
||||
OnlyDetect="no"
|
||||
Language="1033"
|
||||
MigrateFeatures="yes"
|
||||
Property="THIRTYTWOBITINSTALLFOUND"/>
|
||||
<UpgradeVersion Maximum="{version}" IncludeMaximum="yes" OnlyDetect="no" Language="1033" MigrateFeatures="yes" Property="THIRTYTWOBITINSTALLFOUND" />
|
||||
</Upgrade>
|
||||
<CustomAction Id="PreventDowngrading" Error="Newer version of {app} already installed. If you want to downgrade you must uninstall {app} first." />
|
||||
|
||||
<Property Id="APPLICATIONFOLDER">
|
||||
<RegistrySearch Id='calibreInstDir' Type='raw'
|
||||
Root='HKLM' Key="Software\{app}{x64}\Installer" Name="InstallPath" />
|
||||
<RegistrySearch Id="calibreInstDir" Type="raw" Root="HKLM" Key="Software\{app}{x64}\Installer" Name="InstallPath" />
|
||||
</Property>
|
||||
|
||||
<Directory Id='TARGETDIR' Name='SourceDir'>
|
||||
<Directory Id='{ProgramFilesFolder}' Name='PFiles'>
|
||||
<!-- The name must be calibre on 32 bit to ensure
|
||||
that the component guids dont change compared to previous msis.
|
||||
However, on 64 bit it must be Calibre2 otherwise by default it
|
||||
will install to C:\Program Files\calibre -->
|
||||
<Directory Id='APPLICATIONFOLDER' Name="{appfolder}" />
|
||||
</Directory>
|
||||
<Directory Id="ProgramMenuFolder">
|
||||
<Directory Id="ApplicationProgramsFolder" Name="{app}{x64} - E-book Management"/>
|
||||
</Directory>
|
||||
<Directory Id="DesktopFolder" Name="Desktop"/>
|
||||
</Directory>
|
||||
|
||||
|
||||
<Icon Id="main_icon" SourceFile="{main_icon}" />
|
||||
<!-- <Icon Id="viewer_icon" SourceFile="{viewer_icon}"/> -->
|
||||
<!-- <Icon Id="editor_icon" SourceFile="{editor_icon}"/> -->
|
||||
|
||||
<StandardDirectory Id="ProgramFiles64Folder">
|
||||
<Directory Id="APPLICATIONFOLDER" Name="Calibre2" />
|
||||
</StandardDirectory>
|
||||
<StandardDirectory Id="ProgramMenuFolder">
|
||||
<Directory Id="ApplicationProgramsFolder" Name="{app}{x64} - E-book Management" />
|
||||
</StandardDirectory>
|
||||
<StandardDirectory Id="DesktopFolder" />
|
||||
|
||||
<DirectoryRef Id="APPLICATIONFOLDER">
|
||||
{app_components}
|
||||
<Component Id="AddToPath" Guid="*">
|
||||
<Environment Id='UpdatePath' Name='PATH' Action='set' System='yes' Part='last' Value='[APPLICATIONFOLDER]' />
|
||||
<Component Id="AddToPath">
|
||||
<Environment Id="UpdatePath" Name="PATH" Action="set" System="yes" Part="last" Value="[APPLICATIONFOLDER]" />
|
||||
<RegistryValue Root="HKCU" Key="Software\Microsoft\{app}{x64}" Name="system_path_updated" Type="integer" Value="1" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="RememberInstallDir" Guid="*">
|
||||
<Component Id="RememberInstallDir">
|
||||
<RegistryValue Root="HKLM" Key="Software\{app}{x64}\Installer" Name="InstallPath" Type="string" Value="[APPLICATIONFOLDER]" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="calibreProtocol" Guid="*">
|
||||
<Component Id="calibreProtocol">
|
||||
<RegistryKey Root="HKCR" Key="calibre" ForceDeleteOnUninstall="yes">
|
||||
<RegistryValue Type="string" Value="URL:calibre Protocol" KeyPath="yes" />
|
||||
<RegistryValue Type="string" Name="URL Protocol" Value="" />
|
||||
@ -101,71 +77,46 @@
|
||||
</DirectoryRef>
|
||||
|
||||
<DirectoryRef Id="ApplicationProgramsFolder">
|
||||
<Component Id="StartMenuShortcuts" Guid="*">
|
||||
<Shortcut Id="s1" Name="{app}{x64} - E-book management"
|
||||
Description="Manage your e-book collection, read or edit your e-books and download news"
|
||||
Target="[#{exe_map[calibre]}]"
|
||||
WorkingDirectory="APPLICATIONROOTDIRECTORY" />
|
||||
<Shortcut Id="s2" Name="E-book viewer{x64}"
|
||||
Description="Viewer for all the major e-book formats"
|
||||
Target="[#{exe_map[ebook-viewer]}]"
|
||||
WorkingDirectory="APPLICATIONROOTDIRECTORY" />
|
||||
<Shortcut Id="s4" Name="Edit E-book{x64}"
|
||||
Description="Edit e-books"
|
||||
Target="[#{exe_map[ebook-edit]}]"
|
||||
WorkingDirectory="APPLICATIONROOTDIRECTORY" />
|
||||
<Shortcut Id="s3" Name="LRF viewer{x64}"
|
||||
Description="Viewer for LRF format e-books"
|
||||
Target="[#{exe_map[lrfviewer]}]"
|
||||
WorkingDirectory="APPLICATIONROOTDIRECTORY" />
|
||||
<util:InternetShortcut Id="OnlineDocumentationShortcut"
|
||||
Name="User Manual" Type="url"
|
||||
Target="https://manual.calibre-ebook.com"/>
|
||||
<util:InternetShortcut Id="GetInvolvedS"
|
||||
Name="Get Involved" Type="url"
|
||||
Target="https://calibre-ebook.com/get-involved"/>
|
||||
<Component Id="StartMenuShortcuts">
|
||||
<Shortcut Id="s1" Name="{app}{x64} - E-book management" Description="Manage your e-book collection, read or edit your e-books and download news" Target="[#{exe_map[calibre]}]" WorkingDirectory="APPLICATIONFOLDER" />
|
||||
<Shortcut Id="s2" Name="E-book viewer{x64}" Description="Viewer for all the major e-book formats" Target="[#{exe_map[ebook-viewer]}]" WorkingDirectory="APPLICATIONFOLDER" />
|
||||
<Shortcut Id="s4" Name="Edit E-book{x64}" Description="Edit e-books" Target="[#{exe_map[ebook-edit]}]" WorkingDirectory="APPLICATIONFOLDER" />
|
||||
<Shortcut Id="s3" Name="LRF viewer{x64}" Description="Viewer for LRF format e-books" Target="[#{exe_map[lrfviewer]}]" WorkingDirectory="APPLICATIONFOLDER" />
|
||||
<util:InternetShortcut Id="OnlineDocumentationShortcut" Name="User Manual" Type="url" Target="https://manual.calibre-ebook.com" />
|
||||
<util:InternetShortcut Id="GetInvolvedS" Name="Get Involved" Type="url" Target="https://calibre-ebook.com/get-involved" />
|
||||
|
||||
<RemoveFolder Id="ApplicationProgramsFolder" On="uninstall" />
|
||||
<RegistryValue Root="HKCU" Key="Software\Microsoft\{app}{x64}" Name="start_menu_shortcuts_installed" Type="integer" Value="1" KeyPath="yes" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<DirectoryRef Id="DesktopFolder">
|
||||
<Component Id="DesktopShortcut" Guid="*">
|
||||
<Shortcut Id="ds1" Name="{app}{x64} - E-book management"
|
||||
Description="Manage your e-book collection, read or edit your e-books and download news"
|
||||
Target="[#{exe_map[calibre]}]"
|
||||
WorkingDirectory="APPLICATIONROOTDIRECTORY" />
|
||||
<StandardDirectory Id="DesktopFolder">
|
||||
<Component Id="DesktopShortcut">
|
||||
<Shortcut Id="ds1" Name="{app}{x64} - E-book management" Description="Manage your e-book collection, read or edit your e-books and download news" Target="[#{exe_map[calibre]}]" WorkingDirectory="APPLICATIONFOLDER" />
|
||||
<RegistryValue Root="HKCU" Key="Software\Microsoft\{app}{x64}" Name="desktop_shortcut_installed" Type="integer" Value="1" KeyPath="yes" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
</StandardDirectory>
|
||||
|
||||
|
||||
<Feature Id="Complete" Title="{app}" Display="expand" Level="1"
|
||||
ConfigurableDirectory="APPLICATIONFOLDER">
|
||||
<Feature Id="Complete" Title="{app}" Display="expand" Level="1" ConfigurableDirectory="APPLICATIONFOLDER">
|
||||
|
||||
<Feature Id="MainApplication" Title="Program Files" Level="1"
|
||||
Description="All the files needed to run {app}" Absent="disallow">
|
||||
<Feature Id="MainApplication" Title="Program Files" Level="1" Description="All the files needed to run {app}" AllowAbsent="no">
|
||||
<ComponentRef Id="RememberInstallDir" />
|
||||
</Feature>
|
||||
|
||||
<Feature Id="FSMS" Title="Start menu shortcuts" Level="1"
|
||||
Description="Program shortcuts installed in the Start Menu">
|
||||
<Feature Id="FSMS" Title="Start menu shortcuts" Level="1" Description="Program shortcuts installed in the Start Menu">
|
||||
<ComponentRef Id="StartMenuShortcuts" />
|
||||
</Feature>
|
||||
|
||||
<Feature Id="DS" Title="Shortcut on desktop" Level="1"
|
||||
Description="Shortcut to {app} on your desktop">
|
||||
<Feature Id="DS" Title="Shortcut on desktop" Level="1" Description="Shortcut to {app} on your desktop">
|
||||
<ComponentRef Id="DesktopShortcut" />
|
||||
</Feature>
|
||||
|
||||
<Feature Id="FAddToPath" Title="Add install directory to path" Level="1"
|
||||
Description="Add installation directory to PATH. Makes using command line tools easier">
|
||||
<Feature Id="FAddToPath" Title="Add install directory to path" Level="1" Description="Add installation directory to PATH. Makes using command line tools easier">
|
||||
<ComponentRef Id="AddToPath" />
|
||||
</Feature>
|
||||
|
||||
<Feature Id="FcalibreProtocol" Title="Register calibre:// URLs" Level="1"
|
||||
Description="Register to handle URLs starting with calibre://">
|
||||
<Feature Id="FcalibreProtocol" Title="Register calibre:// URLs" Level="1" Description="Register to handle URLs starting with calibre://">
|
||||
<ComponentRef Id="calibreProtocol" />
|
||||
</Feature>
|
||||
</Feature>
|
||||
@ -173,64 +124,56 @@
|
||||
<!-- Add icon to entry in Add/Remove programs -->
|
||||
<Property Id="ARPPRODUCTICON" Value="main_icon" />
|
||||
<Property Id="ARPURLINFOABOUT" Value="https://calibre-ebook.com" />
|
||||
<Property Id='ARPHELPLINK' Value="https://calibre-ebook.com/help" />
|
||||
<Property Id='ARPURLUPDATEINFO' Value="https://calibre-ebook.com/download_windows" />
|
||||
<Property Id="ARPHELPLINK" Value="https://calibre-ebook.com/help" />
|
||||
<Property Id="ARPURLUPDATEINFO" Value="https://calibre-ebook.com/download_windows" />
|
||||
<SetProperty Id="ARPINSTALLLOCATION" Value="[APPLICATIONFOLDER]" After="CostFinalize" />
|
||||
|
||||
<Condition Message="calibre requires Windows 10 or newer.">
|
||||
<!-- See https://en.wikipedia.org/wiki/Windows_10_version_history for build numbers -->
|
||||
<![CDATA[Installed OR (WINDOWSBUILDNUMBER >= 10240)]]>
|
||||
</Condition>
|
||||
|
||||
<Launch Condition="Installed OR (WINDOWSBUILDNUMBER >= 10240)" Message="calibre requires Windows 10 or newer." />
|
||||
<!-- On 64 bit installers there is a bug in WiX that causes the
|
||||
WixSetDefaultPerMachineFolder action to incorrectly set
|
||||
APPLICATIONFOLDER to the x86 value, so we override it. See
|
||||
http://stackoverflow.com/questions/5479790/wix-how-to-override-c-program-files-x86-on-x64-machine-in-wixui-advanced-s
|
||||
-->
|
||||
<CustomAction
|
||||
Id="OverwriteWixSetDefaultPerMachineFolder"
|
||||
Property="WixPerMachineFolder"
|
||||
Value="[APPLICATIONFOLDER]"
|
||||
Execute="immediate"
|
||||
/>
|
||||
<CustomAction Id="OverwriteWixSetDefaultPerMachineFolder" Property="WixPerMachineFolder" Value="[APPLICATIONFOLDER]" Execute="immediate" />
|
||||
|
||||
<InstallExecuteSequence>
|
||||
<Custom Action="PreventDowngrading" After="FindRelatedProducts">NEWPRODUCTFOUND</Custom>
|
||||
{fix_wix}
|
||||
<Custom Action="PreventDowngrading" After="FindRelatedProducts" Condition="NEWPRODUCTFOUND" />
|
||||
<Custom Action="OverwriteWixSetDefaultPerMachineFolder" After="WixSetDefaultPerMachineFolder" />
|
||||
<RemoveExistingProducts After="InstallFinalize" />
|
||||
</InstallExecuteSequence>
|
||||
<InstallUISequence>
|
||||
<Custom Action="PreventDowngrading" After="FindRelatedProducts">NEWPRODUCTFOUND</Custom>
|
||||
{fix_wix}
|
||||
<Custom Action="PreventDowngrading" After="FindRelatedProducts" Condition="NEWPRODUCTFOUND" />
|
||||
<Custom Action="OverwriteWixSetDefaultPerMachineFolder" After="WixSetDefaultPerMachineFolder" />
|
||||
</InstallUISequence>
|
||||
|
||||
<UI>
|
||||
<UIRef Id="WixUI_Advanced" />
|
||||
<ui:WixUI Id="WixUI_Advanced" />
|
||||
<UIRef Id="WixUI_ErrorProgressText" />
|
||||
<Publish Dialog="ExitDialog"
|
||||
Control="Finish"
|
||||
Event="DoAction"
|
||||
Value="LaunchApplication">WIXUI_EXITDIALOGOPTIONALCHECKBOX = 1 and NOT Installed</Publish>
|
||||
<Publish Dialog="ExitDialog" Control="Finish" Event="DoAction" Value="LaunchApplication" Condition="WIXUI_EXITDIALOGOPTIONALCHECKBOX = 1 and NOT Installed" />
|
||||
|
||||
</UI>
|
||||
|
||||
<!--
|
||||
Set default folder name and allow only per machine installs.
|
||||
For a per-machine installation, the default installation location
|
||||
will be [ProgramFilesFolder][ApplicationFolderName] and the user
|
||||
will be able to change it in the setup UI. This is no longer necessary
|
||||
(i.e. per user installs should work) but left this way as I
|
||||
dont want to deal with the complications
|
||||
Set default folder name. For a per-machine installation, the default
|
||||
installation location will be [ProgramFilesFolder][ApplicationFolderName]
|
||||
and the user will be able to change it in the setup UI.
|
||||
-->
|
||||
<Property Id="ApplicationFolderName" Value="Calibre2" />
|
||||
<Property Id="WixAppFolder" Value="WixPerMachineFolder" />
|
||||
<Property Id="ALLUSERS" Value="1" />
|
||||
<WixVariable Id="WixUISupportPerUser" Value="0" />
|
||||
|
||||
<!-- Add option to launch calibre after install -->
|
||||
<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT" Value="Launch {app}" />
|
||||
<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOX" Value="1" />
|
||||
<Property Id="WixShellExecTarget" Value="[#{exe_map[calibre]}]" />
|
||||
<CustomAction Id="LaunchApplication" BinaryKey="WixCA" DllEntry="WixShellExec" Impersonate="yes"/>
|
||||
<CustomAction Id="LaunchApplication" DllEntry="WixShellExec" Impersonate="yes" BinaryRef="Wix4UtilCA_X86" />
|
||||
|
||||
</Product>
|
||||
<!-- UI -->
|
||||
<WixVariable Id="WixUILicenseRtf" Value="{license}" />
|
||||
<WixVariable Id="WixUIBannerBmp" Value="{banner}" />
|
||||
<WixVariable Id="WixUIDialogBmp" Value="{dialog}" />
|
||||
|
||||
</Package>
|
||||
</Wix>
|
||||
|
@ -9,19 +9,22 @@ import shutil
|
||||
from bypy.constants import is64bit
|
||||
from bypy.utils import run
|
||||
|
||||
WIXP = r'C:\Program Files (x86)\WiX Toolset v3.14'
|
||||
WIX = os.path.expanduser('~/.dotnet/tools/wix.exe')
|
||||
if is64bit:
|
||||
UPGRADE_CODE = '5DD881FF-756B-4097-9D82-8C0F11D521EA'
|
||||
else:
|
||||
UPGRADE_CODE = 'BEB2A80D-E902-4DAD-ADF9-8BD2DA42CFE1'
|
||||
calibre_constants = globals()['calibre_constants']
|
||||
|
||||
CANDLE = WIXP + r'\bin\candle.exe'
|
||||
LIGHT = WIXP + r'\bin\light.exe'
|
||||
j, d, a, b = os.path.join, os.path.dirname, os.path.abspath, os.path.basename
|
||||
|
||||
|
||||
def create_installer(env):
|
||||
def create_installer(env, compression_level='9'):
|
||||
cl = int(compression_level)
|
||||
if cl > 4:
|
||||
dcl = 'high'
|
||||
else:
|
||||
dcl = {1: 'none', 2: 'low', 3: 'medium', 4: 'mszip'}[cl]
|
||||
if os.path.exists(env.installer_dir):
|
||||
shutil.rmtree(env.installer_dir)
|
||||
os.makedirs(env.installer_dir)
|
||||
@ -32,12 +35,9 @@ def create_installer(env):
|
||||
components, smap = get_components_from_files(env)
|
||||
wxs = template.format(
|
||||
app=calibre_constants['appname'],
|
||||
appfolder='Calibre2' if is64bit else 'Calibre',
|
||||
version=calibre_constants['version'],
|
||||
upgrade_code=UPGRADE_CODE,
|
||||
ProgramFilesFolder='ProgramFiles64Folder' if is64bit else 'ProgramFilesFolder',
|
||||
x64=' 64bit' if is64bit else '',
|
||||
fix_wix='<Custom Action="OverwriteWixSetDefaultPerMachineFolder" After="WixSetDefaultPerMachineFolder" />' if is64bit else '',
|
||||
compression='high',
|
||||
app_components=components,
|
||||
exe_map=smap,
|
||||
@ -45,6 +45,9 @@ def create_installer(env):
|
||||
viewer_icon=j(env.src_root, 'icons', 'viewer.ico'),
|
||||
editor_icon=j(env.src_root, 'icons', 'ebook-edit.ico'),
|
||||
web_icon=j(env.src_root, 'icons', 'web.ico'),
|
||||
license=j(env.src_root, 'LICENSE.rtf'),
|
||||
banner=j(env.src_root, 'icons', 'wix-banner.bmp'),
|
||||
dialog=j(env.src_root, 'icons', 'wix-dialog.bmp'),
|
||||
)
|
||||
with open(j(d(__file__), 'en-us.xml'), 'rb') as f:
|
||||
template = f.read().decode('utf-8')
|
||||
@ -56,30 +59,16 @@ def create_installer(env):
|
||||
f.write(wxs.encode('utf-8'))
|
||||
with open(enusf, 'wb') as f:
|
||||
f.write(enus.encode('utf-8'))
|
||||
wixobj = j(env.installer_dir, calibre_constants['appname'] + '.wixobj')
|
||||
arch = 'x64' if is64bit else 'x86'
|
||||
cmd = [CANDLE, '-nologo', '-arch', arch, '-ext', 'WiXUtilExtension', '-o', wixobj, wxsf]
|
||||
run(*cmd)
|
||||
installer = j(env.dist, '%s%s-%s.msi' % (
|
||||
calibre_constants['appname'], ('-64bit' if is64bit else ''), calibre_constants['version']))
|
||||
license = j(env.src_root, 'LICENSE.rtf')
|
||||
banner = j(env.src_root, 'icons', 'wix-banner.bmp')
|
||||
dialog = j(env.src_root, 'icons', 'wix-dialog.bmp')
|
||||
cmd = [LIGHT, '-nologo', '-ext', 'WixUIExtension',
|
||||
'-cultures:en-us', '-loc', enusf, wixobj,
|
||||
'-ext', 'WixUtilExtension',
|
||||
'-o', installer,
|
||||
'-dWixUILicenseRtf=' + license,
|
||||
'-dWixUIBannerBmp=' + banner,
|
||||
'-dWixUIDialogBmp=' + dialog]
|
||||
cmd.extend([
|
||||
'-sice:ICE60', # No language in dlls warning
|
||||
'-sice:ICE61', # Allow upgrading with same version number
|
||||
'-sice:ICE40', # Re-install mode overridden
|
||||
'-sice:ICE69', # Shortcut components are part of a different feature than the files they point to
|
||||
])
|
||||
cmd.append('-sval') # Disable all checks since they fail when running under ssh
|
||||
run(WIX, 'extension', 'add', '-g', 'WixToolset.Util.wixext')
|
||||
run(WIX, 'extension', 'add', '-g', 'WixToolset.UI.wixext')
|
||||
cmd = [WIX, 'build', '-arch', arch, '-culture', 'en-us', '-loc', enusf, '-dcl', dcl,
|
||||
'-ext', 'WixToolset.Util.wixext', '-ext', 'WixToolset.UI.wixext', '-o', installer, wxsf]
|
||||
run(*cmd)
|
||||
pdb = installer.rpartition('.')[0] + '.wixpdb'
|
||||
os.remove(pdb)
|
||||
|
||||
|
||||
def get_components_from_files(env):
|
||||
|
@ -1,11 +1 @@
|
||||
<svg width="512" height="512" version="1.1" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="#2271d5">
|
||||
<path d="m140 191.1v159.6c0 31.26 12.31 61.09 34.1 83.35 22.26 22.73 51.62 35.52 82.4 35.52h2.367c62.99-0.4766 114.1-52.57 114.1-116v-162.4c0-54.93-44.99-99.93-99.93-99.93h-33.62c-54.46 0-99.45 44.99-99.45 99.93zm25.1 0c0-41.2 33.62-74.82 74.82-74.82h4.262v37.41c3.789-1.422 8.051-1.894 12.31-1.894h0.4727c4.262 0 8.523 0.4727 12.31 1.894v-37.41h4.262c41.2 0 74.82 33.62 74.82 74.82v35.52h-51.61v25.1h51.62v101.8c0 49.73-40.25 90.45-89.98 91.4h-1.894c-24.15 0-47.36-9.945-64.88-27.94-17.52-18-26.99-41.2-26.99-66.3v-99.45h51.62v-25.1l-51.15-4e-3z" fill="#2271d5"/>
|
||||
<path d="m256.7 166.3c-13.99 3.4e-4 -25.34 11.34-25.34 25.34 0.4409 0.4239 0 72.7 0 72.7 3.4e-4 13.99 11.34 25.34 25.34 25.34 13.99-3.4e-4 25.34-11.34 25.34-25.34v-72.7c-3.4e-4 -13.99-11.34-25.34-25.34-25.34z"/>
|
||||
</g>
|
||||
<g fill="#2caf45">
|
||||
<path d="m375.8 121 24.15-13.73c4.262-2.367 9.473-0.9453 11.84 3.316 2.367 4.262 0.9453 9.473-3.316 11.84l-23.68 13.73c-2.367 1.422-5.684 0.4727-7.106-1.894-0.9453-1.894-2.367-3.789-3.316-5.684-1.887-2.371-1.414-5.684 1.426-7.578z"/>
|
||||
<path d="m352.1 103c-1.894-1.422-3.316-2.84-5.211-4.262-2.367-1.894-2.84-5.211-0.9453-7.578l18-21.31c3.316-3.789 8.523-4.262 12.31-0.9453 3.789 3.316 4.262 8.523 0.9453 12.31l-17.52 21.31c-2.363 2.367-5.68 2.367-7.574 0.4727z"/>
|
||||
<path d="m317.6 82.2c-1.894-0.9453-4.262-1.422-6.156-2.367-2.84-0.9453-4.262-3.789-3.316-6.629l9.473-26.05c1.422-4.734 6.629-6.629 10.89-5.211 4.734 1.422 6.629 6.629 5.211 10.89l-9.473 26.05c-0.9453 3.316-4.262 4.738-6.629 3.316z"/>
|
||||
</g>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" version="1.1" viewBox="0 0 512 512"><g fill="#2271d5"><path fill="#2271d5" d="m140 191.1v159.6c0 31.26 12.31 61.09 34.1 83.35 22.26 22.73 51.62 35.52 82.4 35.52h2.367c62.99-0.4766 114.1-52.57 114.1-116v-162.4c0-54.93-44.99-99.93-99.93-99.93h-33.62c-54.46 0-99.45 44.99-99.45 99.93zm25.1 0c0-41.2 33.62-74.82 74.82-74.82h4.262v37.41c3.789-1.422 8.051-1.894 12.31-1.894h0.4727c4.262 0 8.523 0.4727 12.31 1.894v-37.41h4.262c41.2 0 74.82 33.62 74.82 74.82v35.52h-51.61v25.1h51.62v101.8c0 49.73-40.25 90.45-89.98 91.4h-1.894c-24.15 0-47.36-9.945-64.88-27.94-17.52-18-26.99-41.2-26.99-66.3v-99.45h51.62v-25.1l-51.15-4e-3z"/><path d="m256.7 166.3c-13.99 3.4e-4 -25.34 11.34-25.34 25.34 0.4409 0.4239 0 72.7 0 72.7 3.4e-4 13.99 11.34 25.34 25.34 25.34 13.99-3.4e-4 25.34-11.34 25.34-25.34v-72.7c-3.4e-4 -13.99-11.34-25.34-25.34-25.34z"/></g><g fill="#2caf45"><path d="m375.8 121 24.15-13.73c4.262-2.367 9.473-0.9453 11.84 3.316 2.367 4.262 0.9453 9.473-3.316 11.84l-23.68 13.73c-2.367 1.422-5.684 0.4727-7.106-1.894-0.9453-1.894-2.367-3.789-3.316-5.684-1.887-2.371-1.414-5.684 1.426-7.578z"/><path d="m352.1 103c-1.894-1.422-3.316-2.84-5.211-4.262-2.367-1.894-2.84-5.211-0.9453-7.578l18-21.31c3.316-3.789 8.523-4.262 12.31-0.9453 3.789 3.316 4.262 8.523 0.9453 12.31l-17.52 21.31c-2.363 2.367-5.68 2.367-7.574 0.4727z"/><path d="m317.6 82.2c-1.894-0.9453-4.262-1.422-6.156-2.367-2.84-0.9453-4.262-3.789-3.316-6.629l9.473-26.05c1.422-4.734 6.629-6.629 10.89-5.211 4.734 1.422 6.629 6.629 5.211 10.89l-9.473 26.05c-0.9453 3.316-4.262 4.738-6.629 3.316z"/></g></svg>
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
1
imgsrc/external-link-for-dark-theme.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1792" height="1792" viewBox="0 0 1792 1792"><path fill="#6cb4ee" d="M1408 928v-480q0-26-19-45t-45-19h-480q-42 0-59 39-17 41 14 70l144 144-534 534q-19 19-19 45t19 45l102 102q19 19 45 19t45-19l534-534 144 144q18 19 45 19 12 0 25-5 39-17 39-59zm256-512v960q0 119-84.5 203.5t-203.5 84.5h-960q-119 0-203.5-84.5t-84.5-203.5v-960q0-119 84.5-203.5t203.5-84.5h960q119 0 203.5 84.5t84.5 203.5z"/></svg>
|
After Width: | Height: | Size: 439 B |
1
imgsrc/external-link.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1792" height="1792" viewBox="0 0 1792 1792"><path fill="#00f" d="M1408 928v-480q0-26-19-45t-45-19h-480q-42 0-59 39-17 41 14 70l144 144-534 534q-19 19-19 45t19 45l102 102q19 19 45 19t45-19l534-534 144 144q18 19 45 19 12 0 25-5 39-17 39-59zm256-512v960q0 119-84.5 203.5t-203.5 84.5h-960q-119 0-203.5-84.5t-84.5-203.5v-960q0-119 84.5-203.5t203.5-84.5h960q119 0 203.5 84.5t84.5 203.5z"/></svg>
|
After Width: | Height: | Size: 436 B |
@ -1,8 +1 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg id="svg2" width="128" height="128" version="1.1" viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="layer1" transform="translate(0,-924.36216)">
|
||||
<path id="path6-6" d="m 125.24493,1000.8422 c -1.58744,-2.02755 -4.0872,-3.04529 -6.68579,-3.04529 l -92.131013,0 c -4.627058,0 -8.133024,2.79579 -9.368384,7.20509 0,0 0,-0.1661 0,-0.1655 l -12.79591,46.5257 107.224077,0 c 2.20513,0 4.13539,-1.6265 4.69439,-3.7283 l 10.54507,-39.6145 c 0.65969,-2.4768 0.10562,-5.1496 -1.48244,-7.1772 z" style="fill-opacity: 1; fill: rgb(34, 113, 213);"/>
|
||||
<path id="path8" d="m 26.428127,993.53604 16.838636,0 3.520788,0 2.391666,0 0,-60.52687 c 0,-2.32704 3.251479,-2.16878 3.657297,-2.16878 l 42.324205,0 c 1.229805,0.6087 1.580031,0.36096 1.580031,1.59235 l 0,8.90765 c 0,2.83531 2.821573,6.54348 5.73703,6.54348 l 7.43875,0 c 1.36137,0 2.26628,-0.39322 2.26628,1.14922 l 0,44.50295 4.94145,0 0,-47.44478 c 0,-1.92165 -0.19518,-4.36922 -2.03155,-6.2513 l -12.0899,-12.17818 c -1.59732,-1.63739 -3.665941,-2.29965 -6.366448,-2.29965 l -43.799848,0 c -4.601733,0 -9.216437,2.75861 -9.216437,7.64704 l 0,31.42757 c -4.323776,-0.5387 -8.42951,-1.9107 -10.14852,-6.02791 -1.030294,-2.46887 -3.200211,-4.438 -5.909366,-4.438 l -21.052468,0 C 3.588093,953.97083 1,956.23944 1,959.11857 l 0,7.03104 0,1.13583 0,76.97326 10.921863,-40.1587 c 1.71777,-6.44126 7.748202,-10.56396 14.506264,-10.56396 z" style="fill-opacity: 1; fill: rgb(105, 153, 211);"/>
|
||||
<path id="path6" d="m 95.489615,975.4847 -11.935263,-9.67724 c -0.430099,-0.32257 -0.645149,-0.96772 -0.322574,-1.50535 2.365547,-5.05367 1.505348,-11.18259 -2.688123,-15.37606 -5.591294,-5.59129 -15.053484,-5.26872 -20.214679,1.18278 -3.870896,4.83862 -3.870896,11.82773 -0.107524,16.77388 4.085945,5.16119 10.967538,6.45149 16.451307,3.8709 0.537625,-0.21505 1.075249,-0.10753 1.505349,0.32257 l 9.67724,11.93524 c 1.505348,1.82792 4.193471,1.93545 5.806344,0.32258 l 2.258023,-2.25803 c 1.505348,-1.3978 1.397823,-4.08592 -0.4301,-5.59127 z m -17.311507,-9.56971 c -3.978421,3.97842 -10.537439,3.97842 -14.623385,0 -3.978421,-3.97843 -3.978421,-10.53744 0,-14.62339 3.978421,-4.08594 10.537439,-3.97842 14.623385,0 4.085946,4.08595 4.085946,10.64496 0,14.62339 z" style="fill:#2caf45;fill-opacity:1"/>
|
||||
</g>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" id="svg2" width="128" height="128" version="1.1" viewBox="0 0 128 128"><g id="layer1" transform="translate(0,-924.36216)"><path id="path6-6" d="m 125.24493,1000.8422 c -1.58744,-2.02755 -4.0872,-3.04529 -6.68579,-3.04529 l -92.131013,0 c -4.627058,0 -8.133024,2.79579 -9.368384,7.20509 0,0 0,-0.1661 0,-0.1655 l -12.79591,46.5257 107.224077,0 c 2.20513,0 4.13539,-1.6265 4.69439,-3.7283 l 10.54507,-39.6145 c 0.65969,-2.4768 0.10562,-5.1496 -1.48244,-7.1772 z" style="fill-opacity:1;fill:#2271d5"/><path id="path8" d="m 26.428127,993.53604 16.838636,0 3.520788,0 2.391666,0 0,-60.52687 c 0,-2.32704 3.251479,-2.16878 3.657297,-2.16878 l 42.324205,0 c 1.229805,0.6087 1.580031,0.36096 1.580031,1.59235 l 0,8.90765 c 0,2.83531 2.821573,6.54348 5.73703,6.54348 l 7.43875,0 c 1.36137,0 2.26628,-0.39322 2.26628,1.14922 l 0,44.50295 4.94145,0 0,-47.44478 c 0,-1.92165 -0.19518,-4.36922 -2.03155,-6.2513 l -12.0899,-12.17818 c -1.59732,-1.63739 -3.665941,-2.29965 -6.366448,-2.29965 l -43.799848,0 c -4.601733,0 -9.216437,2.75861 -9.216437,7.64704 l 0,31.42757 c -4.323776,-0.5387 -8.42951,-1.9107 -10.14852,-6.02791 -1.030294,-2.46887 -3.200211,-4.438 -5.909366,-4.438 l -21.052468,0 C 3.588093,953.97083 1,956.23944 1,959.11857 l 0,7.03104 0,1.13583 0,76.97326 10.921863,-40.1587 c 1.71777,-6.44126 7.748202,-10.56396 14.506264,-10.56396 z" style="fill-opacity:1;fill:#6999d3"/><path id="path6" d="m 95.489615,975.4847 -11.935263,-9.67724 c -0.430099,-0.32257 -0.645149,-0.96772 -0.322574,-1.50535 2.365547,-5.05367 1.505348,-11.18259 -2.688123,-15.37606 -5.591294,-5.59129 -15.053484,-5.26872 -20.214679,1.18278 -3.870896,4.83862 -3.870896,11.82773 -0.107524,16.77388 4.085945,5.16119 10.967538,6.45149 16.451307,3.8709 0.537625,-0.21505 1.075249,-0.10753 1.505349,0.32257 l 9.67724,11.93524 c 1.505348,1.82792 4.193471,1.93545 5.806344,0.32258 l 2.258023,-2.25803 c 1.505348,-1.3978 1.397823,-4.08592 -0.4301,-5.59127 z m -17.311507,-9.56971 c -3.978421,3.97842 -10.537439,3.97842 -14.623385,0 -3.978421,-3.97843 -3.978421,-10.53744 0,-14.62339 3.978421,-4.08594 10.537439,-3.97842 14.623385,0 4.085946,4.08595 4.085946,10.64496 0,14.62339 z" style="fill:#2caf45;fill-opacity:1"/></g></svg>
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.2 KiB |
1
imgsrc/layout.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" version="1.1" viewBox="0 0 128 128" xml:space="preserve"><path d="m127 15.67v-8.367c0-3.472-2.828-6.299-6.3-6.299h-113.4c-3.472 0-6.3 2.827-6.3 6.299v8.367c0 1.389 1.116 2.529 2.53 2.529h121c1.389 0 2.505-1.116 2.505-2.529z" fill="#0e00c1"/><path d="m92.03 42.79h32.44c1.389 0 2.53 1.116 2.53 2.529v75.35c0 3.472-2.828 6.299-6.3 6.299h-28.67c-1.389 0-2.53-1.116-2.53-2.53v-79.12c0-1.414 1.116-2.529 2.53-2.529z" fill="#803300"/><path d="m82.9 45.32v79.15c0 1.389-1.116 2.53-2.53 2.53h-73.07c-3.472 0-6.3-2.827-6.3-6.299v-75.35c0-1.389 1.116-2.529 2.53-2.529h76.84c1.414-0.02479 2.53 1.091 2.53 2.505z" fill="#3080f0"/><path d="m3.5 25h121c1.385 0 2.5 1.115 2.5 2.5v6c0 1.385-1.115 2.5-2.5 2.5h-121c-1.385 0-2.5-1.115-2.5-2.5v-6c0-1.385 1.115-2.5 2.5-2.5z" fill="#ff8033"/></svg>
|
After Width: | Height: | Size: 843 B |
1
imgsrc/notes-for-dark-theme.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path style="fill:#6cb4ee" d="M491 1536l91-91-235-235-91 91v107h128v128h107zm523-928q0-22-22-22-10 0-17 7l-542 542q-7 7-7 17 0 22 22 22 10 0 17-7l542-542q7-7 7-17zm-54-192l416 416-832 832h-416v-416zm683 96q0 53-37 90l-166 166-416-416 166-165q36-38 90-38 53 0 91 38l235 234q37 39 37 91z"/></svg>
|
After Width: | Height: | Size: 386 B |
1
imgsrc/notes.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path style="fill:blue" d="M491 1536l91-91-235-235-91 91v107h128v128h107zm523-928q0-22-22-22-10 0-17 7l-542 542q-7 7-7 17 0 22 22 22 10 0 17-7l542-542q7-7 7-17zm-54-192l416 416-832 832h-416v-416zm683 96q0 53-37 90l-166 166-416-416 166-165q36-38 90-38 53 0 91 38l235 234q37 39 37 91z"/></svg>
|
After Width: | Height: | Size: 383 B |
1
imgsrc/plugins/plugin_upgrade_ok.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="svg2" width="128" height="128" version="1.1" viewBox="0 0 128 128"><defs id="defs4"><filter style="color-interpolation-filters:sRGB" id="filter4201"><feFlood id="feFlood4203" flood-color="#000" flood-opacity=".498" result="flood"/><feComposite id="feComposite4205" in="flood" in2="SourceGraphic" operator="out" result="composite1"/><feGaussianBlur id="feGaussianBlur4207" in="composite1" result="blur" stdDeviation="1"/><feOffset id="feOffset4209" dx="2" dy="2" result="offset"/><feComposite id="feComposite4211" in="offset" in2="SourceGraphic" operator="atop" result="composite2"/></filter><radialGradient id="radialGradient4151" cx="64" cy="988.362" r="52" fx="64" fy="988.362" gradientTransform="matrix(1,0,0,1.2115383,-83.910714,-146.50501)" gradientUnits="userSpaceOnUse" xlink:href="#linearGradient4145"/><linearGradient id="linearGradient4145"><stop style="stop-color:#7c0000;stop-opacity:1" id="stop4147" offset="0"/><stop style="stop-color:#e20000;stop-opacity:1" id="stop4149" offset="1"/></linearGradient></defs><metadata id="metadata7"/><g id="layer1" transform="translate(0,-924.36216)"><g id="g2640" transform="matrix(1.4101058,0,0,-1.3984462,-8.1269117,1059.7528)" style="fill:#00cc40;fill-opacity:1;filter:url(#filter4201)"><path id="path2642" d="m 23.9,86.9 c 0,-6.6 6,-8.3 6,-14.3 0,-4.3 -2.7,-5.9 -6.7,-6 -4.2,0 -8.3,1.7 -12.4,1.7 l -0.3,0 c 0,-0.6 0,-1.2 -0.1,-1.8 C 9.9,61 8.9,55.4 8.9,49.7 c 0,-3.8 1.5,-7.8 6,-7.8 5.9,0 7.7,6 14.3,6 5.9,0 9.1,-4.7 9.1,-10.2 C 38.3,32 35.2,26.8 28.9,26.8 22,26.8 19.1,32 15.3,32 13.4,32 11.7,30.8 10.5,29.5 8.9,27.8 8.6,25.4 8.6,23.2 c 0,-4.4 0.6,-8.9 1.3,-13.3 0.2,-1 0.3,-2 0.4,-3 l 0.1,-0.7 c 0,-0.1 0,-0.2 0.1,-0.2 l 55.4,0 c -0.2,0.2 -0.5,3.4 -0.6,3.9 -0.7,4.4 -1.3,8.8 -1.3,13.3 0,2.3 0.3,4.6 1.9,6.3 1.2,1.3 2.9,2.5 4.8,2.5 3.7,0 6.7,-5.2 13.6,-5.2 6.2,0 9.4,5.2 9.4,11 0,5.5 -3.2,10.2 -9.1,10.2 -6.6,0 -8.3,-6 -14.3,-6 -4.4,0 -6,4 -6,7.8 0,6.2 1.4,12.4 1.7,18.6 l -0.1,0 c -0.2,-0.2 -3.4,-0.5 -4,-0.7 -4.4,-0.7 -8.8,-1.3 -13.2,-1.3 -2.3,0 -4.6,0.3 -6.3,1.9 -1.3,1.2 -2.5,2.9 -2.5,4.8 0,3.7 5.2,6.7 5.2,13.6 0,6.2 -5.2,9.4 -10.9,9.4 C 28.6,96 23.9,92.8 23.9,86.9 Z" style="fill:#00cc40;fill-opacity:1"/></g></g></svg>
|
After Width: | Height: | Size: 2.3 KiB |
1
imgsrc/srv/external-link.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1792" height="1792" viewBox="0 0 1792 1792"><path d="M1408 928v-480q0-26-19-45t-45-19h-480q-42 0-59 39-17 41 14 70l144 144-534 534q-19 19-19 45t19 45l102 102q19 19 45 19t45-19l534-534 144 144q18 19 45 19 12 0 25-5 39-17 39-59zm256-512v960q0 119-84.5 203.5t-203.5 84.5h-960q-119 0-203.5-84.5t-84.5-203.5v-960q0-119 84.5-203.5t203.5-84.5h960q119 0 203.5 84.5t84.5 203.5z"/></svg>
|
After Width: | Height: | Size: 424 B |
1
imgsrc/srv/fit-to-screen.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M17 4h3c1.1 0 2 .9 2 2v2h-2V6h-3V4zM4 8V6h3V4H4c-1.1 0-2 .9-2 2v2h2zm16 8v2h-3v2h3c1.1 0 2-.9 2-2v-2h-2zM7 18H4v-2H2v2c0 1.1.9 2 2 2h3v-2zM18 8H6v8h12V8z"/></svg>
|
After Width: | Height: | Size: 291 B |
@ -1,26 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
id="SVGRoot"
|
||||
width="128"
|
||||
height="128"
|
||||
version="1.1"
|
||||
viewBox="0 0 128 128"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs10" />
|
||||
<g
|
||||
id="layer1"
|
||||
transform="translate(6.2816136,0.20846979)">
|
||||
<g id="text189">
|
||||
<path
|
||||
d="M 1.336354,0.37399976 H 59.45371 Q 55.982346,4.9651589 54.470623,7.596677 53.01489,10.228195 50.71931,16.051129 l -0.447918,1.119795 Q 46.576069,9.5563181 42.936735,7.3167283 39.353392,5.0771384 30.78696,5.0771384 l -3.191415,0.05599 -5.431005,-0.05599 -2.071621,-0.05599 V 31.22435 h 3.415374 V 8.1005847 l 1.623703,-0.05599 q 3.471364,-0.1679693 7.390647,-0.1679693 11.421908,0 14.277385,5.9349133 -2.743498,-2.631518 -5.990903,-3.527354 -3.191416,-0.9518259 -9.910185,-0.9518259 -2.407559,0 -5.990903,0.2799487 V 31.22435 h 8.454452 l 8.958359,-9.462267 V 45.221786 L 32.914571,35.927488 H 20.092919 V 64.14632 l 7.166687,7.278667 H -0.23135887 L 8.8949697,64.14632 V 40.07073 q -4.3112104,0 -7.5586157,3.247405 L 0.27254884,42.14235 Q 3.5199541,38.559007 8.8949697,38.559007 v -2.631519 q -1.1757846,-0.111979 -1.6796924,-0.111979 -5.2070463,0 -9.0143491,4.255221 L -2.191,39.174894 Q 0.32853859,31.896227 8.8949697,31.22435 V 7.596677 Z M 63.708931,3.7893743 Q 55.702397,13.139662 53.630777,20.922237 L 52.454992,20.13838 Q 54.582602,11.34799 62.701116,2.8375486 Z M 46.4081,23.721724 v 24.18757 L 44.952366,47.069448 V 22.881878 Z M 36.385935,40.630627 H 24.908037 v 23.963611 l 9.854195,12.205765 H 2.3441694 L 0.94442579,75.28828 H 31.626807 L 23.508293,65.266115 V 39.118904 h 11.253939 z"
|
||||
id="path293" />
|
||||
</g>
|
||||
<g id="text301">
|
||||
<path
|
||||
d="m 114.10015,50.782996 q -0.50391,0.951826 -0.67188,1.287764 l -3.8073,6.71877 q -1.95964,3.583344 -3.63934,8.958359 l -0.11198,0.279949 -0.55989,-0.391928 -0.16797,-0.727867 q -1.62371,-6.382831 -4.64715,-8.84638 -2.967459,-2.463549 -9.126331,-2.463549 -2.519539,0 -5.039077,0.223959 h -0.671877 v 60.692887 l 6.60679,6.10288 H 66.676831 l 7.838564,-6.5508 V 60.357243 l -3.975272,-0.05599 q -5.766943,0 -8.230492,2.29558 -2.407559,2.23959 -2.855477,7.950544 H 57.99842 q 0.615888,-6.550801 3.359385,-9.126329 2.799487,-2.575528 9.182318,-2.575528 l 3.359385,0.05599 h 0.615887 v -2.743498 q -2.855477,-0.335939 -5.431005,-0.335939 -7.222677,0 -10.414093,2.967457 -3.191415,2.911467 -3.527354,9.910185 H 54.471066 Q 52.063507,60.91714 47.02443,51.342894 l -0.335938,-0.559898 z m 3.52735,3.527354 q -3.86329,4.927098 -8.11851,16.349006 l -0.22396,0.559898 -1.23178,-1.063806 0.16797,-0.503907 q 4.14324,-11.589878 8.00654,-16.125047 l 0.27994,-0.335939 z m -14.94926,8.734401 q -4.311213,-2.799488 -10.078157,-2.799488 -1.287764,0 -2.687507,0.16797 l 0.223959,56.269697 8.902369,10.52607 h -28.61076 l -1.287764,-1.51172 h 26.819088 l -7.502626,-8.56643 V 58.78953 l 3.023446,-0.05599 q 5.431006,0 7.670596,0.895836 2.295576,0.839846 3.527356,3.415375 z"
|
||||
id="path296" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" id="SVGRoot" width="128" height="128" version="1.1" viewBox="0 0 128 128"><g id="layer1" transform="translate(6.2816136,0.20846979)"><g id="text189"><path id="path293" d="M 1.336354,0.37399976 H 59.45371 Q 55.982346,4.9651589 54.470623,7.596677 53.01489,10.228195 50.71931,16.051129 l -0.447918,1.119795 Q 46.576069,9.5563181 42.936735,7.3167283 39.353392,5.0771384 30.78696,5.0771384 l -3.191415,0.05599 -5.431005,-0.05599 -2.071621,-0.05599 V 31.22435 h 3.415374 V 8.1005847 l 1.623703,-0.05599 q 3.471364,-0.1679693 7.390647,-0.1679693 11.421908,0 14.277385,5.9349133 -2.743498,-2.631518 -5.990903,-3.527354 -3.191416,-0.9518259 -9.910185,-0.9518259 -2.407559,0 -5.990903,0.2799487 V 31.22435 h 8.454452 l 8.958359,-9.462267 V 45.221786 L 32.914571,35.927488 H 20.092919 V 64.14632 l 7.166687,7.278667 H -0.23135887 L 8.8949697,64.14632 V 40.07073 q -4.3112104,0 -7.5586157,3.247405 L 0.27254884,42.14235 Q 3.5199541,38.559007 8.8949697,38.559007 v -2.631519 q -1.1757846,-0.111979 -1.6796924,-0.111979 -5.2070463,0 -9.0143491,4.255221 L -2.191,39.174894 Q 0.32853859,31.896227 8.8949697,31.22435 V 7.596677 Z M 63.708931,3.7893743 Q 55.702397,13.139662 53.630777,20.922237 L 52.454992,20.13838 Q 54.582602,11.34799 62.701116,2.8375486 Z M 46.4081,23.721724 v 24.18757 L 44.952366,47.069448 V 22.881878 Z M 36.385935,40.630627 H 24.908037 v 23.963611 l 9.854195,12.205765 H 2.3441694 L 0.94442579,75.28828 H 31.626807 L 23.508293,65.266115 V 39.118904 h 11.253939 z"/></g><g id="text301"><path id="path296" d="m 114.10015,50.782996 q -0.50391,0.951826 -0.67188,1.287764 l -3.8073,6.71877 q -1.95964,3.583344 -3.63934,8.958359 l -0.11198,0.279949 -0.55989,-0.391928 -0.16797,-0.727867 q -1.62371,-6.382831 -4.64715,-8.84638 -2.967459,-2.463549 -9.126331,-2.463549 -2.519539,0 -5.039077,0.223959 h -0.671877 v 60.692887 l 6.60679,6.10288 H 66.676831 l 7.838564,-6.5508 V 60.357243 l -3.975272,-0.05599 q -5.766943,0 -8.230492,2.29558 -2.407559,2.23959 -2.855477,7.950544 H 57.99842 q 0.615888,-6.550801 3.359385,-9.126329 2.799487,-2.575528 9.182318,-2.575528 l 3.359385,0.05599 h 0.615887 v -2.743498 q -2.855477,-0.335939 -5.431005,-0.335939 -7.222677,0 -10.414093,2.967457 -3.191415,2.911467 -3.527354,9.910185 H 54.471066 Q 52.063507,60.91714 47.02443,51.342894 l -0.335938,-0.559898 z m 3.52735,3.527354 q -3.86329,4.927098 -8.11851,16.349006 l -0.22396,0.559898 -1.23178,-1.063806 0.16797,-0.503907 q 4.14324,-11.589878 8.00654,-16.125047 l 0.27994,-0.335939 z m -14.94926,8.734401 q -4.311213,-2.799488 -10.078157,-2.799488 -1.287764,0 -2.687507,0.16797 l 0.223959,56.269697 8.902369,10.52607 h -28.61076 l -1.287764,-1.51172 h 26.819088 l -7.502626,-8.56643 V 58.78953 l 3.023446,-0.05599 q 5.431006,0 7.670596,0.895836 2.295576,0.839846 3.527356,3.415375 z"/></g></g></svg>
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 2.8 KiB |
1
imgsrc/srv/off.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1792" height="1792" viewBox="-50 0 1300 1200"><path fill="currentColor" d="M513.94 0v693.97h172.12V0H513.94zM175.708 175.708C67.129 284.287 0 434.314 0 600c0 331.371 268.629 600 600 600s600-268.629 600-600c0-165.686-67.13-315.713-175.708-424.292l-120.85 120.85c77.66 77.658 125.684 184.952 125.684 303.442c0 236.981-192.146 429.126-429.126 429.126c-236.981 0-429.126-192.145-429.126-429.126c0-118.49 48.025-225.784 125.684-303.442l-120.85-120.85z"/></svg>
|
After Width: | Height: | Size: 502 B |
@ -1 +1 @@
|
||||
<svg width="300" height="300" enable-background="new 0 0 97.8 97.8" version="1.1" viewBox="0 0 97.8 97.8" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="m32.38 34.13c-0.1625-4.4e-4 -0.3151 0.04564-0.4489 0.1484l-18.37 14.03c-0.1386 0.1055-0.2601 0.2585-0.2993 0.4241-0.01305 0.05519 0 0.1121 0 0.17 0 0.2314 0.1144 0.4534 0.2993 0.5941l18.39 14.05c0.1345 0.1027 0.2658 0.1484 0.4272 0.1484 0.1593 0 0.3361-0.04777 0.4699-0.1484 0.2691-0.2012 0.3792-0.5798 0.256-0.8914l-3.695-9.273h38.98l-3.695 9.273c-0.1232 0.3116-0.01311 0.6902 0.256 0.8914 0.1338 0.1006 0.3106 0.1484 0.4699 0.1484 0.1614 0 0.2927-0.04568 0.4272-0.1484l18.39-14.05c0.1848-0.1407 0.2993-0.3626 0.2993-0.5941 0-0.05786 0.01305-0.1148 0-0.17-0.03916-0.1656-0.1607-0.3185-0.2993-0.4241l-18.37-14.03c-0.1338-0.1027-0.2864-0.1488-0.4489-0.1484-0.1625 4.41e-4 -0.3354 0.04739-0.4699 0.1484-0.2691 0.2012-0.3799 0.5384-0.256 0.8494l3.695 9.294s-38.84 0.1753-38.98 0l3.695-9.294c0.1239-0.3109 0.0131-0.6482-0.256-0.8494-0.1345-0.101-0.3074-0.1479-0.4699-0.1484z" fill="#2caf45" stroke-width="1.221"/><path d="m86.71 11.75c-0.7817 0-1.41 1.118-1.41 2.51v69.28c0 1.392 0.6272 2.511 1.41 2.51h9.547c0.7817 0 1.431-1.118 1.431-2.51v-69.28c0-1.392-0.6493-2.51-1.431-2.51z" fill="#2271d5" stroke-width="1.635"/><path d="m1.522 11.75c-0.7817 0-1.41 1.118-1.41 2.51v69.28c0 1.392 0.6272 2.511 1.41 2.51h9.547c0.7817 0 1.431-1.118 1.431-2.51v-69.28c0-1.392-0.6493-2.51-1.431-2.51z" fill="#2271d5" stroke-width="1.635"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="300" height="300" enable-background="new 0 0 97.8 97.8" version="1.1" viewBox="0 0 97.8 97.8" xml:space="preserve"><path fill="#2caf45" stroke-width="1.221" d="m32.38 34.13c-0.1625-4.4e-4 -0.3151 0.04564-0.4489 0.1484l-18.37 14.03c-0.1386 0.1055-0.2601 0.2585-0.2993 0.4241-0.01305 0.05519 0 0.1121 0 0.17 0 0.2314 0.1144 0.4534 0.2993 0.5941l18.39 14.05c0.1345 0.1027 0.2658 0.1484 0.4272 0.1484 0.1593 0 0.3361-0.04777 0.4699-0.1484 0.2691-0.2012 0.3792-0.5798 0.256-0.8914l-3.695-9.273h38.98l-3.695 9.273c-0.1232 0.3116-0.01311 0.6902 0.256 0.8914 0.1338 0.1006 0.3106 0.1484 0.4699 0.1484 0.1614 0 0.2927-0.04568 0.4272-0.1484l18.39-14.05c0.1848-0.1407 0.2993-0.3626 0.2993-0.5941 0-0.05786 0.01305-0.1148 0-0.17-0.03916-0.1656-0.1607-0.3185-0.2993-0.4241l-18.37-14.03c-0.1338-0.1027-0.2864-0.1488-0.4489-0.1484-0.1625 4.41e-4 -0.3354 0.04739-0.4699 0.1484-0.2691 0.2012-0.3799 0.5384-0.256 0.8494l3.695 9.294s-38.84 0.1753-38.98 0l3.695-9.294c0.1239-0.3109 0.0131-0.6482-0.256-0.8494-0.1345-0.101-0.3074-0.1479-0.4699-0.1484z"/><path fill="#2271d5" stroke-width="1.635" d="m86.71 11.75c-0.7817 0-1.41 1.118-1.41 2.51v69.28c0 1.392 0.6272 2.511 1.41 2.51h9.547c0.7817 0 1.431-1.118 1.431-2.51v-69.28c0-1.392-0.6493-2.51-1.431-2.51z"/><path fill="#2271d5" stroke-width="1.635" d="m1.522 11.75c-0.7817 0-1.41 1.118-1.41 2.51v69.28c0 1.392 0.6272 2.511 1.41 2.51h9.547c0.7817 0 1.431-1.118 1.431-2.51v-69.28c0-1.392-0.6493-2.51-1.431-2.51z"/></svg>
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
@ -144,8 +144,8 @@ calibre's plugin loading system defines a couple of built-in functions that allo
|
||||
a forward slash as the path separator, even on Windows. When you pass
|
||||
in a single name, the function will return the raw bytes of that file
|
||||
or None if the name was not found in the ZIP file. If you pass in more
|
||||
than one name then it returns a dict mapping the names to bytes. If a
|
||||
name is not found, it will not be present in the returned dict.
|
||||
than one name then it returns a dictionary mapping the names to bytes. If a
|
||||
name is not found, it will not be present in the returned dictionary.
|
||||
|
||||
**get_icons(name_or_list_of_names, plugin_name='')**
|
||||
A wrapper for get_resources() that creates QIcon objects
|
||||
@ -292,6 +292,11 @@ with the ``CALIBRE_OVERRIDE_LANG`` environment variable set. For example::
|
||||
|
||||
Replace ``de`` with the language code of the language you want to test.
|
||||
|
||||
For translations with plurals, use the ``ngettext()`` function instead of
|
||||
``_()``. For example::
|
||||
|
||||
ngettext('Delete a book', 'Delete {} books', num_books).format(num_books)
|
||||
|
||||
The plugin API
|
||||
--------------------------------
|
||||
|
||||
|
@ -302,9 +302,9 @@ Similarly, you can start the E-book viewer as::
|
||||
|
||||
calibre-debug -w /path/to/file/to/be/viewed
|
||||
|
||||
The e-book-editor can be started as::
|
||||
The e-book editor can be started as::
|
||||
|
||||
calibre-debug -t /path/to/be/edited
|
||||
calibre-debug --edit-book /path/to/be/edited
|
||||
|
||||
Using an interactive Python interpreter
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -406,7 +406,7 @@ you can also directly import calibre, as follows::
|
||||
import init_calibre
|
||||
import calibre
|
||||
|
||||
print calibre.__version__
|
||||
print(calibre.__version__)
|
||||
|
||||
It is essential that you import the init_calibre module before any other calibre modules/packages as
|
||||
it sets up the interpreter to run calibre code.
|
||||
|
@ -133,11 +133,14 @@ Changing text file order
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
You can re-arrange the order in which text (HTML) files are opened when reading
|
||||
the book by simply dragging and dropping them in the Files browser. For the
|
||||
technically inclined, this is called re-ordering the book spine. Note that you
|
||||
have to drop the items *between* other items, not on top of them, this can be a
|
||||
little fiddly until you get used to it. Dropping on top of another file will
|
||||
cause the files to be merged.
|
||||
the book by simply dragging and dropping them in the :guilabel:`File browser` or clicking
|
||||
on the file to move and then pressing the :kbd:`Ctrl+Shift` modifiers with the
|
||||
:kbd:`Up`, :kbd:`Down`, :kbd:`Home` or :kbd:`End` keys. For the technically
|
||||
inclined, this is called re-ordering the book spine.
|
||||
|
||||
Note that you have to drop the items *between* other items, not on top of them,
|
||||
this can be a little fiddly until you get used to it. Dropping on top of
|
||||
another file will cause the files to be merged.
|
||||
|
||||
Marking the cover
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -252,7 +252,7 @@ In such apps you can go to the online catalog screen and add the IP address of
|
||||
the calibre server to browse and download books from your calibre library
|
||||
within the app.
|
||||
|
||||
How do I use calibre with my Android phone/tablet or Kindle Fire HD?
|
||||
How do I use calibre with my Android phone/tablet or Kindle Fire?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
There are two ways that you can connect your Android device to calibre. Using a USB cable -- or wirelessly, over the air.
|
||||
@ -792,6 +792,10 @@ calibre is not starting on Windows?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
There can be several causes for this:
|
||||
|
||||
* If you get no errors but the calibre window does not appear, it has
|
||||
probably just appeared off screen. You can gather all windows onto the
|
||||
current screen using one of the techniques described `here <https://www.wikihow.com/Bring-an-Off-Screen-Window-Back-on-Windows>`__.
|
||||
|
||||
* If you get an error about calibre not being able to open a file because it is in use by another program, do the following:
|
||||
|
||||
* Uninstall calibre
|
||||
@ -880,7 +884,7 @@ incompatibility with your system's GPU (graphics) drivers. Try updating these
|
||||
first, and reboot. If that does not fix it, you can set the
|
||||
``QTWEBENGINE_CHROMIUM_FLAGS`` environment variable to the value
|
||||
``--disable-gpu`` to turn off hardware acceleration. See
|
||||
`this page <https://doc.qt.io/qt-5/qtwebengine-debugging.html>`_ for details.
|
||||
`this page <https://doc.qt.io/qt-6/qtwebengine-debugging.html>`_ for details.
|
||||
|
||||
|
||||
Using the viewer or doing any conversions results in a permission denied error on Windows
|
||||
@ -1085,7 +1089,7 @@ a modern Linux distribution, you should have no problems installing calibre onto
|
||||
because of Qt, which is used for various image processing tasks, and links
|
||||
against these libraries. If you get an ImportError about some Qt modules,
|
||||
you are likely missing some X libraries. Typical candidates are:
|
||||
``libxcb-xinerama0``, ``libegl1``, ``libopengl0``.
|
||||
``libxcb-cursor0``, ``libxcb-xinerama0``, ``libegl1``, ``libopengl0``.
|
||||
|
||||
You can run the calibre server via the command::
|
||||
|
||||
|
@ -207,7 +207,7 @@ HTML Table of Contents, ready to be pasted into :file:`toc.html`.
|
||||
The function above is heavily commented, so it should be easy to follow. The
|
||||
key new feature is the use of another useful extra argument to the
|
||||
``replace()`` function, the ``data`` object. The ``data`` object is a Python
|
||||
*dict* that persists between all successive invocations of ``replace()`` during
|
||||
*dictionary* that persists between all successive invocations of ``replace()`` during
|
||||
a single :guilabel:`Replace All` operation.
|
||||
|
||||
Another new feature is the use of ``call_after_last_match`` -- setting that to
|
||||
@ -278,9 +278,9 @@ for the current book's language.
|
||||
The ``data`` argument
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This a simple Python ``dict``. When you run
|
||||
This a simple Python ``dictionary``. When you run
|
||||
:guilabel:`Replace all`, every successive match will cause ``replace()`` to be
|
||||
called with the same ``dict`` as data. You can thus use it to store arbitrary
|
||||
called with the same ``dictionary`` as data. You can thus use it to store arbitrary
|
||||
data between invocations of ``replace()`` during a :guilabel:`Replace all`
|
||||
operation.
|
||||
|
||||
|
@ -57,7 +57,9 @@ Add books
|
||||
|
||||
6. **Add files to selected book records**: Allows you to add or update the files associated with an existing book in your library.
|
||||
|
||||
7. **Add an empty file to selected book records**: Allows you to add an empty file of the specified format to the selected book records.
|
||||
7. **Add data files to selected book records**: Allows you to add any number of extra files that will be stored in a :file:`data` sub-directory in the book directory. See :ref:`data_files` for details.
|
||||
|
||||
8. **Add an empty file to selected book records**: Allows you to add an empty file of the specified format to the selected book records.
|
||||
|
||||
The :guilabel:`Add books` action can read metadata from a wide variety of e-book formats. In addition, it tries to guess metadata from the filename.
|
||||
See the :ref:`config_filename_metadata` section, to learn how to configure this.
|
||||
@ -83,6 +85,7 @@ Edit metadata
|
||||
2. **Edit metadata in bulk**: Allows you to edit common metadata fields for large numbers of books simultaneously. It operates on all the books you have selected in the :ref:`Library view <search_sort>`.
|
||||
3. **Download metadata and covers**: Downloads metadata and covers (if available) for the books that are selected in the book list.
|
||||
4. **Merge book records**: Gives you the capability of merging the metadata and formats of two or more book records. You can choose to either delete or keep the records that were not clicked first.
|
||||
5. **Manage data files**: Manage the extra data files associated with the selected books.
|
||||
|
||||
For more details, see :ref:`metadata`.
|
||||
|
||||
@ -270,8 +273,10 @@ Remove books
|
||||
|
||||
6. **Remove matching books from device**: Allows you to remove e-book files from a connected device that match the books that are selected in the book list.
|
||||
|
||||
7. **Restore recently deleted**: Allows you to undo the removal of books or formats.
|
||||
|
||||
.. note::
|
||||
Note that when you use :guilabel:`Remove books` to delete books from your calibre library, the book record is permanently deleted, but the files are placed into the :guilabel:`Recycle Bin/Trash`. This allows you to recover the files if you change your mind.
|
||||
Note that when you use :guilabel:`Remove books` to delete books from your calibre library, the book record is deleted, but the books are temporarily stored, for a few days, in a trash folder. You can undo the delete by right clicking the :guilabel:`Remove books` button and choosing to :guilabel:`Restore recently deleted` books.
|
||||
|
||||
.. _configuration:
|
||||
|
||||
@ -311,7 +316,10 @@ Search & sort
|
||||
|
||||
The Search & Sort section allows you to perform several powerful actions on your book collections.
|
||||
|
||||
* You can sort them by title, author, date, rating, etc. by clicking on the column titles. You can also sub-sort, i.e. sort on multiple columns. For example, if you click on the title column and then the author column, the book will be sorted by author and then all the entries for the same author will be sorted by title.
|
||||
* You can sort them by title, author, date, rating, etc. by clicking on the column titles.
|
||||
You can also sub-sort, i.e. sort on multiple columns.
|
||||
For example, if you click on the title column and then the author column, the book will be sorted by
|
||||
author and then all the entries for the same author will be sorted by title.
|
||||
|
||||
* You can search for a particular book or set of books using the Search bar. More on that below.
|
||||
|
||||
@ -325,6 +333,9 @@ The Search & Sort section allows you to perform several powerful actions on your
|
||||
|
||||
* You can configure which fields you want displayed by using the :ref:`configuration` dialog.
|
||||
|
||||
* To perform complex multiple column based sub-sorting add the :guilabel:`Sort by`
|
||||
tool to a toolbar via :guilabel:`Preferences->Toolbars & menus`.
|
||||
|
||||
.. _search_interface:
|
||||
|
||||
The search interface
|
||||
@ -489,11 +500,11 @@ search. More about saving searches below.
|
||||
|
||||
*Virtual libraries*
|
||||
|
||||
The special field ``vl`` is used to search for books in a virtual library. For
|
||||
example, ``vl:Read`` will find all the books in the *Read* virtual library. The search
|
||||
The special field ``vl`` is used to search for books in a Virtual library. For
|
||||
example, ``vl:Read`` will find all the books in the *Read* Virtual library. The search
|
||||
``vl:Read and vl:"Science Fiction"`` will find all the books that are in both the *Read* and
|
||||
*Science Fiction* virtual libraries. The value following ``vl:`` must be the name of a
|
||||
virtual library. If the virtual library name contains spaces then surround it with quotes.
|
||||
Virtual library. If the Virtual library name contains spaces then surround it with quotes.
|
||||
|
||||
*Whether a field has a value*
|
||||
|
||||
@ -611,7 +622,7 @@ learn how to create and use Virtual libraries, see the tutorial:
|
||||
Temporarily marking books
|
||||
----------------------------
|
||||
|
||||
You can temporarily mark arbitrary sets of books. Marked books will have a pin on them and can be found with the search ``marked:true``. To mark a book press :kbd:`Ctrl+m` or go to :guilabel:`Preferences->Toolbars & menus` and add the :guilabel:`Mark books` button to the main toolbar.
|
||||
You can temporarily mark arbitrary sets of books. Marked books will have a pin on them and can be found with the search ``marked:true``. To mark a book press :kbd:`Ctrl+M` or go to :guilabel:`Preferences->Toolbars & menus` and add the :guilabel:`Mark books` button to the main toolbar.
|
||||
|
||||
You can mark books with a specific text label by right clicking the :guilabel:`Mark books` button and choosing :guilabel:`Mark books with text label`. Books marked with text labels can later be found using the search ``marked:"=the-text-you-entered"``.
|
||||
|
||||
@ -745,6 +756,31 @@ corner of the main window. In :guilabel:`Preferences->Interface->Look & feel->Co
|
||||
browser` you can change the number of covers displayed, and even have the
|
||||
:guilabel:`Cover browser` display itself in a separate popup window.
|
||||
|
||||
Adding notes for authors, series, etc.
|
||||
------------------------------------------
|
||||
|
||||
.. image:: images/notes.png
|
||||
:class: float-left-img
|
||||
|
||||
You can add notes for an author/series/tag/publisher/etc. to your calibre
|
||||
library. To do so right click on the author name in the :guilabel:`Tag browser` on the left
|
||||
or the :guilabel:`Book details` panel on the right and choose :guilabel:`Create note`
|
||||
or :guilabel:`Edit note`.
|
||||
|
||||
A simple popup window will allow you to enter your notes using basic
|
||||
formatting and supporting links and images. Once a note for an author is
|
||||
created, it can be viewed easily from the :guilabel:`Book details` panel by
|
||||
clicking the little pencil icon next to the author name.
|
||||
|
||||
You can search through all the notes in your library using the
|
||||
:guilabel:`Browse notes` tool by pressing :kbd:`Ctrl+Shift+N` or adding
|
||||
it to the toolbar via :guilabel:`Preferences->Toolbars & menus`.
|
||||
|
||||
.. raw:: html epub
|
||||
|
||||
<div style="clear:both"></div>
|
||||
|
||||
|
||||
Quickview
|
||||
----------
|
||||
|
||||
@ -800,7 +836,7 @@ The Jobs panel shows the number of currently running jobs. Jobs are tasks that r
|
||||
Keyboard shortcuts
|
||||
---------------------
|
||||
|
||||
calibre has several keyboard shortcuts to save you time and mouse movement. These shortcuts are active in the book list view (when you're not editing the details of a particular book), and most of them affect the title you have selected. The calibre E-book viewer has its own shortcuts which can be customised by clicking the :guilabel:`Preferences` button in the viewer.
|
||||
calibre has several keyboard shortcuts to save you time and mouse movement. These shortcuts are active in the book list view (when you're not editing the details of a particular book), and most of them affect the title you have selected. The calibre E-book viewer :ref:`has its own shortcuts <viewer_shortcuts>` which can be customised in the viewer :guilabel:`Preferences`.
|
||||
|
||||
.. note::
|
||||
|
||||
@ -919,3 +955,9 @@ calibre has several keyboard shortcuts to save you time and mouse movement. Thes
|
||||
* - :kbd:`Ctrl+Alt+Shift+F`
|
||||
- Restrict the displayed books to only those books that are in a category
|
||||
currently displayed in the :guilabel:`Tag browser`
|
||||
* - :kbd:`B`
|
||||
- Browse annotations (highlights and bookmarks) made in the calibre viewer for all books in the library
|
||||
* - :kbd:`Ctrl+Shift+N`
|
||||
- Browse notes associated with authors/series/tags/etc.
|
||||
* - :kbd:`Alt+Shift+L`
|
||||
- Toggle the layout between wide and narrow views
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 135 KiB After Width: | Height: | Size: 134 KiB |
Before Width: | Height: | Size: 399 KiB After Width: | Height: | Size: 397 KiB |
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 114 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 232 KiB After Width: | Height: | Size: 229 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 9.5 KiB |
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
BIN
manual/images/notes.png
Normal file
After Width: | Height: | Size: 144 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 9.1 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 59 KiB |
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 9.7 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 90 KiB |
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 49 KiB |
@ -82,3 +82,19 @@ Bulk downloading of metadata
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If you want to download the metadata for multiple books at once, right-click the :guilabel:`Edit metadata` button and select :guilabel:`Download metadata`. You can choose to download only metadata, only covers, or both.
|
||||
|
||||
|
||||
.. _data_files:
|
||||
|
||||
Adding extra data files to a book
|
||||
--------------------------------------
|
||||
|
||||
calibre can store any number of extra data files associated to a book. These
|
||||
can be alternate covers, supplementary material, etc. They cannot be viewed
|
||||
directly or used as conversion sources. Nor are they indexed by the Full text
|
||||
search engine in calibre. To view/add/delete them select the book and right
|
||||
click the :guilabel:`Edit metadata` button and choose :guilabel:`Manage data
|
||||
files`. This will pop-up a window where you can perform operations on these
|
||||
files. Alternately, you can right click the :guilabel:`Add books` button and
|
||||
choose :guilabel:`Add data files to selected book records` to more quickly add
|
||||
data files.
|
||||
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 16 KiB |
@ -21,7 +21,7 @@ available <help>`.
|
||||
|
||||
.. only:: online
|
||||
|
||||
**An e-book version of this User Manual is available in** `EPUB format <calibre.epub>`_, `AZW3 (Kindle Fire) format <calibre.azw3>`_ and `PDF format <calibre.pdf>`_.
|
||||
**An e-book version of this User Manual is available in** `EPUB format <calibre.epub>`_, `AZW3 (Kindle) format <calibre.azw3>`_ and `PDF format <calibre.pdf>`_.
|
||||
|
||||
.. rubric:: Sections
|
||||
|
||||
|
@ -116,6 +116,32 @@ Composite columns can use any template option, including formatting.
|
||||
|
||||
Note: You cannot edit the data displayed in a composite column. Instead you edit the source columns. If you edit a composite column, for example by double-clicking it, calibre will open the template for editing, not the underlying data.
|
||||
|
||||
|
||||
Templates and plugboards
|
||||
---------------------------
|
||||
|
||||
Plugboards are used for changing the metadata written into books during send-to-device and save-to-disk operations. A plugboard permits you to specify a template to provide the data to write into the book's metadata. You can use plugboards to modify the following fields: authors, author_sort, language, publisher, tags, title, title_sort. This feature helps people who want to use different metadata in books on devices to solve sorting or display issues.
|
||||
|
||||
When you create a plugboard, you specify the format and device for which the plugboard is to be used. A special device is provided, ``save_to_disk``, that is used when saving formats (as opposed to sending them to a device). Once you have chosen the format and device, you choose the metadata fields to change, providing templates to supply the new values. These templates are `connected` to their destination fields, hence the name `plugboards`. You can of course use composite columns in these templates.
|
||||
|
||||
Plugboards are quite flexible and can be written in Single Function Mode, Template Program Mode, General Program Mode, or Python Template mode.
|
||||
|
||||
When a plugboard might apply (Content server, save to disk, or send to device), calibre searches the
|
||||
defined plugboards to choose the correct one for the given format and device. For example, to find the appropriate plugboard for an EPUB book being sent to an ANDROID device, calibre searches
|
||||
the plugboards using the following search order:
|
||||
|
||||
* a plugboard with an exact match on format and device, e.g., ``EPUB`` and ``ANDROID``
|
||||
* a plugboard with an exact match on format and the special ``any device`` choice, e.g., ``EPUB`` and ``any device``
|
||||
* a plugboard with the special ``any format`` choice and an exact match on device, e.g., ``any format`` and ``ANDROID``
|
||||
* a plugboard with ``any format`` and ``any device``
|
||||
|
||||
The tags and authors fields have special treatment, because both of these fields can hold more than one item. A book can have many tags and many authors. When you specify that one of these two fields is to be changed, the template's result is examined to see if more than one item is there. For tags, the result is cut apart wherever calibre finds a comma. For example, if the template produces
|
||||
the value ``Thriller, Horror``, then the result will be two tags, ``Thriller`` and ``Horror``. There is no way to put a comma in the middle of a tag.
|
||||
|
||||
The same thing happens for authors, but using a different character for the cut, a `&` (ampersand) instead of a comma. For example, if the template produces the value ``Blogs, Joe&Posts, Susan``, then the book will end up with two authors, ``Blogs, Joe`` and ``Posts, Susan``. If the template produces the value ``Blogs, Joe;Posts, Susan``, then the book will have one author with a rather strange name.
|
||||
|
||||
Plugboards affect the metadata written into the book when it is saved to disk or written to the device. Plugboards do not affect the metadata used by ``save to disk`` and ``send to device`` to create the file names. Instead, file names are constructed using the templates entered on the appropriate preferences window.
|
||||
|
||||
.. _single_mode:
|
||||
|
||||
Using functions in templates - Single Function Mode
|
||||
@ -216,7 +242,7 @@ General Program Mode
|
||||
top_expression ::= or_expression
|
||||
or_expression ::= and_expression [ '||' and_expression ]*
|
||||
and_expression ::= not_expression [ '&&' not_expression ]*
|
||||
not_expression ::= [ '!' not_expression ]* | compare_exp
|
||||
not_expression ::= [ '!' not_expression ]* | concatenate_expr
|
||||
concatenate_expr::= compare_expr [ '&' compare_expr ]*
|
||||
compare_expr ::= add_sub_expr [ compare_op add_sub_expr ]
|
||||
compare_op ::= '==' | '!=' | '>=' | '>' | '<=' | '<' | 'in' | 'inlist' |
|
||||
@ -389,7 +415,7 @@ Examples:
|
||||
|
||||
* ``program: field('series') == 'foo'`` returns ``'1'`` if the book's series is 'foo', otherwise ``''``.
|
||||
* ``program: 'f.o' in field('series')`` returns ``'1'`` if the book's series matches the regular expression ``f.o`` (e.g., `foo`, `Off Onyx`, etc.), otherwise ``''``.
|
||||
* ``program: 'science' inlist field('#genre')`` returns ``'1'`` if any of the book's genres match the regular expression ``science``, e.g., `Science`, `History of Science`, `Science Fiction` etc.), otherwise ``''``.
|
||||
* ``program: 'science' inlist field('#genre')`` returns ``'1'`` if any of the book's genres match the regular expression ``science``, e.g., `Science`, `History of Science`, `Science Fiction` etc., otherwise ``''``.
|
||||
* ``program: '^science$' inlist field('#genre')`` returns ``'1'`` if any of the book's genres exactly match the regular expression ``^science$``, e.g., `Science`. The genres `History of Science` and `Science Fiction` don't match. If there isn't a match then returns ``''``.
|
||||
* ``program: if field('series') != 'foo' then 'bar' else 'mumble' fi`` returns ``'bar'`` if the book's series is not ``foo``. Otherwise it returns ``'mumble'``.
|
||||
* ``program: if field('series') == 'foo' || field('series') == '1632' then 'yes' else 'no' fi`` returns ``'yes'`` if series is either ``'foo'`` or ``'1632'``, otherwise ``'no'``.
|
||||
@ -443,7 +469,7 @@ In `GPM` the functions described in `Single Function Mode` all require an additi
|
||||
* ``booksize()`` -- returns the value of the calibre 'size' field. Returns '' if there are no formats.
|
||||
* ``check_yes_no(field_name, is_undefined, is_false, is_true)`` -- checks if the value of the yes/no field named by the lookup name ``field_name`` is one of the values specified by the parameters, returning ``'yes'`` if a match is found otherwise returning the empty string. Set the parameter ``is_undefined``, ``is_false``, or ``is_true`` to 1 (the number) to check that condition, otherwise set it to 0. Example:
|
||||
|
||||
``check_yes_no("#bool", 1, 0, 1)`` returns ``'yes'`` if the yes/no field ``#bool`` is either True or undefined (neither True nor False).
|
||||
``check_yes_no("#bool", 1, 0, 1)`` returns ``'Yes'`` if the yes/no field ``#bool`` is either True or undefined (neither True nor False).
|
||||
|
||||
More than one of ``is_undefined``, ``is_false``, or ``is_true`` can be set to 1.
|
||||
* ``ceiling(x)`` -- returns the smallest integer greater than or equal to ``x``. Throws an exception if ``x`` is not a number.
|
||||
@ -467,6 +493,9 @@ In `GPM` the functions described in `Single Function Mode` all require an additi
|
||||
* ``days_between(date1, date2)`` -- return the number of days between ``date1`` and ``date2``. The number is positive if ``date1`` is greater than ``date2``, otherwise negative. If either ``date1`` or ``date2`` are not dates, the function returns the empty string.
|
||||
* ``divide(x, y)`` -- returns ``x / y``. Throws an exception if either ``x`` or ``y`` are not numbers. This function can usually be replaced by the ``/`` operator.
|
||||
* ``eval(string)`` -- evaluates the string as a program, passing the local variables. This permits using the template processor to construct complex results from local variables. In :ref:`Template Program Mode <template_mode>`, because the `{` and `}` characters are interpreted before the template is evaluated you must use `[[` for the `{` character and `]]` for the ``}`` character. They are converted automatically. Note also that prefixes and suffixes (the `|prefix|suffix` syntax) cannot be used in the argument to this function when using :ref:`Template Program Mode <template_mode>`.
|
||||
* ``extra_file_size(file_name)`` -- returns the size in bytes of the extra file ``file_name`` in the book's ``data/`` folder if it exists, otherwise ``-1``. See also the functions ``has_extra_files()``, ``extra_file_names()`` and ``extra_file_modtime()``. This function can be used only in the GUI.
|
||||
* ``extra_file_modtime(file_name, format_string)`` -- returns the modification time of the extra file ``file_name`` in the book's ``data/`` folder if it exists, otherwise ``-1``. The modtime is formatted according to ``format_string`` (see ``format_date()`` for details). If ``format_string`` is the empty string, returns the modtime as the floating point number of seconds since the epoch. See also the functions ``has_extra_files()``, ``extra_file_names()`` and ``extra_file_size()``. The epoch is OS dependent. This function can be used only in the GUI.
|
||||
* ``extra_file_names(sep [, pattern])`` returns a ``sep``-separated list of extra files in the book's ``data/`` folder. If the optional parameter ``pattern``, a regular expression, is supplied then the list is filtered to files that match ``pattern``. The pattern match is case insensitive. See also the functions ``has_extra_files()``, ``extra_file_modtime()`` and ``extra_file_size()``. This function can be used only in the GUI.
|
||||
* ``field(lookup_name)`` -- returns the value of the metadata field with lookup name ``lookup_name``.
|
||||
* ``field_exists(field_name)`` -- checks if a field (column) with the lookup name ``field_name`` exists, returning ``'1'`` if so and the empty string if not.
|
||||
* ``finish_formatting(val, fmt, prefix, suffix)`` -- apply the format, prefix, and suffix to a value in the same way as done in a template like ``{series_index:05.2f| - |- }``. This function is provided to ease conversion of complex single-function- or template-program-mode templates to `GPM` Templates. For example, the following program produces the same output as the above template::
|
||||
@ -523,11 +552,36 @@ In `GPM` the functions described in `Single Function Mode` all require an additi
|
||||
|
||||
format_date(raw_field('pubdate'), 'yyyy')
|
||||
|
||||
* ``format_date_field(field_name, format_string)`` -- format the value in the field ``field_name``, which must be the lookup name of date field, either standard or custom. See ``format_date()`` for the formatting codes. This function is much faster than format_date and should be used when you are formatting the value in a field (column). It can't be used for computed dates or dates in string variables. Examples::
|
||||
|
||||
format_date_field('pubdate', 'yyyy.MM.dd')
|
||||
format_date_field('#date_read', 'MMM dd, yyyy')
|
||||
|
||||
* ``formats_modtimes(date_format_string)`` -- return a comma-separated list of colon-separated items ``FMT:DATE`` representing modification times for the formats of a book. The ``date_format_string`` parameter specifies how the date is to be formatted. See the ``format_date()`` function for details. You can use the ``select`` function to get the modification time for a specific format. Note that format names are always uppercase, as in EPUB.
|
||||
* ``formats_paths()`` -- return a comma-separated list of colon-separated items ``FMT:PATH`` giving the full path to the formats of a book. You can use the select function to get the path for a specific format. Note that format names are always uppercase, as in EPUB.
|
||||
* ``formats_sizes()`` -- return a comma-separated list of colon-separated ``FMT:SIZE`` items giving the sizes in bytes of the formats of a book. You can use the select function to get the size for a specific format. Note that format names are always uppercase, as in EPUB.
|
||||
* ``fractional_part(x)`` -- returns the value after the decimal point. For example, ``fractional_part(3.14)`` returns ``0.14``. Throws an exception if ``x`` is not a number.
|
||||
* ``get_link(field_name, field_value)`` -- fetch the link for field ``field_name`` with value ``field_value``. If there is no attached link, return the empty string. Examples:
|
||||
|
||||
* The following returns the link attached to the tag ``Fiction``::
|
||||
|
||||
get_link('tags', 'Fiction')
|
||||
|
||||
* This template makes a list of the links for all the tags associated with a book in the form ``value:link, ...``::
|
||||
|
||||
program:
|
||||
ans = '';
|
||||
for t in $tags:
|
||||
l = get_link('tags', t);
|
||||
if l then
|
||||
ans = list_join(', ', ans, ',', t & ':' & get_link('tags', t), ',')
|
||||
fi
|
||||
rof;
|
||||
ans
|
||||
|
||||
* ``has_cover()`` -- return ``'Yes'`` if the book has a cover, otherwise the empty string.
|
||||
* ``has_extra_files([pattern])`` -- returns the count of extra files, otherwise '' (the empty string). If the optional parameter ``pattern`` (a regular expression) is supplied then the list is filtered to files that match ``pattern`` before the files are counted. The pattern match is case insensitive. See also the functions ``extra_file_names()``, ``extra_file_size()`` and ``extra_file_modtime()``. This function can be used only in the GUI.
|
||||
* ``identifier_in_list(val, id_name [, found_val, not_found_val])`` -- treat ``val`` as a list of identifiers separated by commas. An identifier has the format ``id_name:value``. The ``id_name`` parameter is the id_name text to search for, either ``id_name`` or ``id_name:regexp``. The first case matches if there is any identifier matching that id_name. The second case matches if id_name matches an identifier and the regexp matches the identifier's value. If ``found_val`` and ``not_found_val`` are provided then if there is a match then return ``found_val``, otherwise return ``not_found_val``. If ``found_val`` and ``not_found_val`` are not provided then if there is a match then return the ``identifier:value`` pair, otherwise the empty string (``''``).
|
||||
* ``is_marked()`` -- check whether the book is `marked` in calibre. If it is then return the value of the mark, either ``'true'`` (lower case) or a comma-separated list of named marks. Returns ``''`` (the empty string) if the book is not marked. This function works only in the GUI.
|
||||
* ``language_codes(lang_strings)`` -- return the `language codes <https://www.loc.gov/standards/iso639-2/php/code_list.php>`_ for the language names passed in `lang_strings`. The strings must be in the language of the current locale. ``Lang_strings`` is a comma-separated list.
|
||||
* ``list_contains(value, separator, [ pattern, found_val, ]* not_found_val)`` -- (Alias of ``in_list``) Interpreting the value as a list of items separated by ``separator``, evaluate the ``pattern`` against each value in the list. If the ``pattern`` matches any value then return ``found_val``, otherwise return ``not_found_val``. The ``pattern`` and ``found_value`` can be repeated as many times as desired, permitting returning different values depending on the search. The patterns are checked in order. The first match is returned. Aliases: ``in_list()``, ``list_contains()``
|
||||
@ -610,6 +664,7 @@ In `GPM` the functions described in `Single Function Mode` all require an additi
|
||||
* ``strlen(value)`` -- Returns the length of the string ``value``.
|
||||
* ``substr(str, start, end)`` -- returns the ``start``'th through the ``end``'th characters of ``str``. The first character in ``str`` is the zero'th character. If ``end`` is negative, then it indicates that many characters counting from the right. If ``end`` is zero, then it indicates the last character. For example, ``substr('12345', 1, 0)`` returns ``'2345'``, and ``substr('12345', 1, -1)`` returns ``'234'``.
|
||||
* ``subtract(x, y)`` -- returns ``x - y``. Throws an exception if either ``x`` or ``y`` are not numbers. This function can usually be replaced by the ``-`` operator.
|
||||
* ``switch_if([test_expression, value_expression,]+ else_expression)`` -- for each ``test_expression, value_expression`` pair, checks if ``test_expression`` is True (non-empty) and if so returns the result of ``value_expression``. If no ``test_expression`` is True then the result of ``else_expression` is returned. You can have as many ``test_expression, value_expression`` pairs as you want.
|
||||
* ``today()`` -- return a date+time string for today (now). This value is designed for use in `format_date` or `days_between`, but can be manipulated like any other string. The date is in `ISO <https://en.wikipedia.org/wiki/ISO_8601>`_ date/time format.
|
||||
* ``template(x)`` -- evaluates ``x`` as a template. The evaluation is done in its own context, meaning that variables are not shared between the caller and the template evaluation.
|
||||
* ``to_hex(val)`` -- returns the string ``val`` encoded in hex. This is useful when constructing calibre URLs.
|
||||
@ -736,9 +791,9 @@ A developer can choose to pass additional information to the template processor,
|
||||
|
||||
**Developer: how to pass additional information**
|
||||
|
||||
The additional information is a Python dictionary containing pairs ``variable_name: variable_value`` where the values must be strings. The template can access the dict, creating template local variables named ``variable_name`` containing the value ``variable_value``. The user cannot change the name so it is best to use names that won't collide with other template local variables, for example by prefixing the name with an underscore.
|
||||
The additional information is a Python dictionary containing pairs ``variable_name: variable_value`` where the values must be strings. The template can access the dictionary, creating template local variables named ``variable_name`` containing the value ``variable_value``. The user cannot change the name so it is best to use names that won't collide with other template local variables, for example by prefixing the name with an underscore.
|
||||
|
||||
This dict is passed to the template processor (the ``formatter``) using the named parameter ``global_vars=your_dict``. The full method signature is::
|
||||
This dictionary is passed to the template processor (the ``formatter``) using the named parameter ``global_vars=your_dict``. The full method signature is::
|
||||
|
||||
def safe_format(self, fmt, kwargs, error_value, book,
|
||||
column_name=None, template_cache=None,
|
||||
@ -748,17 +803,17 @@ This dict is passed to the template processor (the ``formatter``) using the name
|
||||
|
||||
**Template writer: how to access the additional information**
|
||||
|
||||
You access the additional information (the ``globals`` dict) in a template using the template function::
|
||||
You access the additional information (the ``globals`` dictionary) in a template using the template function::
|
||||
|
||||
globals(id[=expression] [, id[=expression]]*)
|
||||
|
||||
where ``id`` is any legal variable name. This function checks whether the additional information provided by the developer contains the name. If it does then the function assigns the provided value to a template local variable with that name. If the name is not in the additional information and if an ``expression`` is provided, the ``expression`` is evaluated and the result is assigned to the local variable. If neither a value nor an expression is provided, the function assigns the empty string (``''``) to the local variable.
|
||||
|
||||
A template can set a value in the ``globals`` dict using the template function::
|
||||
A template can set a value in the ``globals`` dictionary using the template function::
|
||||
|
||||
set_globals(id[=expression] [, id[=expression]]*)
|
||||
|
||||
This function sets the ``globals`` dict key:value pair ``id:value`` where ``value`` is the value of the template local variable ``id``. If that local variable doesn't exist then ``value`` is set to the result of evaluating ``expression``.
|
||||
This function sets the ``globals`` dictionary key:value pair ``id:value`` where ``value`` is the value of the template local variable ``id``. If that local variable doesn't exist then ``value`` is set to the result of evaluating ``expression``.
|
||||
|
||||
Notes on the difference between modes
|
||||
-----------------------------------------
|
||||
@ -820,30 +875,7 @@ To accomplish this, we:
|
||||
|
||||
1. Create a composite field (give it lookup name #aa) containing ``{series}/{series_index} - {title}``. If the series is not empty, then this template will produce `series/series_index - title`.
|
||||
2. Create a composite field (give it lookup name #bb) containing ``{#genre:ifempty(Unknown)}/{author_sort}/{title}``. This template produces `genre/author_sort/title`, where an empty genre is replaced with `Unknown`.
|
||||
3. Set the save template to ``{series:lookup(.,#aa,#bb}``. This template chooses composite field ``#aa`` if series is not empty and composite field ``#bb`` if series is empty. We therefore have two completely different save paths, depending on whether or not `series` is empty.
|
||||
|
||||
Templates and plugboards
|
||||
---------------------------
|
||||
|
||||
Plugboards are used for changing the metadata written into books during send-to-device and save-to-disk operations. A plugboard permits you to specify a template to provide the data to write into the book's metadata. You can use plugboards to modify the following fields: authors, author_sort, language, publisher, tags, title, title_sort. This feature helps people who want to use different metadata in books on devices to solve sorting or display issues.
|
||||
|
||||
When you create a plugboard, you specify the format and device for which the plugboard is to be used. A special device is provided, ``save_to_disk``, that is used when saving formats (as opposed to sending them to a device). Once you have chosen the format and device, you choose the metadata fields to change, providing templates to supply the new values. These templates are `connected` to their destination fields, hence the name `plugboards`. You can of course use composite columns in these templates.
|
||||
|
||||
When a plugboard might apply (Content server, save to disk, or send to device), calibre searches the
|
||||
defined plugboards to choose the correct one for the given format and device. For example, to find the appropriate plugboard for an EPUB book being sent to an ANDROID device, calibre searches
|
||||
the plugboards using the following search order:
|
||||
|
||||
* a plugboard with an exact match on format and device, e.g., ``EPUB`` and ``ANDROID``
|
||||
* a plugboard with an exact match on format and the special ``any device`` choice, e.g., ``EPUB`` and ``any device``
|
||||
* a plugboard with the special ``any format`` choice and an exact match on device, e.g., ``any format`` and ``ANDROID``
|
||||
* a plugboard with ``any format`` and ``any device``
|
||||
|
||||
The tags and authors fields have special treatment, because both of these fields can hold more than one item. A book can have many tags and many authors. When you specify that one of these two fields is to be changed, the template's result is examined to see if more than one item is there. For tags, the result is cut apart wherever calibre finds a comma. For example, if the template produces
|
||||
the value ``Thriller, Horror``, then the result will be two tags, ``Thriller`` and ``Horror``. There is no way to put a comma in the middle of a tag.
|
||||
|
||||
The same thing happens for authors, but using a different character for the cut, a `&` (ampersand) instead of a comma. For example, if the template produces the value ``Blogs, Joe&Posts, Susan``, then the book will end up with two authors, ``Blogs, Joe`` and ``Posts, Susan``. If the template produces the value ``Blogs, Joe;Posts, Susan``, then the book will have one author with a rather strange name.
|
||||
|
||||
Plugboards affect the metadata written into the book when it is saved to disk or written to the device. Plugboards do not affect the metadata used by ``save to disk`` and ``send to device`` to create the file names. Instead, file names are constructed using the templates entered on the appropriate preferences window.
|
||||
3. Set the save template to ``{series:lookup(.,#aa,#bb)}``. This template chooses composite field ``#aa`` if series is not empty and composite field ``#bb`` if series is empty. We therefore have two completely different save paths, depending on whether or not `series` is empty.
|
||||
|
||||
Tips
|
||||
-----
|
||||
|
@ -56,6 +56,20 @@ brackets at the end of the path to the book folder.
|
||||
You can copy a link to the current book displayed in calibre by right clicking
|
||||
the :guilabel:`Book details` panel and choosing :guilabel:`Copy link to book`.
|
||||
|
||||
If a search is active and the book is not matched by the search then the search is cleared.
|
||||
|
||||
If a Virtual library is selected, calibre will use it when showing the book. If
|
||||
the book isn't found in that virtual library then the virtual library is cleared.
|
||||
|
||||
If you want to switch to a particular Virtual library when showing the book, use::
|
||||
|
||||
calibre://show-book/Library_Name/book_id?virtual_library=Library%20Name
|
||||
or
|
||||
calibre://show-book/Library_Name/book_id?encoded_virtual_library=hex_encoded_virtual_library_name
|
||||
|
||||
replacing spaces in the Virtual library name by ``%20``. If the book isn't found in that
|
||||
virtual library then the virtual library is ignored.
|
||||
|
||||
|
||||
Open a specific book in the E-book viewer at a specific position
|
||||
-------------------------------------------------------------------
|
||||
@ -102,6 +116,39 @@ If you perform a search in calibre and want to generate a link for it you can
|
||||
do so by right clicking the search bar and choosing :guilabel:`Copy search as
|
||||
URL`.
|
||||
|
||||
Open a book details window on a book in some library
|
||||
------------------------------------------------------
|
||||
|
||||
The URL syntax is::
|
||||
|
||||
calibre://book-details/Library_Name/book_id
|
||||
|
||||
This opens a book details window on the specified book from the specified library without changing the
|
||||
current library or the selected book.
|
||||
|
||||
|
||||
Open the notes associated with an author/series/etc.
|
||||
------------------------------------------------------
|
||||
|
||||
The URL syntax is::
|
||||
|
||||
calibre://book-details/Library_Name/Field_Name/id_Item_Id
|
||||
|
||||
This opens a window showing the notes of the specified item.
|
||||
The easiest way to create such URLs is to show the notes you want
|
||||
in calibre and click the :guilabel:`Copy URL` button to copy the URL
|
||||
to the clipboard and paste it wherever you need.
|
||||
|
||||
Here ``Field_Name`` is the name of the columns such as ``authors`` or ``tags``.
|
||||
For user created columns, replace the leading ``#`` in the field name with
|
||||
an underscore, so ``#mytags`` becomes ``_mytags``.
|
||||
|
||||
In addition to specifying items by id using ``Item_Id`` you can also specify
|
||||
them by name using either ``val_Item_Name`` or ``hex_Hex_Encoded_Item_Name``.
|
||||
For example::
|
||||
|
||||
calibre://book-details/Library_Name/authors/val_John%20Doe
|
||||
|
||||
|
||||
.. _hex_encoding:
|
||||
|
||||
|
@ -254,6 +254,145 @@ You can zoom in to show an image at full size in a separate window by either
|
||||
double clicking or long tapping on it. You can also right click on it and
|
||||
choose :guilabel:`View image`.
|
||||
|
||||
.. _viewer_shortcuts:
|
||||
|
||||
Keyboard shortcuts
|
||||
-----------------------
|
||||
|
||||
The viewer has extensive keyboard shortcuts, like the rest of calibre. They can
|
||||
be customised in the viewer :guilabel:`Preferences`. The default shortcuts are listed below:
|
||||
|
||||
|
||||
.. list-table:: Keyboard shortcuts for the calibre viewer
|
||||
:widths: 10 100
|
||||
:header-rows: 1
|
||||
|
||||
* - Keyboard shortcut
|
||||
- Action
|
||||
* - :kbd:`Home, Ctrl+ArrowUp, Ctrl+ArrowLeft`
|
||||
- Scroll to the start of the current file in a multi file book
|
||||
* - :kbd:`Ctrl+Home`
|
||||
- Scroll to the beginning of the book
|
||||
* - :kbd:`Ctrl+End`
|
||||
- Scroll to the end of the book
|
||||
* - :kbd:`End, Ctrl+ArrowDown, Ctrl+ArrowRight`
|
||||
- Scroll to the end of the current file in a multi file book
|
||||
* - :kbd:`ArrowUp`
|
||||
- Scroll backwards, smoothly in flow mode and by screen fulls in paged mode
|
||||
* - :kbd:`ArrowDown`
|
||||
- Scroll forwards, smoothly in flow mode and by screen fulls in paged mode
|
||||
* - :kbd:`ArrowLeft`
|
||||
- Scroll leftwards by a little in flow mode and by a page in paged mode
|
||||
* - :kbd:`ArrowRight`
|
||||
- Scroll rightwards by a little in flow mode and by a page in paged mode
|
||||
* - :kbd:`PageUp, Shift+Spacebar`
|
||||
- Scroll backwards by screen-fulls
|
||||
* - :kbd:`PageDown, Spacebar`
|
||||
- Scroll forwards by screen-fulls
|
||||
* - :kbd:`Ctrl+PageUp`
|
||||
- Scroll to the previous section
|
||||
* - :kbd:`Ctrl+PageDown`
|
||||
- Scroll to the next section
|
||||
* - :kbd:`Alt+ArrowLeft`
|
||||
- Back
|
||||
* - :kbd:`Alt+ArrowRight`
|
||||
- Forward
|
||||
* - :kbd:`Ctrl+T`
|
||||
- Toggle Table of Contents
|
||||
* - :kbd:`Ctrl+S`
|
||||
- Read aloud
|
||||
* - :kbd:`Alt+P`
|
||||
- Change settings quickly by creating and switching to :guilabel:`profiles`
|
||||
* - :kbd:`Alt+f`
|
||||
- Follow links with the keyboard
|
||||
* - :kbd:`Ctrl+C`
|
||||
- Copy to clipboard
|
||||
* - :kbd:`Alt+C`
|
||||
- Copy current location to clipboard
|
||||
* - :kbd:`Ctrl+Shift+C`
|
||||
- Copy current location as calibre:// URL to clipboard
|
||||
* - :kbd:`/, Ctrl+f, Cmd+f`
|
||||
- Start search
|
||||
* - :kbd:`F3, Enter`
|
||||
- Find next
|
||||
* - :kbd:`Shift+F3, Shift+Enter`
|
||||
- Find previous
|
||||
* - :kbd:`Ctrl+Plus, Meta+Plus`
|
||||
- Increase font size
|
||||
* - :kbd:`Ctrl+Minus, Meta+Minus`
|
||||
- Decrease font size
|
||||
* - :kbd:`Ctrl+0`
|
||||
- Restore default font size
|
||||
* - :kbd:`Ctrl+]`
|
||||
- Increase number of pages per screen
|
||||
* - :kbd:`Ctrl+[`
|
||||
- Decrease number of pages per screen
|
||||
* - :kbd:`Ctrl+Alt+C`
|
||||
- Make number of pages per screen automatic
|
||||
* - :kbd:`F11, Ctrl+Shift+F`
|
||||
- Toggle full screen
|
||||
* - :kbd:`Ctrl+M`
|
||||
- Toggle between Paged mode and Flow mode for text layout
|
||||
* - :kbd:`Ctrl+W`
|
||||
- Toggle the scrollbar
|
||||
* - :kbd:`Ctrl+X`
|
||||
- Toggle the Reference mode
|
||||
* - :kbd:`Ctrl+B`
|
||||
- Show/hide bookmarks
|
||||
* - :kbd:`Ctrl+Alt+B`
|
||||
- New bookmark
|
||||
* - :kbd:`Ctrl+N, Ctrl+E`
|
||||
- Show the book metadata
|
||||
* - :kbd:`Ctrl+Alt+F5, Ctrl+Alt+R`
|
||||
- Reload book
|
||||
* - :kbd:`Ctrl+Shift+ArrowRight`
|
||||
- Alter the current selection forward by a word
|
||||
* - :kbd:`Ctrl+Shift+ArrowLeft`
|
||||
- Alter the current selection backwards by a word
|
||||
* - :kbd:`Shift+ArrowRight`
|
||||
- Alter the current selection forward by a character
|
||||
* - :kbd:`Shift+ArrowLeft`
|
||||
- Alter the current selection backwards by a character
|
||||
* - :kbd:`Shift+ArrowDown`
|
||||
- Alter the current selection forward by a line
|
||||
* - :kbd:`Shift+Home`
|
||||
- Extend the current selection to the start of the line
|
||||
* - :kbd:`Shift+End`
|
||||
- Extend the current selection to the end of the line
|
||||
* - :kbd:`Ctrl+A`
|
||||
- Select all
|
||||
* - :kbd:`Shift+ArrowUp`
|
||||
- Alter the current selection backwards by a line
|
||||
* - :kbd:`Ctrl+Shift+ArrowDown`
|
||||
- Alter the current selection forward by a paragraph
|
||||
* - :kbd:`Ctrl+Shift+ArrowUp`
|
||||
- Alter the current selection backwards by a paragraph
|
||||
* - :kbd:`Esc, MenuKey`
|
||||
- Show the E-book viewer controls
|
||||
* - :kbd:`Ctrl+Comma, Ctrl+Esc, Meta+Esc, Meta+Comma`
|
||||
- Show E-book viewer preferences
|
||||
* - :kbd:`Ctrl+G, ;, :`
|
||||
- Go to a specified book location or position
|
||||
* - :kbd:`Ctrl+Spacebar`
|
||||
- Toggle auto-scroll
|
||||
* - :kbd:`Alt+ArrowUp`
|
||||
- Auto scroll faster
|
||||
* - :kbd:`Alt+ArrowDown`
|
||||
- Auto scroll slower
|
||||
* - :kbd:`Ctrl+I`
|
||||
- Show/hide Inspector
|
||||
* - :kbd:`Ctrl+L`
|
||||
- Show/hide the word lookup panel
|
||||
* - :kbd:`Ctrl+Q (Cmd+Q on macOS)`
|
||||
- Quit
|
||||
* - :kbd:`Ctrl+P`
|
||||
- Print book to PDF
|
||||
* - :kbd:`Ctrl+F11`
|
||||
- Toggle the toolbar
|
||||
* - :kbd:`Ctrl+H`
|
||||
- Toggle the highlights panel
|
||||
* - :kbd:`Ctrl+D`
|
||||
- Edit this book
|
||||
|
||||
Non re-flowable content
|
||||
--------------------------
|
||||
@ -287,6 +426,9 @@ the viewer will set the following classes on the ``body`` element:
|
||||
``body.calibre-viewer-scrolling``
|
||||
Set when in flow (non-paginated) mode
|
||||
|
||||
``body.calibre-footnote-container``
|
||||
Set when displaying a popup footnote
|
||||
|
||||
Finally, you can use the calibre color scheme colors via `CSS variables
|
||||
<https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties>`_.
|
||||
The calibre viewer defines the following variables:
|
||||
|
24
pyproject.toml
Normal file
@ -0,0 +1,24 @@
|
||||
[tool.ruff]
|
||||
line-length = 160
|
||||
target-version = 'py38'
|
||||
builtins = ['_']
|
||||
|
||||
[tool.ruff.lint]
|
||||
ignore = ['E741', 'E402', 'E722', 'E401']
|
||||
select = ['E', 'F']
|
||||
|
||||
[tool.ruff.lint.per-file-ignores]
|
||||
"src/calibre/ebooks/unihandecode/unicodepoints.py" = ["E501"]
|
||||
"src/qt/__init__.py" = ["E501"]
|
||||
|
||||
[tool.black]
|
||||
target-version = ['py38']
|
||||
|
||||
[tool.isort]
|
||||
profile = "black"
|
||||
combine_as_imports = true
|
||||
multi_line_output = 5
|
||||
known_future_library = "__python__"
|
||||
known_third_party = "qt"
|
||||
known_standard_library = "aes,elementmaker,encodings"
|
||||
known_first_party = "calibre_extensions"
|
@ -2,14 +2,7 @@
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPLv3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
from calibre.web.feeds.recipes import BasicNewsRecipe
|
||||
|
||||
|
||||
def classes(classes):
|
||||
q = frozenset(classes.split(' '))
|
||||
return dict(attrs={
|
||||
'class': lambda x: x and frozenset(x.split()).intersection(q)})
|
||||
from calibre.web.feeds.news import BasicNewsRecipe, classes
|
||||
|
||||
|
||||
class E1843(BasicNewsRecipe):
|
||||
@ -20,34 +13,41 @@ class E1843(BasicNewsRecipe):
|
||||
no_stylesheets = True
|
||||
remove_javascript = True
|
||||
encoding = 'utf-8'
|
||||
# economist.com has started throttling after about 60% of the total has
|
||||
# downloaded with connection reset by peer (104) errors.
|
||||
delay = 1
|
||||
|
||||
|
||||
keep_only_tags = [
|
||||
dict(id='content')
|
||||
]
|
||||
remove_tags = [
|
||||
classes('advert ad ds-share-list article__wordmark related-articles newsletter-signup')
|
||||
classes('advert ad ds-share-list article__wordmark related-articles newsletter-signup'),
|
||||
dict(attrs={'data-test-id':'sharing-modal'}),
|
||||
]
|
||||
|
||||
def parse_index(self):
|
||||
soup = self.index_to_soup('https://economist.com/1843')
|
||||
ans = []
|
||||
main = soup.find(id='content')
|
||||
|
||||
for a in soup.findAll(**classes('headline-link')):
|
||||
for h3 in main.find_all('h3'):
|
||||
a = h3.find('a')
|
||||
url = a['href']
|
||||
if url.startswith('/'):
|
||||
url = 'https://economist.com' + url
|
||||
title = self.tag_to_string(a)
|
||||
self.log(title, ' at ', url)
|
||||
desc = ''
|
||||
d = a.parent.findNextSibling(itemprop='description')
|
||||
d = a.parent.findNextSibling('p')
|
||||
if d is not None:
|
||||
desc = self.tag_to_string(d)
|
||||
ans.append({'title': title, 'url': url, 'description': desc})
|
||||
return [('Articles', ans)]
|
||||
|
||||
def postprocess_html(self, soup, *a):
|
||||
main = soup.find(id='content')
|
||||
header = soup.find(**classes('article__header'))
|
||||
header.extract()
|
||||
main.insert(0, header)
|
||||
a = soup.find('a', string='More from 1843 magazine')
|
||||
if a is not None:
|
||||
more = a.parent.parent
|
||||
more.extract()
|
||||
return soup
|
||||
|
@ -1,113 +0,0 @@
|
||||
from calibre.web.feeds.recipes import BasicNewsRecipe
|
||||
|
||||
|
||||
class AdvancedUserRecipe(BasicNewsRecipe):
|
||||
|
||||
title = u'Aachener Nachrichten'
|
||||
__author__ = 'schuster' # AGE update 2012-11-28
|
||||
oldest_article = 1
|
||||
max_articles_per_feed = 100
|
||||
no_stylesheets = True
|
||||
remove_javascript = True
|
||||
remove_empty_feeds = True
|
||||
language = 'de'
|
||||
|
||||
# cover_url = 'http://www.aachener-nachrichten.de/img/logos/an_website_retina.png'
|
||||
masthead_url = 'http://www.aachener-nachrichten.de/img/logos/an_website_retina.png'
|
||||
|
||||
keep_only_tags = [
|
||||
dict(name='article', attrs={'class': ['single']})
|
||||
]
|
||||
|
||||
remove_tags = [
|
||||
dict(name='div', attrs={'class': ["clearfix navi-wrapper"]}),
|
||||
dict(name='div', attrs={'id': ["article_actions"]}),
|
||||
dict(name='style', attrs={'type': ["text/css"]}),
|
||||
dict(name='aside'),
|
||||
dict(name='a', attrs={'class': ["btn btn-action"]})
|
||||
]
|
||||
|
||||
feeds = [
|
||||
(u'Lokales - Euregio',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/euregio-rss-1.357285'),
|
||||
(u'Lokales - Aachen',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/aachen-rss-1.357286'),
|
||||
(u'Lokales - Nordkreis',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/nordkreis-rss-1.358150'),
|
||||
(u'Lokales - Düren',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/dueren-rss-1.358626'),
|
||||
(u'Lokales - Eiffel',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/eifel-rss-1.358978'),
|
||||
(u'Lokales - Eschweiler',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/eschweiler-rss-1.359332'),
|
||||
(u'Lokales - Geilenkirchen',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/geilenkirchen-rss-1.359643'),
|
||||
(u'Lokales - Heinsberg',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/heinsberg-rss-1.359724'),
|
||||
(u'Lokales - Jülich',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/juelich-rss-1.359725'),
|
||||
(u'Lokales - Stolberg',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/stolberg-rss-1.359726'),
|
||||
(u'News - Politik',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/politik-rss-1.359727'),
|
||||
(u'News - Aus aller Welt',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/ausallerwelt-rss-1.453282'),
|
||||
(u'News - Wirtschaft',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/wirtschaft-rss-1.359872'),
|
||||
(u'News - Kultur',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/kultur-rss-1.365018'),
|
||||
(u'News - Kino', u'http://www.aachener-nachrichten.de/cmlink/kino-rss-1.365019'),
|
||||
(u'News - Digital',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/digital-rss-1.365020'),
|
||||
(u'News - Wissenschaft',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/wissenschaft-rss-1.365021'),
|
||||
(u'News - Hochschule',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/hochschule-rss-1.365022'),
|
||||
(u'News - Auto', u'http://www.aachener-nachrichten.de/cmlink/auto-rss-1.365023'),
|
||||
(u'News - Kurioses',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/kurioses-rss-1.365067'),
|
||||
(u'News - Musik',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/musik-rss-1.365305'),
|
||||
(u'News - Tagesthema',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/tagesthema-rss-1.365519'),
|
||||
(u'News - Newsticker',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/newsticker-rss-1.451948'),
|
||||
(u'Sport - Aktuell',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/aktuell-rss-1.366716'),
|
||||
(u'Sport - Fußball',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/fussball-rss-1.367060'),
|
||||
(u'Sport - Bundesliga',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/bundesliga-rss-1.453367'),
|
||||
(u'Sport - Alemannia Aachen',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/alemanniaaachen-rss-1.366057'),
|
||||
(u'Sport - Volleyball',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/volleyball-rss-1.453370'),
|
||||
(u'Sport - Chio',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/chio-rss-1.453371'),
|
||||
(u'Dossier - Kinderuni',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/kinderuni-rss-1.453375'),
|
||||
(u'Dossier - Karlspreis',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/karlspreis-rss-1.453376'),
|
||||
(u'Dossier - Ritterorden',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/ritterorden-rss-1.453377'),
|
||||
(u'Dossier - ZAB-Aachen',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/zabaachen-rss-1.453380'),
|
||||
(u'Dossier - Karneval',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/karneval-rss-1.453384'),
|
||||
(u'Ratgeber - Geld',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/geld-rss-1.453385'),
|
||||
(u'Ratgeber - Recht',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/recht-rss-1.453386'),
|
||||
(u'Ratgeber - Gesundheit',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/gesundheit-rss-1.453387'),
|
||||
(u'Ratgeber - Familie',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/familie-rss-1.453388'),
|
||||
(u'Ratgeber - Livestyle',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/lifestyle-rss-1.453389'),
|
||||
(u'Ratgeber - Reisen',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/reisen-rss-1.453390'),
|
||||
(u'Ratgeber - Bauen und Wohnen',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/bauen-rss-1.453398'),
|
||||
(u'Ratgeber - Bildung und Beruf',
|
||||
u'http://www.aachener-nachrichten.de/cmlink/bildung-rss-1.453400'),
|
||||
]
|
@ -1,24 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
|
||||
class AdvancedUserRecipe1334868409(BasicNewsRecipe):
|
||||
title = u'AÇIK BİLİM DERGİSİ'
|
||||
description = ' Aylık çevrimiçi bilim dergisi'
|
||||
__author__ = u'thomass'
|
||||
oldest_article = 30
|
||||
max_articles_per_feed = 300
|
||||
auto_cleanup = True
|
||||
encoding = 'UTF-8'
|
||||
publisher = 'açık bilim'
|
||||
category = 'haber, bilim,TR,dergi'
|
||||
language = 'tr'
|
||||
publication_type = 'magazine '
|
||||
conversion_options = {
|
||||
'tags': category, 'language': language, 'publisher': publisher, 'linearize_tables': True
|
||||
}
|
||||
cover_img_url = 'http://www.acikbilim.com/wp-content/themes/Equilibrium/images/logodene.jpg'
|
||||
masthead_url = 'http://www.acikbilim.com/wp-content/themes/Equilibrium/images/logodene.jpg'
|
||||
|
||||
feeds = [(u'Tüm Yayınlar', u'http://www.acikbilim.com/feed')]
|
89
recipes/afr.recipe
Normal file
@ -0,0 +1,89 @@
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
from calibre.ptempfile import PersistentTemporaryFile
|
||||
|
||||
|
||||
class afr(BasicNewsRecipe):
|
||||
title = 'Australian Financial Review'
|
||||
__author__ = 'unkn0wn'
|
||||
description = (
|
||||
'For more than 65 years The Australian Financial Review has been the authority on business,'
|
||||
' finance and investment news in Australia. It has a reputation for independent, award-winning '
|
||||
'journalism and is essential reading for Australia\'s business and investor community.'
|
||||
)
|
||||
masthead_url = 'https://www.nineforbrands.com.au/wp-content/uploads/2020/08/AFR-DHOSP-Logo-black-RGB.png'
|
||||
encoding = 'utf-8'
|
||||
language = 'en_AU'
|
||||
|
||||
use_embedded_content = False
|
||||
timefmt = ' [%d %b %Y]'
|
||||
max_articles_per_feed = 25
|
||||
no_stylesheets = True
|
||||
remove_empty_feeds = True
|
||||
remove_attributes = ['style', 'height', 'width']
|
||||
|
||||
keep_only_tags = [
|
||||
dict(name=['article', 'main'], attrs={'id':'content'})
|
||||
]
|
||||
|
||||
remove_tags = [
|
||||
dict(attrs={'data-testid': [
|
||||
'ArticleTools', 'ArticleBreadcrumb-Links', 'ad-wrapper', 'ArticleFooter', 'ArticleTags',
|
||||
'beyondwords-player-wrapper'
|
||||
]}),
|
||||
dict(name=['button', 'aside', 'svg']),
|
||||
]
|
||||
|
||||
remove_tags_after= [ dict(name='aside', attrs={'id':'stickyContainer'})]
|
||||
|
||||
extra_css = '''
|
||||
#img-cap {font-size:small; text-align:center;}
|
||||
[data-testid="AuthorNames"], [data-testid="ArticleTimestamp"] {font-size:small;}
|
||||
'''
|
||||
|
||||
ignore_duplicate_articles = {'title'}
|
||||
resolve_internal_links = True
|
||||
remove_empty_feeds = True
|
||||
|
||||
articles_are_obfuscated = True
|
||||
|
||||
def get_obfuscated_article(self, url):
|
||||
br = self.get_browser()
|
||||
try:
|
||||
br.open(url)
|
||||
except Exception as e:
|
||||
url = e.hdrs.get('location')
|
||||
soup = self.index_to_soup(url)
|
||||
link = soup.find('a', href=True)
|
||||
skip_sections =[ # add sections you want to skip
|
||||
'/video/', '/videos/', '/media/', 'podcast-'
|
||||
]
|
||||
if any(x in link['href'] for x in skip_sections):
|
||||
self.log('Aborting Article ', link['href'])
|
||||
self.abort_article('skipping video links')
|
||||
|
||||
self.log('Downloading ', link['href'])
|
||||
html = br.open(link['href']).read()
|
||||
pt = PersistentTemporaryFile('.html')
|
||||
pt.write(html)
|
||||
pt.close()
|
||||
return pt.name
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
for img in soup.findAll('img', attrs={'data-src':True}):
|
||||
img['src'] = img['data-src']
|
||||
for fig in soup.findAll('figcaption'):
|
||||
fig['id'] = 'img-cap'
|
||||
return soup
|
||||
|
||||
feeds = []
|
||||
|
||||
sections = [
|
||||
'companies', 'market', 'politics', 'policy', 'world', 'wealth', 'street-talk',
|
||||
'chaticleer', 'rear-window', 'life-and-luxury', 'technology', 'property',
|
||||
'work-and-careers',
|
||||
]
|
||||
|
||||
for sec in sections:
|
||||
a = 'https://news.google.com/rss/search?q=when:27h+allinurl:https%3A%2F%2Fwww.afr.com{}&hl=en-AU&gl=AU&ceid=AU:en'
|
||||
feeds.append((sec.capitalize(), a.format('%2F' + sec + '%2F')))
|
||||
feeds.append(('Others', a.format('')))
|
@ -1,20 +0,0 @@
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
|
||||
class Aftenposten(BasicNewsRecipe):
|
||||
title = u'Aftenposten'
|
||||
__author__ = 'davotibarna'
|
||||
description = 'Norske nyheter'
|
||||
language = 'no'
|
||||
oldest_article = 5
|
||||
max_articles_per_feed = 100
|
||||
recipe_disabled = ('The recipe to download Aftenposten has been '
|
||||
'temporarily disabled at the publisher\'s request, while '
|
||||
'they finalize their digital strategy.')
|
||||
no_stylesheets = True
|
||||
encoding = 'ISO-8859-1'
|
||||
|
||||
feeds = [(u'Aftenposten', u'http://www.aftenposten.no/eksport/rss-1_0/')]
|
||||
|
||||
def print_version(self, url):
|
||||
return url.replace('#xtor=RSS-3', '?service=print')
|
@ -1,36 +0,0 @@
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
|
||||
'''
|
||||
boljevac.blogspot.com
|
||||
'''
|
||||
|
||||
import re
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
|
||||
class AgroGerila(BasicNewsRecipe):
|
||||
title = 'Agro Gerila'
|
||||
__author__ = 'Darko Miletic'
|
||||
description = 'Politicki nekorektan blog.'
|
||||
oldest_article = 45
|
||||
max_articles_per_feed = 100
|
||||
language = 'sr'
|
||||
encoding = 'utf-8'
|
||||
no_stylesheets = True
|
||||
use_embedded_content = True
|
||||
publication_type = 'blog'
|
||||
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: "Trebuchet MS",Trebuchet,Verdana,sans1,sans-serif} .article_description{font-family: sans1, sans-serif} img{margin-bottom: 0.8em; border: 1px solid #333333; padding: 4px } ' # noqa
|
||||
|
||||
conversion_options = {
|
||||
'comment': description, 'tags': 'film, blog, srbija', 'publisher': 'Dry-Na-Nord', 'language': language
|
||||
}
|
||||
|
||||
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
|
||||
|
||||
feeds = [(u'Posts', u'http://boljevac.blogspot.com/feeds/posts/default')]
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
for item in soup.findAll(style=True):
|
||||
del item['style']
|
||||
return self.adeify_images(soup)
|