browser: open last download with external commands
This commit is contained in:
parent
f1c5d8dfc9
commit
3a88a898c9
13
BOARD.txt
13
BOARD.txt
|
@ -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?)
|
||||
|
|
12
README.md
12
README.md
|
@ -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.
|
||||
|
@ -74,11 +74,13 @@ 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. |
|
||||
| `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
|
||||
)
|
||||
|
|
Reference in a new issue