Skip to content

feat: Improve 4K content visibility and related user experience#3060

Draft
Flawkee wants to merge 6 commits into
seerr-team:developfrom
Flawkee:feat/4k-enhanced-ux
Draft

feat: Improve 4K content visibility and related user experience#3060
Flawkee wants to merge 6 commits into
seerr-team:developfrom
Flawkee:feat/4k-enhanced-ux

Conversation

@Flawkee

@Flawkee Flawkee commented May 22, 2026

Copy link
Copy Markdown

Description

This completes three requests:

Until now, to request a title in 4K you had to open the title page and the 4K request was hidden inside a dropdown under the normal Request button, so a lot of people miss it. On top of that the thumbnail never showed when a title is already available in 4K, only the normal quality. So users were requesting titles again that already exist in 4K and it created duplicates.

In addition, the status badges in TV\Movie details page was small and hard to miss for less-intuitive users.

What I did:

  • Added a "Request in 4K" button on the thumbnail (search, discover, sliders, person and collection pages), right under the normal Request button. It only shows when a 4K Radarr/Sonarr is set as the default 4K server and the user has the 4K request permission, same conditions as the title page.
  • The thumbnail now also shows the 4K availability, the same way it already shows the normal one. So a title that exists only in 4K is now visible without opening the page.
  • When a title is available the request button is replaced with a green button that links to the title page (Available / 4K Available, and also the Partially Available cases). I did the same for the requested state, now it shows Requested / 4K Requested instead of just removing the button, so it is clear it was already requested and people dont request it twice.
  • On the title page the 4K request was hidden in the dropdown. I added a new setting in Settings > General called "Separate 4K Request Button". The default keeps the current behaviour (4K stays inside the dropdown). When you turn it on, the 4K actions (Request in 4K, and also View/Approve/Decline 4K) move to their own button next to the normal one. The non 4K actions stay like before.
  • Fixed a small bug where requesting a TV show in 4K did not update the button until you refreshed the page (movies already worked).
  • Increased the status badges size in TV\Movie details page while preserving other badges sizes using the same component.

No database migration is needed, the new setting is stored in settings.json and falls back to false for existing installs.

AI Disclosure: I used AI only to better understand the project structure and to fix some typos, nothing else. Everything else was fully written by me and fully tested by me both on desktop and on phone.

How Has This Been Tested?

Tested manually on desktop and on mobile (the mobile layout needed some specific fixes for the badges).

My environment was HD Radarr + 4K Radarr and HD Sonarr + 4K Sonarr, with Emby connected for the availability sync on localhost.
Then I tested again on a production setup similar to this with thousands of requests and titles.

What I checked:

  • Requesting from the thumbnail in normal and in 4K, both open the right modal and create the right request.
  • 4K availability badge on the thumbnail, including a title that is only available in 4K.
  • The Available / 4K Available / Partially Available green buttons link to the title page, and Requested / 4K Requested show correctly for pending and processing.
  • The new "Separate 4K Request Button" setting, both off (default, dropdown) and on (two buttons side by side), on movie and on tv pages.
  • That the request management (View / Approve / Decline, also for 4K) still works as admin.
  • Type check and lint pass, and the production build passes.

Screenshots / Logs (if applicable)

Request in 4K now available on the title cards:
image

When requested, instead of removing the button, preserve it to show current status + link to the details page:
image
image

4K have its own badge and status shows up on the card:
image

TV\Movie detail page status badges are now bigger and harder to miss yet still elegant and fit the theme:
image

New admin setting in General section to allow separate 4K and regular requests buttons (false by default to preserve current dropdown behavior):
image
image

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

  • New Features

    • New setting to optionally separate 4K requests into a dedicated button/dropdown.
    • Title cards gain a parallel 4K workflow including 4K status, request flow, and 4K request modal.
  • UI / Style

    • Improved 4K status visuals across lists, cards, sliders, and detail pages.
    • Badges and status components added a larger size option and updated styling for clearer hierarchy.
  • Localization

    • Added English strings for 4K status labels and the new setting.

