Commit Diff


commit - 4acbf994ae02d25a0bf1246afa8a910382a03bff
commit + 9f761a0c0a4789c52a4e767bcc5f9f3699de5a53
blob - 61b7bd6bc9df99a108fca291d18a79aeacf0bfb4
blob + f08611d87263eb82aa444c73f7bcf8f283755ad2
--- lonk.py
+++ lonk.py
@@ -236,59 +236,14 @@ def _proxy_url_factory(proxy_media_enabled, lonk_url):
             url
         )
     return _get_proxy_url
-
-
-def demo(lonk_url, honk_url):
-    collected = {}
-    banned = set()
-
-    home = honk_url.do_get(action="gethonks", page="home")
-    for honk in reversed(home["honks"]):
-        convoy = honk["Convoy"]
-        if convoy in collected or convoy in banned:
-            continue
-        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"):
-                    from_ = honk_in_convoy.get("Oondle") or honk_in_convoy["Handle"]
-                    header = f'## From: {from_}, {honk_in_convoy["Date"]} (๐Ÿงต {honk["Handle"]})'
-                    collected[convoy] = (honk_in_convoy, header)
-                    break
-            else:
-                banned.add(convoy)
-        else:
-            oondle = honk.get("Oondle")
-            if oondle:
-                header = f'## From: {oondle}, {honk["Date"]} (๐Ÿ” {honk["Handle"]})'
-            else:
-                header = f'## From: {honk["Handle"]}, {honk["Date"]}'
-            collected[convoy] = (honk, header)
-
-    print("20 text/gemini\r")
-    print("# ๐“— onk\n")
-
-    line = f"=> {honk_url.build_url(path='atme')} @me"
-    if home["mecount"]:
-        line += f' ({home["mecount"]})'
-    print(line)
 
-    line = f"=> {honk_url.build_url(path='chatter')} chatter"
-    if home["chatcount"]:
-        line += f' ({home["chatcount"]})'
-    print(line)
 
