Commit Diff


commit - fafb2ce7fd7a140705547330b120fa1e68c0d961
commit + 8b4f10af8c5df796723cc66ee799c06f0c84875a
blob - d110abd2c054f4b095428779a88ab0be21bcce59
blob + 8e114e9f198bf3aabe8cbe4e4dcfa5fba1edba84
--- lonk.py
+++ lonk.py
@@ -247,10 +247,12 @@ def _create_schema(db_con):
         CREATE TABLE
             donk (
                 donk_id INTEGER PRIMARY KEY,
+                client_id INTEGER,
                 convoy_id INTEGER,
                 url TEXT NOT NULL,
                 mime TEXT,
                 alt_text TEXT,
+                FOREIGN KEY (client_id) REFERENCES client (client_id),
                 FOREIGN KEY (convoy_id) REFERENCES convoy (convoy_id)
             )
         """
@@ -277,7 +279,7 @@ def db_connect():
     return db_con
 
 
-class _Collected:
+class _LonkTreeItem:
     def __init__(self, convoy_id, convoy, honk_id, honker, url, html, date):
         self.convoy_id = convoy_id
         self.convoy = convoy
@@ -286,192 +288,140 @@ class _Collected:
         self.url = url
         self.html = html
         self.date = date
-        self._donks = None
-        self._reason_thread = []
-        self._reason_repost = []
-
-    def add_donk(self, donk_url, mime, alt_text):
-        if self._donks is None:
-            self._donks = [(donk_url, mime, alt_text)]
-        else:
-            self._donks.append((donk_url, mime, alt_text))
-
-    def end_of_donks(self):
-        if self._donks is None:
-            self._donks = []
-
-    def iterate_donks(self, db_con):
-        if self._donks is not None:
-            yield from self._donks
-            return
-
-        res_donks = db_con.execute(
-            "SELECT url, mime, alt_text FROM donk WHERE convoy_id=?",
-            (self.convoy_id, )
-        )
-        while True:
-            donks = res_donks.fetchmany()
-            if not donks:
-                return
-
-            yield from donks
+        self.donks = []
+        self.reposters = []
+        self.thread = []
 
-    def add_reason_thread(self, reason):
-        if reason not in self._reason_thread:
-            self._reason_thread.append(reason)
-
-    def add_reason_repost(self, reason):
-        if reason not in self._reason_repost:
-            self._reason_repost.append(reason)
-
-    def format_reason(self):
-        repost = ", ".join(reason for reason in self._reason_repost)
-        thread = ", ".join(thread for thread in self._reason_thread)
-        rv = ""
-        if repost:
-            rv += f" (๐Ÿ” {repost})"
-        if thread:
-            rv += f" (๐Ÿงต {thread})"
-        return rv
+    def iterate_honks(self):
+        if self.html is not None:
+            handle = self.honker
+            if self.reposters:
+                handle += " (๐Ÿ” " + ", ".join(reason for reason in set(self.reposters)) + ")"
+            yield {
+                "Convoy": self.convoy,
+                "Handle": handle,
+                "ID": self.honk_id,
+                "XID": self.url,
+                "HTML": self.html,
+                "Date": self.date,
+                "Donks": [
+                    {"URL": donk[0], "Media": donk[1], "Desc": donk[2]}
+                    for donk in self.donks
+                ]
+            }
+            child_honks = self.thread[:]
+            child_honks.reverse()
+            yield from reversed(child_honks)
 
 
-def lonk(db_con, client_id, lonk_url, honk_url):
+def page_lonk(db_con, client_id, lonk_url, honk_url):
     gethonks_answer = honk_url.do_get(action="gethonks", page="home")
-    lonk_page = {}
-    for honk in reversed(gethonks_answer.get("honks") or []):
-        if honk.get("RID"):
-            reason_fn = _Collected.add_reason_thread
-            reason = honk["Handle"]
-        else:
-            reason_fn = _Collected.add_reason_repost
-            oondle = honk.get("Oondle")
-            reason = honk["Handle"] if oondle else None
 
+    lonk_page = {}
+    for honk in (gethonks_answer.pop("honks", None) or []):
         convoy = honk["Convoy"]
-        if convoy in lonk_page:
-            if reason_fn and reason:
-                reason_fn(lonk_page[convoy], reason)
-            continue
 
-        row = db_con.execute(
-            "SELECT convoy_id, convoy, honk_id, honker, url, html, date FROM convoy WHERE client_id=? AND convoy=?",
-            (client_id, convoy)
-        ).fetchone()
-        if row:
-            lonk_page[convoy] = _Collected(*row)
-            if reason_fn and reason:
-                reason_fn(lonk_page[convoy], reason)
-            continue
-
-        def _save_convoy(convoy, honker, honk):
+        if convoy not in lonk_page:
             row = db_con.execute(
-                """
-                INSERT INTO 
-                    convoy(convoy, client_id, honk_id, honker, url, html, date)
-                VALUES 
-                    (?, ?, ?, ?, ?, ?, ?)
-                RETURNING
-                    convoy_id
-                """,
-                (convoy, client_id, honk["ID"], honker, honk["XID"], honk["HTML"], honk["Date"])
+                "SELECT convoy_id, convoy, honk_id, honker, url, html, date FROM convoy WHERE client_id=? AND convoy=?",
+                (client_id, convoy)
             ).fetchone()
-            convoy_id, = row
-            lonk_page[convoy] = _Collected(
-                convoy_id, convoy, honk["ID"], honker, honk["XID"], honk["HTML"], honk["Date"]
-            )
-
-            for donk in (honk.get("Donks") or []):
-                donk_url = honk_url.build_url(path=f'/d/{donk["XID"]}') if donk.get("XID") else donk["URL"]
-                mime, alt_text = donk["Media"], donk.get("Desc") or donk.get("Name") or None
-                db_con.execute(
-                    "INSERT INTO donk (convoy_id, url, mime, alt_text) VALUES (?, ?, ?, ?)",
-                    (lonk_page[convoy].convoy_id, donk_url, mime, alt_text, )
-                )
-                lonk_page[convoy].add_donk(donk_url, mime, alt_text)
-            lonk_page[convoy].end_of_donks()
+            if row:
+                lonk_page[convoy] = _LonkTreeItem(*row)
+                res_donks = db_con.execute(
+                    "SELECT url, mime, alt_text FROM donk WHERE client_id=? AND convoy_id=?",
+                    (client_id, lonk_page[convoy].convoy_id, )
+                )
+                while True:
+                    donks = res_donks.fetchmany()
+                    if not donks:
+                        break
 
-        if honk.get("RID"):
-            for honk_in_convoy in honk_url.do_get(action="gethonks", page="convoy", c=convoy)["honks"]:
-                if not honk_in_convoy.get("RID"):
-                    honker = honk_in_convoy.get("Oondle") or honk_in_convoy["Handle"]
-                    _save_convoy(convoy, honker, honk_in_convoy)
-                    if reason_fn and reason:
-                        reason_fn(lonk_page[convoy], reason)
-                    break
-            else:
+                    for donk in donks:
+                        donk_url, donk_mime, donk_text = donk
+                        lonk_page[convoy].donks.append((donk_url, donk_mime, donk_text))
+
+        if convoy not in lonk_page:
+            def _save_convoy(convoy, honker, honk):
                 row = db_con.execute(
                     """
                     INSERT INTO 
