~nhanb/mcross-devel

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch
1

[PATCH] Download binary files

Details
Message ID
<20200711133603.6697-1-fkfd@macaw.me>
DKIM signature
missing
Download raw message
Patch: +59 -5
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"):
-- 
2.27.0
Details
Message ID
<752AC1E6-D9FF-48D6-BE68-4B9E8FF198E5@macaw.me>
In-Reply-To
<20200711133603.6697-1-fkfd@macaw.me> (view parent)
DKIM signature
missing
Download raw message
On July 11, 2020 1:36:04 PM UTC, Frederick Yin <fkfd@macaw.me> wrote:
>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
Reply to thread Export thread (mbox)