51 lines
2.7 KiB
Python
51 lines
2.7 KiB
Python
#!/usr/bin/env python3
|
|
"""jfsetup.py — S5 prep: Jellyfin's first-run wizard and two libraries, by its own API, INSIDE the guest.
|
|
The admin password is generated on DooPlex (kept ONLY in ~/.felhom-tester1/secrets.json, 0600) and substituted into
|
|
this file's copy on the box for the run; the copy is deleted afterwards. Nothing secret is printed."""
|
|
import json, subprocess, time, urllib.parse, urllib.request
|
|
PW = "__JF_PW__"
|
|
ip = subprocess.run("docker inspect jellyfin -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'", shell=True,
|
|
capture_output=True, text=True).stdout.strip()
|
|
B = f"http://{ip}:8096"
|
|
AUTH = 'MediaBrowser Client="felhom-test", Device="wire", DeviceId="felhom-wire-1", Version="1"'
|
|
|
|
|
|
def call(m, path, body=None, tok=None):
|
|
h = {"Content-Type": "application/json", "Authorization": AUTH + (f', Token="{tok}"' if tok else "")}
|
|
r = urllib.request.Request(B + path, data=json.dumps(body).encode() if body is not None else None, headers=h, method=m)
|
|
try:
|
|
with urllib.request.urlopen(r, timeout=60) as x:
|
|
t = x.read().decode(); print(f" {m} {path.split('?')[0]} -> {x.status}"); return json.loads(t) if t else None
|
|
except urllib.error.HTTPError as e:
|
|
print(f" {m} {path.split('?')[0]} -> {e.code} {e.read()[:150]}"); return None
|
|
|
|
|
|
for _ in range(30):
|
|
try:
|
|
urllib.request.urlopen(B + "/health", timeout=5); break
|
|
except Exception:
|
|
time.sleep(3)
|
|
call("POST", "/Startup/Configuration", {"UICulture": "en-US", "MetadataCountryCode": "HU", "PreferredMetadataLanguage": "hu"})
|
|
call("GET", "/Startup/User")
|
|
call("POST", "/Startup/User", {"Name": "admin", "Password": PW})
|
|
call("POST", "/Startup/RemoteAccess", {"EnableRemoteAccess": True, "EnableAutomaticPortMapping": False})
|
|
call("POST", "/Startup/Complete")
|
|
a = call("POST", "/Users/AuthenticateByName", {"Username": "admin", "Pw": PW})
|
|
tok = a["AccessToken"]
|
|
for name, ct, sub in (("TV Shows", "tvshows", "tv"), ("Movies", "movies", "movies")):
|
|
q = urllib.parse.urlencode({"name": name, "collectionType": ct, "refreshLibrary": "true"})
|
|
call("POST", f"/Library/VirtualFolders?{q}", {"LibraryOptions": {"PathInfos": [
|
|
{"Path": f"/mnt/felhom-drives/{d}/userdata/media/{sub}"} for d in ("media_a", "media_b")]}}, tok)
|
|
for _ in range(40):
|
|
time.sleep(6)
|
|
s = call("GET", "/Items?Recursive=true&IncludeItemTypes=Series,Movie,Episode&Fields=Path", tok) or {}
|
|
items = s.get("Items", [])
|
|
eps = [i for i in items if i["Type"] == "Episode"]
|
|
if len(eps) >= 16:
|
|
break
|
|
for t in ("Series", "Movie"):
|
|
print(t, sorted(i["Name"] for i in items if i["Type"] == t))
|
|
print("Episodes:", len(eps))
|
|
for v in call("GET", "/Library/VirtualFolders", tok) or []:
|
|
print("library", v["Name"], v.get("Locations"))
|