chiark / gitweb /
Show a Re: header on reply posts.
authorSimon Tatham <anakin@pobox.com>
Thu, 7 Dec 2023 05:33:13 +0000 (05:33 +0000)
committerSimon Tatham <anakin@pobox.com>
Thu, 7 Dec 2023 07:09:14 +0000 (07:09 +0000)
client.py
text.py

index 302c1355b8d3b9ce52c462a3a6a44fe0f3ce52fe..38bf8dc6e3690dc0f3aeec98edfe27c85fa415f0 100644 (file)
--- a/client.py
+++ b/client.py
@@ -27,6 +27,10 @@ class Client:
         self.bearer_token = None
         self.log_response = lambda *args, **kws: None
 
+        # A global cache across all feeds etc of statuses by id, so
+        # that we can look up the text of one to show in a 'Re:' header
+        self.status_cache = {}
+
     def set_instance_url(self, instance_url):
         self.instance_url = instance_url
         self.urls = {
@@ -156,6 +160,16 @@ class Client:
     def ego_feed(self):
         return EgoFeed(self)
 
+    def cache_status(self, status):
+        self.status_cache[status['id']] = status
+
+    def get_status_by_id(self, id):
+        if id in self.status_cache:
+            return self.status_cache[id]
+        st = self.get(f"statuses/{id}")
+        self.cache_status(st)
+        return st
+
 class Feed:
     """Base class that encapsulates some kind of collection of _things_ we
     can get from the server, with both the ability to go backwards in
@@ -242,6 +256,8 @@ class Status:
         else:
             self.booster = None
 
+        client.cache_status(data)
+
         self.post_id = data['id']
 
         self.datestamp = parse_creation_time(data['created_at'])
@@ -255,6 +271,8 @@ class Status:
 
         self.media = data.get('media_attachments', [])
 
+        self.reply_id = data.get('in_reply_to_id')
+
         self.client = client
 
     def text(self):
@@ -264,6 +282,15 @@ class Status:
         if self.booster is not None:
             yield text.BoosterLine(self.client.fq(self.booster['acct']),
                                    self.booster['display_name'])
+        if self.reply_id is not None:
+            hp = text.HTMLParser()
+            try:
+                reply_status = self.client.get_status_by_id(self.reply_id)
+                hp.feed(reply_status['content'])
+            except HTTPError as ex:
+                hp.feed(f'[unavailable: {ex.response.status_code}]')
+            hp.done()
+            yield text.InReplyToLine(hp.paras)
         yield text.BlankLine()
         yield from self.content
         if len(self.content) > 0:
@@ -279,6 +306,7 @@ class Notification:
         self.datestamp = parse_creation_time(data['created_at'])
         st = data.get('status')
         if st is not None:
+            client.cache_status(st)
             hp = text.HTMLParser()
             hp.feed(st['content'])
             hp.done()
diff --git a/text.py b/text.py
index 7e1de02f1eec8047de522dedce3442cb09837036..43220b94ef35171fe251ad0bac9fa1f5225d3c4a 100644 (file)
--- a/text.py
+++ b/text.py
@@ -142,6 +142,30 @@ class BoosterLine(UsernameHeader):
     header = "Via"
     colour = "f"
 
+class InReplyToLine:
+    def __init__(self, cparas):
+        self.para = Paragraph()
+        self.para.add(ColouredString("Re:"))
+        self.para.end_word()
+
+        currlen = len(self.para)
+        for cpara in cparas:
+            self.para.add_para(cpara)
+        self.para.delete_mention_words_from(currlen)
+
+    def render(self, width):
+        it = self.para.render(width-3)
+        line = next(it)
+        try:
+            next(it)
+
+            if line.width < width-3:
+                line += ColouredString(" ")
+            line += ColouredString("...")
+        except StopIteration:
+            pass
+        yield line
+
 class Media:
     def __init__(self, url, description):
         self.url = url