abstracting renderers to make them more coherent
This commit is contained in:
parent
67fbf9902e
commit
85551f5af5
131
offpunk.py
131
offpunk.py
|
@ -233,40 +233,31 @@ class AbstractRenderer():
|
||||||
self.title = None
|
self.title = None
|
||||||
self.validity = True
|
self.validity = True
|
||||||
|
|
||||||
def with_width(func):
|
|
||||||
def inner(*args, **kwargs):
|
|
||||||
if not kwargs["width"]:
|
|
||||||
kwargs["width"] = TERM_WIDTH
|
|
||||||
func(*args, **kwargs)
|
|
||||||
return inner
|
|
||||||
|
|
||||||
def is_valid(self):
|
def is_valid(self):
|
||||||
return self.validity
|
return self.validity
|
||||||
def get_links(self):
|
def get_links(self):
|
||||||
if not self.links:
|
if self.links == None :
|
||||||
self.links = []
|
rendered_text, self.links = self.render(self.body,mode="links_only")
|
||||||
return self.links
|
return self.links
|
||||||
def get_title(self):
|
def get_title(self):
|
||||||
return "Abstract title"
|
return "Abstract title"
|
||||||
|
|
||||||
@with_width
|
|
||||||
def get_body(self,readable=True,width=None):
|
def get_body(self,readable=True,width=None):
|
||||||
pass
|
if not width:
|
||||||
#return self.body
|
width = TERM_WIDTH
|
||||||
|
if self.rendered_text == None or not readable:
|
||||||
|
if readable :
|
||||||
|
mode = "readable"
|
||||||
|
else :
|
||||||
|
mode = "full"
|
||||||
|
self.rendered_text, self.links = self.render(self.body,width=width,mode=mode)
|
||||||
|
return self.rendered_text
|
||||||
|
# An instance of AbstractRenderer should have a self.render(body,width,mode) method.
|
||||||
|
# 3 modes are used : readable (by default), full and links_only (the fastest, when
|
||||||
|
# rendered content is not used, only the links are needed)
|
||||||
|
|
||||||
# Gemtext Rendering Engine
|
# Gemtext Rendering Engine
|
||||||
class GemtextRenderer(AbstractRenderer):
|
class GemtextRenderer(AbstractRenderer):
|
||||||
def get_body(self,readable=True,width=None):
|
|
||||||
super().get_body(readable=readable,width=width)
|
|
||||||
if self.rendered_text == None :
|
|
||||||
self.rendered_text, self.links = self.render_gemtext(self.body,width=width)
|
|
||||||
return self.rendered_text
|
|
||||||
|
|
||||||
def get_links(self):
|
|
||||||
if self.links == None :
|
|
||||||
rendered_text, self.links = self.render_gemtext(self.body)
|
|
||||||
return self.links
|
|
||||||
|
|
||||||
def get_title(self):
|
def get_title(self):
|
||||||
if self.title:
|
if self.title:
|
||||||
return self.title
|
return self.title
|
||||||
|
@ -287,8 +278,9 @@ class GemtextRenderer(AbstractRenderer):
|
||||||
else:
|
else:
|
||||||
self.title = "Empty Page"
|
self.title = "Empty Page"
|
||||||
return self.title
|
return self.title
|
||||||
|
|
||||||
def render_gemtext(self,gemtext, width=None):
|
#render_gemtext
|
||||||
|
def render(self,gemtext, width=None,mode=None):
|
||||||
if not width:
|
if not width:
|
||||||
width = TERM_WIDTH
|
width = TERM_WIDTH
|
||||||
links = []
|
links = []
|
||||||
|
@ -361,35 +353,26 @@ class GemtextRenderer(AbstractRenderer):
|
||||||
return rendered_text, links
|
return rendered_text, links
|
||||||
|
|
||||||
class GopherRenderer(AbstractRenderer):
|
class GopherRenderer(AbstractRenderer):
|
||||||
def get_body(self,readable=True,width=None):
|
|
||||||
super().get_body(readable=readable,width=width)
|
|
||||||
if self.rendered_text == None:
|
|
||||||
self.rendered_text,self.links = self.menu_or_text(width=width)
|
|
||||||
return self.rendered_text
|
|
||||||
|
|
||||||
def get_links(self):
|
|
||||||
if self.links == None:
|
|
||||||
rendered_text,self.links = self.menu_or_text()
|
|
||||||
return self.links
|
|
||||||
|
|
||||||
def get_title(self):
|
def get_title(self):
|
||||||
return "Gopher - No Title"
|
return "Gopher - No Title"
|
||||||
|
|
||||||
def menu_or_text(self,width=None):
|
#menu_or_text
|
||||||
|
def render(self,body,width=None,mode=None):
|
||||||
|
print("Gopher rendering with width %s" %width)
|
||||||
if not width:
|
if not width:
|
||||||
width = TERM_WIDTH
|
width = TERM_WIDTH
|
||||||
try:
|
try:
|
||||||
render,links = self._render_goph(width=width)
|
render,links = self._render_goph(width=width,mode=mode)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
print("Error ",err)
|
print("Error ",err)
|
||||||
lines = self.body.split("\n")
|
lines = body.split("\n")
|
||||||
render = ""
|
render = ""
|
||||||
for line in lines:
|
for line in lines:
|
||||||
render += textwrap.fill(line,width) + "\n"
|
render += textwrap.fill(line,width) + "\n"
|
||||||
links = []
|
links = []
|
||||||
return render,links
|
return render,links
|
||||||
|
|
||||||
def _render_goph(self,width=None):
|
def _render_goph(self,width=None,mode=None):
|
||||||
if not width:
|
if not width:
|
||||||
width = TERM_WIDTH
|
width = TERM_WIDTH
|
||||||
# This is copied straight from Agena (and thus from VF1)
|
# This is copied straight from Agena (and thus from VF1)
|
||||||
|
@ -429,7 +412,7 @@ class GopherRenderer(AbstractRenderer):
|
||||||
|
|
||||||
|
|
||||||
class FolderRenderer(AbstractRenderer):
|
class FolderRenderer(AbstractRenderer):
|
||||||
def get_body(self,readable=True,width=None):
|
def render(self,body,mode=None,width=None):
|
||||||
def write_list(l):
|
def write_list(l):
|
||||||
path = os.path.join(listdir,l+".gmi")
|
path = os.path.join(listdir,l+".gmi")
|
||||||
gi = GeminiItem("file://" + path)
|
gi = GeminiItem("file://" + path)
|
||||||
|
@ -472,34 +455,26 @@ class FolderRenderer(AbstractRenderer):
|
||||||
body +="\n## System Lists\n"
|
body +="\n## System Lists\n"
|
||||||
for l in system_lists:
|
for l in system_lists:
|
||||||
body += write_list(l)
|
body += write_list(l)
|
||||||
self.rendered_body,self.links = GemtextRenderer.render_gemtext(self,body)
|
self.rendered_body,self.links = GemtextRenderer.render(self,body,width=width)
|
||||||
return self.rendered_body
|
return self.rendered_body, self.links
|
||||||
|
|
||||||
class FeedRenderer(AbstractRenderer):
|
class FeedRenderer(AbstractRenderer):
|
||||||
def is_valid(self):
|
def is_valid(self):
|
||||||
self.render_feed(self.body)
|
if _DO_FEED:
|
||||||
return self.validity
|
parsed = feedparser.parse(self.body)
|
||||||
|
|
||||||
def get_body(self,readable=True,width=None):
|
|
||||||
super().get_body(readable=readable,width=width)
|
|
||||||
if readable:
|
|
||||||
if not self.rendered_text:
|
|
||||||
self.rendered_text = self.render_feed(self.body,width=width)
|
|
||||||
return self.rendered_text
|
|
||||||
else:
|
else:
|
||||||
return self.render_feed(self.body,full=True)
|
return False
|
||||||
|
if parsed.bozo:
|
||||||
def get_links(self):
|
return False
|
||||||
if not self.links:
|
else:
|
||||||
self.render_feed(self.body)
|
return True
|
||||||
return self.links
|
|
||||||
|
|
||||||
def get_title(self):
|
def get_title(self):
|
||||||
if not self.title:
|
if not self.title:
|
||||||
self.render_feed(self.body)
|
self.render(self.body)
|
||||||
return self.title
|
return self.title
|
||||||
|
|
||||||
def render_feed(self,content,full=False,width=None):
|
def render(self,content,mode="readable",width=None):
|
||||||
if not width:
|
if not width:
|
||||||
width = TERM_WIDTH
|
width = TERM_WIDTH
|
||||||
self.links = []
|
self.links = []
|
||||||
|
@ -546,11 +521,11 @@ class FeedRenderer(AbstractRenderer):
|
||||||
line += "on %s"%i.published
|
line += "on %s"%i.published
|
||||||
page += textwrap.fill(line,width)
|
page += textwrap.fill(line,width)
|
||||||
page += "\n\n"
|
page += "\n\n"
|
||||||
if full:
|
if mode == "full":
|
||||||
if "summary" in i:
|
if "summary" in i:
|
||||||
page += textwrap.fill(i.summary,width)
|
page += textwrap.fill(i.summary,width)
|
||||||
page += "\n\n"
|
page += "\n\n"
|
||||||
return page
|
return page, self.links
|
||||||
|
|
||||||
class ImageRenderer(AbstractRenderer):
|
class ImageRenderer(AbstractRenderer):
|
||||||
def is_valid(self):
|
def is_valid(self):
|
||||||
|
@ -558,16 +533,13 @@ class ImageRenderer(AbstractRenderer):
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
def get_body(self,readable=True,width=None):
|
|
||||||
super().get_body(readable=readable,width=width)
|
|
||||||
if self.rendered_text == None:
|
|
||||||
self.rendered_text = self.render_image(self.body,width)
|
|
||||||
return self.rendered_text
|
|
||||||
def get_links(self):
|
def get_links(self):
|
||||||
return []
|
return []
|
||||||
def get_title(self):
|
def get_title(self):
|
||||||
return "Picture file"
|
return "Picture file"
|
||||||
def render_image(self,img,width=None):
|
def render(self,img,width=None,mode=None):
|
||||||
|
if mode == "links_only":
|
||||||
|
return "", []
|
||||||
if not width:
|
if not width:
|
||||||
width = TERM_WIDTH
|
width = TERM_WIDTH
|
||||||
try:
|
try:
|
||||||
|
@ -580,24 +552,9 @@ class ImageRenderer(AbstractRenderer):
|
||||||
ansi_img = return_code.stdout.decode()
|
ansi_img = return_code.stdout.decode()
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
ansi_img = "***image failed : %s***\n" %err
|
ansi_img = "***image failed : %s***\n" %err
|
||||||
return ansi_img
|
return ansi_img, []
|
||||||
|
|
||||||
class HtmlRenderer(AbstractRenderer):
|
class HtmlRenderer(AbstractRenderer):
|
||||||
def get_body(self,readable=True,width=None):
|
|
||||||
super().get_body(readable=readable,width=width)
|
|
||||||
if self.rendered_text == None or not readable:
|
|
||||||
if readable:
|
|
||||||
mode = "readable"
|
|
||||||
else:
|
|
||||||
mode = "full"
|
|
||||||
self.rendered_text, self.links = self.render_html(self.body,mode=mode,width=width)
|
|
||||||
return self.rendered_text
|
|
||||||
|
|
||||||
def get_links(self):
|
|
||||||
if self.links == None :
|
|
||||||
rendered_text, self.links = self.render_html(self.body,mode="quick")
|
|
||||||
return self.links
|
|
||||||
|
|
||||||
def get_title(self):
|
def get_title(self):
|
||||||
if self.title:
|
if self.title:
|
||||||
return self.title
|
return self.title
|
||||||
|
@ -608,8 +565,8 @@ class HtmlRenderer(AbstractRenderer):
|
||||||
|
|
||||||
# Our own HTML engine (crazy, isn’t it?)
|
# Our own HTML engine (crazy, isn’t it?)
|
||||||
# Return [rendered_body, list_of_links]
|
# Return [rendered_body, list_of_links]
|
||||||
# mode is either quick, readable or full
|
# mode is either links_only, readable or full
|
||||||
def render_html(self,body,mode="readable",width=None):
|
def render(self,body,mode="readable",width=None):
|
||||||
if not width:
|
if not width:
|
||||||
width = TERM_WIDTH
|
width = TERM_WIDTH
|
||||||
if not _DO_HTML:
|
if not _DO_HTML:
|
||||||
|
@ -701,7 +658,7 @@ class HtmlRenderer(AbstractRenderer):
|
||||||
src = element.get("src")
|
src = element.get("src")
|
||||||
text = ""
|
text = ""
|
||||||
ansi_img = ""
|
ansi_img = ""
|
||||||
if _RENDER_IMAGE and mode != "quick" and src:
|
if _RENDER_IMAGE and mode != "links_only" and src:
|
||||||
abs_url = urllib.parse.urljoin(self.url, src)
|
abs_url = urllib.parse.urljoin(self.url, src)
|
||||||
try:
|
try:
|
||||||
g = GeminiItem(abs_url)
|
g = GeminiItem(abs_url)
|
||||||
|
|
Loading…
Reference in New Issue