| 1 | #!/usr/bin/env python3 |
| 2 | import json |
| 3 | import ssl |
| 4 | import sys |
| 5 | import time |
| 6 | import urllib.error |
| 7 | import urllib.parse |
| 8 | import urllib.request |
| 9 | |
| 10 | |
| 11 | config = json.load(sys.stdin) |
| 12 | base = f"https://{config['host']}" |
| 13 | context = ssl.create_default_context(cafile="/var/lib/studio/ca-bundle.crt") |
| 14 | |
| 15 | |
| 16 | def request(path, data=None, token=None): |
| 17 | headers = { |
| 18 | "Content-Type": "application/json", |
| 19 | "Authorization": 'MediaBrowser Client="home server", Device="server", DeviceId="studio", Version="1"', |
| 20 | } |
| 21 | if token: |
| 22 | headers["X-Emby-Token"] = token |
| 23 | body = json.dumps(data).encode() if data is not None else None |
| 24 | req = urllib.request.Request(base + path, data=body, headers=headers, method="POST" if body is not None else "GET") |
| 25 | with urllib.request.urlopen(req, context=context, timeout=30) as response: |
| 26 | content = response.read() |
| 27 | return json.loads(content) if content else None |
| 28 | |
| 29 | |
| 30 | for _ in range(600): |
| 31 | try: |
| 32 | info = request("/System/Info/Public") |
| 33 | completed = info.get("StartupWizardCompleted", info.get("startupWizardCompleted")) if isinstance(info, dict) else None |
| 34 | if completed is not None and (completed or request("/Startup/FirstUser")): |
| 35 | break |
| 36 | except urllib.error.HTTPError as error: |
| 37 | if error.code not in (404, 500, 502, 503): |
| 38 | raise |
| 39 | except (urllib.error.URLError, TimeoutError): |
| 40 | pass |
| 41 | time.sleep(2) |
| 42 | else: |
| 43 | raise RuntimeError("Jellyfin did not finish loading") |
| 44 | |
| 45 | if completed: |
| 46 | sys.exit(0) |
| 47 | |
| 48 | request("/Startup/User", {"Name": "snow", "Password": config["admin_password"]}) |
| 49 | request("/Startup/Configuration", { |
| 50 | "ServerName": "Jellyfin", "UICulture": "en-US", "MetadataCountryCode": "US", "PreferredMetadataLanguage": "en", |
| 51 | }) |
| 52 | request("/Startup/Complete", {}) |
| 53 | |
| 54 | auth = request("/Users/AuthenticateByName", { |
| 55 | "Username": "snow", "Pw": config["admin_password"], |
| 56 | }) |
| 57 | token = auth["AccessToken"] |
| 58 | libraries = ( |
| 59 | ("Anime", "tvshows", ("Anime",)), |
| 60 | ("Movies", "movies", ("Movies",)), |
| 61 | ("paper clover", "musicvideos", ("Paper Clover",)), |
| 62 | ("Shows", "tvshows", ("Shows", "Indie Shows")), |
| 63 | ("Videos", "homevideos", ("Independent",)), |
| 64 | ) |
| 65 | for name, kind, folders in libraries: |
| 66 | query = urllib.parse.urlencode({ |
| 67 | "name": name, "collectionType": kind, |
| 68 | "paths": ",".join(f"/media/jellyfin/{folder}" for folder in folders), |
| 69 | "refreshLibrary": "false", |
| 70 | }) |
| 71 | request(f"/Library/VirtualFolders?{query}", {}, token) |