improved handling of gopher connections and support for animated gif
This commit is contained in:
parent
2413c1bf19
commit
dc7e9156c8
|
@ -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
|
||||
|
||||
|
|
51
offpunk.py
51
offpunk.py
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue