From 5df12a6434fe85e680c2bf9903a3b71bd98f980d Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 1 Apr 2023 10:29:26 +0530 Subject: [PATCH] A new tweak in Preferences->Tweaks to control what program is run when clicking on URLs in calibre --- resources/default_tweaks.py | 11 +++++++++++ src/calibre/gui2/__init__.py | 27 ++++++++++++++++++++++----- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/resources/default_tweaks.py b/resources/default_tweaks.py index 3f8c016722..fa5ef4ea78 100644 --- a/resources/default_tweaks.py +++ b/resources/default_tweaks.py @@ -561,3 +561,14 @@ value_for_undefined_numbers_when_sorting = 0 # using these functions in composites can be very slow. # Default: False allow_template_database_functions_in_composites = False + + +#: Change the programs that are run when opening files/URLS +# By default, calibre passes URLs to the operating system to open using +# whatever default programs are configured there. Here you can override +# that by specifying the program to use, per URL type. For local files, +# the type is "file" for web links it is "http*". For example: +# openers_by_scheme = { "http*": "firefox %u" } will make calibre run firefox +# for https://whatever URLs. %u is replaced by the URL to be opened. The scheme +# takes a glob pattern allowing a single entry to match multiple URL types. +openers_by_scheme = {} diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index 024e403ca7..768312bd1b 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -1410,13 +1410,30 @@ SanitizeLibraryPath = sanitize_env_vars # For old plugins def open_url(qurl): - # Qt 5 requires QApplication to be constructed before trying to use - # QDesktopServices::openUrl() - ensure_app() if isinstance(qurl, string_or_bytes): qurl = QUrl(qurl) + scheme = qurl.scheme().lower() or 'file' + import fnmatch + opener = [] + with suppress(Exception): + for scheme_pat, spec in tweaks['openers_by_scheme'].items(): + if fnmatch.fnmatch(scheme, scheme_pat): + with suppress(Exception): + import shlex + opener = shlex.split(spec) + break with sanitize_env_vars(): - QDesktopServices.openUrl(qurl) + if opener: + import subprocess + cmd = [x.replace('%u', qurl.toString()) for x in opener] + if DEBUG: + print('Running opener:', cmd) + subprocess.Popen(cmd, stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + else: + # Qt 5 requires QApplication to be constructed before trying to use + # QDesktopServices::openUrl() + ensure_app() + QDesktopServices.openUrl(qurl) def safe_open_url(qurl): @@ -1426,7 +1443,7 @@ def safe_open_url(qurl): path = qurl.toLocalFile() ext = os.path.splitext(path)[-1].lower()[1:] if ext in ('exe', 'com', 'cmd', 'bat', 'sh', 'psh', 'ps1', 'vbs', 'js', 'wsf', 'vba', 'py', 'rb', 'pl', 'app'): - prints('Refusing to open file:', path) + prints('Refusing to open file:', path, file=sys.stderr) return open_url(qurl)