Broken project to implement a cross-protocol browser in textual
Browsing: Actually browse gemini!
Zach DeCook 2022-12-23
parent f62aa8b · commit 259946e
-rw-r--r--browset.py11
-rw-r--r--gemtext.py10
-rw-r--r--protocol/gemini.py29
3 files changed, 41 insertions, 9 deletions
diff --git a/browset.py b/browset.py
index 9dce9c3..817ad91 100644
--- a/browset.py
+++ b/browset.py
@@ -4,6 +4,7 @@ from textual.containers import Container
from rich.markdown import Markdown
from textual.binding import Binding
from gemtext import Gemtext
+from protocol.gemini import GeminiProtocol
class Browset(App):
CSS_PATH = "browset.css"
@@ -11,7 +12,7 @@ class Browset(App):
Binding("ctrl+c,ctrl+q", "app.quit", "Quit", show=True),
]
- content = "## Hello\n* Bullet points\n*OH Yeah!\n=>URI some link"
+ content = ["## Hello","* Bullet points","*OH Yeah!","=>URI some link"]
def compose(self) -> ComposeResult:
yield Footer()
yield Container(
@@ -23,11 +24,11 @@ class Browset(App):
Input(placeholder="Enter URI"),
id="toolbar"
)
- yield Gemtext(txt=self.content, id="content")
+ yield Gemtext(fp=self.content, id="content")
async def on_input_submitted(self, message: Input.Submitted) -> None:
- self.content = "## new stuff\n"+message.value
- self.query_one("#content", Gemtext).remove()
- self.mount(Gemtext(txt=self.content, id="content"))
+ (mime, fp) = GeminiProtocol.get(message.value)
+ self.query_one("#content").remove()
+ self.mount(Gemtext(fp=fp, id="content"))
if __name__ == "__main__":
app = Browset()
diff --git a/gemtext.py b/gemtext.py
index 66a2ad6..959f565 100644
--- a/gemtext.py
+++ b/gemtext.py
@@ -5,11 +5,13 @@ from textual.containers import Container
class Gemtext(Static):
"""Gemtext widget."""
- def __init__(self, txt, id):
+ def __init__(self, fp, id):
super().__init__(id=id)
- self.addlines(txt)
- def addlines(self, txt):
- for line in txt.split('\n'):
+ self.addlines(fp)
+ def addlines(self, fp):
+ for line in fp:
+ if type(line) is bytes:
+ line = line.decode("UTF-8")
if line.startswith("=>"):
path = line[2:].lstrip().split(' ')[0]
text = ' '.join(line[2:].lstrip().split(' ')[1:])
diff --git a/protocol/gemini.py b/protocol/gemini.py
new file mode 100644
index 0000000..c55e523
--- /dev/null
+++ b/protocol/gemini.py
@@ -0,0 +1,29 @@
+import socket
+import ssl
+
+class GeminiProtocol():
+ def get(url):
+ hostname = _gethostname(url)
+ try:
+ s = socket.create_connection((hostname, 1965),timeout=2)
+ context = ssl.SSLContext()
+ context.check_hostname = False
+ context.verify_mode = ssl.CERT_NONE
+ s = context.wrap_socket(s, server_hostname = hostname)
+ s.sendall((url + '\r\n').encode("UTF-8"))
+ fp = s.makefile("rb")
+ except:
+ return ("error",["error"])
+ header = fp.readline()
+ header = header.decode("UTF-8").strip()
+ if header[0:1] == "2":
+ return (header[3:], fp)
+ return ("error", [header])
+
+def _gethostname(url):
+ return url.split('/')[2]
+
+if __name__ == "__main__":
+ (mime, fp) = GeminiProtocol.get("gemini://gemini.zachdecook.com/")
+ print(mime)
+ print(fp)