Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions seerr-api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,9 @@ components:
hideAvailable:
type: boolean
example: false
merge4kAvailability:
type: boolean
example: false
partialRequestsEnabled:
type: boolean
example: false
Expand Down
1 change: 1 addition & 0 deletions server/interfaces/api/settingsInterfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export interface PublicSettingsResponse {
applicationUrl: string;
hideAvailable: boolean;
hideBlocklisted: boolean;
merge4kAvailability: boolean;
localLogin: boolean;
mediaServerLogin: boolean;
movie4kEnabled: boolean;
Expand Down
4 changes: 4 additions & 0 deletions server/lib/settings/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ export interface MainSettings {
};
hideAvailable: boolean;
hideBlocklisted: boolean;
merge4kAvailability: boolean;
localLogin: boolean;
mediaServerLogin: boolean;
newPlexLogin: boolean;
Expand Down Expand Up @@ -194,6 +195,7 @@ interface FullPublicSettings extends PublicSettings {
applicationUrl: string;
hideAvailable: boolean;
hideBlocklisted: boolean;
merge4kAvailability: boolean;
localLogin: boolean;
mediaServerLogin: boolean;
movie4kEnabled: boolean;
Expand Down Expand Up @@ -416,6 +418,7 @@ class Settings {
},
hideAvailable: false,
hideBlocklisted: false,
merge4kAvailability: false,
localLogin: true,
mediaServerLogin: true,
newPlexLogin: true,
Expand Down Expand Up @@ -712,6 +715,7 @@ class Settings {
applicationUrl: this.data.main.applicationUrl,
hideAvailable: this.data.main.hideAvailable,
hideBlocklisted: this.data.main.hideBlocklisted,
merge4kAvailability: this.data.main.merge4kAvailability,
localLogin: this.data.main.localLogin,
mediaServerLogin: this.data.main.mediaServerLogin,
jellyfinExternalHost: this.data.jellyfin.externalHostname,
Expand Down
1 change: 1 addition & 0 deletions src/components/CollectionDetails/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,7 @@ const CollectionDetails = ({ collection }: CollectionDetailsProps) => {
isAddedToWatchlist={title.mediaInfo?.watchlists?.length ?? 0}
image={title.posterPath}
status={title.mediaInfo?.status}
status4k={title.mediaInfo?.status4k}
summary={title.overview}
title={title.title}
userScore={title.voteAverage}
Expand Down
2 changes: 2 additions & 0 deletions src/components/Common/ListView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ const ListView = ({
}
image={title.posterPath}
status={title.mediaInfo?.status}
status4k={title.mediaInfo?.status4k}
summary={title.overview}
title={title.title}
userScore={title.voteAverage}
Expand All @@ -109,6 +110,7 @@ const ListView = ({
}
image={title.posterPath}
status={title.mediaInfo?.status}
status4k={title.mediaInfo?.status4k}
summary={title.overview}
title={title.name}
userScore={title.voteAverage}
Expand Down
2 changes: 2 additions & 0 deletions src/components/MediaSlider/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ const MediaSlider = ({
isAddedToWatchlist={title.mediaInfo?.watchlists?.length ?? 0}
image={title.posterPath}
status={title.mediaInfo?.status}
status4k={title.mediaInfo?.status4k}
summary={title.overview}
title={title.title}
userScore={title.voteAverage}
Expand All @@ -143,6 +144,7 @@ const MediaSlider = ({
isAddedToWatchlist={title.mediaInfo?.watchlists?.length ?? 0}
image={title.posterPath}
status={title.mediaInfo?.status}
status4k={title.mediaInfo?.status4k}
summary={title.overview}
title={title.name}
userScore={title.voteAverage}
Expand Down
2 changes: 2 additions & 0 deletions src/components/PersonDetails/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ const PersonDetails = () => {
summary={media.overview}
mediaType={media.mediaType as 'movie' | 'tv'}
status={media.mediaInfo?.status}
status4k={media.mediaInfo?.status4k}
canExpand
/>
{media.character && (
Expand Down Expand Up @@ -224,6 +225,7 @@ const PersonDetails = () => {
summary={media.overview}
mediaType={media.mediaType as 'movie' | 'tv'}
status={media.mediaInfo?.status}
status4k={media.mediaInfo?.status4k}
canExpand
/>
{media.job && (
Expand Down
31 changes: 31 additions & 0 deletions src/components/Settings/SettingsMain/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ const messages = defineMessages('components.Settings.SettingsMain', {
hideAvailable: 'Hide Available Media',
hideAvailableTip:
'Hide available media from the discover pages but not search results',
merge4kAvailability: 'Display 4K Availability on Title Cards',
merge4kAvailabilityTip:
'Show titles that are only available in 4K as available on discover cards',
cacheImages: 'Enable Image Caching',
cacheImagesTip:
'Cache externally sourced images (requires a significant amount of disk space)',
Expand Down Expand Up @@ -173,6 +176,7 @@ const SettingsMain = () => {
applicationUrl: data?.applicationUrl,
hideAvailable: data?.hideAvailable,
hideBlocklisted: data?.hideBlocklisted,
merge4kAvailability: data?.merge4kAvailability,
locale: data?.locale ?? 'en',
discoverRegion: data?.discoverRegion,
originalLanguage: data?.originalLanguage,
Expand All @@ -196,6 +200,7 @@ const SettingsMain = () => {
applicationUrl: values.applicationUrl,
hideAvailable: values.hideAvailable,
hideBlocklisted: values.hideBlocklisted,
merge4kAvailability: values.merge4kAvailability,
locale: values.locale,
discoverRegion: values.discoverRegion,
streamingRegion: values.streamingRegion,
Expand Down Expand Up @@ -519,6 +524,32 @@ const SettingsMain = () => {
/>
</div>
</div>
<div className="form-row">
<label
htmlFor="merge4kAvailability"
className="checkbox-label"
>
<span className="mr-2">
{intl.formatMessage(messages.merge4kAvailability)}
</span>
<span className="label-tip">
{intl.formatMessage(messages.merge4kAvailabilityTip)}
</span>
</label>
<div className="form-input-area">
<Field
type="checkbox"
id="merge4kAvailability"
name="merge4kAvailability"
onChange={() => {
setFieldValue(
'merge4kAvailability',
!values.merge4kAvailability
);
}}
/>
</div>
</div>
<div className="form-row">
<label htmlFor="hideBlocklisted" className="checkbox-label">
<span className="mr-2">
Expand Down
2 changes: 2 additions & 0 deletions src/components/TitleCard/TmdbTitleCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ const TmdbTitleCard = ({
}
image={title.posterPath}
status={title.mediaInfo?.status}
status4k={title.mediaInfo?.status4k}
summary={title.overview}
title={title.title}
userScore={title.voteAverage}
Expand All @@ -84,6 +85,7 @@ const TmdbTitleCard = ({
}
image={title.posterPath}
status={title.mediaInfo?.status}
status4k={title.mediaInfo?.status4k}
summary={title.overview}
title={title.name}
userScore={title.voteAverage}
Expand Down
42 changes: 39 additions & 3 deletions src/components/TitleCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import RequestModal from '@app/components/RequestModal';
import ErrorCard from '@app/components/TitleCard/ErrorCard';
import Placeholder from '@app/components/TitleCard/Placeholder';
import { useIsTouch } from '@app/hooks/useIsTouch';
import useSettings from '@app/hooks/useSettings';
import useToasts from '@app/hooks/useToasts';
import { Permission, UserType, useUser } from '@app/hooks/useUser';
import globalMessages from '@app/i18n/globalMessages';
Expand Down Expand Up @@ -39,6 +40,7 @@ interface TitleCardProps {
userScore?: number;
mediaType: MediaType;
status?: MediaStatus;
status4k?: MediaStatus;
canExpand?: boolean;
inProgress?: boolean;
isAddedToWatchlist?: number | boolean;
Expand All @@ -62,6 +64,7 @@ const TitleCard = ({
year,
title,
status,
status4k,
mediaType,
isAddedToWatchlist = false,
inProgress = false,
Expand All @@ -71,8 +74,40 @@ const TitleCard = ({
const isTouch = useIsTouch();
const intl = useIntl();
const { user, hasPermission } = useUser();
const settings = useSettings();
const [isUpdating, setIsUpdating] = useState(false);
const [currentStatus, setCurrentStatus] = useState(status);

const has4kPermission =
mediaType === 'movie'
? settings.currentSettings.movie4kEnabled &&
hasPermission(
[
Permission.MANAGE_REQUESTS,
Permission.REQUEST_4K,
Permission.REQUEST_4K_MOVIE,
],
{ type: 'or' }
)
: settings.currentSettings.series4kEnabled &&
hasPermission(
[
Permission.MANAGE_REQUESTS,
Permission.REQUEST_4K,
Permission.REQUEST_4K_TV,
],
{ type: 'or' }
);
const showAs4k =
settings.currentSettings.merge4kAvailability &&
has4kPermission &&
(!status ||
status === MediaStatus.UNKNOWN ||
status === MediaStatus.DELETED) &&
(status4k === MediaStatus.AVAILABLE ||
status4k === MediaStatus.PARTIALLY_AVAILABLE);
const displayStatus = showAs4k ? status4k : status;

const [currentStatus, setCurrentStatus] = useState(displayStatus);
const [showDetail, setShowDetail] = useState(false);
const [showRequestModal, setShowRequestModal] = useState(false);
const { addToast } = useToasts();
Expand All @@ -87,8 +122,8 @@ const TitleCard = ({
}

useEffect(() => {
setCurrentStatus(status);
}, [status]);
setCurrentStatus(displayStatus);
}, [displayStatus]);

const requestComplete = useCallback((newStatus: MediaStatus) => {
setCurrentStatus(newStatus);
Expand Down Expand Up @@ -461,6 +496,7 @@ const TitleCard = ({
<div className="pointer-events-none z-40 flex">
<StatusBadgeMini
status={currentStatus}
is4k={showAs4k}
inProgress={inProgress}
shrink
/>
Expand Down
1 change: 1 addition & 0 deletions src/context/SettingsContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const defaultSettings = {
applicationTitle: 'Seerr',
applicationUrl: '',
hideAvailable: false,
merge4kAvailability: false,
hideBlocklisted: false,
localLogin: true,
mediaServerLogin: true,
Expand Down
2 changes: 2 additions & 0 deletions src/i18n/locale/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1036,6 +1036,8 @@
"components.Settings.SettingsMain.hideBlocklisted": "Hide Blocklisted Items",
"components.Settings.SettingsMain.hideBlocklistedTip": "Hide blocklisted items from discover pages for all users with the \"Manage Blocklist\" permission",
"components.Settings.SettingsMain.locale": "Display Language",
"components.Settings.SettingsMain.merge4kAvailability": "Display 4K Availability on Title Cards",
"components.Settings.SettingsMain.merge4kAvailabilityTip": "Show titles that are only available in 4K as available on discover cards",
"components.Settings.SettingsMain.originallanguage": "Discover Language",
"components.Settings.SettingsMain.originallanguageTip": "Filter content by original language",
"components.Settings.SettingsMain.partialRequestsEnabled": "Allow Partial Series Requests",
Expand Down
1 change: 1 addition & 0 deletions src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ CoreApp.getInitialProps = async (initialProps) => {
applicationTitle: '',
applicationUrl: '',
hideAvailable: false,
merge4kAvailability: false,
hideBlocklisted: false,
movie4kEnabled: false,
series4kEnabled: false,
Expand Down