Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix(rules): inherit parent show for Streamystats watchlist at season/episode level (#3127)#3133

Merged
enoch85 merged 1 commit into
developmentfrom
fix/streamystats-watchlist-parent-inheritance
Jun 19, 2026
Merged

fix(rules): inherit parent show for Streamystats watchlist at season/episode level (#3127)#3133
enoch85 merged 1 commit into
developmentfrom
fix/streamystats-watchlist-parent-inheritance

Conversation

@enoch85

@enoch85 enoch85 commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator

Fixes #3127.

A Streamystats watchlist holds the show item ID, so the existing item-only isInWatchlist / watchlistedByUsers props return empty when a rule is evaluated at the season/episode level. A NOT_CONTAINS <user> protection rule then wrongly matches a watchlisted show's seasons and sweeps them into deletion/unmonitoring.

  • Adds isInWatchlist_including_parent and watchlistedByUsers_including_parent (show-only, season/episode), mirroring the existing Jellyfin sw_favoritedBy_including_parent precedent.
  • Resolves the parent chain through the media server's getMetadata — the same canonical path the Jellyfin/Emby/Plex getters use — so parent IDs come from the mapper's hierarchy resolution (SeriesId for seasons, not the library-folder parentId). Gated on the server-agnostic type so a movie is never rolled up.
  • Skips (returns undefined, transient) when metadata can't be fetched, rather than falling back to an item-only check that could let a protected item match a destructive rule.
  • Base props remain item-only (no behavioral change); union/dedupe reuses the shared definedUniqueValues helper.

…episode level (#3127)

A Streamystats list holds the show item ID, so the item-only
`isInWatchlist` / `watchlistedByUsers` props return empty at the
season/episode level, wrongly matching a watchlisted show's seasons in
destructive rules.

- add `isInWatchlist_including_parent` and `watchlistedByUsers_including_parent`
  (show-only, season/episode), mirroring the Jellyfin `sw_favoritedBy_including_parent` precedent
- resolve the parent chain via the media server's `getMetadata` (same path the
  other getters use); skip (undefined) when metadata can't be fetched rather
  than falling back to an item-only check
- base props left item-only; union/dedupe via the shared `definedUniqueValues`
@enoch85 enoch85 force-pushed the fix/streamystats-watchlist-parent-inheritance branch from cf0032a to c6abb79 Compare June 19, 2026 18:22
@enoch85 enoch85 merged commit 0e8ea2c into development Jun 19, 2026
14 checks passed
@enoch85 enoch85 deleted the fix/streamystats-watchlist-parent-inheritance branch June 19, 2026 18:26
maintainerr-automation Bot added a commit that referenced this pull request Jun 20, 2026
* build(deps-dev): bump vitest from 4.1.8 to 4.1.9 (#3116)

Bumps [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) from 4.1.8 to 4.1.9.
- [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.9/packages/vitest)

---
updated-dependencies:
- dependency-name: vitest
  dependency-version: 4.1.9
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @tailwindcss/vite from 4.3.0 to 4.3.1 (#3117)

Bumps [@tailwindcss/vite](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite) from 4.3.0 to 4.3.1.
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.3.1/packages/@tailwindcss-vite)

---
updated-dependencies:
- dependency-name: "@tailwindcss/vite"
  dependency-version: 4.3.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @typescript-eslint/eslint-plugin (#3118)

Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 8.61.0 to 8.61.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.61.1/packages/eslint-plugin)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.61.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump react-router-dom from 7.17.0 to 7.18.0 (#3119)

Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 7.17.0 to 7.18.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/[email protected]/packages/react-router-dom)

---
updated-dependencies:
- dependency-name: react-router-dom
  dependency-version: 7.18.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump nodemailer from 9.0.0 to 9.0.1 (#3120)

Bumps [nodemailer](https://github.com/nodemailer/nodemailer) from 9.0.0 to 9.0.1.
- [Release notes](https://github.com/nodemailer/nodemailer/releases)
- [Changelog](https://github.com/nodemailer/nodemailer/blob/master/CHANGELOG.md)
- [Commits](nodemailer/nodemailer@v9.0.0...v9.0.1)

---
updated-dependencies:
- dependency-name: nodemailer
  dependency-version: 9.0.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump rolldown from 1.1.1 to 1.1.2 (#3122)

Bumps [rolldown](https://github.com/rolldown/rolldown/tree/HEAD/packages/rolldown) from 1.1.1 to 1.1.2.
- [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.2/packages/rolldown)

---
updated-dependencies:
- dependency-name: rolldown
  dependency-version: 1.1.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump typescript-eslint from 8.61.0 to 8.61.1 (#3126)

Bumps [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) from 8.61.0 to 8.61.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.61.1/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: typescript-eslint
  dependency-version: 8.61.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump better-sqlite3 from 12.10.0 to 12.11.1 (#3124)

Bumps [better-sqlite3](https://github.com/WiseLibs/better-sqlite3) from 12.10.0 to 12.11.1.
- [Release notes](https://github.com/WiseLibs/better-sqlite3/releases)
- [Commits](WiseLibs/better-sqlite3@v12.10.0...v12.11.1)

---
updated-dependencies:
- dependency-name: better-sqlite3
  dependency-version: 12.11.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(ui): adopt ESLint 10 via @eslint-react (#3121)

Replace eslint-plugin-react (no ESLint 10 support) with
@eslint-react/eslint-plugin and bump eslint/@eslint/js to v10 across
workspaces; drop the legacy FlatCompat React config.

Adopt the v10-compatible modern rules (ref-as-prop instead of forwardRef,
use() for context, <Context> providers, hook/ref naming, set-state-in-effect)
and re-enable the reverse-tabnabbing check. Leave no-array-index-key off
(documented): the codebase has legitimate id-less ordered lists where it only
forces disables or fragile keys. Also fix a listener leak in useClickOutside
(capture flag mismatch).

Raise the supported Node floor to 22 (drop Node 20; @eslint-react requires
Node 22+) and align the devcontainer to production (Node 26). Disable the
@eslint-react hook rules that duplicate eslint-plugin-react-hooks so each
issue is reported once.

* build(deps-dev): bump @faker-js/faker from 9.9.0 to 10.5.0 (#3123)

* build(deps-dev): bump @faker-js/faker from 9.9.0 to 10.5.0

Bumps [@faker-js/faker](https://github.com/faker-js/faker) from 9.9.0 to 10.5.0.
- [Release notes](https://github.com/faker-js/faker/releases)
- [Changelog](https://github.com/faker-js/faker/blob/next/CHANGELOG.md)
- [Commits](faker-js/faker@v9.9.0...v10.5.0)

---
updated-dependencies:
- dependency-name: "@faker-js/faker"
  dependency-version: 10.5.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>

* test: transform faker esm in server jest

---------

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: enoch85 <[email protected]>

* fix(servarr): fail closed on transient Sonarr/Radarr lookup failures (#3125) (#3128)

getWithoutCache swallows transport/5xx errors to `undefined` without throwing,
so getSeriesByTvdbId/getMovieByTmdbId collapsed a transient failure into `null`
("not tracked") via the empty-response check, leaving the helpers' catch-path
`undefined` unreachable for HTTP failures. The comparator only treats strict
`=== undefined` as transient, so the misclassified `null` bypassed the
transient-removal guard: the item was dropped from the collection, then
re-added next run when the lookup succeeded — the churn reported in #3125. The
Sonarr action handler likewise read the transient miss as "not in Sonarr" and
fell through to a media-server delete.

- Distinguish `response === undefined` (transient -> `undefined`, fail closed)
  from an empty array (`null`, confirmed not tracked) in both arr helpers.
- Add the missing `=== undefined` fail-closed branch to the Radarr getter.
- Fail the Sonarr action handler closed on a transient lookup (return false, so
  the item is retried next run) instead of deleting it from disk.
- Cover the helper contract, the Radarr getter, and the action-handler paths.

Also drops a dead buildSeasonList helper and a no-op `await` on `new Date()`.

* build(deps-dev): bump knip from 6.16.1 to 6.17.1 (#3130)

Bumps [knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip) from 6.16.1 to 6.17.1.
- [Release notes](https://github.com/webpro-nl/knip/releases)
- [Commits](https://github.com/webpro-nl/knip/commits/[email protected]/packages/knip)

---
updated-dependencies:
- dependency-name: knip
  dependency-version: 6.17.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump sharp from 0.35.1 to 0.35.2 (#3131)

Bumps [sharp](https://github.com/lovell/sharp) from 0.35.1 to 0.35.2.
- [Release notes](https://github.com/lovell/sharp/releases)
- [Commits](lovell/sharp@v0.35.1...v0.35.2)

---
updated-dependencies:
- dependency-name: sharp
  dependency-version: 0.35.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix(rules): inherit parent show for Streamystats watchlist at season/episode level (#3127) (#3133)

A Streamystats list holds the show item ID, so the item-only
`isInWatchlist` / `watchlistedByUsers` props return empty at the
season/episode level, wrongly matching a watchlisted show's seasons in
destructive rules.

- add `isInWatchlist_including_parent` and `watchlistedByUsers_including_parent`
  (show-only, season/episode), mirroring the Jellyfin `sw_favoritedBy_including_parent` precedent
- resolve the parent chain via the media server's `getMetadata` (same path the
  other getters use); skip (undefined) when metadata can't be fetched rather
  than falling back to an item-only check
- base props left item-only; union/dedupe via the shared `definedUniqueValues`

* fix(collections): heal empty Jellyfin/Emby collections (#3129) (#3134)

* fix(collections): heal empty Jellyfin/Emby collections (#3129)

Jellyfin/Emby BoxSets are not auto-deleted when they go empty, and they
drain when underlying items are re-imported with new ids while the local
DB keeps the rows. The empty-collection heal in
checkAutomaticMediaServerLink was Plex-only, so such collections sat
empty on the server with no path to recover.

Extend the heal to Jellyfin/Emby: re-add rule-owned DB items missing
from the BoxSet (repopulate in place, keeping the BoxSet id stable), and
delete a confirmed-empty non-shared collection so it does not linger.
The destructive path is gated on the media server's reported child count
(a successful read that distinguishes empty from a transient enumeration
failure, which returns [] per the read contract), plus an empty live
read, no rule-owned item to re-add, and the collection not being shared,
so a populated or repopulatable collection is never removed.

* fix(rules): skip the manual import on the run that links an automatic collection

When handleCollection links a freshly created automatic collection to a
pre-existing, same-named media server collection, the post-handle state looks
"already linked", so the membership-provenance guard (#2663) — which reads the
link state in the sync phase — never skipped and imported that collection's
existing contents as manual.

Capture the link state BEFORE the run so the run that establishes the link
skips the import. Honest about scope: this only suppresses the first-run
flood. On a later run the collection is already linked, so the import runs and
pre-existing, rule-unselected items get tracked as manual then. Distinguishing
adoption-time contents from items the user adds to the BoxSet afterwards needs
persisted provenance, which is out of scope here.

* build(deps-dev): bump @types/node from 22.19.21 to 26.0.0 (#3132)

* build(deps-dev): bump @types/node from 22.19.21 to 26.0.0

Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 22.19.21 to 26.0.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 26.0.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>

* fix(ui): raise tsconfig lib/target to ES2022 for Array.prototype.at

---------

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: enoch85 <[email protected]>

* fix(collections): don't resurrect a deleted collection's media-server link (#3135)

When handling the last item empties an automatic collection,
removeFromCollection deletes the media-server collection and clears
mediaServerId in the DB. handleMedia discarded that result, then
saveCollection-ed its stale snapshot and rewrote the dead mediaServerId
back onto the row. The next rule run then finds a dangling link it can
only resolve via a getCollection 404 before the heal clears it.

Continue from removeFromCollection's returned collection so the
post-handle save carries the cleared link forward — matching what the
rule executor already does.

---------

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: maintainerr-automation[bot] <261505141+maintainerr-automation[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: enoch85 <[email protected]>
@maintainerr-automation

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 3.15.2 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

doonga pushed a commit to greyrock-labs/home-ops that referenced this pull request Jun 20, 2026
…➔ 3.15.2) (#349)

This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [ghcr.io/maintainerr/maintainerr](https://github.com/Maintainerr/Maintainerr) | patch | `3.15.1` → `3.15.2` |

---

### Release Notes

<details>
<summary>Maintainerr/Maintainerr (ghcr.io/maintainerr/maintainerr)</summary>

### [`v3.15.2`](https://github.com/Maintainerr/Maintainerr/blob/HEAD/CHANGELOG.md#3152-2026-06-20)

[Compare Source](Maintainerr/Maintainerr@v3.15.1...v3.15.2)

#### Highlights

- Fixed transient failure handling for Sonarr and Radarr lookups, preventing data loss during rule evaluations under heavy load ([#&#8203;3125](Maintainerr/Maintainerr#3125), [#&#8203;3128](Maintainerr/Maintainerr#3128), [#&#8203;3139](Maintainerr/Maintainerr#3139)).
- Resolved issues with Jellyfin/Emby automatic collections, ensuring proper handling of empty collections and preventing resurrection of deleted media-server links ([#&#8203;3129](Maintainerr/Maintainerr#3129), [#&#8203;3134](Maintainerr/Maintainerr#3134), [#&#8203;3135](Maintainerr/Maintainerr#3135), [#&#8203;3137](Maintainerr/Maintainerr#3137)).
- Improved Streamystats watchlist handling by inheriting parent show information for season/episode-level rules, preventing unintended deletions or unmonitoring ([#&#8203;3127](Maintainerr/Maintainerr#3127), [#&#8203;3133](Maintainerr/Maintainerr#3133)).

#### Fixes

- Fixed transient failure handling for Sonarr and Radarr lookups, ensuring fail-closed behavior to prevent data loss during rule evaluations under heavy load ([#&#8203;3125](Maintainerr/Maintainerr#3125), [#&#8203;3128](Maintainerr/Maintainerr#3128), [#&#8203;3139](Maintainerr/Maintainerr#3139)).
- Resolved issues with Jellyfin/Emby automatic collections:
  - Fixed empty collections not healing properly for Jellyfin/Emby servers ([#&#8203;3129](Maintainerr/Maintainerr#3129), [#&#8203;3134](Maintainerr/Maintainerr#3134)).
  - Prevented resurrection of deleted media-server links when handling empty collections ([#&#8203;3135](Maintainerr/Maintainerr#3135)).
  - Removed redundant empty-collection delete logic for Jellyfin/Emby, retaining only the repopulation path ([#&#8203;3137](Maintainerr/Maintainerr#3137)).
- Improved Streamystats watchlist handling by inheriting parent show information for season/episode-level rules, preventing unintended deletions or unmonitoring ([#&#8203;3127](Maintainerr/Maintainerr#3127), [#&#8203;3133](Maintainerr/Maintainerr#3133)).

#### Dependencies

- Updated 12 dependencies, including [@&#8203;types/node](https://github.com/types/node), sharp, [@&#8203;faker-js/faker](https://github.com/faker-js/faker), and typescript-eslint.

</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:eyJjcmVhdGVkSW5WZXIiOiI0My4yMjQuMCIsInVwZGF0ZWRJblZlciI6IjQzLjIyNC4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZS9jb250YWluZXIiLCJ0eXBlL3BhdGNoIl19-->

Reviewed-on: https://git.greyrock.io/greyrock-labs/home-ops/pulls/349
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Streamystats watchlist property lacks parent inheritance when executing rules at SEASONS mediaType level

1 participant