From b3de4afc848e67e15a4e6bf9218e6de837b5b2e6 Mon Sep 17 00:00:00 2001
From: viown <48097677+viown@users.noreply.github.com>
Date: Thu, 27 Mar 2025 20:06:11 +0300
Subject: [PATCH] Migrate transcoding page to React
---
.../controllers/encodingsettings.html | 407 --------
.../dashboard/controllers/encodingsettings.js | 309 ------
.../features/playback/constants/codecs.ts | 113 +++
src/apps/dashboard/routes/_asyncRoutes.ts | 1 +
src/apps/dashboard/routes/_legacyRoutes.ts | 7 -
.../dashboard/routes/libraries/display.tsx | 7 +-
src/apps/dashboard/routes/libraries/nfo.tsx | 23 +-
src/apps/dashboard/routes/playback/resume.tsx | 2 +-
.../dashboard/routes/playback/streaming.tsx | 2 +-
.../dashboard/routes/playback/transcoding.tsx | 899 ++++++++++++++++++
src/hooks/useNamedConfiguration.ts | 6 +-
src/strings/en-us.json | 3 +-
12 files changed, 1031 insertions(+), 748 deletions(-)
delete mode 100644 src/apps/dashboard/controllers/encodingsettings.html
delete mode 100644 src/apps/dashboard/controllers/encodingsettings.js
create mode 100644 src/apps/dashboard/features/playback/constants/codecs.ts
create mode 100644 src/apps/dashboard/routes/playback/transcoding.tsx
diff --git a/src/apps/dashboard/controllers/encodingsettings.html b/src/apps/dashboard/controllers/encodingsettings.html
deleted file mode 100644
index 962c625ed2..0000000000
--- a/src/apps/dashboard/controllers/encodingsettings.html
+++ /dev/null
@@ -1,407 +0,0 @@
-
diff --git a/src/apps/dashboard/controllers/encodingsettings.js b/src/apps/dashboard/controllers/encodingsettings.js
deleted file mode 100644
index 6ae4fdbb28..0000000000
--- a/src/apps/dashboard/controllers/encodingsettings.js
+++ /dev/null
@@ -1,309 +0,0 @@
-import 'jquery';
-import loading from 'components/loading/loading';
-import globalize from 'lib/globalize';
-import dom from 'scripts/dom';
-import Dashboard from 'utils/dashboard';
-import alert from 'components/alert';
-
-function loadPage(page, config, systemInfo) {
- Array.prototype.forEach.call(page.querySelectorAll('.chkDecodeCodec'), function (c) {
- c.checked = (config.HardwareDecodingCodecs || []).indexOf(c.getAttribute('data-codec')) !== -1;
- });
- page.querySelector('#chkDecodingColorDepth10Hevc').checked = config.EnableDecodingColorDepth10Hevc;
- page.querySelector('#chkDecodingColorDepth10Vp9').checked = config.EnableDecodingColorDepth10Vp9;
- page.querySelector('#chkDecodingColorDepth10HevcRext').checked = config.EnableDecodingColorDepth10HevcRext;
- page.querySelector('#chkDecodingColorDepth12HevcRext').checked = config.EnableDecodingColorDepth12HevcRext;
- page.querySelector('#chkEnhancedNvdecDecoder').checked = config.EnableEnhancedNvdecDecoder;
- page.querySelector('#chkSystemNativeHwDecoder').checked = config.PreferSystemNativeHwDecoder;
- page.querySelector('#chkIntelLpH264HwEncoder').checked = config.EnableIntelLowPowerH264HwEncoder;
- page.querySelector('#chkIntelLpHevcHwEncoder').checked = config.EnableIntelLowPowerHevcHwEncoder;
- page.querySelector('#chkHardwareEncoding').checked = config.EnableHardwareEncoding;
- page.querySelector('#chkAllowHevcEncoding').checked = config.AllowHevcEncoding;
- page.querySelector('#chkAllowAv1Encoding').checked = config.AllowAv1Encoding;
- page.querySelector('#selectVideoDecoder').value = config.HardwareAccelerationType || 'none';
- page.querySelector('#selectThreadCount').value = config.EncodingThreadCount;
- page.querySelector('#chkEnableAudioVbr').checked = config.EnableAudioVbr;
- page.querySelector('#txtDownMixAudioBoost').value = config.DownMixAudioBoost;
- page.querySelector('#selectStereoDownmixAlgorithm').value = config.DownMixStereoAlgorithm || 'None';
- page.querySelector('#txtMaxMuxingQueueSize').value = config.MaxMuxingQueueSize || '';
- page.querySelector('.txtEncoderPath').value = config.EncoderAppPathDisplay || '';
- page.querySelector('#txtTranscodingTempPath').value = systemInfo.TranscodingTempPath || '';
- page.querySelector('#txtFallbackFontPath').value = config.FallbackFontPath || '';
- page.querySelector('#chkEnableFallbackFont').checked = config.EnableFallbackFont;
- page.querySelector('#txtVaapiDevice').value = config.VaapiDevice || '';
- page.querySelector('#txtQsvDevice').value = config.QsvDevice || '';
- page.querySelector('#chkTonemapping').checked = config.EnableTonemapping;
- page.querySelector('#chkVppTonemapping').checked = config.EnableVppTonemapping;
- page.querySelector('#chkVideoToolboxTonemapping').checked = config.EnableVideoToolboxTonemapping;
- page.querySelector('#selectTonemappingAlgorithm').value = config.TonemappingAlgorithm || 'none';
- page.querySelector('#selectTonemappingMode').value = config.TonemappingMode || 'auto';
- page.querySelector('#selectTonemappingRange').value = config.TonemappingRange || 'auto';
- page.querySelector('#txtTonemappingDesat').value = config.TonemappingDesat;
- page.querySelector('#txtTonemappingPeak').value = config.TonemappingPeak;
- page.querySelector('#txtTonemappingParam').value = config.TonemappingParam || '';
- page.querySelector('#txtVppTonemappingBrightness').value = config.VppTonemappingBrightness;
- page.querySelector('#txtVppTonemappingContrast').value = config.VppTonemappingContrast;
- page.querySelector('#selectEncoderPreset').value = config.EncoderPreset || 'auto';
- page.querySelector('#txtH264Crf').value = config.H264Crf || '';
- page.querySelector('#txtH265Crf').value = config.H265Crf || '';
- page.querySelector('#selectDeinterlaceMethod').value = config.DeinterlaceMethod || 'yadif';
- page.querySelector('#chkDoubleRateDeinterlacing').checked = config.DeinterlaceDoubleRate;
- page.querySelector('#chkEnableSubtitleExtraction').checked = config.EnableSubtitleExtraction || false;
- page.querySelector('#chkEnableThrottling').checked = config.EnableThrottling || false;
- page.querySelector('#chkEnableSegmentDeletion').checked = config.EnableSegmentDeletion || false;
- page.querySelector('#txtThrottleDelaySeconds').value = config.ThrottleDelaySeconds || '';
- page.querySelector('#txtSegmentKeepSeconds').value = config.SegmentKeepSeconds || '';
- page.querySelector('#selectVideoDecoder').dispatchEvent(new CustomEvent('change', {
- bubbles: true
- }));
- loading.hide();
-}
-
-function onSaveEncodingPathFailure() {
- loading.hide();
- alert(globalize.translate('FFmpegSavePathNotFound'));
-}
-
-function updateEncoder(form) {
- return ApiClient.getSystemInfo().then(function () {
- return ApiClient.ajax({
- url: ApiClient.getUrl('System/MediaEncoder/Path'),
- type: 'POST',
- data: JSON.stringify({
- Path: form.querySelector('.txtEncoderPath').value,
- PathType: 'Custom'
- }),
- contentType: 'application/json'
- }).then(Dashboard.processServerConfigurationUpdateResult, onSaveEncodingPathFailure);
- });
-}
-
-function onSubmit() {
- const form = this;
-
- const onDecoderConfirmed = function () {
- loading.show();
- ApiClient.getNamedConfiguration('encoding').then(function (config) {
- config.EnableAudioVbr = form.querySelector('#chkEnableAudioVbr').checked;
- config.DownMixAudioBoost = form.querySelector('#txtDownMixAudioBoost').value;
- config.DownMixStereoAlgorithm = form.querySelector('#selectStereoDownmixAlgorithm').value || 'None';
- config.MaxMuxingQueueSize = form.querySelector('#txtMaxMuxingQueueSize').value;
- config.TranscodingTempPath = form.querySelector('#txtTranscodingTempPath').value;
- config.FallbackFontPath = form.querySelector('#txtFallbackFontPath').value;
- config.EnableFallbackFont = form.querySelector('#txtFallbackFontPath').value ? form.querySelector('#chkEnableFallbackFont').checked : false;
- config.EncodingThreadCount = form.querySelector('#selectThreadCount').value;
- config.HardwareAccelerationType = form.querySelector('#selectVideoDecoder').value;
- config.VaapiDevice = form.querySelector('#txtVaapiDevice').value;
- config.QsvDevice = form.querySelector('#txtQsvDevice').value;
- config.EnableTonemapping = form.querySelector('#chkTonemapping').checked;
- config.EnableVppTonemapping = form.querySelector('#chkVppTonemapping').checked;
- config.EnableVideoToolboxTonemapping = form.querySelector('#chkVideoToolboxTonemapping').checked;
- config.TonemappingAlgorithm = form.querySelector('#selectTonemappingAlgorithm').value;
- config.TonemappingMode = form.querySelector('#selectTonemappingMode').value;
- config.TonemappingRange = form.querySelector('#selectTonemappingRange').value;
- config.TonemappingDesat = form.querySelector('#txtTonemappingDesat').value;
- config.TonemappingPeak = form.querySelector('#txtTonemappingPeak').value;
- config.TonemappingParam = form.querySelector('#txtTonemappingParam').value || '0';
- config.VppTonemappingBrightness = form.querySelector('#txtVppTonemappingBrightness').value;
- config.VppTonemappingContrast = form.querySelector('#txtVppTonemappingContrast').value;
- config.EncoderPreset = form.querySelector('#selectEncoderPreset').value;
- config.H264Crf = parseInt(form.querySelector('#txtH264Crf').value || '0', 10);
- config.H265Crf = parseInt(form.querySelector('#txtH265Crf').value || '0', 10);
- config.DeinterlaceMethod = form.querySelector('#selectDeinterlaceMethod').value;
- config.DeinterlaceDoubleRate = form.querySelector('#chkDoubleRateDeinterlacing').checked;
- config.EnableSubtitleExtraction = form.querySelector('#chkEnableSubtitleExtraction').checked;
- config.EnableThrottling = form.querySelector('#chkEnableThrottling').checked;
- config.EnableSegmentDeletion = form.querySelector('#chkEnableSegmentDeletion').checked;
- config.ThrottleDelaySeconds = parseInt(form.querySelector('#txtThrottleDelaySeconds').value || '0', 10);
- config.SegmentKeepSeconds = parseInt(form.querySelector('#txtSegmentKeepSeconds').value || '0', 10);
- config.HardwareDecodingCodecs = Array.prototype.map.call(Array.prototype.filter.call(form.querySelectorAll('.chkDecodeCodec'), function (c) {
- return c.checked;
- }), function (c) {
- return c.getAttribute('data-codec');
- });
- config.EnableDecodingColorDepth10Hevc = form.querySelector('#chkDecodingColorDepth10Hevc').checked;
- config.EnableDecodingColorDepth10Vp9 = form.querySelector('#chkDecodingColorDepth10Vp9').checked;
- config.EnableDecodingColorDepth10HevcRext = form.querySelector('#chkDecodingColorDepth10HevcRext').checked;
- config.EnableDecodingColorDepth12HevcRext = form.querySelector('#chkDecodingColorDepth12HevcRext').checked;
- config.EnableEnhancedNvdecDecoder = form.querySelector('#chkEnhancedNvdecDecoder').checked;
- config.PreferSystemNativeHwDecoder = form.querySelector('#chkSystemNativeHwDecoder').checked;
- config.EnableIntelLowPowerH264HwEncoder = form.querySelector('#chkIntelLpH264HwEncoder').checked;
- config.EnableIntelLowPowerHevcHwEncoder = form.querySelector('#chkIntelLpHevcHwEncoder').checked;
- config.EnableHardwareEncoding = form.querySelector('#chkHardwareEncoding').checked;
- config.AllowHevcEncoding = form.querySelector('#chkAllowHevcEncoding').checked;
- config.AllowAv1Encoding = form.querySelector('#chkAllowAv1Encoding').checked;
- ApiClient.updateNamedConfiguration('encoding', config).then(function () {
- updateEncoder(form);
- }, function () {
- alert(globalize.translate('ErrorDefault'));
- Dashboard.processServerConfigurationUpdateResult();
- });
- });
- };
-
- if (form.querySelector('#selectVideoDecoder').value !== 'none') {
- alert({
- title: globalize.translate('TitleHardwareAcceleration'),
- text: globalize.translate('HardwareAccelerationWarning')
- }).then(onDecoderConfirmed);
- } else {
- onDecoderConfirmed();
- }
-
- return false;
-}
-
-function setDecodingCodecsVisible(context, value) {
- value = value || '';
- let any;
- Array.prototype.forEach.call(context.querySelectorAll('.chkDecodeCodec'), function (c) {
- if (c.getAttribute('data-types').split(',').indexOf(value) === -1) {
- dom.parentWithTag(c, 'LABEL').classList.add('hide');
- } else {
- dom.parentWithTag(c, 'LABEL').classList.remove('hide');
- any = true;
- }
- });
-
- if (any) {
- context.querySelector('.decodingCodecsList').classList.remove('hide');
- } else {
- context.querySelector('.decodingCodecsList').classList.add('hide');
- }
-}
-
-let systemInfo;
-function getSystemInfo() {
- return systemInfo ? Promise.resolve(systemInfo) : ApiClient.getPublicSystemInfo().then(
- info => {
- systemInfo = info;
- return info;
- }
- );
-}
-
-$(document).on('pageinit', '#encodingSettingsPage', function () {
- const page = this;
- getSystemInfo();
- page.querySelector('#selectVideoDecoder').addEventListener('change', function () {
- if (this.value == 'vaapi') {
- page.querySelector('.fldVaapiDevice').classList.remove('hide');
- page.querySelector('#txtVaapiDevice').setAttribute('required', 'required');
- } else {
- page.querySelector('.fldVaapiDevice').classList.add('hide');
- page.querySelector('#txtVaapiDevice').removeAttribute('required');
- }
-
- if (this.value == 'amf' || this.value == 'nvenc' || this.value == 'qsv' || this.value == 'vaapi' || this.value == 'rkmpp') {
- page.querySelector('.fld10bitHevcVp9HwDecoding').classList.remove('hide');
- } else {
- page.querySelector('.fld10bitHevcVp9HwDecoding').classList.add('hide');
- }
-
- if (this.value == 'nvenc' || this.value == 'qsv' || this.value == 'vaapi') {
- page.querySelector('.fldHevcRextHwDecoding').classList.remove('hide');
- } else {
- page.querySelector('.fldHevcRextHwDecoding').classList.add('hide');
- }
-
- const isHwaSelected = [ 'amf', 'nvenc', 'qsv', 'vaapi', 'rkmpp', 'videotoolbox' ].includes(this.value);
- if (this.value === 'none') {
- page.querySelector('.tonemappingOptions').classList.remove('hide');
- page.querySelector('.fldTonemapCheckbox').classList.add('hide');
- } else if (isHwaSelected) {
- page.querySelector('.tonemappingOptions').classList.remove('hide');
- page.querySelector('.fldTonemapCheckbox').classList.remove('hide');
- } else {
- page.querySelector('.tonemappingOptions').classList.add('hide');
- page.querySelector('.fldTonemapCheckbox').classList.add('hide');
- }
-
- page.querySelector('.tonemappingModeOptions').classList.toggle('hide', !isHwaSelected);
- page.querySelector('.allowTonemappingHardwareHelp').classList.toggle('hide', !isHwaSelected);
- page.querySelector('.allowTonemappingSoftwareHelp').classList.toggle('hide', isHwaSelected);
-
- if (this.value == 'qsv' || this.value == 'vaapi') {
- page.querySelector('.fldIntelLp').classList.remove('hide');
- } else {
- page.querySelector('.fldIntelLp').classList.add('hide');
- }
-
- if (this.value === 'videotoolbox') {
- page.querySelector('.videoToolboxTonemappingOptions').classList.remove('hide');
- } else {
- page.querySelector('.videoToolboxTonemappingOptions').classList.add('hide');
- }
-
- if (this.value == 'qsv' || this.value == 'vaapi') {
- page.querySelector('.vppTonemappingOptions').classList.remove('hide');
- } else {
- page.querySelector('.vppTonemappingOptions').classList.add('hide');
- }
-
- if (this.value == 'qsv') {
- page.querySelector('.fldSysNativeHwDecoder').classList.remove('hide');
- page.querySelector('.fldQsvDevice').classList.remove('hide');
- } else {
- page.querySelector('.fldSysNativeHwDecoder').classList.add('hide');
- page.querySelector('.fldQsvDevice').classList.add('hide');
- }
-
- if (this.value == 'nvenc') {
- page.querySelector('.fldEnhancedNvdec').classList.remove('hide');
- } else {
- page.querySelector('.fldEnhancedNvdec').classList.add('hide');
- }
-
- if (this.value !== 'none') {
- page.querySelector('.hardwareAccelerationOptions').classList.remove('hide');
- } else {
- page.querySelector('.hardwareAccelerationOptions').classList.add('hide');
- }
-
- setDecodingCodecsVisible(page, this.value);
- });
- $('#btnSelectTranscodingTempPath', page).on('click.selectDirectory', function () {
- import('components/directorybrowser/directorybrowser').then(({ default: DirectoryBrowser }) => {
- const picker = new DirectoryBrowser();
- picker.show({
- callback: function (path) {
- if (path) {
- page.querySelector('#txtTranscodingTempPath').value = path;
- }
-
- picker.close();
- },
- validateWriteable: true,
- header: globalize.translate('HeaderSelectTranscodingPath'),
- instruction: globalize.translate('HeaderSelectTranscodingPathHelp')
- });
- });
- });
- $('#btnSelectFallbackFontPath', page).on('click.selectDirectory', function () {
- import('components/directorybrowser/directorybrowser').then(({ default: DirectoryBrowser }) => {
- const picker = new DirectoryBrowser();
- picker.show({
- includeDirectories: true,
- callback: function (path) {
- if (path) {
- page.querySelector('#txtFallbackFontPath').value = path;
- }
-
- picker.close();
- },
- header: globalize.translate('HeaderSelectFallbackFontPath'),
- instruction: globalize.translate('HeaderSelectFallbackFontPathHelp')
- });
- });
- });
- $('.encodingSettingsForm').off('submit', onSubmit).on('submit', onSubmit);
-}).on('pageshow', '#encodingSettingsPage', function () {
- loading.show();
- const page = this;
- ApiClient.getNamedConfiguration('encoding').then(function (config) {
- ApiClient.getSystemInfo().then(function (fetchedSystemInfo) {
- loadPage(page, config, fetchedSystemInfo);
- });
- });
-});
-
diff --git a/src/apps/dashboard/features/playback/constants/codecs.ts b/src/apps/dashboard/features/playback/constants/codecs.ts
new file mode 100644
index 0000000000..98b3e5fad5
--- /dev/null
+++ b/src/apps/dashboard/features/playback/constants/codecs.ts
@@ -0,0 +1,113 @@
+/** List of codecs and their supported hardware acceleration types */
+export const CODECS = [
+ {
+ name: 'H264',
+ codec: 'h264',
+ types: [
+ 'amf',
+ 'nvenc',
+ 'qsv',
+ 'vaapi',
+ 'rkmpp',
+ 'videotoolbox',
+ 'v4l2m2m'
+ ]
+ },
+ {
+ name: 'HEVC',
+ codec: 'hevc',
+ types: [
+ 'amf',
+ 'nvenc',
+ 'qsv',
+ 'vaapi',
+ 'rkmpp',
+ 'videotoolbox'
+ ]
+ },
+ {
+ name: 'MPEG1',
+ codec: 'mpeg1video',
+ types: [ 'rkmpp' ]
+ },
+ {
+ name: 'MPEG2',
+ codec: 'mpeg2video',
+ types: [
+ 'amf',
+ 'nvenc',
+ 'qsv',
+ 'vaapi',
+ 'rkmpp'
+ ]
+ },
+ {
+ name: 'MPEG4',
+ codec: 'mpeg4',
+ types: [
+ 'nvenc',
+ 'rkmpp'
+ ]
+ },
+ {
+ name: 'VC1',
+ codec: 'vc1',
+ types: [
+ 'amf',
+ 'nvenc',
+ 'qsv',
+ 'vaapi'
+ ]
+ },
+ {
+ name: 'VP8',
+ codec: 'vp8',
+ types: [
+ 'nvenc',
+ 'qsv',
+ 'vaapi',
+ 'rkmpp',
+ 'videotoolbox'
+ ]
+ },
+ {
+ name: 'VP9',
+ codec: 'vp9',
+ types: [
+ 'amf',
+ 'nvenc',
+ 'qsv',
+ 'vaapi',
+ 'rkmpp',
+ 'videotoolbox'
+ ]
+ },
+ {
+ name: 'AV1',
+ codec: 'av1',
+ types: [
+ 'amf',
+ 'nvenc',
+ 'qsv',
+ 'vaapi',
+ 'rkmpp',
+ 'videotoolbox'
+ ]
+ }
+];
+
+/** Hardware decoders which support 10-bit HEVC & VP9 */
+export const HEVC_VP9_HW_DECODING_TYPES = [
+ 'amf',
+ 'nvenc',
+ 'qsv',
+ 'vaapi',
+ 'rkmpp'
+];
+
+/** Hardware decoders which support HEVC RExt */
+export const HEVC_REXT_DECODING_TYPES = [
+ 'nvenc',
+ 'qsv',
+ 'vaapi'
+];
diff --git a/src/apps/dashboard/routes/_asyncRoutes.ts b/src/apps/dashboard/routes/_asyncRoutes.ts
index 2ab21c5d4f..2fd77056f8 100644
--- a/src/apps/dashboard/routes/_asyncRoutes.ts
+++ b/src/apps/dashboard/routes/_asyncRoutes.ts
@@ -14,6 +14,7 @@ export const ASYNC_ADMIN_ROUTES: AsyncRoute[] = [
{ path: 'logs/:file', page: 'logs/file', type: AppType.Dashboard },
{ path: 'playback/resume', type: AppType.Dashboard },
{ path: 'playback/streaming', type: AppType.Dashboard },
+ { path: 'playback/transcoding', type: AppType.Dashboard },
{ path: 'playback/trickplay', type: AppType.Dashboard },
{ path: 'plugins/:pluginId', page: 'plugins/plugin', type: AppType.Dashboard },
{ path: 'tasks', type: AppType.Dashboard },
diff --git a/src/apps/dashboard/routes/_legacyRoutes.ts b/src/apps/dashboard/routes/_legacyRoutes.ts
index ceedb72651..e656d2d7c6 100644
--- a/src/apps/dashboard/routes/_legacyRoutes.ts
+++ b/src/apps/dashboard/routes/_legacyRoutes.ts
@@ -23,13 +23,6 @@ export const LEGACY_ADMIN_ROUTES: LegacyRoute[] = [
controller: 'library',
view: 'library.html'
}
- }, {
- path: 'playback/transcoding',
- pageProps: {
- appType: AppType.Dashboard,
- controller: 'encodingsettings',
- view: 'encodingsettings.html'
- }
}, {
path: 'plugins/catalog',
pageProps: {
diff --git a/src/apps/dashboard/routes/libraries/display.tsx b/src/apps/dashboard/routes/libraries/display.tsx
index 9cd0852c9b..7e47367acd 100644
--- a/src/apps/dashboard/routes/libraries/display.tsx
+++ b/src/apps/dashboard/routes/libraries/display.tsx
@@ -14,12 +14,13 @@ import Loading from 'components/loading/LoadingComponent';
import Page from 'components/Page';
import { getConfigurationApi } from '@jellyfin/sdk/lib/utils/api/configuration-api';
import { QUERY_KEY as CONFIG_QUERY_KEY, useConfiguration } from 'hooks/useConfiguration';
-import { QUERY_KEY as NAMED_CONFIG_QUERY_KEY, NamedConfiguration, useNamedConfiguration } from 'hooks/useNamedConfiguration';
+import { QUERY_KEY as NAMED_CONFIG_QUERY_KEY, useNamedConfiguration } from 'hooks/useNamedConfiguration';
import globalize from 'lib/globalize';
import { ServerConnections } from 'lib/jellyfin-apiclient';
import { type ActionFunctionArgs, Form, useActionData, useNavigation } from 'react-router-dom';
import { ActionData } from 'types/actionData';
import { queryClient } from 'utils/query/queryClient';
+import type { MetadataConfiguration } from '@jellyfin/sdk/lib/generated-client/models/metadata-configuration';
const CONFIG_KEY = 'metadata';
@@ -32,7 +33,7 @@ export const action = async ({ request }: ActionFunctionArgs) => {
const { data: config } = await getConfigurationApi(api).getConfiguration();
- const metadataConfig: NamedConfiguration = {
+ const metadataConfig: MetadataConfiguration = {
UseFileCreationTimeForDateAdded: data.DateAddedBehavior.toString() === '1'
};
@@ -70,7 +71,7 @@ export const Component = () => {
data: namedConfig,
isPending: isNamedConfigPending,
isError: isNamedConfigError
- } = useNamedConfiguration(CONFIG_KEY);
+ } = useNamedConfiguration(CONFIG_KEY);
const navigation = useNavigation();
const actionData = useActionData() as ActionData | undefined;
diff --git a/src/apps/dashboard/routes/libraries/nfo.tsx b/src/apps/dashboard/routes/libraries/nfo.tsx
index 326834a831..bbbaf6fdfd 100644
--- a/src/apps/dashboard/routes/libraries/nfo.tsx
+++ b/src/apps/dashboard/routes/libraries/nfo.tsx
@@ -21,17 +21,10 @@ import React, { useCallback, useState } from 'react';
import { type ActionFunctionArgs, Form, useActionData, useNavigation } from 'react-router-dom';
import { ActionData } from 'types/actionData';
import { queryClient } from 'utils/query/queryClient';
+import type { XbmcMetadataOptions } from '@jellyfin/sdk/lib/generated-client/models/xbmc-metadata-options';
const CONFIG_KEY = 'xbmcmetadata';
-interface NFOSettingsConfig {
- UserId?: string;
- EnableExtraThumbsDuplication?: boolean;
- EnablePathSubstitution?: boolean;
- ReleaseDateFormat?: string;
- SaveImagePathsInNfo?: boolean;
-};
-
export const action = async ({ request }: ActionFunctionArgs) => {
const api = ServerConnections.getCurrentApi();
if (!api) throw new Error('No Api instance available');
@@ -39,7 +32,7 @@ export const action = async ({ request }: ActionFunctionArgs) => {
const formData = await request.formData();
const data = Object.fromEntries(formData);
- const newConfig: NFOSettingsConfig = {
+ const newConfig: XbmcMetadataOptions = {
UserId: data.UserId?.toString(),
ReleaseDateFormat: 'yyyy-MM-dd',
SaveImagePathsInNfo: data.SaveImagePathsInNfo?.toString() === 'on',
@@ -64,7 +57,7 @@ export const Component = () => {
data: config,
isPending: isConfigPending,
isError: isConfigError
- } = useNamedConfiguration(CONFIG_KEY);
+ } = useNamedConfiguration(CONFIG_KEY);
const {
data: users,
isPending: isUsersPending,
@@ -75,8 +68,6 @@ export const Component = () => {
const isSubmitting = navigation.state === 'submitting';
const [isAlertOpen, setIsAlertOpen] = useState(false);
- const nfoConfig = config as NFOSettingsConfig;
-
const onAlertClose = useCallback(() => {
setIsAlertOpen(false);
}, []);
@@ -117,7 +108,7 @@ export const Component = () => {
{
control={
}
label={globalize.translate('LabelKodiMetadataSaveImagePaths')}
@@ -154,7 +145,7 @@ export const Component = () => {
control={
}
label={globalize.translate('LabelKodiMetadataEnablePathSubstitution')}
@@ -167,7 +158,7 @@ export const Component = () => {
control={
}
label={globalize.translate('LabelKodiMetadataEnableExtraThumbs')}
diff --git a/src/apps/dashboard/routes/playback/resume.tsx b/src/apps/dashboard/routes/playback/resume.tsx
index 6bd23a8ce7..76e5fce9e6 100644
--- a/src/apps/dashboard/routes/playback/resume.tsx
+++ b/src/apps/dashboard/routes/playback/resume.tsx
@@ -66,7 +66,7 @@ export const Component = () => {