Broken project to implement a cross-protocol browser in textual
Browsing: Actually browse gemini!
| -rw-r--r-- | browset.py | 11 | ||||
| -rw-r--r-- | gemtext.py | 10 | ||||
| -rw-r--r-- | protocol/gemini.py | 29 |
3 files changed, 41 insertions, 9 deletions
@@ -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() @@ -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) |