chiark / gitweb /
Proof of concept using Link response headers for pagination.
authorSimon Tatham <anakin@pobox.com>
Sat, 2 Dec 2023 18:24:53 +0000 (18:24 +0000)
committerSimon Tatham <anakin@pobox.com>
Sat, 2 Dec 2023 18:24:53 +0000 (18:24 +0000)
client.py
mastodonochrome

index e7640f15e63c8978ef82e9e4f452a191c7a73b41..e83f42f3f07eb08e2c15c20db288a3836983ad7e 100644 (file)
--- a/client.py
+++ b/client.py
@@ -1,5 +1,6 @@
 import calendar
 import os
+import re
 import requests
 import string
 import time
@@ -26,6 +27,7 @@ class Client:
     def set_instance(self, instance):
         self.instance = instance
         self.urls = {
+            None: '',
             'auth': "https://" + instance + "/oauth/",
             'api': "https://" + instance + "/api/v1/",
         }
@@ -53,7 +55,7 @@ class Client:
 
         self.log_response = log_response
 
-    def method(self, method, path, base, params):
+    def method(self, method, path, base, params, links={}):
         headers = {}
         if self.bearer_token is not None:
             headers['Authorization'] = 'Bearer ' + self.bearer_token
@@ -61,6 +63,13 @@ class Client:
         self.log_response(rsp)
         if rsp.status_code != 200:
             raise HTTPError(rsp)
+        linkhdr = rsp.headers.get('Link', '')
+        while len(linkhdr) > 0:
+            m = re.match(r'<([^>]+)>\s*;\s*rel="([^"]+)"(?:,\s*)?', linkhdr)
+            if m is None:
+                break
+            links[m.group(2)] = m.group(1)
+            linkhdr = linkhdr[m.end():]
         return rsp.json()
 
     def get(self, path, base='api', **params):
@@ -68,6 +77,16 @@ class Client:
     def post(self, path, base='api', **params):
         return self.method(requests.post, path, base, params)
 
+    def get_incremental(self, path, base='api', **params):
+        params.setdefault('limit', 32)
+        while True:
+            links = {}
+            data = self.method(requests.get, path, base, params, links)
+            yield from data
+            if 'next' not in links:
+                break
+            base, path = None, links['next']
+
     def get_url(self, path, base='api', **params):
         r = requests.Request(method="GET", url=self.urls[base] + path,
                              params=params)
index 13048e73e95963bdfe17a16ebe66402660c3008a..823681daa32ea632f1bf1bb59a5020e57ab71b0c 100755 (executable)
@@ -22,10 +22,16 @@ class TimelineUI(client.Client):
 
 class MentionsUI(client.Client):
     def run(self):
-        for item in reversed(self.get("notifications", limit=40)):
+        g = self.get_incremental("notifications")
+        things = []
+        for item in g:
             if item['type'] != 'mention':
                 continue
             p = client.Status(item['status'])
+            things.append(p)
+            if len(things) >= 40:
+                break
+        for p in reversed(things):
             for thing in p.text():
                 for line in thing.render(80):
                     print(line.ecma48())