From 3e52375da4e4137590fe056a2ab96d5d7fc09f52 Mon Sep 17 00:00:00 2001 From: Malik Kennedy Date: Tue, 25 Feb 2025 11:36:43 -0500 Subject: [PATCH] Add Library UI to support custom resolvers --- .../libraryoptionseditor.js | 93 ++++++++++++++++++- .../libraryoptionseditor.template.html | 3 + src/strings/en-us.json | 1 + 3 files changed, 95 insertions(+), 2 deletions(-) diff --git a/src/components/libraryoptionseditor/libraryoptionseditor.js b/src/components/libraryoptionseditor/libraryoptionseditor.js index 67c8e3a012..901f28517b 100644 --- a/src/components/libraryoptionseditor/libraryoptionseditor.js +++ b/src/components/libraryoptionseditor/libraryoptionseditor.js @@ -119,6 +119,21 @@ function renderMetadataSavers(page, metadataSavers) { return true; } +function renderMetadataResolvers(page, availableOptions, libraryOptions) { + let html = ''; + const elem = page.querySelector('.metadataResolvers'); + for (const availableTypeOptions of availableOptions.TypeOptions) { + html += getMetadataResolversForTypeHtml(availableTypeOptions, getTypeOptions(libraryOptions, availableTypeOptions.Type) || {}); + } + elem.innerHTML = html; + if (html) { + elem.classList.remove('hide'); + } else { + elem.classList.add('hide'); + } + return true; +} + function getMetadataFetchersForTypeHtml(availableTypeOptions, libraryOptionsForType) { let html = ''; let plugins = availableTypeOptions.MetadataFetchers; @@ -154,6 +169,41 @@ function getMetadataFetchersForTypeHtml(availableTypeOptions, libraryOptionsForT return html; } +function getMetadataResolversForTypeHtml(availableTypeOptions, libraryOptionsForType) { + let html = ''; + let plugins = availableTypeOptions.MetadataResolvers; + + plugins = getOrderedPlugins(plugins, libraryOptionsForType.MetadataResolverOrder || []); + if (!plugins.length) return html; + + html += '
'; + html += '

' + globalize.translate('LabelTypeMetadataResolvers', globalize.translate('TypeOptionPlural' + availableTypeOptions.Type)) + '

'; + html += '
'; + + plugins.forEach((plugin, index) => { + html += '
'; + const isChecked = libraryOptionsForType.MetadataResolvers ? libraryOptionsForType.MetadataResolvers.includes(plugin.Name) : plugin.DefaultEnabled; + const checkedHtml = isChecked ? ' checked="checked"' : ''; + html += ''; + html += '
'; + html += '

'; + html += escapeHtml(plugin.Name); + html += '

'; + html += '
'; + if (index > 0) { + html += ''; + } else if (plugins.length > 1) { + html += ''; + } + html += '
'; + }); + + html += '
'; + html += '
' + globalize.translate('LabelMetadataResolversHelp') + '
'; + html += '
'; + return html; +} + function getTypeOptions(allOptions, type) { const allTypeOptions = allOptions.TypeOptions || []; for (const typeOptions of allTypeOptions) { @@ -191,7 +241,7 @@ function renderSubtitleFetchers(page, availableOptions, libraryOptions) { plugins = getOrderedPlugins(plugins, libraryOptions.SubtitleFetcherOrder || []); if (!plugins.length) return html; - html += `

${globalize.translate('LabelSubtitleDownloaders')}

`; + html += `

${globalize.translate('LabelSubtitleResolvers')}

`; html += '
'; for (let i = 0; i < plugins.length; i++) { const plugin = plugins[i]; @@ -212,7 +262,7 @@ function renderSubtitleFetchers(page, availableOptions, libraryOptions) { html += '
'; } html += ''; - html += `
${globalize.translate('SubtitleDownloadersHelp')}
`; + html += `
${globalize.translate('SubtitleResolversHelp')}
`; elem.innerHTML = html; } @@ -349,6 +399,7 @@ function populateMetadataSettings(parent, contentType) { currentAvailableOptions = availableOptions; parent.availableOptions = availableOptions; renderMetadataSavers(parent, availableOptions.MetadataSavers); + renderMetadataResolvers(parent, availableOptions.MetadataResolvers); renderMetadataReaders(parent, availableOptions.MetadataReaders); renderMetadataFetchers(parent, availableOptions, {}); renderSubtitleFetchers(parent, availableOptions, {}); @@ -581,6 +632,29 @@ function setMetadataFetchersIntoOptions(parent, options) { } } +function setMetadataResolversIntoOptions(parent, options) { + const sections = parent.querySelectorAll('.metadataResolver'); + for (const section of sections) { + const type = section.getAttribute('data-type'); + let typeOptions = getTypeOptions(options, type); + if (!typeOptions) { + typeOptions = { + Type: type + }; + options.TypeOptions.push(typeOptions); + } + typeOptions.MetadataResolvers = Array.prototype.map.call(Array.prototype.filter.call(section.querySelectorAll('.chkMetadataResolver'), elem => { + return elem.checked; + }), elem => { + return elem.getAttribute('data-pluginname'); + }); + + typeOptions.MetadataResolverOrder = Array.prototype.map.call(section.querySelectorAll('.metadataResolverItem'), elem => { + return elem.getAttribute('data-pluginname'); + }); + } +} + function setImageFetchersIntoOptions(parent, options) { const sections = parent.querySelectorAll('.imageFetcher'); for (const section of sections) { @@ -656,6 +730,16 @@ export function getLibraryOptions(parent) { }), elem => { return elem.getAttribute('data-pluginname'); }), + MetadataResolvers: Array.prototype.map.call(Array.prototype.filter.call(parent.querySelectorAll('.chkMetadataResolver'), elem => { + return elem.checked; + }), elem => { + return elem.getAttribute('data-pluginname'); + }), + MetadataResolvers: Array.prototype.map.call(Array.prototype.filter.call(parent.querySelectorAll('.chkMetadataResolver'), elem => { + return elem.checked; + }), elem => { + return elem.getAttribute('data-pluginname'); + }), TypeOptions: [] }; @@ -673,6 +757,7 @@ export function getLibraryOptions(parent) { setLyricFetchersIntoOptions(parent, options); setMediaSegmentProvidersIntoOptions(parent, options); setMetadataFetchersIntoOptions(parent, options); + setMetadataResolversIntoOptions(parent, options); setImageFetchersIntoOptions(parent, options); setImageOptionsIntoOptions(options); @@ -723,6 +808,9 @@ export function setLibraryOptions(parent, options) { Array.prototype.forEach.call(parent.querySelectorAll('.chkMetadataSaver'), elem => { elem.checked = options.MetadataSavers ? options.MetadataSavers.includes(elem.getAttribute('data-pluginname')) : elem.getAttribute('data-defaultenabled') === 'true'; }); + Array.prototype.forEach.call(parent.querySelectorAll('.chkMetadataResolver'), elem => { + elem.checked = options.MetadataResolvers ? options.MetadataResolvers.includes(elem.getAttribute('data-pluginname')) : elem.getAttribute('data-defaultenabled') === 'true'; + }); Array.prototype.forEach.call(parent.querySelectorAll('.chkSubtitleLanguage'), elem => { elem.checked = !!options.SubtitleDownloadLanguages && options.SubtitleDownloadLanguages.includes(elem.getAttribute('data-lang')); }); @@ -730,6 +818,7 @@ export function setLibraryOptions(parent, options) { parent.querySelector('#tagDelimiterWhitelist').value = options.DelimiterWhitelist.filter(item => item.trim()).join('\n'); renderMetadataReaders(parent, getOrderedPlugins(parent.availableOptions.MetadataReaders, options.LocalMetadataReaderOrder || [])); renderMetadataFetchers(parent, parent.availableOptions, options); + renderMetadataResolvers(parent, parent.availableOptions, options); renderImageFetchers(parent, parent.availableOptions, options); renderSubtitleFetchers(parent, parent.availableOptions, options); renderLyricFetchers(parent, parent.availableOptions, options); diff --git a/src/components/libraryoptionseditor/libraryoptionseditor.template.html b/src/components/libraryoptionseditor/libraryoptionseditor.template.html index f487bc482b..8617327c9d 100644 --- a/src/components/libraryoptionseditor/libraryoptionseditor.template.html +++ b/src/components/libraryoptionseditor/libraryoptionseditor.template.html @@ -7,6 +7,9 @@
${EnableLibraryHelp}
+
+
+
diff --git a/src/strings/en-us.json b/src/strings/en-us.json index 5377cbd88a..5368064ef5 100644 --- a/src/strings/en-us.json +++ b/src/strings/en-us.json @@ -753,6 +753,7 @@ "LabelLanguage": "Language", "LabelLanNetworks": "LAN networks", "LabelLevel": "Level", + "LabelLibraryScannerSelectionSetting": "Folder to Metadata Translaters", "LabelLibraryPageSize": "Library page size", "LabelLibraryPageSizeHelp": "Set the amount of items to show on a library page. Set to 0 in order to disable paging.", "LabelMaxDaysForNextUp": "Max days in 'Next Up'",