browser: open last download with external commands

exec
dece 3 years ago
parent f1c5d8dfc9
commit 3a88a898c9

@ -4,7 +4,7 @@ TODO DONE
links
redirections
web links
history (back/forward)
history (back)
simple caching
simple text files
encodings
@ -14,21 +14,26 @@ TODO DONE
configuration
help page
TOFU
open last download
view history
open last download
media files
home page
media files
view history
identity management
--------------------------------------------------------------------------------
BACKLOG
click on links to open them
download to disk, not in memory
download in the background
download view instead of last download
does encoding really work? cf. egsam
margins / centering
pre blocks folding
buffers (tabs)
a11y? tts?
handle soft-hyphens on wrapping
bug: combining chars reduce lengths
non shit command-line
response code 11 (if still there)
gopher?
save history
history (forward) (useful?)

@ -57,7 +57,7 @@ It also provide these features:
- History
- Caching
- Bookmarks: it's just a text file with bindings.
- Bookmarks (it's just a text file with bindings)
- Downloads
Check out [this board](BOARD.txt) for what's done and coming next.
@ -73,12 +73,14 @@ you want, just restart Bebop to take changes into account.
Here are the available options:
| Key | Type | Default | Description |
|-------------------|-------------|----------|---------------------------------------|
| `connect_timeout` | int | 10 | Seconds before connection times out. |
| `text_width` | int | 80 | Rendered line length. |
| `source_editor` | string list | `["vi"]` | Command to use for editing sources. |
| `command_editor` | string list | `["vi"]` | Command to use for editing CLI input. |
| Key | Type | Default | Description |
|----------------------------|--------------|----------------|---------------------------------------|
| `connect_timeout` | int | 10 | Seconds before connection times out. |
| `text_width` | int | 80 | Rendered line length. |
| `source_editor` | string list | `["vi"]` | Command to use for editing sources. |
| `command_editor` | string list | `["vi"]` | Command to use for editing CLI input. |
| `external_commands` | (see note 2) | {} | Commands to open various files. |
| `external_command_default` | string list | `["xdg-open"]` | Default command to open files. |
Note: for the "command" parameters such as `source_editor` and `command_editor`,
a string list is used to separate the different program arguments, e.g. if you
@ -86,6 +88,12 @@ wish to use `vim -c 'startinsert'`, you should write the list `["vim", "-c",
"startinsert"]`. In both case, a temporary or regular file name will be appended
to this command when run.
2: the `external_commands` dict maps MIME types to commands just as above. For
example, if you want to open video files with VLC and audio files in Clementine,
you can use the following dict: `{"audio": ["clementine"], "video", ["vlc"]}`.
For now only "main" MIME types are supported, i.e. you cannot specify precise
types like "audio/flac", just "audio".
FAQ

@ -4,8 +4,11 @@ import curses
import curses.ascii
import curses.textpad
import os
import subprocess
import tempfile
from math import inf
from pathlib import Path
from typing import Optional, Tuple
from bebop.bookmarks import (
get_bookmarks_path, get_bookmarks_document, save_bookmark
@ -16,6 +19,7 @@ from bebop.external import open_external_program
from bebop.help import HELP_PAGE
from bebop.history import History
from bebop.links import Links
from bebop.mime import MimeType
from bebop.mouse import ButtonState
from bebop.navigation import (
get_parent_url, get_root_url, join_url, parse_url, unparse_url
@ -44,6 +48,7 @@ class Browser:
values are dicts as well: the "open" key maps to a callable to use when
the page is accessed, and the optional "source" key maps to callable
returning the page source path.
- last_download: tuple of MimeType and path, or None.
"""
def __init__(self, config, cert_stash):
@ -59,6 +64,7 @@ class Browser:
self.history = History(self.config["history_limit"])
self.cache = {}
self.special_pages = self.setup_special_pages()
self.last_download: Optional[Tuple[MimeType, Path]] = None
self._current_url = ""
@property
@ -168,6 +174,8 @@ class Browser:
self.scroll_page_vertically(inf)
elif char == ord("o"):
self.quick_command("open")
elif char == ord("O"):
self.open_last_download()
elif char == ord("p"):
self.go_back()
elif char == ord("u"):
@ -574,3 +582,23 @@ class Browser:
def open_history(self):
"""Show a generated history of visited pages."""
self.open_internal_page("history", self.history.to_gemtext())
def open_last_download(self):
"""Open the last downloaded file."""
if not self.last_download:
return
mime_type, path = self.last_download
command = self.config["external_commands"].get(mime_type.main_type)
if not command:
command = self.config["external_command_default"]
command = command + [str(path)]
self.set_status(f"Running '{' '.join(command)}'...")
try:
subprocess.Popen(
command,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
start_new_session=True
)
except FileNotFoundError as exc:
self.set_status_error(f"Failed to run command: {exc}")

@ -193,6 +193,7 @@ def _handle_successful_response(browser: Browser, response: Response, url: str):
browser.set_status_error(f"Failed to save {url} ({exc})")
else:
browser.set_status(f"Downloaded {url} ({mime_type.short}).")
browser.last_download = mime_type, filepath
return True
elif error:
browser.set_status_error(error)

@ -10,6 +10,8 @@ DEFAULT_CONFIG = {
"source_editor": ["vi"],
"command_editor": ["vi"],
"history_limit": 1000,
"external_commands": {},
"external_command_default": ["xdg-open"]
}

@ -26,6 +26,7 @@ name, not the symbol itself.
- gg: go to the top of the page
- G: go to the bottom of the page
- o: open an URL
- O: open last download with an external command
- p: go to the previous page
- u: go to the parent page (up a level in URL)
- U: go to the root page (root URL for the current domain)

@ -6,7 +6,6 @@ turned into a basic re-implementation of the RFC.
"""
import re
from ssl import RAND_pseudo_bytes
from typing import Any, Dict, Optional
from urllib.parse import quote

@ -79,7 +79,7 @@ class TestNavigation(unittest.TestCase):
self.assertEqual(
remove_dot_segments(path),
expected,
msg=f"path was " + path
msg="path was " + path
)
def test_remove_last_segment(self):
@ -123,7 +123,7 @@ class TestNavigation(unittest.TestCase):
self.assertEqual(
get_parent_url(url),
parent,
msg=f"URL was " + url)
msg="URL was " + url)
def test_get_root_url(self):
urls_and_roots = [
@ -140,5 +140,5 @@ class TestNavigation(unittest.TestCase):
self.assertEqual(
get_root_url(url),
root,
msg=f"URL was " + url
msg="URL was " + url
)

Loading…
Cancel
Save