Review Change Stack

Flawkee added 3 commits May 21, 2026 17:03
…ser experience

improve 4K content visibility and enable inline request from thumbnails + status and availability +
separate 4k request button in title page admin config

"re seerr-team#2598", "re seerr-team#1826"
next.js changed the import when tested locally - reveted it
…ted, available, etc) larger

This commit makes details page badges for request status (requested, available, partially available,
etc...) bigger and more visible to avoid user duplicate requests.

"re seerr-team#2993"
@Flawkee
Flawkee requested a review from a team as a code owner May 22, 2026 06:25
@coderabbitai

coderabbitai Bot commented May 22, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: de607a91-942f-48d4-a965-49f573946dda

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds boolean setting separate4kRequestButton, exposes it via public settings, wires it into frontend settings UI, passes status4k through components, refactors badges with a size prop, implements parallel 4K flows in TitleCard, and optionally splits request buttons into main and 4K groups.

Changes

4K Separate Request Button and Status Display Feature

Layer / File(s) Summary
Backend Settings Definition
server/interfaces/api/settingsInterfaces.ts, server/lib/settings/index.ts
Adds separate4kRequestButton: boolean to server setting types, default main settings, and public serialization.
Frontend Settings Management
src/context/SettingsContext.tsx, src/pages/_app.tsx, src/components/Settings/SettingsMain/index.tsx, src/i18n/locale/en.json
Initializes separate4kRequestButton in defaults/context/app, adds i18n keys, Formik initialValues, POST payload, and a settings checkbox row.
Badge Sizing & StatusBadge Refactor
src/components/Common/Badge/index.tsx, src/components/StatusBadge/index.tsx, src/components/Common/StatusBadgeMini/index.tsx, src/components/MovieDetails/index.tsx, src/components/TvDetails/index.tsx
Adds size prop to Badge/StatusBadge, refactors StatusBadge unified render with icons, adjusts StatusBadgeMini sizing/styling, and sets size="lg" in detail views.
4K Status Propagation
src/components/TitleCard/index.tsx, src/components/TitleCard/TmdbTitleCard.tsx, src/components/CollectionDetails/index.tsx, src/components/Common/ListView/index.tsx, src/components/MediaSlider/index.tsx, src/components/PersonDetails/index.tsx
Adds optional status4k prop to TitleCard and updates collection/list/slider/person components and TmdbTitleCard to forward status4k from mediaInfo.
TitleCard 4K State and Modal Integration
src/components/TitleCard/index.tsx
Implements currentStatus4k, showRequest4kModal, effect sync, settings/permission gating, second RequestModal for 4K, layout and UI changes, and parallel standard/4K action buttons with 4K i18n.
Request Button Splitting & Modal Status Updates
src/components/RequestButton/index.tsx, src/components/RequestModal/TvRequestModal.tsx
Conditionally splits buttons into main and 4K groups when enabled and updates TvRequestModal to pass status4k on 4K requests.

Sequence Diagram

sequenceDiagram
  participant User
  participant TitleCard
  participant Settings
  participant RequestButton
  participant RequestModal
  participant API

  User->>TitleCard: view title (includes status4k)
  TitleCard->>Settings: read separate4kRequestButton & permissions
  Settings-->>TitleCard: returns flags
  TitleCard->>RequestButton: render actions
  RequestButton->>RequestButton: split into mainButtons + fourKButtons (if enabled)
  User->>RequestButton: click 4K request
  RequestButton->>RequestModal: open modal (is4k=true)
  User->>RequestModal: confirm
  RequestModal->>API: POST request (is4k=true)
  API-->>RequestModal: success (response.data.media.status4k)
  RequestModal->>TitleCard: onComplete(status4k)
  TitleCard->>TitleCard: update currentStatus4k
  TitleCard-->>User: show updated 4K badge/state
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • gauthier-th
  • fallenbagel
  • M0NsTeRRR

