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)