-                        convoy(convoy, client_id, honk_id)
+                        convoy(convoy, client_id, honk_id, honker, url, html, date)
                     VALUES 
-                        (?, ?, ?)
-                    RETURNING 
+                        (?, ?, ?, ?, ?, ?, ?)
+                    RETURNING
                         convoy_id
                     """,
-                    (convoy, client_id, honk["ID"])
+                    (convoy, client_id, honk["ID"], honker, honk["XID"], honk["HTML"], honk["Date"])
                 ).fetchone()
                 convoy_id, = row
-                lonk_page[convoy] = _Collected(convoy_id, convoy, None, None, None, None, None)
-        else:
-            honker = honk.get("Oondle") or honk["Handle"]
-            _save_convoy(convoy, honker, honk)
-            if reason_fn and reason:
-                reason_fn(lonk_page[convoy], reason)
+                lonk_page[convoy] = _LonkTreeItem(
+                    convoy_id, convoy, honk["ID"], honker, honk["XID"], honk["HTML"], honk["Date"]
+                )
 
-    print("20 text/gemini\r")
-    print("# ๐“— onk: lonk\r")
-    print("\r")
+                for donk in (honk.get("Donks") or []):
+                    donk_url = honk_url.build_url(path=f'/d/{donk["XID"]}') if donk.get("XID") else donk["URL"]
+                    donk_mime, donk_text = donk["Media"], donk.get("Desc") or donk.get("Name") or None
+                    db_con.execute(
+                        "INSERT INTO donk (client_id, convoy_id, url, mime, alt_text) VALUES (?, ?, ?, ?, ?)",
+                        (client_id, lonk_page[convoy].convoy_id, donk_url, donk_mime, donk_text, )
+                    )
+                    lonk_page[convoy].donks.append((donk_url, donk_mime, donk_text))
 
-    line = f"=> {lonk_url.build('atme')} @me"
-    if gethonks_answer["mecount"]:
-        line += f' ({gethonks_answer["mecount"]})'
-    print(line + "\r")
+            if honk.get("RID"):
+                for honk_in_convoy in honk_url.do_get(action="gethonks", page="convoy", c=convoy)["honks"]:
+                    if not honk_in_convoy.get("RID"):
+                        honker = honk_in_convoy.get("Oondle") or honk_in_convoy["Handle"]
+                        _save_convoy(convoy, honker, honk_in_convoy)
+                        break
+                else:
+                    _save_convoy(convoy, None, {"ID": None, "XID": None, "HTML": None, "Date": None})
+            else:
+                _save_convoy(convoy, honk.get("Oondle") or honk["Handle"], honk)
 
-    line = f"=> {honk_url.build_url(path='chatter')} chatter"
-    if gethonks_answer["chatcount"]:
-        line += f' ({gethonks_answer["chatcount"]})'
-    print(line + "\r")
-    print("\r")
+        if honk.get("What") == "bonked":
+            lonk_page[convoy].reposters.append(honk["Handle"])
+        if honk.get("RID"):
+            lonk_page[convoy].thread.append(honk)
 
-    for collected in reversed(lonk_page.values()):
-        if collected.honker is None:
-            continue
+    gethonks_answer["honks"] = []
+    for tree_item in lonk_page.values():
+        gethonks_answer["honks"] += list(tree_item.iterate_honks())
 
-        lines = [
-            f"## From {collected.honker}{collected.format_reason()} {collected.date}",
-            f'=> {lonk_url.build("convoy", urlencode({"c": collected.convoy}))} Convoy {collected.convoy}',
-            HtmlToGmi(honk_url.build_url(), lonk_url.media).feed(collected.html)
-        ]
-        for donk_url, donk_mime, donk_text in collected.iterate_donks(db_con):
-            lines.append(f'=> {lonk_url.media(donk_mime, donk_url)}')
-            if donk_text:
-                lines.append(donk_text)
-        print("\r\n".join(lines))
-        print("\r")
+    print("20 text/gemini\r")
+    print("# ๐“— onk: lonk\r")
+    print("\r")
+    print_gethonks(gethonks_answer, lonk_url, honk_url)
 
 
-def convoy(db_con, client_id, lonk_url, honk_url):
+def page_convoy(db_con, client_id, lonk_url, honk_url):
     query = {pair[0]: pair[1] for pair in parse_qsl(lonk_url.query)}
     if "c" not in query:
         print("51 Not found\r")
         return
 
+
     gethonks_answer = honk_url.do_get(action="gethonks", page="convoy", c=query["c"])
+    gethonks_answer["honks"] = [
+        honk
+        for honk in (gethonks_answer.pop("honks", None) or [])
+        if honk.get("What") != "bonked"
+    ]
     print("20 text/gemini\r")
     print(f"# ๐“— onk: convoy {query['c']}\r")
     print("\r")
-    _gethonks(gethonks_answer, lonk_url, honk_url)
+    print_gethonks(gethonks_answer, lonk_url, honk_url)
 
 
-def atme(db_con, client_id, lonk_url, honk_url):
+def page_atme(db_con, client_id, lonk_url, honk_url):
     gethonks_answer = honk_url.do_get(action="gethonks", page="atme")
     print("20 text/gemini\r")
     print("# ๐“— onk: @me")
     print("\r")
-    _gethonks(gethonks_answer, lonk_url, honk_url)
+    print_gethonks(gethonks_answer, lonk_url, honk_url)
 
 
-def _gethonks(gethonks_answer, lonk_url, honk_url):
+def print_gethonks(gethonks_answer, lonk_url, honk_url):
     line = f"=> {lonk_url.build('atme')} @me"
     if gethonks_answer["mecount"]:
         line += f' ({gethonks_answer["mecount"]})'
@@ -577,11 +527,11 @@ def proxy(mime, url):
 def vgi(cert_hash, raw_url):
     lonk_url = LonkUrl(raw_url)
     if lonk_url.page == "lonk":
-        authenticated(cert_hash, lonk_url, lonk)
+        authenticated(cert_hash, lonk_url, page_lonk)
     elif lonk_url.page == "convoy":
-        authenticated(cert_hash, lonk_url, convoy)
+        authenticated(cert_hash, lonk_url, page_convoy)
     elif lonk_url.page == "atme":
-        authenticated(cert_hash, lonk_url, atme)
+        authenticated(cert_hash, lonk_url, page_atme)
     elif lonk_url.page == "ask_server":
         new_client_stage_1_ask_server(lonk_url)
     elif lonk_url.page == "ask_username":