1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

Add media segment action settings

This commit is contained in:
Bill Thornton 2024-09-25 16:55:53 -04:00
parent c6b4d41535
commit 809dba510a
5 changed files with 68 additions and 4 deletions

View file

@ -0,0 +1,7 @@
/**
* Actions that are triggered for media segments.
*/
export enum MediaSegmentAction {
None = 'None',
Skip = 'Skip'
}

View file

@ -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 appSettings from '../../scripts/settings/appSettings';
import { appHost } from '../apphost'; import { appHost } from '../apphost';
import browser from '../../scripts/browser'; import browser from '../../scripts/browser';
@ -6,12 +11,12 @@ import qualityoptions from '../qualityOptions';
import globalize from '../../lib/globalize'; import globalize from '../../lib/globalize';
import loading from '../loading/loading'; import loading from '../loading/loading';
import Events from '../../utils/events.ts'; import Events from '../../utils/events.ts';
import '../../elements/emby-select/emby-select';
import '../../elements/emby-checkbox/emby-checkbox';
import ServerConnections from '../ServerConnections'; import ServerConnections from '../ServerConnections';
import toast from '../toast/toast'; import toast from '../toast/toast';
import template from './playbackSettings.template.html'; 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) { function fillSkipLengths(select) {
const options = [5, 10, 15, 20, 25, 30]; const options = [5, 10, 15, 20, 25, 30];
@ -40,6 +45,37 @@ function populateLanguages(select, languages) {
select.innerHTML = html; select.innerHTML = html;
} }
function populateMediaSegments(container, userSettings) {
const selectedValues = {};
const actionOptions = Object.values(MediaSegmentAction)
.map(action => {
const actionLabel = globalize.translate(`MediaSegmentAction.${action}`);
return `<option value='${action}'>${actionLabel}</option>`;
})
.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 `<div class="selectContainer">
<select is="emby-select" id="${id}" class="segmentTypeAction" label="${segmentTypeLabel}">
${actionOptions}
</select>
</div>`;
})
.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) { function fillQuality(select, isInNetwork, mediatype, maxVideoWidth) {
const options = mediatype === 'Audio' ? qualityoptions.getAudioQualityOptions({ const options = mediatype === 'Audio' ? qualityoptions.getAudioQualityOptions({
@ -219,6 +255,9 @@ function loadForm(context, user, userSettings, systemInfo, apiClient) {
fillSkipLengths(selectSkipBackLength); fillSkipLengths(selectSkipBackLength);
selectSkipBackLength.value = userSettings.skipBackLength(); selectSkipBackLength.value = userSettings.skipBackLength();
const mediaSegmentContainer = context.querySelector('.mediaSegmentActionContainer');
populateMediaSegments(mediaSegmentContainer, userSettings);
loading.hide(); loading.hide();
} }
@ -257,6 +296,11 @@ function saveUser(context, user, userSettingsInstance, apiClient) {
userSettingsInstance.skipForwardLength(context.querySelector('.selectSkipForwardLength').value); userSettingsInstance.skipForwardLength(context.querySelector('.selectSkipForwardLength').value);
userSettingsInstance.skipBackLength(context.querySelector('.selectSkipBackLength').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); return apiClient.updateUserConfiguration(user.Id, user.Configuration);
} }

View file

@ -156,6 +156,9 @@
<div class="selectContainer"> <div class="selectContainer">
<select is="emby-select" class="selectSkipBackLength" label="${LabelSkipBackLength}"></select> <select is="emby-select" class="selectSkipBackLength" label="${LabelSkipBackLength}"></select>
</div> </div>
<h3 class="sectionTitle">${HeaderMediaSegmentActions}</h3>
<div class="mediaSegmentActionContainer"></div>
</div> </div>
<div class="verticalSection verticalSection-extrabottompadding"> <div class="verticalSection verticalSection-extrabottompadding">

View file

@ -19,7 +19,7 @@ export default function (view, params) {
} else { } else {
settingsInstance = new PlaybackSettings({ settingsInstance = new PlaybackSettings({
serverId: ApiClient.serverId(), serverId: ApiClient.serverId(),
userId: userId, userId,
element: view.querySelector('.settingsContainer'), element: view.querySelector('.settingsContainer'),
userSettings: currentSettings, userSettings: currentSettings,
enableSaveButton: true, enableSaveButton: true,

View file

@ -446,6 +446,7 @@
"HeaderLyricDownloads": "Lyric Downloads", "HeaderLyricDownloads": "Lyric Downloads",
"HeaderMedia": "Media", "HeaderMedia": "Media",
"HeaderMediaFolders": "Media Folders", "HeaderMediaFolders": "Media Folders",
"HeaderMediaSegmentActions": "Media Segment Actions",
"HeaderMetadataSettings": "Metadata Settings", "HeaderMetadataSettings": "Metadata Settings",
"HeaderMoreLikeThis": "More Like This", "HeaderMoreLikeThis": "More Like This",
"HeaderMusicQuality": "Music Quality", "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.", "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", "LabelMaxVideoResolution": "Maximum Allowed Video Transcoding Resolution",
"LabelMediaDetails": "Media details", "LabelMediaDetails": "Media details",
"LabelMediaSegmentsType": "{0} Segments",
"LabelLineup": "Lineup", "LabelLineup": "Lineup",
"LabelLocalCustomCss": "Custom CSS code for styling which applies to this client only. You may want to disable server custom CSS code.", "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", "LabelLocalHttpServerPortNumber": "Local HTTP port number",
@ -1065,6 +1067,14 @@
"MediaInfoTitle": "Title", "MediaInfoTitle": "Title",
"MediaInfoVideoRange": "Video range", "MediaInfoVideoRange": "Video range",
"MediaIsBeingConverted": "The media is being converted into a format that is compatible with the device that is playing the media.", "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", "Menu": "Menu",
"MenuOpen": "Open Menu", "MenuOpen": "Open Menu",
"MenuClose": "Close Menu", "MenuClose": "Close Menu",