Skip to content

feat: clean up empty Sonarr shows after season actions#2618

Merged
enoch85 merged 6 commits into
developmentfrom
feat/clean-up-empty-ended-shows-892-v2
Apr 8, 2026
Merged

feat: clean up empty Sonarr shows after season actions#2618
enoch85 merged 6 commits into
developmentfrom
feat/clean-up-empty-ended-shows-892-v2

Conversation

@enoch85

@enoch85 enoch85 commented Apr 7, 2026

Copy link
Copy Markdown
Collaborator

Summary

Closes #892
Supersedes #2458

  • adds two season-level Sonarr actions:
    • Unmonitor and delete season + delete show if empty
    • Unmonitor season + unmonitor show if empty
  • rebuilds the empty-show cleanup on top of current development and the newer metadata lookup flow
  • only deletes the show when Seerr explicitly reports that no other requested seasons remain, preserving the existing fail-safe behavior on ambiguous or failed Seerr lookups
  • falls back to the ended-and-no-monitored-seasons case when Seerr is not configured
  • excludes the delete-show-if-empty action from Force Seerr request mutation
  • consolidates ServarrAction onto the shared contracts enum and re-exports it from the existing server import path
  • simplifies Sonarr action handling by giving the season-only empty-show actions their own switch branches
  • adds focused Sonarr, Seerr, and collection-handler tests

enoch85 commented Apr 7, 2026

Copy link
Copy Markdown
Collaborator Author

@andrew-kennedy this is the fresh rebuild of the still-valid carryovers from #2458 on top of current development. I kept the empty-show delete path conservative around remaining Seerr season requests, including the ended-show review scenario you called out.

@enoch85 enoch85 added this to the 3.5.0 milestone Apr 7, 2026
@enoch85 enoch85 force-pushed the development branch 2 times, most recently from fed35fc to 0d78268 Compare April 7, 2026 17:41
@enoch85

enoch85 commented Apr 7, 2026

Copy link
Copy Markdown
Collaborator Author

This is double checked now. All pass!

@enoch85

enoch85 commented Apr 7, 2026

Copy link
Copy Markdown
Collaborator Author

@andrew-kennedy Please have a last look at this.

I'm happy, but would be nice with some confirmation. 👍

@enoch85

enoch85 commented Apr 8, 2026

Copy link
Copy Markdown
Collaborator Author

I've been over this several times now. It checks out.

I will merge to development if you want to try it out even further. 👍 This will be in 3.5.0.

