Repository navigation
Conversation
…PageMeta, ioredis probe)
# Conflicts: # server/database/migrations/meta/0008_snapshot.json # server/database/migrations/meta/_journal.json # server/database/migrations/postgres/meta/0007_snapshot.json # server/database/migrations/postgres/meta/_journal.json # server/types/entities.ts # server/types/status.ts # server/utils/i18n-server.ts # server/utils/torrents/torrent-sync.ts # test/utils/torrents/torrent-sync.test.ts
- update existing plex.tv shares in place instead of remove-then-create, so a failed create can no longer leave a user without library access - validate libraryAccess/toggles in the plex presets and admin user routes; share one Plex defaults builder between the orchestrator and the provider (also fixes per-user settings being reset to defaults on unrelated user edits) - bound every PMS/plex.tv request with a 10s timeout and truncate error bodies before they reach the logs - stop section pagination when the server repeats a page, ignore empty section paths, and drop the unused inviteExistingUser method - surface Plex library load failures in the admin UI (new plexLibrariesError key in all six locales)
- tolerate Plex collapsing single-element JSON lists into bare objects (sections, locations, metadata, home users, shares) in both the client and the setup script - keep a Plex-only user's Lode password when force-syncing (a mapping on any provider now means the external account exists) and let password-less providers provision users - parse stored library access leniently in the user list and Plex presets so one corrupt row cannot break the admin UI - drop the unused PMS createSection method and rewrite invite-based wording/theming in all six locales, CHANGELOG, README and docs; document the Plex env vars, settings keys and Docker setup
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds Plex Media Server as a first-class sync provider alongside Jellyfin. Lode provisions users on Plex itself, so a Plex-only install can run without Jellyfin, and a Jellyfin-only install behaves exactly as before.
User model (read this first)
POST /api/v2/home/users), then creates or updates a server share granting the selected library sections.NUXT_PLEX_TOKENbelonging to the server owner, and a claimed server (myPlexSigninState).Changes
PlexSyncProviderregistered in the orchestrator;syncNewUser/syncUserUpdateaccept per-provider settings overrides, so Plex section keys never collide with Jellyfin library IDs. Providers may declarerequiresPassword: false(Plex does), which lets provisioning run without a password. Per-user surface is library access, Live TV (allowTuners) and Sync downloads (allowSync) - Plex has no per-user transcoding/remuxing/session/avatar API, so those optional hooks are not implemented and are skipped by the orchestrator.server/utils/clients/plex.ts):PlexPmsClient(sections, paginated library walk, GUID → TMDB/IMDB/TVDB resolution, post-download section refresh with a 60 s per-section debounce) andPlexTvClient(home users + v2 shares) kept separate, since two different hosts are involved. 10 s request timeouts, a 200-page pagination guard, andasListnormalisation because Plex collapses single-element JSON lists into bare objects.GET/PUT /api/admin/plex/presets,GET /api/admin/plex/status(version +myPlexSigninState), Plex fields on user create/edit/list, and Plex in/api/admin/sync/libraries+/api/admin/sync/providers. Request bodies are validated with zod (server/utils/sync/provider-settings.ts), shared by create and edit so the same malformed value cannot pass one route and fail the other.PlexUserFields, and the sharedMediaServerStatusBanner(renamed fromJellyfinStatusBanner, now used by both). The force-sync button is enabled when any media server is configured, with provider-aware wording.falsefor that item instead of failing the request).enable_synccolumn on per-user sync settings -0009_nosy_tarantula(SQLite) /0008_cold_dark_phoenix(PostgreSQL), singleALTEReach.admin.plex*keys, hand-written in all six locales (no machine translation); the key-parity test covers them.docker-compose.plex.ymloverlay (plexinc/pms-docker, port 32400),scripts/setup-plex.mjscreating the Movies + TV Shows sections on container start (idempotent, best-effort), entrypoint wiring.README(media-server matrix + roadmap),CHANGELOG1.1.0,docs/configuration.md(env vars + settings keys),docs/deployment.md(overlay, volumes, entrypoint, Plex setup section),docs/api/admin.md,docs/features/admin-features.md,.env.example,AGENTS.md.server/types/status.tsdeleted, duplicateRankedTorrent/ParsedTitleremoved,DiscordLocaleconsolidated, sync DB rows renamed to*Record), removed the no-opdefinePageMetafrom the default layout (NUXT_E1007 ×12), and hardened the system-status Redis probe so a down Redis no longer emits unhandled ioredis errors.Review fixes included
008060b- harden share sync and validate admin settingsupdateShare(via newfindShareId/getSharedServers) and only falls back to remove+create when no share exists; a failed create is logged and rethrown instead of silently leaving a user without access.provider-settings.ts.inviteExistingUserpath rather than wiring it up - auto-inviting arbitrary addresses would email people Lode knows nothing about.[id].put.tsno longer clobbers untouched Plex fields.admin.plexLibrariesErrorkey in all six locales.58b801c- align docs and harden single-item responsesasListnormalisation in the Plex client andscripts/setup-plex.mjs(sections,Location, metadata, home users, shared servers).requiresPasswordadded to theSyncProvidercontract (Plex:false).users.get.tsandplex/presets.get.tsuse the lenientparseStoredLibraryAccess, so one corrupt row cannot break the admin UI.PlexPmsClient.createSection(the setup script owns provisioning).CHANGELOG,docs/api/admin.mdand the force-sync strings in all six locales;READMEmatrix/roadmap,docs/configuration.md,docs/deployment.mdand.env.examplenow describe the real behaviour.Testing
pnpm typecheck- 0 errors, 0 warningspnpm lint- cleanpnpm test- 164 files / 1785 tests passing (baseline onmainbefore this work: 150 / 1504). New/updated coverage: Plex client (GUID false-positives, section mapping, single-object collapse, pagination guard, share lookup), sync multi-provider matrix (Jellyfin-only, Plex-only, both, both with one failing, neither, password-less provisioning), admin Plex routes, admin user list leniency, force-sync password behaviour,usePlexStatus/usePlexConfigured, i18n key parity.cli/): verified in CI by thecheckjob (install + typecheck + lint + test). Not run locally - Bun is not installed in this environment, so the CI job is the source of truth forcli/**.Notes for reviewers
enable_synccolumn.machineIdentifier: shares are keyed by the PMSmachineIdentifierread fromGET /and cached. Re-claiming/reinstalling the server changes it, and Lode will then create a new share - the stale one must be removed in Plex.asListhandles that at every boundary; there are regression tests for each.PlexTvClientso a shape change is a one-file fix.enableUserre-derives share settings from the server-wide Plex presets; per-user settings are intentionally ignored on re-enable (documented behaviour).NUXT_PLEX_TOKENis account-wide (warned about in.env.example), never logged, and test fixtures use obvious fake values.definePageMeta({ middleware: 'auth' })inapp/layouts/default.vuewas a no-op (the macro is only compiled in pages), and every protected page declares its own middleware - no behaviour change.[nostics] import.meta.hot.send()comes fromnostics@1.3.0(a dev-only transitive dependency of@nuxt/kit).