mirror of
https://github.com/fallenbagel/jellyseerr.git
synced 2026-01-05 06:08:36 -05:00
feat(rebase): rebase
This commit is contained in:
@@ -71,19 +71,18 @@ export interface JellyfinLibraryItemExtended extends JellyfinLibraryItem {
|
|||||||
|
|
||||||
class JellyfinAPI {
|
class JellyfinAPI {
|
||||||
private authToken?: string;
|
private authToken?: string;
|
||||||
|
private userId?: string;
|
||||||
private jellyfinHost: string;
|
private jellyfinHost: string;
|
||||||
private axios: AxiosInstance;
|
private axios: AxiosInstance;
|
||||||
|
|
||||||
constructor(jellyfinHost: string, authToken?: string) {
|
constructor(jellyfinHost: string, authToken?: string, userId?: string) {
|
||||||
this.jellyfinHost = jellyfinHost;
|
this.jellyfinHost = jellyfinHost;
|
||||||
this.authToken = authToken;
|
this.authToken = authToken;
|
||||||
|
this.userId = userId;
|
||||||
|
|
||||||
let authHeaderVal = '';
|
let authHeaderVal = '';
|
||||||
if (this.authToken) {
|
if (this.authToken) {
|
||||||
authHeaderVal =
|
authHeaderVal = `MediaBrowser Client="Overseerr", Device="Axios", DeviceId="TW96aWxsYS81LjAgKFdpbmRvd3MgTlQgMTAuMDsgV2luNjQ7IHg2NDsgcnY6ODUuMCkgR2Vja28vMjAxMDAxMDEgRmlyZWZveC84NS4wfDE2MTI5MjcyMDM5NzM1", Version="10.8.0", Token="${authToken}"`;
|
||||||
'MediaBrowser Client="Overseerr", Device="Axios", DeviceId="TW96aWxsYS81LjAgKFdpbmRvd3MgTlQgMTAuMDsgV2luNjQ7IHg2NDsgcnY6ODUuMCkgR2Vja28vMjAxMDAxMDEgRmlyZWZveC84NS4wfDE2MTI5MjcyMDM5NzM1", Version="10.8.0", Token="' +
|
|
||||||
authToken +
|
|
||||||
'"';
|
|
||||||
} else {
|
} else {
|
||||||
authHeaderVal =
|
authHeaderVal =
|
||||||
'MediaBrowser Client="Overseerr", Device="Axios", DeviceId="TW96aWxsYS81LjAgKFdpbmRvd3MgTlQgMTAuMDsgV2luNjQ7IHg2NDsgcnY6ODUuMCkgR2Vja28vMjAxMDAxMDEgRmlyZWZveC84NS4wfDE2MTI5MjcyMDM5NzM1", Version="10.8.0"';
|
'MediaBrowser Client="Overseerr", Device="Axios", DeviceId="TW96aWxsYS81LjAgKFdpbmRvd3MgTlQgMTAuMDsgV2luNjQ7IHg2NDsgcnY6ODUuMCkgR2Vja28vMjAxMDAxMDEgRmlyZWZveC84NS4wfDE2MTI5MjcyMDM5NzM1", Version="10.8.0"';
|
||||||
@@ -117,9 +116,26 @@ class JellyfinAPI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async getServerName(): Promise<string> {
|
||||||
|
try {
|
||||||
|
const account = await this.axios.get<JellyfinUserResponse>(
|
||||||
|
`/System/Info/Public'}`
|
||||||
|
);
|
||||||
|
return account.data.ServerName;
|
||||||
|
} catch (e) {
|
||||||
|
logger.error(
|
||||||
|
`Something went wrong while getting the server name from the Jellyfin server: ${e.message}`,
|
||||||
|
{ label: 'Jellyfin API' }
|
||||||
|
);
|
||||||
|
throw new Error('girl idk');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async getUser(): Promise<JellyfinUserResponse> {
|
public async getUser(): Promise<JellyfinUserResponse> {
|
||||||
try {
|
try {
|
||||||
const account = await this.axios.get<JellyfinUserResponse>('/Users/Me');
|
const account = await this.axios.get<JellyfinUserResponse>(
|
||||||
|
`/Users/${this.userId ?? 'Me'}`
|
||||||
|
);
|
||||||
return account.data;
|
return account.data;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(
|
logger.error(
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
export enum MediaServerType {
|
export enum MediaServerType {
|
||||||
PLEX = 1,
|
PLEX = 1,
|
||||||
JELLYFIN, //also works for emby (identical APIs, etc)
|
JELLYFIN,
|
||||||
|
EMBY,
|
||||||
NOT_CONFIGURED,
|
NOT_CONFIGURED,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export interface SettingsAboutResponse {
|
|||||||
|
|
||||||
export interface PublicSettingsResponse {
|
export interface PublicSettingsResponse {
|
||||||
jellyfinHost?: string;
|
jellyfinHost?: string;
|
||||||
|
jellyfinServerName?: string;
|
||||||
initialized: boolean;
|
initialized: boolean;
|
||||||
applicationTitle: string;
|
applicationTitle: string;
|
||||||
hideAvailable: boolean;
|
hideAvailable: boolean;
|
||||||
|
|||||||
@@ -552,7 +552,7 @@ class JobJellyfinSync {
|
|||||||
this.running = true;
|
this.running = true;
|
||||||
const userRepository = getRepository(User);
|
const userRepository = getRepository(User);
|
||||||
const admin = await userRepository.findOne({
|
const admin = await userRepository.findOne({
|
||||||
select: ['id', 'jellyfinAuthToken'],
|
select: ['id', 'jellyfinAuthToken', 'jellyfinId'],
|
||||||
order: { id: 'ASC' },
|
order: { id: 'ASC' },
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -562,7 +562,8 @@ class JobJellyfinSync {
|
|||||||
|
|
||||||
this.jfClient = new JellyfinAPI(
|
this.jfClient = new JellyfinAPI(
|
||||||
settings.jellyfin.hostname ?? '',
|
settings.jellyfin.hostname ?? '',
|
||||||
admin.jellyfinAuthToken ?? ''
|
admin.jellyfinAuthToken ?? '',
|
||||||
|
admin.jellyfinId ?? ''
|
||||||
);
|
);
|
||||||
|
|
||||||
this.libraries = settings.jellyfin.libraries.filter(
|
this.libraries = settings.jellyfin.libraries.filter(
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ interface FullPublicSettings extends PublicSettings {
|
|||||||
originalLanguage: string;
|
originalLanguage: string;
|
||||||
mediaServerType: number;
|
mediaServerType: number;
|
||||||
jellyfinHost?: string;
|
jellyfinHost?: string;
|
||||||
|
jellyfinServerName?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NotificationAgentConfig {
|
export interface NotificationAgentConfig {
|
||||||
@@ -368,17 +369,10 @@ class Settings {
|
|||||||
series4kEnabled: this.data.sonarr.some(
|
series4kEnabled: this.data.sonarr.some(
|
||||||
(sonarr) => sonarr.is4k && sonarr.isDefault
|
(sonarr) => sonarr.is4k && sonarr.isDefault
|
||||||
),
|
),
|
||||||
<<<<<<< HEAD
|
|
||||||
region: this.data.main.region,
|
region: this.data.main.region,
|
||||||
originalLanguage: this.data.main.originalLanguage,
|
originalLanguage: this.data.main.originalLanguage,
|
||||||
=======
|
|
||||||
mediaServerType: this.main.mediaServerType,
|
mediaServerType: this.main.mediaServerType,
|
||||||
<<<<<<< HEAD
|
|
||||||
jfHost: this.jellyfin.hostname ?? '',
|
|
||||||
>>>>>>> feat(all): add initial Jellyfin/Emby support
|
|
||||||
=======
|
|
||||||
jellyfinHost: this.jellyfin.hostname,
|
jellyfinHost: this.jellyfin.hostname,
|
||||||
>>>>>>> feat(rebase): rebase
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -181,6 +181,7 @@ authRoutes.post('/jellyfin', async (req, res, next) => {
|
|||||||
: body.hostname;
|
: body.hostname;
|
||||||
// First we need to attempt to log the user in to jellyfin
|
// First we need to attempt to log the user in to jellyfin
|
||||||
const jellyfinserver = new JellyfinAPI(hostname ?? '');
|
const jellyfinserver = new JellyfinAPI(hostname ?? '');
|
||||||
|
settings.jellyfin.name = await jellyfinserver.getServerName();
|
||||||
|
|
||||||
const account = await jellyfinserver.login(body.username, body.password);
|
const account = await jellyfinserver.login(body.username, body.password);
|
||||||
|
|
||||||
|
|||||||
@@ -74,10 +74,8 @@ const messages = defineMessages({
|
|||||||
openradarr: 'Open Movie in Radarr',
|
openradarr: 'Open Movie in Radarr',
|
||||||
openradarr4k: 'Open Movie in 4K Radarr',
|
openradarr4k: 'Open Movie in 4K Radarr',
|
||||||
downloadstatus: 'Download Status',
|
downloadstatus: 'Download Status',
|
||||||
playonplex: 'Play on Plex',
|
play: 'Play on {mediaServerName}',
|
||||||
play4konplex: 'Play 4K on Plex',
|
play4k: 'Play 4K on {mediaServerName}',
|
||||||
playonjellyfin: 'Play on Jellyfin',
|
|
||||||
play4konjellyfin: 'Play 4K on Jellyfin',
|
|
||||||
markavailable: 'Mark as Available',
|
markavailable: 'Mark as Available',
|
||||||
mark4kavailable: 'Mark 4K as Available',
|
mark4kavailable: 'Mark 4K as Available',
|
||||||
});
|
});
|
||||||
@@ -396,8 +394,8 @@ const MovieDetails: React.FC<MovieDetailsProps> = ({ movie }) => {
|
|||||||
<StatusBadge
|
<StatusBadge
|
||||||
status={data.mediaInfo?.status}
|
status={data.mediaInfo?.status}
|
||||||
inProgress={(data.mediaInfo.downloadStatus ?? []).length > 0}
|
inProgress={(data.mediaInfo.downloadStatus ?? []).length > 0}
|
||||||
plexUrl={data.mediaInfo?.mediaUrl}
|
mediaUrl={data.mediaInfo?.mediaUrl}
|
||||||
plexUrl4k={data.mediaInfo?.mediaUrl4k}
|
mediaUrl4k={data.mediaInfo?.mediaUrl4k}
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
@@ -406,8 +404,8 @@ const MovieDetails: React.FC<MovieDetailsProps> = ({ movie }) => {
|
|||||||
status={data.mediaInfo?.status4k}
|
status={data.mediaInfo?.status4k}
|
||||||
is4k
|
is4k
|
||||||
inProgress={(data.mediaInfo?.downloadStatus4k ?? []).length > 0}
|
inProgress={(data.mediaInfo?.downloadStatus4k ?? []).length > 0}
|
||||||
plexUrl={data.mediaInfo?.mediaUrl}
|
mediaUrl={data.mediaInfo?.mediaUrl}
|
||||||
plexUrl4k={
|
mediaUrl4k={
|
||||||
data.mediaInfo?.mediaUrl4k &&
|
data.mediaInfo?.mediaUrl4k &&
|
||||||
(hasPermission(Permission.REQUEST_4K) ||
|
(hasPermission(Permission.REQUEST_4K) ||
|
||||||
hasPermission(Permission.REQUEST_4K_MOVIE))
|
hasPermission(Permission.REQUEST_4K_MOVIE))
|
||||||
@@ -487,21 +485,23 @@ const MovieDetails: React.FC<MovieDetailsProps> = ({ movie }) => {
|
|||||||
</svg>
|
</svg>
|
||||||
<span>
|
<span>
|
||||||
{data.mediaInfo?.mediaUrl || data.mediaInfo?.mediaUrl4k
|
{data.mediaInfo?.mediaUrl || data.mediaInfo?.mediaUrl4k
|
||||||
? intl.formatMessage(
|
? intl.formatMessage(messages.play, {
|
||||||
settings.currentSettings.mediaServerType ==
|
mediaServerName:
|
||||||
|
settings.currentSettings.mediaServerType ===
|
||||||
MediaServerType.PLEX
|
MediaServerType.PLEX
|
||||||
? messages.playonplex
|
? 'Plex'
|
||||||
: messages.playonjellyfin
|
: settings.currentSettings.jellyfinServerName,
|
||||||
)
|
})
|
||||||
: data.mediaInfo?.mediaUrl4k &&
|
: data.mediaInfo?.mediaUrl4k &&
|
||||||
(hasPermission(Permission.REQUEST_4K) ||
|
(hasPermission(Permission.REQUEST_4K) ||
|
||||||
hasPermission(Permission.REQUEST_4K_MOVIE))
|
hasPermission(Permission.REQUEST_4K_MOVIE))
|
||||||
? intl.formatMessage(
|
? intl.formatMessage(messages.play4k, {
|
||||||
settings.currentSettings.mediaServerType ==
|
mediaServerName:
|
||||||
|
settings.currentSettings.mediaServerType ===
|
||||||
MediaServerType.PLEX
|
MediaServerType.PLEX
|
||||||
? messages.playonplex
|
? 'Plex'
|
||||||
: messages.playonjellyfin
|
: settings.currentSettings.jellyfinServerName,
|
||||||
)
|
})
|
||||||
: intl.formatMessage(messages.watchtrailer)}
|
: intl.formatMessage(messages.watchtrailer)}
|
||||||
</span>
|
</span>
|
||||||
</>
|
</>
|
||||||
@@ -538,12 +538,13 @@ const MovieDetails: React.FC<MovieDetailsProps> = ({ movie }) => {
|
|||||||
}}
|
}}
|
||||||
buttonType="ghost"
|
buttonType="ghost"
|
||||||
>
|
>
|
||||||
{intl.formatMessage(
|
{intl.formatMessage(messages.play4k, {
|
||||||
settings.currentSettings.mediaServerType ==
|
mediaServerName:
|
||||||
|
settings.currentSettings.mediaServerType ===
|
||||||
MediaServerType.PLEX
|
MediaServerType.PLEX
|
||||||
? messages.play4konplex
|
? 'Plex'
|
||||||
: messages.play4konjellyfin
|
: settings.currentSettings.jellyfinServerName,
|
||||||
)}
|
})}
|
||||||
</ButtonWithDropdown.Item>
|
</ButtonWithDropdown.Item>
|
||||||
)}
|
)}
|
||||||
{trailerUrl && (
|
{trailerUrl && (
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import globalMessages from '../../i18n/globalMessages';
|
|||||||
import PermissionEdit from '../PermissionEdit';
|
import PermissionEdit from '../PermissionEdit';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
import RegionSelector from '../RegionSelector';
|
import RegionSelector from '../RegionSelector';
|
||||||
import { MediaServerType } from '../../../server/constants/server';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
generalsettings: 'General Settings',
|
generalsettings: 'General Settings',
|
||||||
@@ -36,7 +35,6 @@ const messages = defineMessages({
|
|||||||
toastSettingsSuccess: 'Settings successfully saved!',
|
toastSettingsSuccess: 'Settings successfully saved!',
|
||||||
toastSettingsFailure: 'Something went wrong while saving settings.',
|
toastSettingsFailure: 'Something went wrong while saving settings.',
|
||||||
defaultPermissions: 'Default User Permissions',
|
defaultPermissions: 'Default User Permissions',
|
||||||
useJellyfin: 'Use Jellyfin as Media Server',
|
|
||||||
hideAvailable: 'Hide Available Media',
|
hideAvailable: 'Hide Available Media',
|
||||||
csrfProtection: 'Enable CSRF Protection',
|
csrfProtection: 'Enable CSRF Protection',
|
||||||
csrfProtectionTip:
|
csrfProtectionTip:
|
||||||
@@ -124,8 +122,6 @@ const SettingsMain: React.FC = () => {
|
|||||||
region: data?.region,
|
region: data?.region,
|
||||||
originalLanguage: data?.originalLanguage,
|
originalLanguage: data?.originalLanguage,
|
||||||
trustProxy: data?.trustProxy,
|
trustProxy: data?.trustProxy,
|
||||||
useJellyfin:
|
|
||||||
data?.mediaServerType == MediaServerType.JELLYFIN ? true : false,
|
|
||||||
}}
|
}}
|
||||||
enableReinitialize
|
enableReinitialize
|
||||||
validationSchema={MainSettingsSchema}
|
validationSchema={MainSettingsSchema}
|
||||||
@@ -141,9 +137,6 @@ const SettingsMain: React.FC = () => {
|
|||||||
region: values.region,
|
region: values.region,
|
||||||
originalLanguage: values.originalLanguage,
|
originalLanguage: values.originalLanguage,
|
||||||
trustProxy: values.trustProxy,
|
trustProxy: values.trustProxy,
|
||||||
mediaServerType: values.useJellyfin
|
|
||||||
? MediaServerType.JELLYFIN
|
|
||||||
: MediaServerType.PLEX,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
addToast(intl.formatMessage(messages.toastSettingsSuccess), {
|
addToast(intl.formatMessage(messages.toastSettingsSuccess), {
|
||||||
@@ -367,21 +360,6 @@ const SettingsMain: React.FC = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="form-row">
|
|
||||||
<label htmlFor="useJellyfin" className="checkbox-label">
|
|
||||||
<span>{intl.formatMessage(messages.useJellyfin)}</span>
|
|
||||||
</label>
|
|
||||||
<div className="form-input">
|
|
||||||
<Field
|
|
||||||
type="checkbox"
|
|
||||||
id="useJellyfin"
|
|
||||||
name="useJellyfin"
|
|
||||||
onChange={() => {
|
|
||||||
setFieldValue('useJellyfin', !values.useJellyfin);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
<div
|
||||||
role="group"
|
role="group"
|
||||||
aria-labelledby="group-label"
|
aria-labelledby="group-label"
|
||||||
|
|||||||
@@ -31,7 +31,10 @@ const Setup: React.FC = () => {
|
|||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const [isUpdating, setIsUpdating] = useState(false);
|
const [isUpdating, setIsUpdating] = useState(false);
|
||||||
const [currentStep, setCurrentStep] = useState(1);
|
const [currentStep, setCurrentStep] = useState(1);
|
||||||
const [msSettingsComplete, setMSSettingsComplete] = useState(false);
|
const [
|
||||||
|
mediaServerSettingsComplete,
|
||||||
|
setMediaServerSettingsComplete,
|
||||||
|
] = useState(false);
|
||||||
const [mediaServerType, setMediaServerType] = useState('');
|
const [mediaServerType, setMediaServerType] = useState('');
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
@@ -114,10 +117,12 @@ const Setup: React.FC = () => {
|
|||||||
{currentStep === 2 && (
|
{currentStep === 2 && (
|
||||||
<div>
|
<div>
|
||||||
{mediaServerType == 'PLEX' ? (
|
{mediaServerType == 'PLEX' ? (
|
||||||
<SettingsPlex onComplete={() => setMSSettingsComplete(true)} />
|
<SettingsPlex
|
||||||
|
onComplete={() => setMediaServerSettingsComplete(true)}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<SettingsJellyfin
|
<SettingsJellyfin
|
||||||
onComplete={() => setMSSettingsComplete(true)}
|
onComplete={() => setMediaServerSettingsComplete(true)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<div className="mt-4 text-sm text-gray-500">
|
<div className="mt-4 text-sm text-gray-500">
|
||||||
@@ -131,7 +136,7 @@ const Setup: React.FC = () => {
|
|||||||
<span className="inline-flex ml-3 rounded-md shadow-sm">
|
<span className="inline-flex ml-3 rounded-md shadow-sm">
|
||||||
<Button
|
<Button
|
||||||
buttonType="primary"
|
buttonType="primary"
|
||||||
disabled={!msSettingsComplete}
|
disabled={!mediaServerSettingsComplete}
|
||||||
onClick={() => setCurrentStep(3)}
|
onClick={() => setCurrentStep(3)}
|
||||||
>
|
>
|
||||||
<FormattedMessage {...messages.continue} />
|
<FormattedMessage {...messages.continue} />
|
||||||
|
|||||||
@@ -13,25 +13,25 @@ interface StatusBadgeProps {
|
|||||||
status?: MediaStatus;
|
status?: MediaStatus;
|
||||||
is4k?: boolean;
|
is4k?: boolean;
|
||||||
inProgress?: boolean;
|
inProgress?: boolean;
|
||||||
plexUrl?: string;
|
mediaUrl?: string;
|
||||||
plexUrl4k?: string;
|
mediaUrl4k?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StatusBadge: React.FC<StatusBadgeProps> = ({
|
const StatusBadge: React.FC<StatusBadgeProps> = ({
|
||||||
status,
|
status,
|
||||||
is4k = false,
|
is4k = false,
|
||||||
inProgress = false,
|
inProgress = false,
|
||||||
plexUrl,
|
mediaUrl,
|
||||||
plexUrl4k,
|
mediaUrl4k,
|
||||||
}) => {
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
if (is4k) {
|
if (is4k) {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case MediaStatus.AVAILABLE:
|
case MediaStatus.AVAILABLE:
|
||||||
if (plexUrl4k) {
|
if (mediaUrl4k) {
|
||||||
return (
|
return (
|
||||||
<a href={plexUrl4k} target="_blank" rel="noopener noreferrer">
|
<a href={mediaUrl4k} target="_blank" rel="noopener noreferrer">
|
||||||
<Badge
|
<Badge
|
||||||
badgeType="success"
|
badgeType="success"
|
||||||
className="transition cursor-pointer hover:bg-green-400"
|
className="transition cursor-pointer hover:bg-green-400"
|
||||||
@@ -52,9 +52,9 @@ const StatusBadge: React.FC<StatusBadgeProps> = ({
|
|||||||
</Badge>
|
</Badge>
|
||||||
);
|
);
|
||||||
case MediaStatus.PARTIALLY_AVAILABLE:
|
case MediaStatus.PARTIALLY_AVAILABLE:
|
||||||
if (plexUrl4k) {
|
if (mediaUrl4k) {
|
||||||
return (
|
return (
|
||||||
<a href={plexUrl4k} target="_blank" rel="noopener noreferrer">
|
<a href={mediaUrl4k} target="_blank" rel="noopener noreferrer">
|
||||||
<Badge
|
<Badge
|
||||||
badgeType="success"
|
badgeType="success"
|
||||||
className="transition cursor-pointer hover:bg-green-400"
|
className="transition cursor-pointer hover:bg-green-400"
|
||||||
@@ -104,9 +104,9 @@ const StatusBadge: React.FC<StatusBadgeProps> = ({
|
|||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case MediaStatus.AVAILABLE:
|
case MediaStatus.AVAILABLE:
|
||||||
if (plexUrl) {
|
if (mediaUrl) {
|
||||||
return (
|
return (
|
||||||
<a href={plexUrl} target="_blank" rel="noopener noreferrer">
|
<a href={mediaUrl} target="_blank" rel="noopener noreferrer">
|
||||||
<Badge
|
<Badge
|
||||||
badgeType="success"
|
badgeType="success"
|
||||||
className="transition cursor-pointer hover:bg-green-400"
|
className="transition cursor-pointer hover:bg-green-400"
|
||||||
@@ -129,9 +129,9 @@ const StatusBadge: React.FC<StatusBadgeProps> = ({
|
|||||||
</Badge>
|
</Badge>
|
||||||
);
|
);
|
||||||
case MediaStatus.PARTIALLY_AVAILABLE:
|
case MediaStatus.PARTIALLY_AVAILABLE:
|
||||||
if (plexUrl) {
|
if (mediaUrl) {
|
||||||
return (
|
return (
|
||||||
<a href={plexUrl} target="_blank" rel="noopener noreferrer">
|
<a href={mediaUrl} target="_blank" rel="noopener noreferrer">
|
||||||
<Badge
|
<Badge
|
||||||
badgeType="success"
|
badgeType="success"
|
||||||
className="transition cursor-pointer hover:bg-green-400"
|
className="transition cursor-pointer hover:bg-green-400"
|
||||||
|
|||||||
@@ -67,10 +67,8 @@ const messages = defineMessages({
|
|||||||
opensonarr: 'Open Series in Sonarr',
|
opensonarr: 'Open Series in Sonarr',
|
||||||
opensonarr4k: 'Open Series in 4K Sonarr',
|
opensonarr4k: 'Open Series in 4K Sonarr',
|
||||||
downloadstatus: 'Download Status',
|
downloadstatus: 'Download Status',
|
||||||
playonplex: 'Play on Plex',
|
play: 'Play on {mediaServerName}',
|
||||||
play4konplex: 'Play 4K on Plex',
|
play4k: 'Play 4K on {mediaServerName}',
|
||||||
playonjellyfin: 'Play on Jellyfin',
|
|
||||||
play4konjellyfin: 'Play 4K on Jellyfin',
|
|
||||||
markavailable: 'Mark as Available',
|
markavailable: 'Mark as Available',
|
||||||
mark4kavailable: 'Mark 4K as Available',
|
mark4kavailable: 'Mark 4K as Available',
|
||||||
allseasonsmarkedavailable: '* All seasons will be marked as available.',
|
allseasonsmarkedavailable: '* All seasons will be marked as available.',
|
||||||
@@ -413,8 +411,8 @@ const TvDetails: React.FC<TvDetailsProps> = ({ tv }) => {
|
|||||||
<StatusBadge
|
<StatusBadge
|
||||||
status={data.mediaInfo?.status}
|
status={data.mediaInfo?.status}
|
||||||
inProgress={(data.mediaInfo.downloadStatus ?? []).length > 0}
|
inProgress={(data.mediaInfo.downloadStatus ?? []).length > 0}
|
||||||
plexUrl={data.mediaInfo?.mediaUrl}
|
mediaUrl={data.mediaInfo?.mediaUrl}
|
||||||
plexUrl4k={data.mediaInfo?.mediaUrl4k}
|
mediaUrl4k={data.mediaInfo?.mediaUrl4k}
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
@@ -422,8 +420,8 @@ const TvDetails: React.FC<TvDetailsProps> = ({ tv }) => {
|
|||||||
<StatusBadge
|
<StatusBadge
|
||||||
status={data.mediaInfo?.status}
|
status={data.mediaInfo?.status}
|
||||||
inProgress={(data.mediaInfo?.downloadStatus ?? []).length > 0}
|
inProgress={(data.mediaInfo?.downloadStatus ?? []).length > 0}
|
||||||
plexUrl={data.mediaInfo?.mediaUrl}
|
mediaUrl={data.mediaInfo?.mediaUrl}
|
||||||
plexUrl4k={
|
mediaUrl4k={
|
||||||
data.mediaInfo?.mediaUrl4k &&
|
data.mediaInfo?.mediaUrl4k &&
|
||||||
(hasPermission(Permission.REQUEST_4K) ||
|
(hasPermission(Permission.REQUEST_4K) ||
|
||||||
hasPermission(Permission.REQUEST_4K_TV))
|
hasPermission(Permission.REQUEST_4K_TV))
|
||||||
|
|||||||
@@ -80,10 +80,8 @@
|
|||||||
"components.MovieDetails.overview": "Overview",
|
"components.MovieDetails.overview": "Overview",
|
||||||
"components.MovieDetails.overviewunavailable": "Overview unavailable.",
|
"components.MovieDetails.overviewunavailable": "Overview unavailable.",
|
||||||
"components.MovieDetails.pending": "Pending",
|
"components.MovieDetails.pending": "Pending",
|
||||||
"components.MovieDetails.play4konjellyfin": "Play 4K on Jellyfin",
|
"components.MovieDetails.play": "Play on {mediaServerName}",
|
||||||
"components.MovieDetails.play4konplex": "Play 4K on Plex",
|
"components.MovieDetails.play4k": "Play 4K on {mediaServerName}",
|
||||||
"components.MovieDetails.playonjellyfin": "Play on Jellyfin",
|
|
||||||
"components.MovieDetails.playonplex": "Play on Plex",
|
|
||||||
"components.MovieDetails.recommendations": "Recommendations",
|
"components.MovieDetails.recommendations": "Recommendations",
|
||||||
"components.MovieDetails.recommendationssubtext": "If you liked {title}, you might also like…",
|
"components.MovieDetails.recommendationssubtext": "If you liked {title}, you might also like…",
|
||||||
"components.MovieDetails.releasedate": "Release Date",
|
"components.MovieDetails.releasedate": "Release Date",
|
||||||
@@ -584,7 +582,6 @@
|
|||||||
"components.Settings.toastSettingsSuccess": "Settings successfully saved!",
|
"components.Settings.toastSettingsSuccess": "Settings successfully saved!",
|
||||||
"components.Settings.trustProxy": "Enable Proxy Support",
|
"components.Settings.trustProxy": "Enable Proxy Support",
|
||||||
"components.Settings.trustProxyTip": "Allows Overseerr to correctly register client IP addresses behind a proxy (Overseerr must be reloaded for changes to take effect)",
|
"components.Settings.trustProxyTip": "Allows Overseerr to correctly register client IP addresses behind a proxy (Overseerr must be reloaded for changes to take effect)",
|
||||||
"components.Settings.useJellyfin": "Use Jellyfin as Media Server",
|
|
||||||
"components.Settings.validationApplicationTitle": "You must provide an application title",
|
"components.Settings.validationApplicationTitle": "You must provide an application title",
|
||||||
"components.Settings.validationApplicationUrl": "You must provide a valid URL",
|
"components.Settings.validationApplicationUrl": "You must provide a valid URL",
|
||||||
"components.Settings.validationApplicationUrlTrailingSlash": "URL must not end in a trailing slash",
|
"components.Settings.validationApplicationUrlTrailingSlash": "URL must not end in a trailing slash",
|
||||||
@@ -639,10 +636,8 @@
|
|||||||
"components.TvDetails.overview": "Overview",
|
"components.TvDetails.overview": "Overview",
|
||||||
"components.TvDetails.overviewunavailable": "Overview unavailable.",
|
"components.TvDetails.overviewunavailable": "Overview unavailable.",
|
||||||
"components.TvDetails.pending": "Pending",
|
"components.TvDetails.pending": "Pending",
|
||||||
"components.TvDetails.play4konjellyfin": "Play 4K on Jellyfin",
|
"components.TvDetails.play": "Play on {mediaServerName}",
|
||||||
"components.TvDetails.play4konplex": "Play 4K on Plex",
|
"components.TvDetails.play4k": "Play 4K on {mediaServerName}",
|
||||||
"components.TvDetails.playonjellyfin": "Play on Jellyfin",
|
|
||||||
"components.TvDetails.playonplex": "Play on Plex",
|
|
||||||
"components.TvDetails.recommendations": "Recommendations",
|
"components.TvDetails.recommendations": "Recommendations",
|
||||||
"components.TvDetails.recommendationssubtext": "If you liked {title}, you might also like…",
|
"components.TvDetails.recommendationssubtext": "If you liked {title}, you might also like…",
|
||||||
"components.TvDetails.showtype": "Show Type",
|
"components.TvDetails.showtype": "Show Type",
|
||||||
|
|||||||
Reference in New Issue
Block a user