forked from solderpunk/AV-98
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:
parent
72ea43a59c
commit
767ab82f29
|
@ -968,6 +968,7 @@ class HtmlRenderer(AbstractRenderer):
|
||||||
if _RENDER_IMAGE and mode != "links_only" and imgurl:
|
if _RENDER_IMAGE and mode != "links_only" and imgurl:
|
||||||
try:
|
try:
|
||||||
#4 followings line are there to translate the URL into cache path
|
#4 followings line are there to translate the URL into cache path
|
||||||
|
#TODO: do that with netcache
|
||||||
g = GeminiItem(imgurl)
|
g = GeminiItem(imgurl)
|
||||||
img = g.get_cache_path()
|
img = g.get_cache_path()
|
||||||
if imgdata:
|
if imgdata:
|
||||||
|
@ -1208,11 +1209,17 @@ def get_mime(path):
|
||||||
|
|
||||||
def renderer_from_file(path,url=None):
|
def renderer_from_file(path,url=None):
|
||||||
mime = get_mime(path)
|
mime = get_mime(path)
|
||||||
|
if not url:
|
||||||
|
url = path
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
with open(path) as f:
|
if mime.startswith("text/"):
|
||||||
body = f.read()
|
with open(path) as f:
|
||||||
f.close()
|
print("DEBUG: opening %s"%path)
|
||||||
return set_renderer(body,url,mime)
|
content = f.read()
|
||||||
|
f.close()
|
||||||
|
else:
|
||||||
|
content = path
|
||||||
|
return set_renderer(content,url,mime)
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
66
netcache.py
66
netcache.py
|
@ -635,20 +635,60 @@ def _fetch_gemini(url,timeout=DEFAULT_TIMEOUT,**kwargs):
|
||||||
def fetch(url,**kwargs):
|
def fetch(url,**kwargs):
|
||||||
url = normalize_url(url)
|
url = normalize_url(url)
|
||||||
path=None
|
path=None
|
||||||
|
print_error = "print_error" in kwargs.keys() and kwargs["print_error"]
|
||||||
if "://" in url:
|
if "://" in url:
|
||||||
scheme = url.split("://")[0]
|
try:
|
||||||
if scheme not in standard_ports:
|
scheme = url.split("://")[0]
|
||||||
print("%s is not a supported protocol"%scheme)
|
if scheme not in standard_ports:
|
||||||
elif scheme in ("http","https"):
|
print("%s is not a supported protocol"%scheme)
|
||||||
path=_fetch_http(url,**kwargs)
|
elif scheme in ("http","https"):
|
||||||
elif scheme == "gopher":
|
path=_fetch_http(url,**kwargs)
|
||||||
path=_fetch_gopher(url,**kwargs)
|
elif scheme == "gopher":
|
||||||
elif scheme == "finger":
|
path=_fetch_gopher(url,**kwargs)
|
||||||
path=_fetch_finger(url,**kwargs)
|
elif scheme == "finger":
|
||||||
elif scheme == "gemini":
|
path=_fetch_finger(url,**kwargs)
|
||||||
patch=_fetch_gemini(url,**kwargs)
|
elif scheme == "gemini":
|
||||||
else:
|
patch=_fetch_gemini(url,**kwargs)
|
||||||
print("scheme %s not implemented yet")
|
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:
|
else:
|
||||||
print("Not a supproted URL")
|
print("Not a supproted URL")
|
||||||
return path
|
return path
|
||||||
|
|
60
offpunk.py
60
offpunk.py
|
@ -210,6 +210,7 @@ class GeminiItem():
|
||||||
def cache_last_modified(self):
|
def cache_last_modified(self):
|
||||||
return netcache.cache_last_modified(self.url)
|
return netcache.cache_last_modified(self.url)
|
||||||
|
|
||||||
|
#TODO : move to ansirenderer
|
||||||
def get_body(self,as_file=False):
|
def get_body(self,as_file=False):
|
||||||
if self.is_cache_valid():
|
if self.is_cache_valid():
|
||||||
path = self.get_cache_path()
|
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
|
# 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
|
# 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):
|
def get_links(self,mode=None):
|
||||||
links = []
|
links = []
|
||||||
toreturn = []
|
toreturn = []
|
||||||
|
@ -275,6 +277,7 @@ class GeminiItem():
|
||||||
toreturn.append(None)
|
toreturn.append(None)
|
||||||
return toreturn
|
return toreturn
|
||||||
|
|
||||||
|
#TODO: should be in ansirenderer
|
||||||
def get_link(self,nb):
|
def get_link(self,nb):
|
||||||
# == None allows to return False, even if the list is empty
|
# == None allows to return False, even if the list is empty
|
||||||
links = self.get_links()
|
links = self.get_links()
|
||||||
|
@ -284,6 +287,7 @@ class GeminiItem():
|
||||||
else:
|
else:
|
||||||
return links[nb-1]
|
return links[nb-1]
|
||||||
|
|
||||||
|
#TODO: should be in ansirenderer
|
||||||
def get_subscribe_links(self):
|
def get_subscribe_links(self):
|
||||||
if self.renderer:
|
if self.renderer:
|
||||||
subs = self.renderer.get_subscribe_links()
|
subs = self.renderer.get_subscribe_links()
|
||||||
|
@ -296,7 +300,7 @@ class GeminiItem():
|
||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
#TODO: should be in ansiless
|
||||||
def display(self,mode=None,grep=None):
|
def display(self,mode=None,grep=None):
|
||||||
if self.renderer and self.renderer.is_valid():
|
if self.renderer and self.renderer.is_valid():
|
||||||
if not mode:
|
if not mode:
|
||||||
|
@ -591,6 +595,8 @@ class GeminiClient(cmd.Cmd):
|
||||||
(hostname text, address text, fingerprint text,
|
(hostname text, address text, fingerprint text,
|
||||||
first_seen date, last_seen date, count integer)""")
|
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,\
|
def _go_to_gi(self, gi, update_hist=True, check_cache=True, handle=True,\
|
||||||
mode=None,limit_size=False):
|
mode=None,limit_size=False):
|
||||||
"""This method might be considered "the heart of Offpunk".
|
"""This method might be considered "the heart of Offpunk".
|
||||||
|
@ -644,51 +650,11 @@ class GeminiClient(cmd.Cmd):
|
||||||
return
|
return
|
||||||
|
|
||||||
elif not self.offline_only and not gi.local:
|
elif not self.offline_only and not gi.local:
|
||||||
try:
|
params = {}
|
||||||
params = {}
|
params["timeout"] = self.options["short_timeout"]
|
||||||
params["timeout"] = self.options["short_timeout"]
|
params["max_size"] = int(self.options["max_size_download"])*1000000
|
||||||
params["max_size"] = int(self.options["max_size_download"])*1000000
|
params["print_error"] = not self.sync_only
|
||||||
cachepath = netcache.fetch(gi.url,**params)
|
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
|
|
||||||
|
|
||||||
# Pass file to handler, unless we were asked not to
|
# Pass file to handler, unless we were asked not to
|
||||||
if netcache.is_cache_valid(gi.url) :
|
if netcache.is_cache_valid(gi.url) :
|
||||||
|
@ -696,7 +662,9 @@ class GeminiClient(cmd.Cmd):
|
||||||
#TODO: take into account _RENDER_IMAGE
|
#TODO: take into account _RENDER_IMAGE
|
||||||
if display and self.options["download_images_first"] \
|
if display and self.options["download_images_first"] \
|
||||||
and not self.offline_only:
|
and not self.offline_only:
|
||||||
|
|
||||||
# We download images first
|
# We download images first
|
||||||
|
#TODO: this should go into netcache
|
||||||
for image in gi.get_images(mode=mode):
|
for image in gi.get_images(mode=mode):
|
||||||
if image and image.startswith("http"):
|
if image and image.startswith("http"):
|
||||||
img_gi = GeminiItem(image)
|
img_gi = GeminiItem(image)
|
||||||
|
|
Loading…
Reference in New Issue