We now render images in terminal and introduce the open command. Beware, it is very experimental
This commit is contained in:
parent
ff9adf4aea
commit
980ad72510
96
offpunk.py
96
offpunk.py
|
@ -500,7 +500,41 @@ class FeedRenderer():
|
||||||
page += "\n\n"
|
page += "\n\n"
|
||||||
return page
|
return page
|
||||||
|
|
||||||
|
class ImageRenderer():
|
||||||
|
def __init__(self,img,url):
|
||||||
|
self.url = url
|
||||||
|
self.path = img
|
||||||
|
self.rendered_text = None
|
||||||
|
self.title = "Picture file"
|
||||||
|
def is_valid(self):
|
||||||
|
if _RENDER_IMAGE:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
def get_body(self,readable=True,width=None):
|
||||||
|
if not width:
|
||||||
|
width = TERM_WIDTH
|
||||||
|
if self.rendered_text == None:
|
||||||
|
self.rendered_text = self.render_image(self.path,width)
|
||||||
|
return self.rendered_text
|
||||||
|
def get_links(self):
|
||||||
|
return []
|
||||||
|
def get_title(self):
|
||||||
|
return self.title
|
||||||
|
def render_image(self,img,width=None):
|
||||||
|
if not width:
|
||||||
|
width = TERM_WIDTH
|
||||||
|
try:
|
||||||
|
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)
|
||||||
|
cmd = "chafa --bg white -s %s -w 1 \"%s\"" %(width,img)
|
||||||
|
return_code = subprocess.run(cmd,shell=True, capture_output=True)
|
||||||
|
ansi_img = return_code.stdout.decode()
|
||||||
|
except Exception as err:
|
||||||
|
ansi_img = "***image failed : %s***\n" %err
|
||||||
|
return ansi_img
|
||||||
|
|
||||||
class HtmlRenderer():
|
class HtmlRenderer():
|
||||||
def __init__(self,content,url):
|
def __init__(self,content,url):
|
||||||
|
@ -637,16 +671,13 @@ class HtmlRenderer():
|
||||||
g = GeminiItem(abs_url)
|
g = GeminiItem(abs_url)
|
||||||
if g.is_cache_valid():
|
if g.is_cache_valid():
|
||||||
img = g.get_cache_path()
|
img = g.get_cache_path()
|
||||||
try:
|
renderer = ImageRenderer(img,abs_url)
|
||||||
img_obj = Image.open(img)
|
# Image are 40px wide except if terminal is smaller
|
||||||
if hasattr(img_obj,"n_frames") and img_obj.n_frames > 1:
|
if width > 40:
|
||||||
# we remove all frames but the first one
|
size = 40
|
||||||
img_obj.save(img,save_all=False)
|
else:
|
||||||
cmd = "chafa --bg white -s 40 -w 1 \"%s\"" %img
|
size = width
|
||||||
return_code = subprocess.run(cmd,shell=True, capture_output=True)
|
ansi_img = renderer.get_body(width=size)
|
||||||
ansi_img = return_code.stdout.decode()
|
|
||||||
except Exception as err:
|
|
||||||
ansi_img = "***image failed : %s***\n" %err
|
|
||||||
alt = element.get("alt")
|
alt = element.get("alt")
|
||||||
if alt:
|
if alt:
|
||||||
alt = sanitize_string(alt)
|
alt = sanitize_string(alt)
|
||||||
|
@ -728,6 +759,7 @@ _FORMAT_RENDERERS = {
|
||||||
"text/html" : HtmlRenderer,
|
"text/html" : HtmlRenderer,
|
||||||
"text/xml" : FeedRenderer,
|
"text/xml" : FeedRenderer,
|
||||||
"text/gopher": GopherRenderer,
|
"text/gopher": GopherRenderer,
|
||||||
|
"image/*": ImageRenderer
|
||||||
}
|
}
|
||||||
# Offpunk is organized as follow:
|
# Offpunk is organized as follow:
|
||||||
# - a GeminiClient instance which handles the browsing of GeminiItems (= pages).
|
# - a GeminiClient instance which handles the browsing of GeminiItems (= pages).
|
||||||
|
@ -964,18 +996,28 @@ class GeminiItem():
|
||||||
def _set_renderer(self,mime=None):
|
def _set_renderer(self,mime=None):
|
||||||
if not mime:
|
if not mime:
|
||||||
mime = self.get_mime()
|
mime = self.get_mime()
|
||||||
if mime in _FORMAT_RENDERERS:
|
mime_to_use = []
|
||||||
func = _FORMAT_RENDERERS[mime]
|
for m in _FORMAT_RENDERERS:
|
||||||
#print("Set RENDERER to %s" %mime)
|
if fnmatch.fnmatch(mime, m):
|
||||||
self.renderer = func(self.get_body(),self.url)
|
mime_to_use.append(m)
|
||||||
# We double check if the renderer is correct.
|
if len(mime_to_use) > 0:
|
||||||
# If not, we fallback to html
|
current_mime = mime_to_use[0]
|
||||||
# (this is currently only for XHTML, often being
|
func = _FORMAT_RENDERERS[current_mime]
|
||||||
# mislabelled as xml thus RSS feeds)
|
if current_mime.startswith("text"):
|
||||||
if not self.renderer.is_valid():
|
|
||||||
func = _FORMAT_RENDERERS["text/html"]
|
|
||||||
#print("Set (fallback)RENDERER to html instead of %s"%mime)
|
|
||||||
self.renderer = func(self.get_body(),self.url)
|
self.renderer = func(self.get_body(),self.url)
|
||||||
|
# We double check if the renderer is correct.
|
||||||
|
# If not, we fallback to html
|
||||||
|
# (this is currently only for XHTML, often being
|
||||||
|
# mislabelled as xml thus RSS feeds)
|
||||||
|
if not self.renderer.is_valid():
|
||||||
|
func = _FORMAT_RENDERERS["text/html"]
|
||||||
|
#print("Set (fallback)RENDERER to html instead of %s"%mime)
|
||||||
|
self.renderer = func(self.get_body(),self.url)
|
||||||
|
else:
|
||||||
|
#we don’t parse text, we give the file to the renderer
|
||||||
|
self.renderer = func(self._cache_path,self.url)
|
||||||
|
if not self.renderer.is_valid():
|
||||||
|
self.renderer = None
|
||||||
|
|
||||||
|
|
||||||
def get_rendered_body(self,readable=True):
|
def get_rendered_body(self,readable=True):
|
||||||
|
@ -2466,6 +2508,16 @@ Use "less full" to see a complete html page instead of the article view.
|
||||||
else:
|
else:
|
||||||
self.do_go(self.gi.url)
|
self.do_go(self.gi.url)
|
||||||
|
|
||||||
|
@needs_gi
|
||||||
|
def do_open(self, *args):
|
||||||
|
"""Open current item with the configured handler or xdg-open.
|
||||||
|
see "handler" command to set your own."""
|
||||||
|
cmd_str = self._get_handler_cmd(self.gi.get_mime())
|
||||||
|
file_path = "\"%s\"" %self.gi.get_body(as_file=True)
|
||||||
|
cmd_str = cmd_str % file_path
|
||||||
|
subprocess.call(cmd_str,shell=True)
|
||||||
|
|
||||||
|
|
||||||
@needs_gi
|
@needs_gi
|
||||||
def do_fold(self, *args):
|
def do_fold(self, *args):
|
||||||
"""Run most recently visited item through "fold" command."""
|
"""Run most recently visited item through "fold" command."""
|
||||||
|
|
Loading…
Reference in New Issue