improved handling of gopher connections and support for animated gif

This commit is contained in:
Lionel Dricot 2022-02-11 11:03:19 +01:00
parent 2413c1bf19
commit dc7e9156c8
2 changed files with 48 additions and 6 deletions

View File

@ -73,7 +73,7 @@ To avoid using unstable or too recent libraries, the rule of thumb is that a lib
* [BeautifulSoup4](https://www.crummy.com/software/BeautifulSoup) and [Readability](https://github.com/buriy/python-readability) are both needed to render HTML. Without them, HTML will not be rendered or be sent to an external parser like Lynx. (apt-get install python3-bs4 python3-readability or pip3 install readability-lxml)
* [Python-feedparser](https://github.com/kurtmckee/feedparser) will allow parsing of RSS/Atom feeds and thus subscriptions to them. (apt-get install python3-feedparser)
* The [ansiwrap library](https://pypi.org/project/ansiwrap/) may result in
neater display of text which makes use of ANSI escape codes to control colour (not in Debian?).
neater display of text which makes use of ANSI escape codes to control colour. Ansiwrap is also required to display pictures in HTML pages (together with Chafa and python-pil) (not in Debian?).
* The [cryptography library](https://pypi.org/project/cryptography/) will
provide a better and slightly more secure experience when using the default
TOFU certificate validation mode and is highly recommended (apt-get install python3-cryptography).
@ -81,6 +81,7 @@ To avoid using unstable or too recent libraries, the rule of thumb is that a lib
* [Python editor](https://github.com/fmoo/python-editor) is used to edit your lists with "list edit". (apt-get install python3-editor)
* [Xsel](http://www.vergenet.net/~conrad/software/xsel/) allows to `go` to the URL copied in the clipboard without having to paste it (both X and traditional clipboards are supported). Also needed to use the `copy` command. (apt-get install xsel)
* [Chafa](https://hpjansson.org/chafa/) allows to display pictures in your console. Install it and browse to an HTML page with picture to see the magic.
* [Python-pil](http://python-pillow.github.io/) is required to only display the first frame of animated gif with chafa.
## Features

View File

@ -52,9 +52,23 @@ except ModuleNotFoundError:
try:
import ansiwrap as textwrap
_HAS_ANSIWRAP = True
except ModuleNotFoundError:
print("Try installing python-ansiwrap for better rendering")
import textwrap
_HAS_ANSIWRAP = False
try:
from PIL import Image
if _HAS_ANSIWRAP and shutil.which('chafa'):
_RENDER_IMAGE = True
else:
print("chafa and ansiwrap are required to render images in terminal")
_RENDER_IMAGE = False
except ModuleNotFoundError:
print("python-pil, chafa and ansiwrap are required to render images")
_RENDER_IMAGE = False
try:
from cryptography import x509
@ -586,12 +600,16 @@ class HtmlRenderer():
src = element.get("src")
text = ""
ansi_img = ""
if shutil.which('chafa'):
if _RENDER_IMAGE:
abs_url = urllib.parse.urljoin(self.url, src)
g = GeminiItem(abs_url)
if g.is_cache_valid():
img = g.get_cache_path()
return_code = subprocess.run("chafa --bg white -s 40 %s"%img, \
img_obj = Image.open(img)
if hasattr(img_obj,"n_frames") and img_obj.n_frames > 1:
# we remove all frames but the first one
img_obj.save(img,save_all=False)
return_code = subprocess.run("chafa --bg white -s 40 %s -w 1"%img, \
shell=True, capture_output=True)
ansi_img = return_code.stdout.decode()
alt = element.get("alt")
@ -644,8 +662,14 @@ class HtmlRenderer():
i_indent = ""
s_indent = i_indent
if line.strip() != "":
wrapped = textwrap.fill(line,width,initial_indent=i_indent,
try:
wrapped = textwrap.fill(line,width,initial_indent=i_indent,
subsequent_indent=s_indent)
except Exception as err:
wrapped = line
#print(self.url)
#print(err)
#crash
wrapped += "\n"
else:
wrapped = ""
@ -1254,7 +1278,7 @@ class GeminiClient(cmd.Cmd):
else:
return
elif gi.scheme in ("gopher"):
gi = self._fetch_gopher(gi)
gi = self._fetch_gopher(gi,timeout=self.options["short_timeout"])
else:
gi = self._fetch_over_network(gi)
except UserAbortException:
@ -1340,7 +1364,9 @@ class GeminiClient(cmd.Cmd):
gi.write_body(body,mime)
return gi
def _fetch_gopher(self,gi):
def _fetch_gopher(self,gi,timeout=10):
if not looks_like_url(gi.url):
print("%s is not a valide url" %gi.url)
parsed =urllib.parse.urlparse(gi.url)
host = parsed.hostname
port = parsed.port or 70
@ -1356,7 +1382,22 @@ class GeminiClient(cmd.Cmd):
else:
itemtype = "1"
selector = parsed.path
addresses = socket.getaddrinfo(host, port, family=0,type=socket.SOCK_STREAM)
s = socket.create_connection((host,port))
for address in addresses:
self._debug("Connecting to: " + str(address[4]))
s = socket.socket(address[0], address[1])
s.settimeout(timeout)
try:
s.connect(address[4])
break
except OSError as e:
err = e
else:
# If we couldn't connect to *any* of the addresses, just
# bubble up the exception from the last attempt and deny
# knowledge of earlier failures.
raise err
if parsed.query:
request = selector + "\t" + parsed.query
else: