diff --git a/src/apps/stable/features/playback/constants/mediaSegmentAction.ts b/src/apps/stable/features/playback/constants/mediaSegmentAction.ts new file mode 100644 index 0000000000..c1eb9652f0 --- /dev/null +++ b/src/apps/stable/features/playback/constants/mediaSegmentAction.ts @@ -0,0 +1,7 @@ +/** + * Actions that are triggered for media segments. + */ +export enum MediaSegmentAction { + None = 'None', + Skip = 'Skip' +} diff --git a/src/components/playbackSettings/playbackSettings.js b/src/components/playbackSettings/playbackSettings.js index 1461dbb54d..d9688a210a 100644 --- a/src/components/playbackSettings/playbackSettings.js +++ b/src/components/playbackSettings/playbackSettings.js @@ -1,3 +1,8 @@ +import { MediaSegmentType } from '@jellyfin/sdk/lib/generated-client/models/media-segment-type'; +import escapeHTML from 'escape-html'; + +import { MediaSegmentAction } from 'apps/stable/features/playback/constants/mediaSegmentAction'; + import appSettings from '../../scripts/settings/appSettings'; import { appHost } from '../apphost'; import browser from '../../scripts/browser'; @@ -6,12 +11,12 @@ import qualityoptions from '../qualityOptions'; import globalize from '../../lib/globalize'; import loading from '../loading/loading'; import Events from '../../utils/events.ts'; -import '../../elements/emby-select/emby-select'; -import '../../elements/emby-checkbox/emby-checkbox'; import ServerConnections from '../ServerConnections'; import toast from '../toast/toast'; import template from './playbackSettings.template.html'; -import escapeHTML from 'escape-html'; + +import '../../elements/emby-select/emby-select'; +import '../../elements/emby-checkbox/emby-checkbox'; function fillSkipLengths(select) { const options = [5, 10, 15, 20, 25, 30]; @@ -40,6 +45,37 @@ function populateLanguages(select, languages) { select.innerHTML = html; } +function populateMediaSegments(container, userSettings) { + const selectedValues = {}; + const actionOptions = Object.values(MediaSegmentAction) + .map(action => { + const actionLabel = globalize.translate(`MediaSegmentAction.${action}`); + return ``; + }) + .join(''); + + const segmentSettings = Object.values(MediaSegmentType) + .map(segmentType => { + const segmentTypeLabel = globalize.translate('LabelMediaSegmentsType', globalize.translate(`MediaSegmentType.${segmentType}`)); + const id = `segmentTypeAction__${segmentType}`; + selectedValues[id] = userSettings.get(id, false) || MediaSegmentAction.None; + return `
+ +
`; + }) + .join(''); + + container.innerHTML = segmentSettings; + + Object.entries(selectedValues) + .forEach(([id, value]) => { + const field = container.querySelector(`#${id}`); + if (field) field.value = value; + }); +} + function fillQuality(select, isInNetwork, mediatype, maxVideoWidth) { const options = mediatype === 'Audio' ? qualityoptions.getAudioQualityOptions({ @@ -219,6 +255,9 @@ function loadForm(context, user, userSettings, systemInfo, apiClient) { fillSkipLengths(selectSkipBackLength); selectSkipBackLength.value = userSettings.skipBackLength(); + const mediaSegmentContainer = context.querySelector('.mediaSegmentActionContainer'); + populateMediaSegments(mediaSegmentContainer, userSettings); + loading.hide(); } @@ -257,6 +296,11 @@ function saveUser(context, user, userSettingsInstance, apiClient) { userSettingsInstance.skipForwardLength(context.querySelector('.selectSkipForwardLength').value); userSettingsInstance.skipBackLength(context.querySelector('.selectSkipBackLength').value); + const segmentTypeActions = context.querySelectorAll('.segmentTypeAction') || []; + Array.prototype.forEach.call(segmentTypeActions, actionEl => { + userSettingsInstance.set(actionEl.id, actionEl.value, false); + }); + return apiClient.updateUserConfiguration(user.Id, user.Configuration); } diff --git a/src/components/playbackSettings/playbackSettings.template.html b/src/components/playbackSettings/playbackSettings.template.html index 0ad66b3c9a..ed1409eff0 100644 --- a/src/components/playbackSettings/playbackSettings.template.html +++ b/src/components/playbackSettings/playbackSettings.template.html @@ -156,6 +156,9 @@
+ +

${HeaderMediaSegmentActions}

+
diff --git a/src/controllers/user/playback/index.js b/src/controllers/user/playback/index.js index efb24c76ee..6f652be4a4 100644 --- a/src/controllers/user/playback/index.js +++ b/src/controllers/user/playback/index.js @@ -19,7 +19,7 @@ export default function (view, params) { } else { settingsInstance = new PlaybackSettings({ serverId: ApiClient.serverId(), - userId: userId, + userId, element: view.querySelector('.settingsContainer'), userSettings: currentSettings, enableSaveButton: true, diff --git a/src/strings/en-us.json b/src/strings/en-us.json index 88f0125fbc..8dd84f6110 100644 --- a/src/strings/en-us.json +++ b/src/strings/en-us.json @@ -446,6 +446,7 @@ "HeaderLyricDownloads": "Lyric Downloads", "HeaderMedia": "Media", "HeaderMediaFolders": "Media Folders", + "HeaderMediaSegmentActions": "Media Segment Actions", "HeaderMetadataSettings": "Metadata Settings", "HeaderMoreLikeThis": "More Like This", "HeaderMusicQuality": "Music Quality", @@ -751,6 +752,7 @@ "LabelMaxDaysForNextUpHelp": "Set the maximum amount of days a show should stay in the 'Next Up' list without watching it.", "LabelMaxVideoResolution": "Maximum Allowed Video Transcoding Resolution", "LabelMediaDetails": "Media details", + "LabelMediaSegmentsType": "{0} Segments", "LabelLineup": "Lineup", "LabelLocalCustomCss": "Custom CSS code for styling which applies to this client only. You may want to disable server custom CSS code.", "LabelLocalHttpServerPortNumber": "Local HTTP port number", @@ -1065,6 +1067,14 @@ "MediaInfoTitle": "Title", "MediaInfoVideoRange": "Video range", "MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", + "MediaSegmentAction.None": "None", + "MediaSegmentAction.Skip": "Skip", + "MediaSegmentType.Unknown": "Unknown", + "MediaSegmentType.Commercial": "Commercial", + "MediaSegmentType.Preview": "Preview", + "MediaSegmentType.Recap": "Recap", + "MediaSegmentType.Outro": "Outro", + "MediaSegmentType.Intro": "Intro", "Menu": "Menu", "MenuOpen": "Open Menu", "MenuClose": "Close Menu",