forked from solderpunk/AV-98
pour le moment incapable de décider si ansirenderer doit prendre le path du fichier ou directement le texte en input
This commit is contained in:
parent
ce65850987
commit
cd3177ac87
119
ansirenderer.py
119
ansirenderer.py
|
@ -9,6 +9,7 @@ import time
|
||||||
import html
|
import html
|
||||||
import urllib
|
import urllib
|
||||||
import argparse
|
import argparse
|
||||||
|
import mimetypes
|
||||||
from offutils import run,term_width
|
from offutils import run,term_width
|
||||||
try:
|
try:
|
||||||
from readability import Document
|
from readability import Document
|
||||||
|
@ -704,6 +705,8 @@ class GopherRenderer(AbstractRenderer):
|
||||||
|
|
||||||
|
|
||||||
class FolderRenderer(GemtextRenderer):
|
class FolderRenderer(GemtextRenderer):
|
||||||
|
#it was initialized with:
|
||||||
|
#self.renderer = FolderRenderer("",self.get_cache_path(),datadir=_DATA_DIR)
|
||||||
def __init__(self,content,url,center=True,datadir=None):
|
def __init__(self,content,url,center=True,datadir=None):
|
||||||
GemtextRenderer.__init__(self,content,url,center)
|
GemtextRenderer.__init__(self,content,url,center)
|
||||||
self.datadir = datadir
|
self.datadir = datadir
|
||||||
|
@ -1124,24 +1127,124 @@ class HtmlRenderer(AbstractRenderer):
|
||||||
recursive_render(soup)
|
recursive_render(soup)
|
||||||
return r.get_final(),links
|
return r.get_final(),links
|
||||||
|
|
||||||
def render(text,format):
|
|
||||||
|
# Mapping mimetypes with renderers
|
||||||
|
# (any content with a mimetype text/* not listed here will be rendered with as GemText)
|
||||||
|
_FORMAT_RENDERERS = {
|
||||||
|
"text/gemini": GemtextRenderer,
|
||||||
|
"text/html" : HtmlRenderer,
|
||||||
|
"text/xml" : FeedRenderer,
|
||||||
|
"application/xml" : FeedRenderer,
|
||||||
|
"application/rss+xml" : FeedRenderer,
|
||||||
|
"application/atom+xml" : FeedRenderer,
|
||||||
|
"text/gopher": GopherRenderer,
|
||||||
|
"image/*": ImageRenderer
|
||||||
|
}
|
||||||
|
def get_mime(path):
|
||||||
|
#Beware, this one is really a shaddy ad-hoc function
|
||||||
|
if path.startswith("mailto:"):
|
||||||
|
mime = "mailto"
|
||||||
|
elif os.path.isdir(path):
|
||||||
|
mime = "Local Folder"
|
||||||
|
elif path.endswith(".gmi"):
|
||||||
|
mime = "text/gemini"
|
||||||
|
elif shutil.which("file") :
|
||||||
|
mime = run("file -b --mime-type %s", parameter=path).strip()
|
||||||
|
mime2,encoding = mimetypes.guess_type(path,strict=False)
|
||||||
|
#If we hesitate between html and xml, takes the xml one
|
||||||
|
#because the FeedRendered fallback to HtmlRenderer
|
||||||
|
if mime2 and mime != mime2 and "html" in mime and "xml" in mime2:
|
||||||
|
mime = "text/xml"
|
||||||
|
# If it’s a xml file, consider it as such, regardless of what file thinks
|
||||||
|
elif path.endswith(".xml"):
|
||||||
|
mime = "text/xml"
|
||||||
|
#Some xml/html document are considered as octet-stream
|
||||||
|
if mime == "application/octet-stream":
|
||||||
|
mime = "text/xml"
|
||||||
|
else:
|
||||||
|
mime,encoding = mimetypes.guess_type(path,strict=False)
|
||||||
|
#gmi Mimetype is not recognized yet
|
||||||
|
if not mime and not shutil.which("file") :
|
||||||
|
print("Cannot guess the mime type of the file. Please install \"file\".")
|
||||||
|
print("(and send me an email, I’m curious of systems without \"file\" installed!")
|
||||||
|
if mime.startswith("text") and mime not in _FORMAT_RENDERERS:
|
||||||
|
if mime2 and mime2 in _FORMAT_RENDERERS:
|
||||||
|
mime = mime2
|
||||||
|
else:
|
||||||
|
#by default, we consider it’s gemini except for html
|
||||||
|
mime = "text/gemini"
|
||||||
|
return mime
|
||||||
|
|
||||||
|
def set_renderer(content,url,mime):
|
||||||
|
renderer = None
|
||||||
|
if mime == "Local Folder":
|
||||||
|
renderer = FolderRenderer("",url,datadir=_DATA_DIR)
|
||||||
|
return renderer
|
||||||
|
mime_to_use = []
|
||||||
|
for m in _FORMAT_RENDERERS:
|
||||||
|
if fnmatch.fnmatch(mime, m):
|
||||||
|
mime_to_use.append(m)
|
||||||
|
if len(mime_to_use) > 0:
|
||||||
|
current_mime = mime_to_use[0]
|
||||||
|
func = _FORMAT_RENDERERS[current_mime]
|
||||||
|
if current_mime.startswith("text"):
|
||||||
|
renderer = func(content,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 renderer.is_valid():
|
||||||
|
func = _FORMAT_RENDERERS["text/html"]
|
||||||
|
#print("Set (fallback)RENDERER to html instead of %s"%mime)
|
||||||
|
renderer = func(content,url)
|
||||||
|
else:
|
||||||
|
#TODO: check this code and then remove one if.
|
||||||
|
#we don’t parse text, we give the file to the renderer
|
||||||
|
renderer = func(content,url)
|
||||||
|
if not renderer.is_valid():
|
||||||
|
renderer = None
|
||||||
|
return renderer
|
||||||
|
|
||||||
|
|
||||||
|
def render(input,format="auto",mime=None,url=None):
|
||||||
|
if mime and not format or format=="auto":
|
||||||
|
format = get_format(input)
|
||||||
if format == "gemtext":
|
if format == "gemtext":
|
||||||
r = GemtextRenderer(text,"https://ploum.net")
|
r = GemtextRenderer(input,"https://ploum.net")
|
||||||
elif format == "html":
|
elif format == "html":
|
||||||
r = HtmlRenderer(text,"https://ploum.net")
|
r = HtmlRenderer(input,"https://ploum.net")
|
||||||
r.display()
|
elif format == "feed":
|
||||||
|
r = FeedRenderer(input,"https://ploum.net")
|
||||||
|
elif format == "gopher":
|
||||||
|
r = GopherRenderer(input,"https://ploum.net")
|
||||||
|
elif format == "image":
|
||||||
|
r = ImageRenderer(input,"https://ploum.net")
|
||||||
|
elif format == "folder":
|
||||||
|
r = FolderRenderer(input,"https://ploum.net")
|
||||||
|
else:
|
||||||
|
if not mime:
|
||||||
|
mime = get_mime(input)
|
||||||
|
r = set_renderer(input,url,mime)
|
||||||
|
print("renderer is %s"%r)
|
||||||
|
if r:
|
||||||
|
r.display()
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description=__doc__)
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
parser.add_argument("--format", choices=["gemtext","html","feed","gopher","image","folder"],
|
parser.add_argument("--format", choices=["auto","gemtext","html","feed","gopher","image","folder"],
|
||||||
help="Renderer to use. Available: gemtext, html, feed, gopher, image, folder")
|
help="Renderer to use. Available: auto, gemtext, html, feed, gopher, image, folder")
|
||||||
## The argument needs to be a path to a file. If none, then stdin is used which allows
|
## The argument needs to be a path to a file. If none, then stdin is used which allows
|
||||||
## to pipe text directly into ansirenderer
|
## to pipe text directly into ansirenderer
|
||||||
parser.add_argument("input",metavar="INPUT", nargs="?", type=argparse.FileType("r"),
|
parser.add_argument("--url",metavar="URL", nargs="*",
|
||||||
|
help="Original URL of the content")
|
||||||
|
parser.add_argument("content",metavar="INPUT", nargs="*", type=argparse.FileType("r"),
|
||||||
default=sys.stdin, help="Path to the text to render (default to stdin)")
|
default=sys.stdin, help="Path to the text to render (default to stdin)")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
render(args.input.read(),args.format)
|
print("Input: %s"%args.input)
|
||||||
|
#TODO: find when we have a text or a path.
|
||||||
|
# We cannot get mime from a text!
|
||||||
|
#render(args.input.read(),format=args.format,url=args.url)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|
84
offpunk.py
84
offpunk.py
|
@ -1,3 +1,4 @@
|
||||||
|
#TODO: remove the set_renderer then try to run offpunk
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# Offpunk Offline Gemini client
|
# Offpunk Offline Gemini client
|
||||||
# Derived from AV-98 by Solderpunk,
|
# Derived from AV-98 by Solderpunk,
|
||||||
|
@ -26,7 +27,6 @@ import fnmatch
|
||||||
import glob
|
import glob
|
||||||
import hashlib
|
import hashlib
|
||||||
import io
|
import io
|
||||||
import mimetypes
|
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
import filecmp
|
import filecmp
|
||||||
|
@ -159,18 +159,6 @@ standard_ports = {
|
||||||
"https" : 443,
|
"https" : 443,
|
||||||
"spartan": 300,
|
"spartan": 300,
|
||||||
}
|
}
|
||||||
# Mapping mimetypes with renderers
|
|
||||||
# (any content with a mimetype text/* not listed here will be rendered with as GemText)
|
|
||||||
_FORMAT_RENDERERS = {
|
|
||||||
"text/gemini": ansirenderer.GemtextRenderer,
|
|
||||||
"text/html" : ansirenderer.HtmlRenderer,
|
|
||||||
"text/xml" : ansirenderer.FeedRenderer,
|
|
||||||
"application/xml" : ansirenderer.FeedRenderer,
|
|
||||||
"application/rss+xml" : ansirenderer.FeedRenderer,
|
|
||||||
"application/atom+xml" : ansirenderer.FeedRenderer,
|
|
||||||
"text/gopher": ansirenderer.GopherRenderer,
|
|
||||||
"image/*": ansirenderer.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).
|
||||||
# - There’s only one GeminiClient. Each page is a GeminiItem (name is historical, as
|
# - There’s only one GeminiClient. Each page is a GeminiItem (name is historical, as
|
||||||
|
@ -344,37 +332,6 @@ class GeminiItem():
|
||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def _set_renderer(self,mime=None):
|
|
||||||
if self.local and os.path.isdir(self.get_cache_path()):
|
|
||||||
self.renderer = ansirenderer.FolderRenderer("",self.get_cache_path(),datadir=_DATA_DIR)
|
|
||||||
return
|
|
||||||
if not mime:
|
|
||||||
mime = self.get_mime()
|
|
||||||
#we don’t even have a mime (so probably we don’t have a cache)
|
|
||||||
if not mime:
|
|
||||||
return
|
|
||||||
mime_to_use = []
|
|
||||||
for m in _FORMAT_RENDERERS:
|
|
||||||
if fnmatch.fnmatch(mime, m):
|
|
||||||
mime_to_use.append(m)
|
|
||||||
if len(mime_to_use) > 0:
|
|
||||||
current_mime = mime_to_use[0]
|
|
||||||
func = _FORMAT_RENDERERS[current_mime]
|
|
||||||
if current_mime.startswith("text"):
|
|
||||||
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.get_cache_path(),self.url)
|
|
||||||
if not self.renderer.is_valid():
|
|
||||||
self.renderer = None
|
|
||||||
|
|
||||||
def display(self,mode=None,grep=None):
|
def display(self,mode=None,grep=None):
|
||||||
if not self.renderer:
|
if not self.renderer:
|
||||||
|
@ -415,45 +372,6 @@ class GeminiItem():
|
||||||
return tmpf
|
return tmpf
|
||||||
|
|
||||||
|
|
||||||
def get_mime(self):
|
|
||||||
#Beware, this one is really a shaddy ad-hoc function
|
|
||||||
if self.mime:
|
|
||||||
return self.mime
|
|
||||||
elif self.is_cache_valid():
|
|
||||||
path = self.get_cache_path()
|
|
||||||
if self.scheme == "mailto":
|
|
||||||
mime = "mailto"
|
|
||||||
elif os.path.isdir(path):
|
|
||||||
mime = "Local Folder"
|
|
||||||
elif path.endswith(".gmi"):
|
|
||||||
mime = "text/gemini"
|
|
||||||
elif shutil.which("file") :
|
|
||||||
mime = run("file -b --mime-type %s", parameter=path).strip()
|
|
||||||
mime2,encoding = mimetypes.guess_type(path,strict=False)
|
|
||||||
#If we hesitate between html and xml, takes the xml one
|
|
||||||
#because the FeedRendered fallback to HtmlRenderer
|
|
||||||
if mime2 and mime != mime2 and "html" in mime and "xml" in mime2:
|
|
||||||
mime = "text/xml"
|
|
||||||
# If it’s a xml file, consider it as such, regardless of what file thinks
|
|
||||||
elif path.endswith(".xml"):
|
|
||||||
mime = "text/xml"
|
|
||||||
#Some xml/html document are considered as octet-stream
|
|
||||||
if mime == "application/octet-stream":
|
|
||||||
mime = "text/xml"
|
|
||||||
else:
|
|
||||||
mime,encoding = mimetypes.guess_type(path,strict=False)
|
|
||||||
#gmi Mimetype is not recognized yet
|
|
||||||
if not mime and not shutil.which("file") :
|
|
||||||
print("Cannot guess the mime type of the file. Please install \"file\".")
|
|
||||||
print("(and send me an email, I’m curious of systems without \"file\" installed!")
|
|
||||||
if mime.startswith("text") and mime not in _FORMAT_RENDERERS:
|
|
||||||
if mime2 and mime2 in _FORMAT_RENDERERS:
|
|
||||||
mime = mime2
|
|
||||||
else:
|
|
||||||
#by default, we consider it’s gemini except for html
|
|
||||||
mime = "text/gemini"
|
|
||||||
self.mime = mime
|
|
||||||
return self.mime
|
|
||||||
|
|
||||||
def set_error(self,err):
|
def set_error(self,err):
|
||||||
# If we get an error, we want to keep an existing cache
|
# If we get an error, we want to keep an existing cache
|
||||||
|
|
Loading…
Reference in New Issue