Poem

🐰 I nibbled code at break of dawn,
Split the buttons, badges drawn,
4K status gleams in sight,
Modals hop and update right,
Rabbity cheer — the UI's on!

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main objective of the PR, which is to improve 4K content visibility and enhance the user experience around 4K requests, as evidenced by changes across multiple components including 4K status badges, separate 4K request buttons, and UI improvements.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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.

@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/TitleCard/index.tsx`:
- Around line 367-369: The 4K action visibility variables (showRequest4k,
showAvailable4k, showRequested4k) should also guard against blocklisted titles;
update each expression that uses show4k &&
isRequestableStatus(currentStatus4k)/isAvailableStatus(currentStatus4k)/isRequestedStatus(currentStatus4k)
to additionally check currentStatus4k !== MediaStatus.BLOCKLISTED (or an
equivalent isBlocklistedStatus check) so blocklisted cards do not render any 4K
action buttons; locate these symbols (showRequest4k, showAvailable4k,
showRequested4k, show4k, currentStatus4k, MediaStatus.BLOCKLISTED) in
TitleCard/index.tsx and add the extra condition to each boolean expression.
🪄 Autofix (Beta)

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

Run ID: 4f9bd8e0-713f-4c96-9609-71cdb667285f

📥 Commits

Reviewing files that changed from the base of the PR and between 32169d9 and 8a70d26.

📒 Files selected for processing (19)
  • server/interfaces/api/settingsInterfaces.ts
  • server/lib/settings/index.ts
  • src/components/CollectionDetails/index.tsx
  • src/components/Common/Badge/index.tsx
  • src/components/Common/ListView/index.tsx
  • src/components/Common/StatusBadgeMini/index.tsx
  • src/components/MediaSlider/index.tsx
  • src/components/MovieDetails/index.tsx
  • src/components/PersonDetails/index.tsx
  • src/components/RequestButton/index.tsx
  • src/components/RequestModal/TvRequestModal.tsx
  • src/components/Settings/SettingsMain/index.tsx
  • src/components/StatusBadge/index.tsx
  • src/components/TitleCard/TmdbTitleCard.tsx
  • src/components/TitleCard/index.tsx
  • src/components/TvDetails/index.tsx
  • src/context/SettingsContext.tsx
  • src/i18n/locale/en.json
  • src/pages/_app.tsx

Comment thread src/components/TitleCard/index.tsx Outdated
Flawkee added 2 commits May 22, 2026 09:44
…tons

As code rubbit suggested, I added a blacklist guard for 4K title card buttons - honest mistake
I reverted en.json change by i18n extract by mistake, so I ran it again to pass the CI check
@fallenbagel

fallenbagel commented May 25, 2026

Copy link
Copy Markdown
Member

We already have an existing implementation for this in Overseerr that I’ve essentially ported over to Seerr:
sct/overseerr#3636

That PR was created by one of our team members, and its design aligns with our current design language. This PR conflicts with that implementation, and there are several design elements here that do not align with Seerr’s existing UI patterns.

Before continuing with implementation changes, I’d really appreciate it if you could open a meta discussion in the Discussions tab so the team can align on the intended design direction first:
https://github.com/seerr-team/seerr/discussions

That would help us avoid situations where significant implementation work ends up needing major redesign changes later on, which can be frustrating for both contributors and reviewers.

For the time being, could you please convert this PR to a draft while the design discussion takes place?

CC: @seerr-team/seerr-core

@Flawkee

Flawkee commented Jun 13, 2026

Copy link
Copy Markdown
Author

@fallenbagel This PR is addressing multiple issues.
Additionally, the other PR restricts 4K requests to cases where standard quality already exists, which does not align with community needs. Users want the flexibility to choose content in both 4K and FHD, while also having clear visibility into what is already available on the media server and in which quality.

I have created the discussion #3158
And will move this PR to draft as requested.

@Flawkee
Flawkee marked this pull request as draft June 13, 2026 05:58
…ity Requests are allowed

A new admin configuration that is enabled by default allowing users to request both normal and 4k
quality of a title (current behavior). If disabled, when a title is requested in either quality, the
other quality cannot be requested (unless you are admin \ requests manager)

@fallenbagel fallenbagel left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

see inline comment below

Comment thread server/routes/media.ts Outdated
Comment on lines +283 to +321
const requestRepository = getRepository(MediaRequest);
const removedQualityRequests = media.requests.filter(
(request) => request.is4k === is4k
);
const remainingRequests = media.requests.filter(
(request) => request.is4k !== is4k
);

if (removedQualityRequests.length > 0) {
await requestRepository.remove(removedQualityRequests);
}

media.requests = remainingRequests;

const otherQualityStatus = is4k ? media.status : media.status4k;
const otherQualityInUse =
remainingRequests.length > 0 ||
(otherQualityStatus !== MediaStatus.UNKNOWN &&
otherQualityStatus !== MediaStatus.DELETED);

if (otherQualityInUse) {
media[is4k ? 'status4k' : 'status'] = MediaStatus.UNKNOWN;
media[is4k ? 'serviceId4k' : 'serviceId'] = null;
media[is4k ? 'externalServiceId4k' : 'externalServiceId'] = null;
media[is4k ? 'externalServiceSlug4k' : 'externalServiceSlug'] = null;
media[is4k ? 'ratingKey4k' : 'ratingKey'] = null;
media[is4k ? 'jellyfinMediaId4k' : 'jellyfinMediaId'] = null;

if (media.mediaType === MediaType.TV) {
for (const season of media.seasons) {
season[is4k ? 'status4k' : 'status'] = MediaStatus.UNKNOWN;
}
}

await mediaRepository.save(media);
} else {
await mediaRepository.remove(media);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I know this PR is being discussed first on its implementation, but, this is out of scope for a 4K visibility PR.

Also, deleting the file from Radarr/Sonarr shouldn't delete the request at all. Removing here should just reset the media status for that quality. Request deletion is what the clear/remove-media endpoint is for, so this logic shouldn't exist here regardless of scope.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I can revert it in case you guys decide to move on with this PR.

Anyway - this bug fix resolves an issue when admin clicks Remove from Sonarr/Radarr in Seerr, let's say from 4K instance, and the requests and media status is reset for both instances of that title.

That's an actual bug..

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

That's an actual bug..

Doesn't matter... Once again, out of scope of this PR entirely.

Deleting requests was never the intended behavior, this is an oversight, and it'll get fixed in another PR. Scoping it to the correct quality doesn't change that. It still has no business being in a PR about 4K visibility.

Split it out. This touches delete/cascade semantics across a frontend component and a route, it needs its own focused review, not to ride in as a side effect of an unrelated feature.

Also, the fix hard deletes the request row. Elsewhere, orphaned requests get declined if in-flight, or just stay completed if already completed, not deleted. So this isn't really a fix for the actual bug, which is that the button should not be touching requests in the first place and that's the oversight to fix.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

@fallenbagel you are right. I reverted the "bug fix" commit and completly discarded it from the working tree.
Now this PR is only about the 4K UX, as intended.

@github-actions github-actions Bot added the merge conflict Cannot merge due to merge conflicts label Jul 22, 2026
@github-actions

Copy link
Copy Markdown

This pull request has merge conflicts. Please resolve the conflicts so the PR can be successfully reviewed and merged.

@Flawkee
Flawkee force-pushed the feat/4k-enhanced-ux branch from 17e445e to 886326a Compare July 23, 2026 13:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge conflict Cannot merge due to merge conflicts pending author's response

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants