Ok, it starts to work.

Offpunk is now able to display pages, pictures and follow links. A lot
of TODO have been clearly identified. I think that the whole
GeminiItem() object will be removed and URL will be accessed directly
with a dict{url, renderer} to avoid redrawing all the time.

Next challenge: remove GeminiItems!
This commit is contained in:
Lionel Dricot 2023-07-22 00:27:43 +02:00
parent 72ea43a59c
commit 767ab82f29
3 changed files with 78 additions and 63 deletions

View File

@ -968,6 +968,7 @@ class HtmlRenderer(AbstractRenderer):
if _RENDER_IMAGE and mode != "links_only" and imgurl:
try:
#4 followings line are there to translate the URL into cache path
#TODO: do that with netcache
g = GeminiItem(imgurl)
img = g.get_cache_path()
if imgdata:
@ -1208,11 +1209,17 @@ def get_mime(path):
def renderer_from_file(path,url=None):
mime = get_mime(path)
if not url:
url = path
if os.path.exists(path):
with open(path) as f:
body = f.read()
f.close()
return set_renderer(body,url,mime)
if mime.startswith("text/"):
with open(path) as f:
print("DEBUG: opening %s"%path)
content = f.read()
f.close()
else:
content = path
return set_renderer(content,url,mime)
else:
return None

View File

@ -635,20 +635,60 @@ def _fetch_gemini(url,timeout=DEFAULT_TIMEOUT,**kwargs):
def fetch(url,**kwargs):
url = normalize_url(url)
path=None
print_error = "print_error" in kwargs.keys() and kwargs["print_error"]
if "://" in url:
scheme = url.split("://")[0]
if scheme not in standard_ports:
print("%s is not a supported protocol"%scheme)
elif scheme in ("http","https"):
path=_fetch_http(url,**kwargs)
elif scheme == "gopher":
path=_fetch_gopher(url,**kwargs)
elif scheme == "finger":
path=_fetch_finger(url,**kwargs)
elif scheme == "gemini":
patch=_fetch_gemini(url,**kwargs)
else:
print("scheme %s not implemented yet")
try:
scheme = url.split("://")[0]
if scheme not in standard_ports:
print("%s is not a supported protocol"%scheme)
elif scheme in ("http","https"):
path=_fetch_http(url,**kwargs)
elif scheme == "gopher":
path=_fetch_gopher(url,**kwargs)
elif scheme == "finger":
path=_fetch_finger(url,**kwargs)
elif scheme == "gemini":
patch=_fetch_gemini(url,**kwargs)
else:
print("scheme %s not implemented yet")
except UserAbortException:
return
except Exception as err:
#TODO return the error !
#gi.set_error(err)
# Print an error message
# we fail silently when sync_only
if isinstance(err, socket.gaierror):
if print_error:
print("ERROR: DNS error!")
elif isinstance(err, ConnectionRefusedError):
if print_error:
print("ERROR1: Connection refused!")
elif isinstance(err, ConnectionResetError):
if print_error:
print("ERROR2: Connection reset!")
elif isinstance(err, (TimeoutError, socket.timeout)):
if print_error:
print("""ERROR3: Connection timed out!
Slow internet connection? Use 'set timeout' to be more patient.""")
elif isinstance(err, FileExistsError):
if print_error:
print("""ERROR5: Trying to create a directory which already exists
in the cache : """)
print(err)
elif _DO_HTTP and isinstance(err,requests.exceptions.SSLError):
if print_error:
print("""ERROR6: Bad SSL certificate:\n""")
print(err)
print("""\n If you know what you are doing, you can try to accept bad certificates with the following command:\n""")
print("""set accept_bad_ssl_certificates True""")
else:
if print_error:
import traceback
print("ERROR4: " + str(type(err)) + " : " + str(err))
print("\n" + str(err.with_traceback(None)))
print(traceback.format_exc())
return
else:
print("Not a supproted URL")
return path

View File

@ -210,6 +210,7 @@ class GeminiItem():
def cache_last_modified(self):
return netcache.cache_last_modified(self.url)
#TODO : move to ansirenderer
def get_body(self,as_file=False):
if self.is_cache_valid():
path = self.get_cache_path()
@ -240,6 +241,7 @@ class GeminiItem():
# This method is used to load once the list of links in a gi
# Links can be followed, after a space, by a description/title
#TODO: check all calls of get_links then move it to ansirenderer
def get_links(self,mode=None):
links = []
toreturn = []
@ -275,6 +277,7 @@ class GeminiItem():
toreturn.append(None)
return toreturn
#TODO: should be in ansirenderer
def get_link(self,nb):
# == None allows to return False, even if the list is empty
links = self.get_links()
@ -284,6 +287,7 @@ class GeminiItem():
else:
return links[nb-1]
#TODO: should be in ansirenderer
def get_subscribe_links(self):
if self.renderer:
subs = self.renderer.get_subscribe_links()
@ -296,7 +300,7 @@ class GeminiItem():
else:
return []
#TODO: should be in ansiless
def display(self,mode=None,grep=None):
if self.renderer and self.renderer.is_valid():
if not mode:
@ -591,6 +595,8 @@ class GeminiClient(cmd.Cmd):
(hostname text, address text, fingerprint text,
first_seen date, last_seen date, count integer)""")
#TODO: go_to_gi should take an URL as parameter, not gi
#it should also only be called to really go, not for all links
def _go_to_gi(self, gi, update_hist=True, check_cache=True, handle=True,\
mode=None,limit_size=False):
"""This method might be considered "the heart of Offpunk".
@ -644,51 +650,11 @@ class GeminiClient(cmd.Cmd):
return
elif not self.offline_only and not gi.local:
try:
params = {}
params["timeout"] = self.options["short_timeout"]
params["max_size"] = int(self.options["max_size_download"])*1000000
cachepath = netcache.fetch(gi.url,**params)
except UserAbortException:
return
except Exception as err:
gi.set_error(err)
# Print an error message
# we fail silently when sync_only
print_error = not self.sync_only
if isinstance(err, socket.gaierror):
self.log["dns_failures"] += 1
if print_error:
print("ERROR: DNS error!")
elif isinstance(err, ConnectionRefusedError):
self.log["refused_connections"] += 1
if print_error:
print("ERROR1: Connection refused!")
elif isinstance(err, ConnectionResetError):
self.log["reset_connections"] += 1
if print_error:
print("ERROR2: Connection reset!")
elif isinstance(err, (TimeoutError, socket.timeout)):
self.log["timeouts"] += 1
if print_error:
print("""ERROR3: Connection timed out!
Slow internet connection? Use 'set timeout' to be more patient.""")
elif isinstance(err, FileExistsError):
print("""ERROR5: Trying to create a directory which already exists
in the cache : """)
print(err)
elif _DO_HTTP and isinstance(err,requests.exceptions.SSLError):
print("""ERROR6: Bad SSL certificate:\n""")
print(err)
print("""\n If you know what you are doing, you can try to accept bad certificates with the following command:\n""")
print("""set accept_bad_ssl_certificates True""")
else:
if print_error:
import traceback
print("ERROR4: " + str(type(err)) + " : " + str(err))
print("\n" + str(err.with_traceback(None)))
print(traceback.format_exc())
return
params = {}
params["timeout"] = self.options["short_timeout"]
params["max_size"] = int(self.options["max_size_download"])*1000000
params["print_error"] = not self.sync_only
cachepath = netcache.fetch(gi.url,**params)
# Pass file to handler, unless we were asked not to
if netcache.is_cache_valid(gi.url) :
@ -696,7 +662,9 @@ class GeminiClient(cmd.Cmd):
#TODO: take into account _RENDER_IMAGE
if display and self.options["download_images_first"] \
and not self.offline_only:
# We download images first
#TODO: this should go into netcache
for image in gi.get_images(mode=mode):
if image and image.startswith("http"):
img_gi = GeminiItem(image)