feat: allow changing YouTube host for trailers (#643)
* feat(server settings, movie/tv/settings components): allow changing YouTube URL for trailers * fix: add i18n messages * fix(i18n): remove unwanted translation change --------- Co-authored-by: Gauthier <mail@gauthierth.fr>
This commit is contained in:
@@ -46,6 +46,7 @@ export interface PublicSettingsResponse {
|
|||||||
locale: string;
|
locale: string;
|
||||||
emailEnabled: boolean;
|
emailEnabled: boolean;
|
||||||
newPlexLogin: boolean;
|
newPlexLogin: boolean;
|
||||||
|
youtubeUrl: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CacheItem {
|
export interface CacheItem {
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ export interface MainSettings {
|
|||||||
partialRequestsEnabled: boolean;
|
partialRequestsEnabled: boolean;
|
||||||
enableSpecialEpisodes: boolean;
|
enableSpecialEpisodes: boolean;
|
||||||
locale: string;
|
locale: string;
|
||||||
|
youtubeUrl: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NetworkSettings {
|
export interface NetworkSettings {
|
||||||
@@ -172,6 +173,7 @@ interface FullPublicSettings extends PublicSettings {
|
|||||||
emailEnabled: boolean;
|
emailEnabled: boolean;
|
||||||
userEmailRequired: boolean;
|
userEmailRequired: boolean;
|
||||||
newPlexLogin: boolean;
|
newPlexLogin: boolean;
|
||||||
|
youtubeUrl: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NotificationAgentConfig {
|
export interface NotificationAgentConfig {
|
||||||
@@ -375,6 +377,7 @@ class Settings {
|
|||||||
partialRequestsEnabled: true,
|
partialRequestsEnabled: true,
|
||||||
enableSpecialEpisodes: false,
|
enableSpecialEpisodes: false,
|
||||||
locale: 'en',
|
locale: 'en',
|
||||||
|
youtubeUrl: '',
|
||||||
},
|
},
|
||||||
plex: {
|
plex: {
|
||||||
name: '',
|
name: '',
|
||||||
@@ -646,6 +649,7 @@ class Settings {
|
|||||||
userEmailRequired:
|
userEmailRequired:
|
||||||
this.data.notifications.agents.email.options.userEmailRequired,
|
this.data.notifications.agents.email.options.userEmailRequired,
|
||||||
newPlexLogin: this.data.main.newPlexLogin,
|
newPlexLogin: this.data.main.newPlexLogin,
|
||||||
|
youtubeUrl: this.data.main.youtubeUrl,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -210,10 +210,16 @@ const MovieDetails = ({ movie }: MovieDetailsProps) => {
|
|||||||
svg: <PlayIcon />,
|
svg: <PlayIcon />,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const trailerUrl = data.relatedVideos
|
|
||||||
|
const trailerVideo = data.relatedVideos
|
||||||
?.filter((r) => r.type === 'Trailer')
|
?.filter((r) => r.type === 'Trailer')
|
||||||
.sort((a, b) => a.size - b.size)
|
.sort((a, b) => a.size - b.size)
|
||||||
.pop()?.url;
|
.pop();
|
||||||
|
const trailerUrl =
|
||||||
|
trailerVideo?.site === 'YouTube' &&
|
||||||
|
settings.currentSettings.youtubeUrl != ''
|
||||||
|
? `${settings.currentSettings.youtubeUrl}${trailerVideo?.key}`
|
||||||
|
: trailerVideo?.url;
|
||||||
|
|
||||||
if (trailerUrl) {
|
if (trailerUrl) {
|
||||||
mediaLinks.push({
|
mediaLinks.push({
|
||||||
|
|||||||
@@ -64,6 +64,9 @@ const messages = defineMessages('components.Settings.SettingsMain', {
|
|||||||
partialRequestsEnabled: 'Allow Partial Series Requests',
|
partialRequestsEnabled: 'Allow Partial Series Requests',
|
||||||
enableSpecialEpisodes: 'Allow Special Episodes Requests',
|
enableSpecialEpisodes: 'Allow Special Episodes Requests',
|
||||||
locale: 'Display Language',
|
locale: 'Display Language',
|
||||||
|
youtubeUrl: 'YouTube URL',
|
||||||
|
validationUrl: 'You must provide a valid URL',
|
||||||
|
validationUrlTrailingSlash: 'URL must not end in a trailing slash',
|
||||||
});
|
});
|
||||||
|
|
||||||
const SettingsMain = () => {
|
const SettingsMain = () => {
|
||||||
@@ -105,6 +108,13 @@ const SettingsMain = () => {
|
|||||||
'Number must be less than or equal to 250.',
|
'Number must be less than or equal to 250.',
|
||||||
(value) => (value ?? 0) <= 250
|
(value) => (value ?? 0) <= 250
|
||||||
),
|
),
|
||||||
|
youtubeUrl: Yup.string()
|
||||||
|
.url(intl.formatMessage(messages.validationUrl))
|
||||||
|
.test(
|
||||||
|
'no-trailing-slash',
|
||||||
|
intl.formatMessage(messages.validationUrlTrailingSlash),
|
||||||
|
(value) => !value || !value.endsWith('/')
|
||||||
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
const regenerate = async () => {
|
const regenerate = async () => {
|
||||||
@@ -160,6 +170,7 @@ const SettingsMain = () => {
|
|||||||
partialRequestsEnabled: data?.partialRequestsEnabled,
|
partialRequestsEnabled: data?.partialRequestsEnabled,
|
||||||
enableSpecialEpisodes: data?.enableSpecialEpisodes,
|
enableSpecialEpisodes: data?.enableSpecialEpisodes,
|
||||||
cacheImages: data?.cacheImages,
|
cacheImages: data?.cacheImages,
|
||||||
|
youtubeUrl: data?.youtubeUrl,
|
||||||
}}
|
}}
|
||||||
enableReinitialize
|
enableReinitialize
|
||||||
validationSchema={MainSettingsSchema}
|
validationSchema={MainSettingsSchema}
|
||||||
@@ -179,6 +190,7 @@ const SettingsMain = () => {
|
|||||||
partialRequestsEnabled: values.partialRequestsEnabled,
|
partialRequestsEnabled: values.partialRequestsEnabled,
|
||||||
enableSpecialEpisodes: values.enableSpecialEpisodes,
|
enableSpecialEpisodes: values.enableSpecialEpisodes,
|
||||||
cacheImages: values.cacheImages,
|
cacheImages: values.cacheImages,
|
||||||
|
youtubeUrl: values.youtubeUrl,
|
||||||
});
|
});
|
||||||
mutate('/api/v1/settings/public');
|
mutate('/api/v1/settings/public');
|
||||||
mutate('/api/v1/status');
|
mutate('/api/v1/status');
|
||||||
@@ -519,6 +531,26 @@ const SettingsMain = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="form-row">
|
||||||
|
<label htmlFor="youtubeUrl" className="text-label">
|
||||||
|
{intl.formatMessage(messages.youtubeUrl)}
|
||||||
|
</label>
|
||||||
|
<div className="form-input-area">
|
||||||
|
<div className="form-input-field">
|
||||||
|
<Field
|
||||||
|
id="youtubeUrl"
|
||||||
|
name="youtubeUrl"
|
||||||
|
type="text"
|
||||||
|
inputMode="url"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{errors.youtubeUrl &&
|
||||||
|
touched.youtubeUrl &&
|
||||||
|
typeof errors.youtubeUrl === 'string' && (
|
||||||
|
<div className="error">{errors.youtubeUrl}</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className="actions">
|
<div className="actions">
|
||||||
<div className="flex justify-end">
|
<div className="flex justify-end">
|
||||||
<span className="ml-3 inline-flex rounded-md shadow-sm">
|
<span className="ml-3 inline-flex rounded-md shadow-sm">
|
||||||
|
|||||||
@@ -208,10 +208,15 @@ const TvDetails = ({ tv }: TvDetailsProps) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const trailerUrl = data.relatedVideos
|
const trailerVideo = data.relatedVideos
|
||||||
?.filter((r) => r.type === 'Trailer')
|
?.filter((r) => r.type === 'Trailer')
|
||||||
.sort((a, b) => a.size - b.size)
|
.sort((a, b) => a.size - b.size)
|
||||||
.pop()?.url;
|
.pop();
|
||||||
|
const trailerUrl =
|
||||||
|
trailerVideo?.site === 'YouTube' &&
|
||||||
|
settings.currentSettings.youtubeUrl != ''
|
||||||
|
? `${settings.currentSettings.youtubeUrl}${trailerVideo?.key}`
|
||||||
|
: trailerVideo?.url;
|
||||||
|
|
||||||
if (trailerUrl) {
|
if (trailerUrl) {
|
||||||
mediaLinks.push({
|
mediaLinks.push({
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ const defaultSettings = {
|
|||||||
locale: 'en',
|
locale: 'en',
|
||||||
emailEnabled: false,
|
emailEnabled: false,
|
||||||
newPlexLogin: true,
|
newPlexLogin: true,
|
||||||
|
youtubeUrl: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SettingsContext = React.createContext<SettingsContextProps>({
|
export const SettingsContext = React.createContext<SettingsContextProps>({
|
||||||
|
|||||||
@@ -104,6 +104,7 @@
|
|||||||
"components.Discover.StudioSlider.studios": "Studios",
|
"components.Discover.StudioSlider.studios": "Studios",
|
||||||
"components.Discover.TvGenreList.seriesgenres": "Series Genres",
|
"components.Discover.TvGenreList.seriesgenres": "Series Genres",
|
||||||
"components.Discover.TvGenreSlider.tvgenres": "Series Genres",
|
"components.Discover.TvGenreSlider.tvgenres": "Series Genres",
|
||||||
|
"components.DiscoverTvUpcoming.upcomingtv": "Upcoming Series",
|
||||||
"components.Discover.createnewslider": "Create New Slider",
|
"components.Discover.createnewslider": "Create New Slider",
|
||||||
"components.Discover.customizediscover": "Customize Discover",
|
"components.Discover.customizediscover": "Customize Discover",
|
||||||
"components.Discover.discover": "Discover",
|
"components.Discover.discover": "Discover",
|
||||||
@@ -137,7 +138,6 @@
|
|||||||
"components.Discover.upcomingtv": "Upcoming Series",
|
"components.Discover.upcomingtv": "Upcoming Series",
|
||||||
"components.Discover.updatefailed": "Something went wrong updating the discover customization settings.",
|
"components.Discover.updatefailed": "Something went wrong updating the discover customization settings.",
|
||||||
"components.Discover.updatesuccess": "Updated discover customization settings.",
|
"components.Discover.updatesuccess": "Updated discover customization settings.",
|
||||||
"components.DiscoverTvUpcoming.upcomingtv": "Upcoming Series",
|
|
||||||
"components.DownloadBlock.estimatedtime": "Estimated {time}",
|
"components.DownloadBlock.estimatedtime": "Estimated {time}",
|
||||||
"components.DownloadBlock.formattedTitle": "{title}: Season {seasonNumber} Episode {episodeNumber}",
|
"components.DownloadBlock.formattedTitle": "{title}: Season {seasonNumber} Episode {episodeNumber}",
|
||||||
"components.IssueDetails.IssueComment.areyousuredelete": "Are you sure you want to delete this comment?",
|
"components.IssueDetails.IssueComment.areyousuredelete": "Are you sure you want to delete this comment?",
|
||||||
@@ -975,6 +975,9 @@
|
|||||||
"components.Settings.SettingsMain.validationApplicationTitle": "You must provide an application title",
|
"components.Settings.SettingsMain.validationApplicationTitle": "You must provide an application title",
|
||||||
"components.Settings.SettingsMain.validationApplicationUrl": "You must provide a valid URL",
|
"components.Settings.SettingsMain.validationApplicationUrl": "You must provide a valid URL",
|
||||||
"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash": "URL must not end in a trailing slash",
|
"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash": "URL must not end in a trailing slash",
|
||||||
|
"components.Settings.SettingsMain.validationUrl": "You must provide a valid URL",
|
||||||
|
"components.Settings.SettingsMain.validationUrlTrailingSlash": "URL must not end in a trailing slash",
|
||||||
|
"components.Settings.SettingsMain.youtubeUrl": "YouTube URL",
|
||||||
"components.Settings.SettingsNetwork.csrfProtection": "Enable CSRF Protection",
|
"components.Settings.SettingsNetwork.csrfProtection": "Enable CSRF Protection",
|
||||||
"components.Settings.SettingsNetwork.csrfProtectionHoverTip": "Do NOT enable this setting unless you understand what you are doing!",
|
"components.Settings.SettingsNetwork.csrfProtectionHoverTip": "Do NOT enable this setting unless you understand what you are doing!",
|
||||||
"components.Settings.SettingsNetwork.csrfProtectionTip": "Set external API access to read-only (requires HTTPS)",
|
"components.Settings.SettingsNetwork.csrfProtectionTip": "Set external API access to read-only (requires HTTPS)",
|
||||||
|
|||||||
@@ -248,6 +248,7 @@ CoreApp.getInitialProps = async (initialProps) => {
|
|||||||
locale: 'en',
|
locale: 'en',
|
||||||
emailEnabled: false,
|
emailEnabled: false,
|
||||||
newPlexLogin: true,
|
newPlexLogin: true,
|
||||||
|
youtubeUrl: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
if (ctx.res) {
|
if (ctx.res) {
|
||||||
|
|||||||
Reference in New Issue
Block a user