+
-
-
- {year &&
{year}
}
-
-
- {title}
-
-
- {summary}
-
-
+ {year &&
{year}
}
+
= 2 ? 2 : 3,
+ display: '-webkit-box',
+ overflow: 'hidden',
+ WebkitBoxOrient: 'vertical',
+ wordBreak: 'break-word',
+ }}
+ data-testid="title-card-title"
+ >
+ {title}
+
+
+ {summary}
-
- {showRequestButton &&
- (!currentStatus ||
- currentStatus === MediaStatus.UNKNOWN ||
- currentStatus === MediaStatus.DELETED) && (
+ {bottomButtonCount > 0 && (
+
+ {showRequest ? (
{intl.formatMessage(globalMessages.request)}
- )}
-
+ ) : showAvailable ? (
+
+
+
+ ) : showRequested ? (
+
+
+
+ ) : null}
+ {showRequest4k ? (
+
+ ) : showAvailable4k ? (
+
+
+
+ ) : showRequested4k ? (
+
+
+
+ ) : null}
+
+ )}
diff --git a/src/context/SettingsContext.tsx b/src/context/SettingsContext.tsx
index f2ed116756..ab5262a8cd 100644
--- a/src/context/SettingsContext.tsx
+++ b/src/context/SettingsContext.tsx
@@ -24,6 +24,7 @@ const defaultSettings = {
mediaServerType: MediaServerType.NOT_CONFIGURED,
partialRequestsEnabled: true,
enableSpecialEpisodes: false,
+ separate4kRequestButton: false,
cacheImages: false,
vapidPublic: '',
enablePushRegistration: false,
diff --git a/src/i18n/locale/en.json b/src/i18n/locale/en.json
index bbc28a1ccc..61eab021d0 100644
--- a/src/i18n/locale/en.json
+++ b/src/i18n/locale/en.json
@@ -1018,6 +1018,8 @@
"components.Settings.SettingsMain.originallanguage": "Discover Language",
"components.Settings.SettingsMain.originallanguageTip": "Filter content by original language",
"components.Settings.SettingsMain.partialRequestsEnabled": "Allow Partial Series Requests",
+ "components.Settings.SettingsMain.separate4kRequestButton": "Separate 4K Request Button",
+ "components.Settings.SettingsMain.separate4kRequestButtonTip": "Show the 4K request as its own button next to the Request button on title pages instead of inside the request dropdown",
"components.Settings.SettingsMain.streamingRegion": "Streaming Region",
"components.Settings.SettingsMain.streamingRegionTip": "Show streaming sites by regional availability",
"components.Settings.SettingsMain.toastApiKeyFailure": "Something went wrong while generating a new API key.",
@@ -1328,7 +1330,10 @@
"components.StatusChecker.restartRequired": "Server Restart Required",
"components.StatusChecker.restartRequiredDescription": "Please restart the server to apply the updated settings.",
"components.TitleCard.addToWatchList": "Add to watchlist",
+ "components.TitleCard.available4k": "4K Available",
"components.TitleCard.cleardata": "Clear Data",
+ "components.TitleCard.partiallyavailable4k": "4K Partially Available",
+ "components.TitleCard.requested4k": "4K Requested",
"components.TitleCard.mediaerror": "{mediaType} Not Found",
"components.TitleCard.tmdbid": "TMDB ID",
"components.TitleCard.tvdbid": "TheTVDB ID",
diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx
index 833ecad66b..0c69028eb3 100644
--- a/src/pages/_app.tsx
+++ b/src/pages/_app.tsx
@@ -253,6 +253,7 @@ CoreApp.getInitialProps = async (initialProps) => {
mediaServerType: MediaServerType.NOT_CONFIGURED,
partialRequestsEnabled: true,
enableSpecialEpisodes: false,
+ separate4kRequestButton: false,
cacheImages: false,
vapidPublic: '',
enablePushRegistration: false,
From 49b48f79b53cf329440d6f8dcbd895844ec8774b Mon Sep 17 00:00:00 2001
From: Flawkee <70835293+Flawkee@users.noreply.github.com>
Date: Thu, 21 May 2026 23:58:40 +0300
Subject: [PATCH 2/6] test(next-env.d.ts): revert next.js automatic change
next.js changed the import when tested locally - reveted it
---
next-env.d.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/next-env.d.ts b/next-env.d.ts
index 7996d352f4..19709046af 100644
--- a/next-env.d.ts
+++ b/next-env.d.ts
@@ -1,6 +1,6 @@
///
///
-import "./.next/dev/types/routes.d.ts";
+import "./.next/types/routes.d.ts";
// NOTE: This file should not be edited
// see https://nextjs.org/docs/pages/api-reference/config/typescript for more information.
From 8a70d26ca67b3f9eff932101d18497b570f2850e Mon Sep 17 00:00:00 2001
From: Flawkee <70835293+Flawkee@users.noreply.github.com>
Date: Fri, 22 May 2026 08:54:32 +0300
Subject: [PATCH 3/6] feat(detail pages + badge component): make detail page
badges (requested, 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 #2993"
---
src/components/Common/Badge/index.tsx | 12 +-
src/components/MovieDetails/index.tsx | 2 +
src/components/StatusBadge/index.tsx | 386 +++++++-------------------
src/components/TvDetails/index.tsx | 2 +
4 files changed, 122 insertions(+), 280 deletions(-)
diff --git a/src/components/Common/Badge/index.tsx b/src/components/Common/Badge/index.tsx
index 5ee23bdfd0..31fe088cdf 100644
--- a/src/components/Common/Badge/index.tsx
+++ b/src/components/Common/Badge/index.tsx
@@ -10,17 +10,25 @@ interface BadgeProps {
| 'success'
| 'dark'
| 'light';
+ size?: 'default' | 'lg';
className?: string;
href?: string;
children: React.ReactNode;
}
const Badge = (
- { badgeType = 'default', className, href, children }: BadgeProps,
+ {
+ badgeType = 'default',
+ size = 'default',
+ className,
+ href,
+ children,
+ }: BadgeProps,
ref?: React.Ref
) => {
const badgeStyle = [
- 'px-2 inline-flex text-xs leading-5 font-semibold rounded-full whitespace-nowrap',
+ 'inline-flex items-center font-semibold rounded-full whitespace-nowrap',
+ size === 'lg' ? 'px-3 py-1 text-sm leading-5' : 'px-2 text-xs leading-5',
];
if (href) {
diff --git a/src/components/MovieDetails/index.tsx b/src/components/MovieDetails/index.tsx
index 56a3c0a1f7..861bea945a 100644
--- a/src/components/MovieDetails/index.tsx
+++ b/src/components/MovieDetails/index.tsx
@@ -513,6 +513,7 @@ const MovieDetails = ({ movie }: MovieDetailsProps) => {
mediaType="movie"
plexUrl={plexUrl}
serviceUrl={data.mediaInfo?.serviceUrl}
+ size="lg"
/>
{settings.currentSettings.movie4kEnabled &&
hasPermission(
@@ -537,6 +538,7 @@ const MovieDetails = ({ movie }: MovieDetailsProps) => {
mediaType="movie"
plexUrl={plexUrl4k}
serviceUrl={data.mediaInfo?.serviceUrl4k}
+ size="lg"
/>
)}
diff --git a/src/components/StatusBadge/index.tsx b/src/components/StatusBadge/index.tsx
index faea1fb5c2..44d6d01d65 100644
--- a/src/components/StatusBadge/index.tsx
+++ b/src/components/StatusBadge/index.tsx
@@ -6,6 +6,13 @@ import useSettings from '@app/hooks/useSettings';
import { Permission, useUser } from '@app/hooks/useUser';
import globalMessages from '@app/i18n/globalMessages';
import defineMessages from '@app/utils/defineMessages';
+import { CheckCircleIcon } from '@heroicons/react/20/solid';
+import {
+ BellIcon,
+ ClockIcon,
+ EyeSlashIcon,
+ TrashIcon,
+} from '@heroicons/react/24/solid';
import { MediaStatus } from '@server/constants/media';
import { MediaServerType } from '@server/constants/server';
import type { DownloadingItem } from '@server/lib/downloadtracker';
@@ -32,6 +39,7 @@ interface StatusBadgeProps {
mediaType?: 'movie' | 'tv';
title?: string | string[];
statusLabelOverride?: string;
+ size?: 'default' | 'lg';
}
const StatusBadge = ({
@@ -45,6 +53,7 @@ const StatusBadge = ({
mediaType,
title,
statusLabelOverride,
+ size = 'default',
}: StatusBadgeProps) => {
const intl = useIntl();
const { hasPermission } = useUser();
@@ -154,294 +163,115 @@ const StatusBadge = ({
/>
);
+ let badgeType: 'success' | 'primary' | 'warning' | 'danger';
+ let statusMessage: typeof globalMessages.available;
+ let StatusIcon: typeof CheckCircleIcon;
+
switch (status) {
case MediaStatus.AVAILABLE:
- return (
-