#!/usr/bin/env python3 """ Patch Jellyfin home-screen section layout for every user on a given instance. Default policy (this script): - Continue Watching (`resume`) ENABLED for every user - Resume Audio (`resumeaudio`) preserved if present - Next Up (`nextup`) DISABLED (replaced with `none`) - Latest Media (`latestmedia`) preserved if present - If a user's layout was empty (factory default), seed slot 0 with `resume` Idempotent. Safe to re-run. Usage: JF_URL=https://arrflix.s8n.ru \ JF_TOKEN= \ python3 bin/set-home-layout.py Token retrieval (admin): docker cp jellyfin:/config/data/jellyfin.db /tmp/jf.db sqlite3 /tmp/jf.db \\ 'SELECT d.AccessToken FROM Devices d JOIN Users u ON d.UserId=u.Id WHERE u.Username="s8n" ORDER BY d.DateLastActivity DESC LIMIT 1' """ import json import os import sys import urllib.request JF_URL = os.environ.get("JF_URL") JF_TOKEN = os.environ.get("JF_TOKEN") if not JF_URL or not JF_TOKEN: sys.exit("set JF_URL and JF_TOKEN env vars") def http(method, url, body=None): req = urllib.request.Request(url, method=method) req.add_header("X-Emby-Token", JF_TOKEN) data = None if body is not None: req.add_header("Content-Type", "application/json") data = json.dumps(body).encode() with urllib.request.urlopen(req, data=data) as r: text = r.read().decode() return r.status, (json.loads(text) if text else None) def patch_user(user_id, username): url = f"{JF_URL}/DisplayPreferences/usersettings?userId={user_id}&client=emby" _, prefs = http("GET", url) cp = prefs.get("CustomPrefs") or {} sections = [cp.get(f"homesection{i}", "none") for i in range(10)] before = list(sections) sections = ["none" if s == "nextup" else s for s in sections] if "resume" not in sections: if "none" in sections: sections[sections.index("none")] = "resume" else: sections = ["resume"] + sections[:9] for i, s in enumerate(sections): cp[f"homesection{i}"] = s prefs["CustomPrefs"] = cp changed = before != sections if changed: http("POST", url, body=prefs) return changed, before, sections def main(): users = http("GET", f"{JF_URL}/Users")[1] print(f"{JF_URL} — {len(users)} users") for u in users: changed, before, after = patch_user(u["Id"], u["Name"]) mark = "CHANGED" if changed else " ok " print(f" [{mark}] {u['Name']:<14} {before} -> {after}") if __name__ == "__main__": main()