Skip to content

fix(tv): prevent phantom specials from blocking season request - #3351

Open
fallenbagel wants to merge 1 commit into
developfrom
fix/phantom-specials-blocking-tv-requests
Open

fix(tv): prevent phantom specials from blocking season request#3351
fallenbagel wants to merge 1 commit into
developfrom
fix/phantom-specials-blocking-tv-requests

Conversation

@fallenbagel

@fallenbagel fallenbagel commented Aug 7, 2026

Copy link
Copy Markdown
Member

Description

Adding a Specials folder in Plex for a show whose TMDB specials entry has no episodes made the rest of the series unrequestable. The scanner sees one file against zero expected episodes and writes a season 0 row as PARTIALLY_AVAILABLE, which flips the whole series to Partially Available because the PARTIALLY_AVAILABLE branch of the rollup does not exclude specials the way the AVAILABLE branch does.

TvRequestModal decided whether a show was fully requested by comparing how many seasons are requested or available against how many seasons it offers. That season 0 counts toward the first number but is dropped from the second by the episodeCount !== 0 filter, so a show with one real season looked fully requested: the button read "Already Requested" and was disabled while the season row still said "Not Requested" and its toggle still worked. TvDetails counted seasons too but added one for specials, so it still rendered "Request More" and users could open a modal whose button was already dead. Shows whose specials entry has at least one episode were never affected.

Both now check whether any offered season is still unrequested instead of comparing counts, and TvDetails reads the same filtered season list the modal renders. On the server, processShow zeroes the episode counts for a season the provider reports as empty so files can no longer promote it. This PR does not deliberately add downgrading an existing status to processShow: one scanner only sees one source, and demoting there would reintroduce the race the AVAILABLE stickiness already guards against. Existing records keep their season 0 row and can be fixed with Clear Data followed by a rescan.

How Has This Been Tested?

  • Did not test myself, waiting to be Tested by original reporter on discord and confirmed to be working (preview-phantom-specials for testing).

Screenshots / Logs (if applicable)

Checklist:

  • I have read and followed the contribution guidelines.
  • Disclosed any use of AI (see our policy)
  • I have updated the documentation accordingly.
  • All new and existing tests passed.
  • Successful build pnpm build
  • Translation keys pnpm i18n:extract
  • Database migration (if required)

Summary by CodeRabbit

  • Bug Fixes
    • Empty seasons are no longer incorrectly treated as available when they report no episodes.
    • TV request buttons now accurately reflect whether any seasons remain requestable.
    • Season completion status now excludes empty seasons and handles specials correctly for standard and 4K requests.

@fallenbagel
fallenbagel requested a review from a team as a code owner August 7, 2026 15:22
Copilot AI lite review requested due to automatic review settings August 7, 2026 15:22
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The scanner normalizes seasons with zero reported episodes. TV request controls now evaluate completion from requestable and unrequested seasons instead of season-count comparisons.

Changes

TV season handling

Layer / File(s) Summary
Normalize empty scanner seasons
server/lib/scanners/baseScanner.ts
Seasons with no reported episodes retain their metadata and receive zero standard and 4K episode counts before processing.
Evaluate requestable season completion
src/components/TvDetails/index.tsx, src/components/RequestModal/TvRequestModal.tsx
TV details checks all requestable seasons before marking standard or 4K requests complete. The request modal uses unrequestedSeasons.length for its label and disabled state.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested labels: bug, severity: medium

Suggested reviewers: copilot, 0xsysr3ll

Poem

A rabbit checks each season’s count,
Empty pages no longer mount.
Requestable sets guide the way,
Buttons speak the truth today.
Hop, hop—stale episodes fade!

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the primary change: preventing phantom specials from blocking TV season requests.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses an edge case where “phantom” Specials (season 0) entries with zero provider episodes could incorrectly affect TV request/availability behavior, causing the UI to disagree about whether a series is requestable and, on the server, allowing scanned files to incorrectly influence season availability.

Changes:

  • Aligns TvDetails “complete” computation with the same season filtering logic used by the request modal (excluding zero-episode seasons and optionally excluding specials).
  • Updates TvRequestModal to determine “Already Requested” based on whether any requestable seasons remain unrequested (instead of comparing season counts).
  • Adjusts the scanner processShow logic to zero episode counts for seasons the metadata provider reports as empty, preventing files from promoting those seasons’ availability.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/components/TvDetails/index.tsx Reworks “series complete” logic to use a requestable-season set consistent with the modal.
src/components/RequestModal/TvRequestModal.tsx Switches “already requested / disable” logic to use unrequestedSeasons.length === 0.
server/lib/scanners/baseScanner.ts Prevents empty-provider seasons from being promoted by scanned files by zeroing episode counts.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/components/TvDetails/index.tsx
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Caution

CodeRabbit couldn't update its existing comment. The review summary may be out of date.

Error details
putComment timed out

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/TvDetails/index.tsx`:
- Around line 322-330: Update isSeasonSetComplete to remove the
requestableSeasons.length > 0 guard, allowing every() to mark an empty
requestable season set as complete and keeping RequestButton consistent with
TvRequestModal.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: bf490254-7967-40fb-a182-77d13a5966c6

📥 Commits

Reviewing files that changed from the base of the PR and between 090c659 and ccd9adb.

📒 Files selected for processing (3)
  • server/lib/scanners/baseScanner.ts
  • src/components/RequestModal/TvRequestModal.tsx
  • src/components/TvDetails/index.tsx

Comment thread src/components/TvDetails/index.tsx
Copilot AI review requested due to automatic review settings August 7, 2026 15:33
@fallenbagel
fallenbagel force-pushed the fix/phantom-specials-blocking-tv-requests branch from ccd9adb to 972fe27 Compare August 7, 2026 15:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/components/RequestModal/TvRequestModal.tsx:447

  • There is still a remaining getAllRequestedSeasons().length < getAllSeasons().length comparison later in this component (around line 487) that uses the same count-based logic this change is replacing. In the phantom-specials scenario described in the PR, that check will still evaluate incorrectly (season 0 can inflate getAllRequestedSeasons() while getAllSeasons() drops it), which can make the admin-only alert logic disagree with the new unrequestedSeasons completion logic. Update that remaining comparison to use unrequestedSeasons.length (or an equivalent “any season still unrequested” predicate) so all code paths use the same definition of completeness.
            : hasPermission(Permission.MANAGE_REQUESTS)
              ? intl.formatMessage(messages.approve)
              : intl.formatMessage(messages.edit)
          : unrequestedSeasons.length === 0
            ? intl.formatMessage(messages.alreadyrequested)
            : !settings.currentSettings.partialRequestsEnabled
              ? intl.formatMessage(
                  is4k ? globalMessages.request4k : globalMessages.request
                )
              : selectedSeasons.length === 0
                ? intl.formatMessage(messages.selectseason)
                : intl.formatMessage(
                    is4k ? messages.requestseasons4k : messages.requestseasons,
                    {
                      seasonCount: selectedSeasons.length,
                    }
                  )
      }
      okDisabled={
        editRequest
          ? false
          : !settings.currentSettings.partialRequestsEnabled &&
              quota?.tv.limit &&
              unrequestedSeasons.length > quota.tv.limit &&
              !requestOverrides?.ignoreQuota
            ? true
            : unrequestedSeasons.length === 0 ||
              (settings.currentSettings.partialRequestsEnabled &&
                selectedSeasons.length === 0)
      }

@seerr-automation-bot seerr-automation-bot added this to the v3.5.0 milestone Aug 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants