Bussy-boy/client.py

149 lines
3.9 KiB
Python
Raw Normal View History

2023-07-09 23:00:43 +00:00
import requests
import sys
import os
import math
import time
import shelve
from requests.adapters import HTTPAdapter, Retry
from config import config
class DramaClient:
BASE_URL = "https://rdrama.net"
def __init__(self):
self.db = shelve.open(f"{config['data_dir']}/client_state.p", writeback=True)
self.db.setdefault("processed_replies", set())
self.session = requests.Session()
retries = Retry(
total=5, backoff_factor=5, status_forcelist=[500, 502, 503, 504, 521]
)
self.session.mount("https://", HTTPAdapter(max_retries=retries))
self.chud_phrase = self.get("/@me").get("chud_phrase", "")
def get(self, endpoint):
print("GET", endpoint)
time.sleep(5)
while True:
r = self.session.get(
f"{self.BASE_URL}{endpoint}",
headers={"Authorization": config["api_token"]},
)
if "502 Bad Gateway" in r.text:
print("Received 502")
time.sleep(10)
continue
break
# Return None for country club and chudrama posts.
if r.status_code == 403:
return None
if r.status_code != 200:
print("Error!", r, r.status_code, r.content)
sys.exit(1)
return r.json()
def post(self, endpoint, payload=None, files=[]):
print("POST", endpoint, f"Payload:\n{payload}")
time.sleep(5)
while True:
r = self.session.post(
f"{self.BASE_URL}{endpoint}",
payload,
headers={"Authorization": config["api_token"]},
files=files,
)
if "502 Bad Gateway" in r.text:
print("Received 502")
time.sleep(10)
continue
break
if r.status_code != 200:
print("Error!", r, r.status_code, r.content)
sys.exit(1)
return r.json()
def fetch_new_comments(self, limit=0):
comments = []
last_processed_id = self.db.get("last_processed_id", -1)
earliest_id = math.inf
page = 1
# Fetch comments until we find the last one processed.
while earliest_id > last_processed_id:
page_comments = self.fetch_page(page)
if len(page_comments) == 0:
break
earliest_id = min([c["id"] for c in page_comments])
comments += [c for c in page_comments if c["id"] > last_processed_id]
if limit > 0 and len(comments) >= limit:
break
page += 1
if not comments:
return []
self.db["last_processed_id"] = max(c["id"] for c in comments)
self.db.sync()
# New comments may have pushed others to page n+1 while fetching.
deduped_comments = {c["id"]: c for c in comments}.values()
# Oldest first.
comments.reverse()
return comments
def fetch_new_replies(self):
notifs = self.get("/unread")["data"]
notifs = [n for n in notifs if n["body"]]
return notifs
def fetch_page(self, page):
return self.get(f"/comments?page={page}")["data"]
def fetch_context(self, comment):
post = self.get(f"/post/{comment['post_id']}")
if not post:
return None, None
comments = [comment]
while parent_id := comments[-1].get("parent_comment_id", None):
parent = self.get(f"/comment/{parent_id}")
comments.append(parent)
comments.reverse()
return post, comments
def reply(self, body, comment):
if self.chud_phrase and self.chud_phrase not in body:
body += f"\n{self.chud_phrase}"
payload = {
"parent_fullname": f"c_{comment['id']}",
"body": body,
}
self.post("/comment", payload)