Forked from solderpunk's repo

Added all of my current changes to gemini-demo.py, updated README.md
and LICENSE
This commit is contained in:
Wholesomedonut 2020-09-06 19:35:18 -06:00
parent eca985da3e
commit dcc4b804d2
3 changed files with 113 additions and 23 deletions

View File

@ -1,4 +1,4 @@
Copyright (c) <year> <owner> . All rights reserved. Copyright (c) 2020 Wholesomedonut . All rights reserved.
Redistribution and use in source and binary forms, with or without modification, Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met: are permitted provided that the following conditions are met:
@ -10,7 +10,7 @@ this list of conditions and the following disclaimer.
this list of conditions and the following disclaimer in the documentation this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution. and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS”
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
@ -19,4 +19,4 @@ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,18 +1,27 @@
# gemini-demo-1 # asparagus
Minimal but usable interactive Gemini client in < 100 LOC of Python 3 Larger, more functional version of solderpunk's gemini-demo-1,
which was a Gemini client in <=100 LOC in Python 3.
## Rationale Mine is already 50% larger.
One of the original design criteria for the Gemini protocol was that ## Why the fork?
"a basic but usable (not ultra-spartan) client should fit comfortably
within 50 or so lines of code in a modern high-level language. I really enjoyed solderpunk's work. Quick, clean, and tiny.
Certainly not more than 100". This client was written to gauge how
close to (or far from!) that goal the initial rough specification is. I just wanted to try my luck at getting a more fleshed-out app going.
I've never done FOSS contributions before today. Consider this repo my beginning!
I'm literally developing this entirely on an iPad Pro for kicks and giggles, using:
* Pythonista
* Working Copy
I have no idea how long it'll last, if it even will at all.
## Capabilities ## Capabilities
This crude but functional client: This fork has all of gemini-demo-1's functionality:
* Has a minimal interactive interface for "Gemini maps" * Has a minimal interactive interface for "Gemini maps"
* Will print plain text in any encoding if it is properly declared in * Will print plain text in any encoding if it is properly declared in
@ -23,8 +32,11 @@ This crude but functional client:
* Will report errors * Will report errors
* Does NOT DO ANY validation of TLS certificates * Does NOT DO ANY validation of TLS certificates
It's a *snug* fit in 100 lines, but it's possible. A 50 LOC client ### IN addition to:
would need to be much simpler.
* Has session-persistent history that you can repeatedly maneuver through
* Descriptive error texts
* More keyboard commands and CLI-accessible help text.
## Usage ## Usage
@ -35,6 +47,10 @@ visit a Gemini location.
If a Gemini menu is visited, you'll see numeric indices for links, ala If a Gemini menu is visited, you'll see numeric indices for links, ala
VF-1 or AV-98. Type a number to visit that link. VF-1 or AV-98. Type a number to visit that link.
There is very crude history: you can type `b` to go "back". Press h to see a printout of your history,
b to go back a page,
and f to go forward a page.
Type `q` to quit. Type ? to see a brief help text inside the client.
Press q to quit.

View File

@ -13,6 +13,31 @@ caps = mailcap.getcaps()
menu = [] menu = []
hist = [] hist = []
def printHelp():
help = """ Type in a gemini:// address to go somewhere,
input 'b' to go back a page,
'f' to go forward,
'h' to show your history in order,
'?' to show this help again,
or 'q' to quit.
"""
print(help)
def printIntro():
o = """
Welcome to PyGemini, a single-file Python client for the Gemini protocol.
Original source code by, , at
forked by Wholesomedonut on Sep 6 2020.
Questions about this fork?
Email with subject "PyGemini + whatever-you-need",
to wholesomedonut[at]tuta[dot]io .
"""
print(o)
printHelp()
def absolutise_url(base, relative): def absolutise_url(base, relative):
# Absolutise relative links # Absolutise relative links
if "://" not in relative: if "://" not in relative:
@ -21,6 +46,8 @@ def absolutise_url(base, relative):
relative = urllib.parse.urljoin(base, relative) relative = urllib.parse.urljoin(base, relative)
relative = relative.replace("http://", "gemini://") relative = relative.replace("http://", "gemini://")
return relative return relative
printIntro()
while True: while True:
# Get input # Get input
@ -34,16 +61,61 @@ while True:
url = menu[int(cmd)-1] url = menu[int(cmd)-1]
elif cmd.lower() == "b": elif cmd.lower() == "b":
# Yes, twice # Yes, twice
url = hist.pop() # url = hist.pop()
url = hist.pop() # url = hist.pop()
# updated to preserve history in list
# so you can use 'f' to go forward too. - WD
try:
url = hist[len(hist) - 2]
except IndexError as e:
print(e)
print('You do not have any history to go back to')
continue
elif cmd.lower() == "f":
# now you can go ahead in history too! - WD
try:
url = hist[url+1]
except NameError as e:
print(e)
print('You do not have any history')
except IndexError as e:
print(e)
print('You are at the front of your history already')
continue
elif cmd.lower() == "h":
# Will actually show history. - WD
try:
print("History:")
for x in range(len(hist)):
print('[',x,']',hist[x])
except Exception as e:
print(e)
print('Looks like I dun goofed.')
elif cmd == "?":
try:
printHelp()
continue
except Exception as e:
print(e)
else: else:
url = cmd url = cmd
if not "://" in url: if not "://" in url:
url = "gemini://" + url url = "gemini://" + url
parsed_url = urllib.parse.urlparse(url) # this try/except allows you to check for history with 'h'
# even if you have visited no pages yet, without crashing. - WD
try:
parsed_url = urllib.parse.urlparse(url)
except NameError as e:
print('Error:',e,'\nso try having some history first by visiting a page')
continue
if parsed_url.scheme != "gemini": if parsed_url.scheme != "gemini":
print("Sorry, Gemini links only.") print("Sorry, Gemini links only.")
# break
continue continue
# now it'll just loop again
# instead of quitting the program if you
# put the wrong thing in. - WD
# Do the Gemini transaction # Do the Gemini transaction
try: try:
while True: while True:
@ -76,6 +148,8 @@ while True:
# Fail if transaction was not successful # Fail if transaction was not successful
if not status.startswith("2"): if not status.startswith("2"):
print("Error %s: %s" % (status, mime)) print("Error %s: %s" % (status, mime))
# haha funny error code - WD
print("OH NO I didn't communicate with the Gemini server right")
continue continue
# Handle text # Handle text
if mime.startswith("text/"): if mime.startswith("text/"):
@ -113,4 +187,4 @@ while True:
os.system(cmd_str) os.system(cmd_str)
os.unlink(tmpfp.name) os.unlink(tmpfp.name)
# Update history # Update history
hist.append(url) hist.append(url)