-    fn_media_url = _proxy_url_factory(environ.get("LONK_PROXY_MEDIA"), lonk_url)
-    for honk, header in reversed(collected.values()):
-        print()
-        print(_format_honk(honk, header, honk_url, fn_media_url))
-
-
 def _create_schema(db_con, cert_hash):
     db_con.execute(
         """
         CREATE TABLE
             client (
-                client_id INTEGER PRIMARY KEY AUTOINCREMENT,
+                client_id INTEGER PRIMARY KEY,
                 cert_hash TEXT UNIQUE,
                 honk_url TEXT NOT NULL,
                 token TEXT NOT NULL
@@ -299,32 +254,36 @@ def _create_schema(db_con, cert_hash):
         """
         CREATE TABLE
             convoy (
-                convoy_id TEXT,
+                convoy_id INTEGER PRIMARY KEY,
+                convoy TEXT,
                 client_id INTEGER,
-                header TEXT,
-                FOREIGN KEY (client_id) REFERENCES client(client_id),
-                PRIMARY KEY (convoy_id, client_id)
+                honk_id INTEGER,
+                honker TEXT,
+                url TEXT,
+                html TEXT,
+                date TEXT,
+                FOREIGN KEY (client_id) REFERENCES client (client_id),
+                UNIQUE (convoy, client_id),
+                UNIQUE (honk_id, client_id)
             )
         """
     )
     db_con.execute(
         """
         CREATE TABLE
-            honk (
-                honk_id INTEGER,
-                client_id INTEGER,
-                convoy_id TEXT,
+            donk (
+                donk_id INTEGER PRIMARY KEY,
+                convoy_id INTEGER,
                 url TEXT NOT NULL,
-                html TEXT NOT NULL,
-                FOREIGN KEY (client_id) REFERENCES client(client_id),
-                FOREIGN KEY (convoy_id) REFERENCES convoy(convoy_id),
-                PRIMARY KEY (honk_id, client_id)
+                mime TEXT,
+                alt_text TEXT,
+                FOREIGN KEY (convoy_id) REFERENCES convoy (convoy_id)
             )
         """
     )
 
     # ==========================================================================
-    # TODO: test code
+    # TODO: test code (cert_hash must be removed, cascade)
     with open(".local/settings.json") as f:
         settings = json_loads(f.read())
     db_con.execute(
@@ -347,70 +306,124 @@ def db_connect(cert_hash):
 
 def _lonk_impl(db_con, client_id, lonk_url, honk_url):
     row = db_con.execute(
-        "SELECT MAX(honk_id) FROM honk WHERE client_id=?",
+        "SELECT MAX(honk_id) FROM convoy WHERE client_id=?",
         (client_id, )
-    )
+    ).fetchone()
     after, = row
 
+    fn_media_url = _proxy_url_factory(environ.get("LONK_PROXY_MEDIA"), lonk_url)
+
     home = honk_url.do_get(action="gethonks", page="home", after=after)
-    for honk in reversed(home["honks"]):
-        convoy_id = honk["Convoy"]
-        raise RuntimeError(convoy_id)
+    for honk in reversed(home.get("honks") or []):
+        convoy = honk["Convoy"]
         row = db_con.execute(
-            "SELECT convoy.header, honk.url, honk.html FROM convoy JOIN honk USING (convoy_id) WHERE convoy.client_id=? AND convoy_id=?",
-            (client_id, convoy_id)
+            "SELECT convoy_id FROM convoy WHERE client_id=? AND convoy=?",
+            (client_id, convoy)
         ).fetchone()
         if row:
             continue
 
-        def _save_convoy_and_honk(header, honk):
-            db_con.execute(
+        def _save_convoy(honker, honk):
+            row = db_con.execute(
                 """
                 INSERT INTO 
-                    convoy(convoy_id, client_id, header)
+                    convoy(convoy, client_id, honk_id, honker, url, html, date)
                 VALUES 
-                    (?, ?, ?)
+                    (?, ?, ?, ?, ?, ?, ?)
+                RETURNING convoy_id
                 """,
-                (convoy_id, client_id, header)
-            )
-            db_con.execute(
-                """
-                INSERT INTO
-                    honk (honk_id, client_id, convoy_id, url, html)
-                VALUES
-                    (?, ?, ?, ?, ?)
-                """,
-                (honk["ID"], client_id, convoy_id, honk["XID"], honk["HTML"])
-            )
-            
+                (convoy, client_id, honk["ID"], honker, honk["XID"], honk["HTML"], honk["Date"])
+            ).fetchone()
+            convoy_id, = row
 
+            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"]
+                db_con.execute(
+                    "INSERT INTO donk (convoy_id, url, mime, alt_text) VALUES (?, ?, ?, ?)",
+                    (convoy_id, donk_url, donk["Media"], donk.get("Desc") or donk.get("Name") or None)
+                )
+
         if honk.get("RID"):
-            for honk_in_convoy in honk_url.do_get(action="gethonks", page="convoy", c=convoy_id)["honks"]:
+            for honk_in_convoy in honk_url.do_get(action="gethonks", page="convoy", c=convoy)["honks"]:
                 if not honk_in_convoy.get("RID"):
-                    from_ = honk_in_convoy.get("Oondle") or honk_in_convoy["Handle"]
-                    header = f'## From: {from_}, {honk_in_convoy["Date"]} (๐Ÿงต {honk["Handle"]})'
-                    _save_convoy_and_honk(header, honk_in_convoy)
+                    author = honk_in_convoy.get("Oondle") or honk_in_convoy["Handle"]
+                    honker = f'{author} (๐Ÿงต {honk["Handle"]})'
+                    _save_convoy(honker, honk_in_convoy)
                     break
             else:
                 db_con.execute(
                     """
                     INSERT INTO 
-                        convoy(convoy_id, client_id)
+                        convoy(convoy, client_id, honk_id)
                     VALUES 
-                        (?, ?)
+                        (?, ?, ?)
                     """,
-                    (convoy_id, client_id)
+                    (convoy, client_id, honk["ID"])
                 )
         else:
-            honk_from = honk.get("Oondle") or honk["Handle"]
             oondle = honk.get("Oondle")
-            if oondle:
-                header = f'From: {oondle}, {honk["Date"]} (๐Ÿ” {honk["Handle"]})'
-            else:
-                header = f'From: {honk["Handle"]}, {honk["Date"]}'
-            _save_convoy_and_honk(header, honk)
+            honker = f'{oondle} (๐Ÿ” {honk["Handle"]})' if oondle else f'{honk["Handle"]}'
+            _save_convoy(honker, honk)
 
+    res = db_con.execute(
+        """
+        SELECT 
+            convoy_id, honker, url, html, date
+        FROM
+            convoy
+        WHERE 
+            client_id=? AND honker IS NOT NULL
+        ORDER BY 
+            convoy_id DESC 
+        LIMIT 256
+        """,
+        (client_id, )
+    )
 
+    print("20 text/gemini\r")
+    print("# ๐“— onk\r")
+    print("\r")
+
+    line = f"=> {honk_url.build_url(path='atme')} @me"
+    if home["mecount"]:
+        line += f' ({home["mecount"]})'
+    print(line + "\r")
+
+    line = f"=> {honk_url.build_url(path='chatter')} chatter"
+    if home["chatcount"]:
+        line += f' ({home["chatcount"]})'
+    print(line + "\r")
+    print("\r")
+
+    while True:
+        rows = res.fetchmany()
+        if not rows:
+            break
+
+        for row in rows:
+            convoy_id, honker, url, html, date, = row
+            lines = [
+                f"## From {honker} {date}",
+                f"=> {url}",
+                HtmlToGmi(honk_url.build_url(), fn_media_url).feed(html)
+            ]
+            res_donks = db_con.execute(
+                "SELECT url, mime, alt_text FROM donk WHERE convoy_id=?",
+                (convoy_id, )
+            )
+            while True:
+                donks = res_donks.fetchmany()
+                if not donks:
+                    break
+                for donk in donks:
+                    donk_url, donk_mime, donk_text, = donk
+                    lines.append(f'=> {fn_media_url(donk_mime, donk_url)}')
+                    if donk_text:
+                        lines.append(donk_text)
+            print("\r\n".join(lines))
+            print("\r")
+
+
 def lonk(cert_hash, lonk_url):
     db_con = db_connect(cert_hash)
     row = db_con.execute("SELECT client_id, honk_url, token FROM client WHERE cert_hash=?", (cert_hash, )).fetchone()
@@ -420,7 +433,6 @@ def lonk(cert_hash, lonk_url):
     client_id, honk_url, token = row
     with db_con:
         _lonk_impl(db_con, client_id, lonk_url, HonkUrl(honk_url, token))
-        # demo(lonk_url, HonkUrl(honk_url, token))
 
 
 def new_client_stage_1_ask_server(lonk_url):
@@ -510,7 +522,7 @@ if __name__ == '__main__':
                 raw_url = input().strip()
                 vgi(cert_hash, raw_url)
             finally:
-                stderr.write(f"{raw_url}|{clock_gettime(CLOCK_MONOTONIC) - start_time:.3f}sec.\n")
+                stderr.write(f"{cert_hash}|{raw_url}|{clock_gettime(CLOCK_MONOTONIC) - start_time:.3f}sec.\n")
         except HTTPError as error:
             print(f"43 Remote server return {error.code}: {error.reason}\r")
         except URLError as error: