fix: stop re-processing deleted media stuck in Jellyfin/Emby collections (#3023)#3024
Conversation
Co-authored-by: enoch85 <4511254+enoch85@users.noreply.github.com>
|
@copilot Please format the code. Also run the seeded db in tools to confirm or deny your own theory. |
Co-authored-by: enoch85 <4511254+enoch85@users.noreply.github.com>
Addressed in I formatted the touched comparator line with Prettier. I also ran the dev seed flow ( |
When a disk-freeing action removes a file, the item still resolved on the
media server but stayed linked in every other managed collection. Once the
library dropped it, those collections kept a dead BoxSet link that
Jellyfin/Emby re-resolve on every rule run ("Unable to find linked item at
path" + high CPU).
Cascade-remove the item from sibling collections while a valid id still
exists, and mark it recently-handled per pruned collection so the executor's
next pass does not re-add it.
* build(deps): bump the react group with 3 updates (#3017) Bumps the react group with 3 updates: [react](https://github.com/facebook/react/tree/HEAD/packages/react), [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) and [react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom). Updates `react` from 19.2.6 to 19.2.7 - [Release notes](https://github.com/facebook/react/releases) - [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md) - [Commits](https://github.com/facebook/react/commits/v19.2.7/packages/react) Updates `@types/react` from 19.2.15 to 19.2.16 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react) Updates `react-dom` from 19.2.6 to 19.2.7 - [Release notes](https://github.com/facebook/react/releases) - [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md) - [Commits](https://github.com/facebook/react/commits/v19.2.7/packages/react-dom) --- updated-dependencies: - dependency-name: react dependency-version: 19.2.7 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: react - dependency-name: "@types/react" dependency-version: 19.2.16 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: react - dependency-name: react-dom dependency-version: 19.2.7 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: react ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump knip from 6.14.2 to 6.15.0 (#3018) Bumps [knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip) from 6.14.2 to 6.15.0. - [Release notes](https://github.com/webpro-nl/knip/releases) - [Commits](https://github.com/webpro-nl/knip/commits/knip@6.15.0/packages/knip) --- updated-dependencies: - dependency-name: knip dependency-version: 6.15.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump date-fns from 4.3.0 to 4.4.0 (#3019) Bumps [date-fns](https://github.com/date-fns/date-fns) from 4.3.0 to 4.4.0. - [Release notes](https://github.com/date-fns/date-fns/releases) - [Commits](date-fns/date-fns@v4.3.0...v4.4.0) --- updated-dependencies: - dependency-name: date-fns dependency-version: 4.4.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump vitest from 4.1.7 to 4.1.8 (#3020) Bumps [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) from 4.1.7 to 4.1.8. - [Release notes](https://github.com/vitest-dev/vitest/releases) - [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md) - [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.8/packages/vitest) --- updated-dependencies: - dependency-name: vitest dependency-version: 4.1.8 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump vite from 8.0.14 to 8.0.16 (#3021) Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 8.0.14 to 8.0.16. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v8.0.16/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-version: 8.0.16 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump node from 26.2.0-alpine3.22 to 26.3.0-alpine3.22 (#3022) Bumps node from 26.2.0-alpine3.22 to 26.3.0-alpine3.22. --- updated-dependencies: - dependency-name: node dependency-version: 26.3.0-alpine3.22 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix: stop re-processing deleted media stuck in Jellyfin/Emby collections (#3023) (#3024) --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
…er (#3023) (#3040) When a collection action can't run because the item is already gone from the media server, handle it instead of failing: confirm absence with the transient-safe itemExists primitive, then drop the stale rows from the collection (and any siblings) so it stops being re-processed every run. Also promote itemExists onto the shared IMediaServerService interface as the single existence-check primitive (consumed by the collection handler, removeStaleCollectionMedia, and the overlay processor), replacing the per-overlay-provider copies and the getMetadata-falsiness staleness check that could drop live rows on a transient error. Follow-up to #3024.
* docs: sync v3.13.0 changelog with release notes * build(deps-dev): bump @typescript-eslint/eslint-plugin (#3032) Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 8.60.0 to 8.60.1. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.60.1/packages/eslint-plugin) --- updated-dependencies: - dependency-name: "@typescript-eslint/eslint-plugin" dependency-version: 8.60.1 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump axios from 1.16.1 to 1.17.0 (#3033) Bumps [axios](https://github.com/axios/axios) from 1.16.1 to 1.17.0. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](axios/axios@v1.16.1...v1.17.0) --- updated-dependencies: - dependency-name: axios dependency-version: 1.17.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump react-hook-form from 7.76.1 to 7.77.0 (#3035) Bumps [react-hook-form](https://github.com/react-hook-form/react-hook-form) from 7.76.1 to 7.77.0. - [Release notes](https://github.com/react-hook-form/react-hook-form/releases) - [Changelog](https://github.com/react-hook-form/react-hook-form/blob/master/CHANGELOG.md) - [Commits](react-hook-form/react-hook-form@v7.76.1...v7.77.0) --- updated-dependencies: - dependency-name: react-hook-form dependency-version: 7.77.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump typescript-eslint from 8.60.0 to 8.60.1 (#3034) Bumps [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) from 8.60.0 to 8.60.1. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.60.1/packages/typescript-eslint) --- updated-dependencies: - dependency-name: typescript-eslint dependency-version: 8.60.1 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @tanstack/react-query from 5.100.14 to 5.101.0 (#3036) Bumps [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) from 5.100.14 to 5.101.0. - [Release notes](https://github.com/TanStack/query/releases) - [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md) - [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query@5.101.0/packages/react-query) --- updated-dependencies: - dependency-name: "@tanstack/react-query" dependency-version: 5.101.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump rolldown from 1.0.3 to 1.1.0 (#3037) Bumps [rolldown](https://github.com/rolldown/rolldown/tree/HEAD/packages/rolldown) from 1.0.3 to 1.1.0. - [Release notes](https://github.com/rolldown/rolldown/releases) - [Changelog](https://github.com/rolldown/rolldown/blob/main/CHANGELOG.md) - [Commits](https://github.com/rolldown/rolldown/commits/v1.1.0/packages/rolldown) --- updated-dependencies: - dependency-name: rolldown dependency-version: 1.1.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump react-router-dom from 7.16.0 to 7.17.0 (#3038) Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 7.16.0 to 7.17.0. - [Release notes](https://github.com/remix-run/react-router/releases) - [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md) - [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@7.17.0/packages/react-router-dom) --- updated-dependencies: - dependency-name: react-router-dom dependency-version: 7.17.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump openpgp from 6.3.0 to 6.3.1 (#3039) Bumps [openpgp](https://github.com/openpgpjs/openpgpjs) from 6.3.0 to 6.3.1. - [Release notes](https://github.com/openpgpjs/openpgpjs/releases) - [Commits](openpgpjs/openpgpjs@v6.3.0...v6.3.1) --- updated-dependencies: - dependency-name: openpgp dependency-version: 6.3.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix(collections): prune media that no longer exists on the media server (#3023) (#3040) When a collection action can't run because the item is already gone from the media server, handle it instead of failing: confirm absence with the transient-safe itemExists primitive, then drop the stale rows from the collection (and any siblings) so it stops being re-processed every run. Also promote itemExists onto the shared IMediaServerService interface as the single existence-check primitive (consumed by the collection handler, removeStaleCollectionMedia, and the overlay processor), replacing the per-overlay-provider copies and the getMetadata-falsiness staleness check that could drop live rows on a transient error. Follow-up to #3024. * feat: skip currently-playing media in the collection handler (#3027) Before the collection handler acts on eligible media, skip anything that is currently being streamed so it isn't removed out from under an active viewer. Skipped media stays eligible and is handled on the next run. - Plex: GET /status/sessions - Jellyfin/Emby: GET /Sessions (NowPlayingItem) A playing item protects its episode, season, and show, so a collection tracking any of those levels is deferred. Best-effort: the session snapshot is read once per run and an empty or failed lookup just means "handle as usual". Also consolidate the axios retry config into a shared applyHttpRetry helper, adding retry parity to the Emby and Jellyfin clients. * fix(collections): find manual collections across libraries on Jellyfin/Emby (#3026) (#3042) Jellyfin/Emby BoxSets are server-global and only reported under libraries whose content they currently hold, so a manual collection shared between a movie rule and a show rule was invisible to the show-library lookup. Add a capability-gated cross-library fallback for manual collections, and cache Emby getCollections with invalidation to mirror the Jellyfin adapter. Make Emby getCollections/getCollectionChildren user-scoped; Emby resolves BoxSet queries against a user's library view, so an unscoped read can miss or 404 and break the manual-collection bootstrap. Maintainerr only ever operates as an admin, so when no emby_user_id is configured, resolve and cache the first admin user. The user is passed via the UserId query param on the literal /Items path (not interpolated into the request path), which keeps the read user-scoped without tripping CodeQL's request-forgery sink. Add dev tooling to reproduce this end-to-end: a fake-emby mock plus MEDIA_SERVER=emby support in seed-db, and teach fake-jellyfin to model a server-global BoxSet reported under the movie library only. --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: enoch85 <mailto@danielhansson.nu> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
|
🎉 This PR is included in version 3.14.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
… ➔ 3.14.0) (#207) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [ghcr.io/maintainerr/maintainerr](https://github.com/Maintainerr/Maintainerr) | minor | `3.13.0` → `3.14.0` | --- ### Release Notes <details> <summary>Maintainerr/Maintainerr (ghcr.io/maintainerr/maintainerr)</summary> ### [`v3.14.0`](https://github.com/Maintainerr/Maintainerr/blob/HEAD/CHANGELOG.md#3140-2026-06-05) [Compare Source](Maintainerr/Maintainerr@v3.13.0...v3.14.0) #### Highlights - Added `/api/health` endpoints with liveness and readiness checks for monitoring and integration with tools like Kubernetes and Docker Compose ([#​3029](Maintainerr/Maintainerr#3029)). - Collection handler now skips media currently being streamed to avoid disrupting active viewers ([#​3027](Maintainerr/Maintainerr#3027)). - Fixed issue where saving log settings would overwrite an active `LOG_LEVEL` environment variable override ([#​3053](Maintainerr/Maintainerr#3053)). #### Features - Added `/api/health` endpoints with liveness and readiness checks ([#​3029](Maintainerr/Maintainerr#3029)). - Collection handler now skips media currently being streamed ([#​3027](Maintainerr/Maintainerr#3027)). - Logging system now honors the `LOG_LEVEL` environment variable on startup ([#​3030](Maintainerr/Maintainerr#3030)). #### Fixes - Fixed issue where saving log settings would overwrite an active `LOG_LEVEL` environment variable override ([#​3053](Maintainerr/Maintainerr#3053)). - Validated webhook URL schemes to prevent invalid or potentially harmful requests ([#​3031](Maintainerr/Maintainerr#3031)). - Fixed issue where rule groups lost collection links and visibility on partial updates ([#​3045](Maintainerr/Maintainerr#3045), [#​3046](Maintainerr/Maintainerr#3046)). - Fixed issue with manual collections not being found across libraries on Jellyfin/Emby ([#​3026](Maintainerr/Maintainerr#3026), [#​3042](Maintainerr/Maintainerr#3042)). - Resolved issue where deleted media remained stuck in Jellyfin/Emby collections and caused repeated processing errors ([#​3023](Maintainerr/Maintainerr#3023), [#​3024](Maintainerr/Maintainerr#3024), [#​3040](Maintainerr/Maintainerr#3040)). - Fixed issue where Seerr requests for episode rules incorrectly deleted entire season requests ([#​3015](Maintainerr/Maintainerr#3015)). - Improved error notifications for collection handling failures to include the name of the failing collection ([#​3013](Maintainerr/Maintainerr#3013)). - Used Radarr bulk exclusions endpoint to avoid duplicate 400 errors when adding exclusions ([#​3012](Maintainerr/Maintainerr#3012)). #### Performance - Pruned media that no longer exists on the media server to improve collection handling efficiency ([#​3023](Maintainerr/Maintainerr#3023), [#​3040](Maintainerr/Maintainerr#3040)). #### Internal - Refreshed README with updated features, deployment examples, and credits ([#​3048](Maintainerr/Maintainerr#3048)). - Clarified that a missing `yarn` command indicates a stale `node_modules` directory. #### Dependencies - Updated 20 dependencies, including `@typescript-eslint/parser`, `react-router-dom`, `axios`, and `vite`. #### New Contributors - [@​Arvuno](https://github.com/Arvuno) made their first contribution in [#​3029](Maintainerr/Maintainerr#3029) </details> --- ### Configuration 📅 **Schedule**: (in timezone America/New_York) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about these updates again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yMDYuMCIsInVwZGF0ZWRJblZlciI6IjQzLjIwNi4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZS9jb250YWluZXIiLCJ0eXBlL21pbm9yIl19--> Reviewed-on: https://git.greyrock.io/greyrock-labs/home-ops/pulls/207
Fixes #3023.
A "watched" / "leaving soon" shelf running alongside a delete rule is a normal Maintainerr setup, but a deleted item was only removed from the collection that handled it. It stayed linked in every other collection that listed it; once the library dropped the item, those collections kept a dead Jellyfin/Emby BoxSet link that the server re-resolves on every rule run — the
Unable to find linked item at pathwarning storm and high CPU reported in the issue.ORrules within a section, avoiding redundant getter work for the already-matched subset.