import requests import os from tqdm import tqdm # ================= Config ================= PDS_URL = "" DID = "" ACCESS_JWT = "" OUTPUT_DIR = "backup" # ======================================== session = requests.Session() headers = {} if ACCESS_JWT: headers["Authorization"] = f"Bearer {ACCESS_JWT}" def export_repo(): print("Downloading repo.car...") url = f"{PDS_URL}/xrpc/com.atproto.sync.getRepo?did={DID}" r = session.get(url, headers=headers, stream=True) r.raise_for_status() os.makedirs(OUTPUT_DIR, exist_ok=True) path = os.path.join(OUTPUT_DIR, "repo.car") with open(path, "wb") as f: for chunk in r.iter_content(8192): f.write(chunk) print(f"repo.car saved to {path}") def list_blobs(): print("Listing blobs...") blobs = [] cursor = None while True: params = {} if cursor: params["cursor"] = cursor url = f"{PDS_URL}/xrpc/com.atproto.sync.listBlobs?did={DID}" r = session.get(url, headers=headers, params=params) r.raise_for_status() data = r.json() blobs.extend(data.get("cids", [])) cursor = data.get("cursor") if not cursor: break print(f"Found {len(blobs)} blobs") return blobs def download_blobs(blobs): os.makedirs(os.path.join(OUTPUT_DIR, "blobs"), exist_ok=True) print(f"Downloading {len(blobs)} blobs...") for cid in tqdm(blobs): path = os.path.join(OUTPUT_DIR, "blobs", cid) if os.path.exists(path): continue url = f"{PDS_URL}/xrpc/com.atproto.sync.getBlob?did={DID}&cid={cid}" r = session.get(url, headers=headers) if r.status_code == 200: with open(path, "wb") as f: f.write(r.content) def main(): export_repo() blobs = list_blobs() download_blobs(blobs) print("Backup complete!") if __name__ == "__main__": main()