#!/usr/bin/python3 """load.py — the rehearsal's first-afternoon uploads, repeated (fixes 2026-10-21 Part 4): three streams at once, each sequential — the PDFs to Paperless (as irisz), the photos to Immich (as odon), the Nextcloud tree (rclone, 4 transfers, into a NEW folder so every file is new work). Passwords by env (handed in on stdin by the caller); never printed. One log line per file or event, UTC; each stream ends with its counts.""" import glob, json, os, subprocess, sys, threading, time, datetime as dt import requests, urllib3 urllib3.disable_warnings() IP = "192.168.0.139"; D = "tester4.test" env = dict(l.split("=", 1) for l in sys.stdin.read().splitlines() if "=" in l) log_lock = threading.Lock() def log(*a): with log_lock: print(time.strftime("%H:%M:%SZ", time.gmtime()), *a, flush=True) def s(host): x = requests.Session(); x.verify = False; x.headers["Host"] = f"{host}.{D}" if env.get("COOKIE"): # the household's dashboard session: the setup gate lets only the household make the first admin x.headers["Cookie"] = env["COOKIE"] return x def u(path): return f"https://{IP}{path}" def paperless(): x = s("paperless"); x.auth = ("irisz", env["IRISZ"]); ok = bad = 0 for f in sorted(glob.glob("/root/data/paperless/*")): try: r = x.post(u("/api/documents/post_document/"), files={"document": open(f, "rb")}, timeout=300) ok += r.status_code == 200; bad += r.status_code != 200 log("paperless", os.path.basename(f), r.status_code) except Exception as e: bad += 1; log("paperless", os.path.basename(f), "ERR", str(e)[:120]) log("paperless DONE ok", ok, "bad", bad) def immich(): x = s("photos") r = x.post(u("/api/auth/admin-sign-up"), json={"email": "tester4+odon@felhom.eu", "password": env["ODON"], "name": "Ödön"}, timeout=60) log("immich admin-sign-up", r.status_code) r = x.post(u("/api/auth/login"), json={"email": "tester4+odon@felhom.eu", "password": env["ODON"]}, timeout=60) if r.status_code not in (200, 201): log("immich login", r.status_code); return x.headers["Authorization"] = "Bearer " + r.json()["accessToken"]; ok = bad = 0 for f in sorted(glob.glob("/root/data/immich/**/*", recursive=True)): if not os.path.isfile(f): continue st = os.stat(f); ts = dt.datetime.utcfromtimestamp(st.st_mtime).isoformat() + "Z" try: r = x.post(u("/api/assets"), files={"assetData": open(f, "rb")}, data={"deviceAssetId": f, "deviceId": "rh1021", "fileCreatedAt": ts, "fileModifiedAt": ts}, timeout=600) ok += r.status_code in (200, 201); bad += r.status_code not in (200, 201) log("immich", os.path.basename(f), r.status_code) except Exception as e: bad += 1; log("immich", os.path.basename(f), "ERR", str(e)[:120]) log("immich DONE ok", ok, "bad", bad) def nextcloud(): obs = subprocess.run(["rclone", "obscure", "-"], input=env["ODON"], capture_output=True, text=True).stdout.strip() e = dict(os.environ, RCLONE_CONFIG_NC_TYPE="webdav", RCLONE_CONFIG_NC_URL=f"https://cloud.{D}/remote.php/dav/files/odon", RCLONE_CONFIG_NC_VENDOR="nextcloud", RCLONE_CONFIG_NC_USER="odon", RCLONE_CONFIG_NC_PASS=obs) log("nextcloud rclone START") p = subprocess.run(["rclone", "copy", "--no-check-certificate", "--transfers", "4", "--stats", "60s", "--stats-one-line", "-v", "--max-size", "1G", "/root/data/nextcloud/Csalad", "nc:/Csalad_feltoltes"], env=e, capture_output=True, text=True) for l in (p.stderr or "").splitlines(): if "Transferred:" in l or "ERROR" in l: log("nextcloud", l.strip()[:200]) log("nextcloud DONE rc", p.returncode) want = sys.argv[1:] or ["paperless", "immich", "nextcloud"] ts = [threading.Thread(target=f) for f in (paperless, immich, nextcloud) if f.__name__ in want] log("LOAD START") [t.start() for t in ts]; [t.join() for t in ts] log("LOAD END")