Repository navigation
feat: non-interactive recovery and current Jellyfin/Seerr support (v1.2.2) - #8
Conversation
arrstack install --resume --yes reads state.json and admin.txt and reruns the full install pipeline without the wizard. This makes recovery from an aborted install scriptable and covers every wiring step, including Jellyfin and Jellyseerr, not just the arr logins that update repairs.
Jellyfin 12.x disables legacy X-Emby-Authorization by default and rejects AuthenticateByName without the standard Authorization header (400, request.App null). Send both headers, and skip Startup/User when an earlier attempt already created the first user (Jellyfin answers 403). Seerr 3.x replaced the library sync and bulk-enable query parameters with POST /library/sync and PUT /library/:id. Use the new endpoints with a legacy fallback, and log in without hostname fields when the server is already configured (500 "hostname already configured").
Retry requests whose socket closes mid-flight (Jellyfin startup does this during configuration). Drop depends_on edges to services the user deselected instead of rendering a compose project Docker rejects with "depends on undefined service".
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9985b539fd
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // A previous attempt may have created the first user before failing later | ||
| // (or the user answered part of the startup wizard). POSTing /Startup/User | ||
| // again returns 403, so only create the user when none exists. | ||
| if (!startupUser?.Name) { |
There was a problem hiding this comment.
Do not treat the startup user's name as configured
On every fresh Jellyfin installation, GET /Startup/User initializes and returns the placeholder first user with a nonempty Name; it does not indicate that the user has already been configured. Consequently this condition skips the required POST /Startup/User, leaves the placeholder credentials unchanged, and the subsequent authentication with the requested admin username/password fails, aborting the default install. Detect prior configuration by authenticating or attempting the update and handling the specific already-configured response instead.
Useful? React with 👍 / 👎.
| if (opts.yes) { | ||
| if (!opts.resume) { | ||
| console.error("\n--yes requires --resume. Use 'arrstack install --resume --yes' to finish an existing install.\n"); | ||
| process.exit(1); |
There was a problem hiding this comment.
Validate --yes before purging a fresh install
When an existing user runs arrstack install --fresh --yes without --resume, the --fresh block has already stopped the stack and deleted state.json, admin.txt, .env, and the entire service config/ tree before this newly added validation exits with an error. Since --yes is rejected in this combination, validate it before performing any --fresh side effects (and likewise reject --fresh --resume --yes before purging) to avoid destructive data loss from an invalid invocation.
Useful? React with 👍 / 👎.
| const dependsOn: DependsOnEntry[] = svc.dependsOn | ||
| .filter((service) => enabledIds.has(service)) | ||
| .map((service) => ({ service })); |
There was a problem hiding this comment.
Preserve mandatory dependencies for partial selections
When the independently toggleable Jellyseerr service remains selected but Jellyfin is deselected, this blanket filter removes Jellyseerr's declared jellyfin dependency and lets Compose start the partial project, but runInstall still unconditionally calls linkJellyseerr, whose bootstrap connects to hostname jellyfin; the install therefore fails after deploying containers. Required dependencies need to be auto-included or rejected during selection rather than being discarded alongside optional ordering edges.
Useful? React with 👍 / 👎.
What
Closes the remaining recovery gap from #6: a failed install can now be finished without the interactive wizard, and the Jellyfin/Jellyseerr wiring works against the current upstream images.
arrstack install --resume --yes: readsstate.jsonandadmin.txtand reruns the full pipeline non-interactively. Covers Jellyfin, Jellyseerr, qBittorrent, and arr wiring, not just the arr logins thatupdaterepairs.--yesrequires--resume.AuthenticateByNamereturns 400 withoutAuthorization: MediaBrowser ...because 12.x disables legacyX-Emby-Authorization. Send both headers and skipStartup/Userwhen a prior attempt already created the user (403).POST /settings/jellyfin/library/syncandPUT /settings/jellyfin/library/:id, with the legacy query API as fallback. Log in without hostname fields when the hostname is already configured.depends_onedges to services the user deselected instead of rendering a project Docker rejects.Why
Issue #6 recovery previously required the interactive TUI, and
install --resumeaborted on current Jellyfin 12.2.0 and Seerr 3.3.0 images.How it was tested
Full end-to-end run with a simulated aborted install (Sonarr, Radarr, Jellyfin, Jellyseerr, qBittorrent; no
install_completed_at; unconfigured containers):Afterward:
POST /login: 302 to/POST /auth/login: 204AuthenticateByName: 200settings/public.initialized: truearrstack doctor: all checks passed, exit 0Unit suite: 341 pass. Typecheck clean.
Checklist
bun testpassestsc --noEmitpasses