Frederick Yin: 1 Download binary files 3 files changed, 59 insertions(+), 5 deletions(-)
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~nhanb/mcross-devel/patches/11553/mbox | git am -3Learn more about email & git
Summary: Instead of reinventing the wheel and implementing downloading logic on our own, I turned to the so-called "helpers" for help - CLI commands that handle the dirty work of download jobs. Changes: - Introduced config arguments `download-cmd` and `download-dest` - Download helper, of course - Documentation regarding downloads - Crossed out binary file handling on the bucket list --- README.md | 20 ++++++++++++++++++-- src/mcross/conf.py | 13 ++++++++++--- src/mcross/gui/controller.py | 31 +++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c6b6474..e91f8b1 100644 --- a/README.md +++ b/README.md @@ -48,12 +48,28 @@ text-font = "Ubuntu" The priority is CLI arg > config file > default. -Keyboard shortcuts: +## Keyboard shortcuts: - `Ctrl-l`: jump to address bar. - Hold `Alt` to see possible button shortcuts underlined. This is what Qt calls [Accelerator Keys](https://doc.qt.io/qt-5/accelerators.html). +## Downloading files: + +When the server responds with something that isn't decodable as a string, +McRoss will download the response body as a file with a helper, for example, +[gemget](https://github.com/makeworld-the-better-one/gemget/). + +Configuration: + +```toml +# example for gemget; $URL is self-explanatory, and $DEST is just download-dest +# i.e. where the files will be downloaded to. +download-cmd = "gemget $URL -d $DEST" +download-dest = "~/Downloads/" +``` + +The download job will then be handed to the helper of your choice. # Development @@ -91,7 +107,7 @@ necessarily agree with its "plaintext or nothing" stance. - [x] more visual indicators: waiting cursor, status bar - [x] parse gemini's advanced line types - [x] render `text/*` mime types with correct charset -- [ ] handle `binary/*` mime types +- [x] handle `binary/*` mime types - [x] configurable document styling - [ ] human-friendly distribution - [ ] TOFU TLS (right now it always accepts self-signed certs) diff --git a/src/mcross/conf.py b/src/mcross/conf.py index f37c43a..04341e7 100644 --- a/src/mcross/conf.py +++ b/src/mcross/conf.py @@ -20,6 +20,8 @@ conf_definitions = [ ConfDef("text-color", "t", str, "black"), ConfDef("link-color", "l", str, "brown"), ConfDef("list-item-color", "i", str, "#044604"), + ConfDef("download-cmd", None, str, ""), + ConfDef("download-dest", None, str, "~/Downloads/"), ] @@ -59,9 +61,14 @@ def load_conf_file(): def parse_conf_args(): argparser = argparse.ArgumentParser() for confdef in conf_definitions: - argparser.add_argument( - f"-{confdef.short_name}", f"--{confdef.name}", type=confdef.type, - ) + if confdef.short_name is not None: + argparser.add_argument( + f"-{confdef.short_name}", f"--{confdef.name}", type=confdef.type, + ) + else: + argparser.add_argument( + f"--{confdef.name}", type=confdef.type, + ) args = argparser.parse_args() return {key.replace("_", "-"): val for key, val in vars(args).items() if val} diff --git a/src/mcross/gui/controller.py b/src/mcross/gui/controller.py index 6397404..4b6c889 100644 --- a/src/mcross/gui/controller.py +++ b/src/mcross/gui/controller.py @@ -2,11 +2,14 @@ import logging import threading import time import traceback +from pathlib import Path +import subprocess from ssl import SSLCertVerificationError from tkinter import READABLE, Tk, messagebox import curio +from .. import conf from ..transport import ( MAX_REQUEST_SECONDS, GeminiUrl, @@ -176,6 +179,34 @@ class Controller: "text/plain", ) return resp + except UnicodeDecodeError: + # try downloading as file instead + # with the help of an external downloader, e.g. gemget + try: + if not conf.get("download-cmd") or not conf.get("download-dest"): + await self.put_gui_op( + statusbar_logger.info, "Download configuration incomplete" + ) + return resp + download_cmd = conf.get("download-cmd").split(" ") + download_dest = Path(conf.get("download-dest")).expanduser() + except KeyError: + await self.put_gui_op( + statusbar_logger.info, "Download configuration not found" + ) + + # fill in arguments + for index, fragment in enumerate(download_cmd): + if fragment == "$URL": + download_cmd[index] = str(url) + elif fragment == "$DEST": + download_cmd[index] = str(download_dest) + + proc = subprocess.run(download_cmd) + await self.put_gui_op( + statusbar_logger.info, f"Download initiated: {url}" + ) + return resp # Sucessfully decoded body string! if resp.status.startswith("2"):
Oh wait. Please do not merge it. I need to edit the dynamic argument logic to parse $URL and $DEST when they aren't individual words, i.e. surrounded by spaces. ~fkfd
-- 2.27.0