Fix undefined `resolvedIds` reference (use `media.tmdbId`) and remove
non-existent `getSeriesByTmdbId` call in `refetchSeries` to align with
the metadata-lookup refactor from #2633.
@enoch85 enoch85 merged commit 2addb83 into development Apr 8, 2026
13 checks passed
@enoch85 enoch85 deleted the feat/clean-up-empty-ended-shows-892-v2 branch April 8, 2026 20:27
maintainerr-automation Bot added a commit that referenced this pull request Apr 9, 2026
* build(deps-dev): bump @types/node from 22.19.15 to 22.19.17 (#2630)

Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 22.19.15 to 22.19.17.
- [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: 22.19.17
  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 postcss from 8.5.8 to 8.5.9 (#2629)

Bumps [postcss](https://github.com/postcss/postcss) from 8.5.8 to 8.5.9.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](postcss/postcss@8.5.8...8.5.9)

---
updated-dependencies:
- dependency-name: postcss
  dependency-version: 8.5.9
  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 @typescript-eslint/parser from 8.57.2 to 8.58.1 (#2631)

Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 8.57.2 to 8.58.1.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.58.1/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.58.1
  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-dev): bump vitest from 4.1.2 to 4.1.3 (#2632)

Bumps [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) from 4.1.2 to 4.1.3.
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.3/packages/vitest)

---
updated-dependencies:
- dependency-name: vitest
  dependency-version: 4.1.3
  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>

* fix(jellyfin): clear stale collection link when media server collection is deleted

Re-throw 400/404 errors from Jellyfin getCollectionChildren instead of
swallowing them, so callers can detect when a collection no longer exists.

In getCollectionMediaMetadata, verify the collection is truly gone via
getCollection before clearing the mediaServerId link. This double-check
prevents false positives from resetting collection counters. If the
verification call itself fails transiently, the link is preserved.

* refactor(metadata): generic metadata-lookup utility (#2633)

* fix(jellyfin): exclude virtual episodes from child queries (#2624)

Virtual episodes in Jellyfin are placeholders for unaired content.
Including them caused ended shows to appear as having episodes,
preventing proper cleanup.

Closes #2558

* feat: clean up empty Sonarr shows after season actions (#2618)

* fix(server): import SeerrApiModule into ActionsModule

* fix(jellyfin): lower collection mutation batch size

* build(deps): bump nodemailer from 8.0.4 to 8.0.5 (#2635)

Bumps [nodemailer](https://github.com/nodemailer/nodemailer) from 8.0.4 to 8.0.5.
- [Release notes](https://github.com/nodemailer/nodemailer/releases)
- [Changelog](https://github.com/nodemailer/nodemailer/blob/master/CHANGELOG.md)
- [Commits](nodemailer/nodemailer@v8.0.4...v8.0.5)

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

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

* build(deps): bump the nestjs group with 3 updates (#2639)

Bumps the nestjs group with 3 updates: [@nestjs/serve-static](https://github.com/nestjs/serve-static), [@nestjs/swagger](https://github.com/nestjs/swagger) and [@nestjs/cli](https://github.com/nestjs/nest-cli).


Updates `@nestjs/serve-static` from 5.0.4 to 5.0.5
- [Release notes](https://github.com/nestjs/serve-static/releases)
- [Commits](nestjs/serve-static@5.0.4...5.0.5)

Updates `@nestjs/swagger` from 11.2.6 to 11.2.7
- [Release notes](https://github.com/nestjs/swagger/releases)
- [Commits](nestjs/swagger@11.2.6...11.2.7)

Updates `@nestjs/cli` from 11.0.18 to 11.0.19
- [Release notes](https://github.com/nestjs/nest-cli/releases)
- [Commits](nestjs/nest-cli@11.0.18...11.0.19)

---
updated-dependencies:
- dependency-name: "@nestjs/serve-static"
  dependency-version: 5.0.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: nestjs
- dependency-name: "@nestjs/swagger"
  dependency-version: 11.2.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: nestjs
- dependency-name: "@nestjs/cli"
  dependency-version: 11.0.19
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: nestjs
...

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

* build(deps): bump the react group with 2 updates (#2640)

Bumps the react group with 2 updates: [react](https://github.com/facebook/react/tree/HEAD/packages/react) and [react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom).


Updates `react` from 19.2.4 to 19.2.5
- [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.5/packages/react)

Updates `react-dom` from 19.2.4 to 19.2.5
- [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.5/packages/react-dom)

---
updated-dependencies:
- dependency-name: react
  dependency-version: 19.2.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: react
- dependency-name: react-dom
  dependency-version: 19.2.5
  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 vitest from 4.1.3 to 4.1.4 (#2641)

Bumps [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) from 4.1.3 to 4.1.4.
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.4/packages/vitest)

---
updated-dependencies:
- dependency-name: vitest
  dependency-version: 4.1.4
  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.14.0 to 1.15.0 (#2642)

Bumps [axios](https://github.com/axios/axios) from 1.14.0 to 1.15.0.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](axios/axios@v1.14.0...v1.15.0)

---
updated-dependencies:
- dependency-name: axios
  dependency-version: 1.15.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>

* fix(collections): make Delete Latest send a real sort param (#2634)

Delete Latest was defined as the empty-string "no sort" fallback with
sortParams: undefined. In CollectionMediaPage.fetchCollectionMediaPage,
passing undefined as the override triggered the `= sortParams` default
parameter fallback, so the request sent for Delete Latest was identical
to Delete Soonest.

Introduce a dedicated deleteSoonest.desc option and filter the empty
fallback out when delete sorts are present. Both options still hit the
fast addDate branch in getCollectionMediaWithServerDataAndPaging, so
performance is unchanged.

Fixes #2634

* fix(collections): auto-load next page when viewport already filled

The infinite-scroll hook only fetched more pages in response to a
scroll event. On large viewports that could display all 30 initial
items without producing a scrollbar, no scroll event ever fired and
the list got stuck at 30 until the window was resized.

Re-check isNearBottom() after each append and also listen for resize,
so additional pages cascade in until the document is actually
scrollable (or totalSize is reached).

Fixes #2637

* fix: carry over valid PR 2534 hardening fixes (#2617)

* fix(metadata): validate direct provider IDs by year with cross-provider fallback (#2643)

---------

Signed-off-by: dependabot[bot] <support@github.com>
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 <mailto@danielhansson.nu>
@maintainerr-automation

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 3.5.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

enoch85 added a commit that referenced this pull request Apr 24, 2026
…2763)

DELETE_SHOW_IF_EMPTY silently bailed when Seerr was configured but
the show was not tracked in Seerr, and when every remaining Seerr
request was already COMPLETED. hasRemainingSeasonRequests returned
undefined for missing mediaInfo the same way it does for real
communication errors, and the outer request filter kept COMPLETED
requests in scope so their seasons were still scanned.

- Treat a Seerr response with no mediaInfo as "nothing to protect"
  (returns false); keep undefined strictly for communication errors.
- Exclude COMPLETED requests at the outer filter so fulfilled
  history does not block deletion.
- Add a debug log at every bail path in deleteShowIfEmpty and
  unmonitorShowIfEmptyAndEnded so users can see why a show was kept.
- Add spec coverage for: untracked show, empty requests,
  communication failure, Seerr state unknown from the handler, and
  files-still-remain.

The PR #2618 design intent (Seerr is the authority when configured,
ended shows included) is preserved.

Fixes #2757
maintainerr-automation Bot added a commit that referenced this pull request Apr 24, 2026
* fix(sonarr): unblock DELETE_SHOW_IF_EMPTY and surface cleanup skips (#2763)

DELETE_SHOW_IF_EMPTY silently bailed when Seerr was configured but
the show was not tracked in Seerr, and when every remaining Seerr
request was already COMPLETED. hasRemainingSeasonRequests returned
undefined for missing mediaInfo the same way it does for real
communication errors, and the outer request filter kept COMPLETED
requests in scope so their seasons were still scanned.

- Treat a Seerr response with no mediaInfo as "nothing to protect"
  (returns false); keep undefined strictly for communication errors.
- Exclude COMPLETED requests at the outer filter so fulfilled
  history does not block deletion.
- Add a debug log at every bail path in deleteShowIfEmpty and
  unmonitorShowIfEmptyAndEnded so users can see why a show was kept.
- Add spec coverage for: untracked show, empty requests,
  communication failure, Seerr state unknown from the handler, and
  files-still-remain.

The PR #2618 design intent (Seerr is the authority when configured,
ended shows included) is preserved.

Fixes #2757

* Add token for GitHub authentication in workflow

Added token usage for authentication in docs drift workflow.

* ci(docs-drift): remove create_pr step and input

The draft PR was empty scaffolding — the drift issue already carries
the same report and is the canonical tracking surface. Drop the unused
create_pr dispatch input and the push/PR creation step.

* ci(stale): use GITHUB_TOKEN for stale-issue bot

The job already requests issues: write, which GITHUB_TOKEN satisfies —
no need for the ACTIONS_TOKEN PAT. Dropping this removes the last
workflow reference to ACTIONS_TOKEN.

---------

Co-authored-by: enoch85 <mailto@danielhansson.nu>
enoch85 added a commit that referenced this pull request May 13, 2026
…shows

Builds on the file-count gate removal from the previous commit, but
reverses the universal "ended" requirement that was too strict for
long-running continuing shows. PR #2618's Seerr-as-authority design is
restored: when Seerr is configured, "no remaining season requests" is
the user's done-with-this-show signal regardless of series status. When
Seerr is not configured, the action falls back to series.status ===
'ended' as the only reliable "no more episodes coming" signal.

Rename (numeric enum, source-only — no DB migration):

  DELETE_SHOW_IF_ENDED    -> DELETE_SHOW_IF_DONE
  UNMONITOR_SHOW_IF_ENDED -> UNMONITOR_SHOW_IF_DONE

Method names follow:

  deleteShowIfEnded   -> deleteShowWhenDone
  unmonitorShowIfEnded -> unmonitorShowWhenDone

UI labels, tooltips, and calendar action labels updated to "if done" /
"when done" — accurate about both gate inputs (ended fallback, Seerr
signal) without privileging either.
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.

TV shows are missing from Maintainerr when they are monitored but have no files

1 participant