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

Add Library UI to support custom resolvers

This commit is contained in:
Malik Kennedy 2025-02-25 11:36:43 -05:00
parent 2290a78adf
commit 3e52375da4
No known key found for this signature in database
3 changed files with 95 additions and 2 deletions

View file

@ -119,6 +119,21 @@ function renderMetadataSavers(page, metadataSavers) {
return true; 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) { function getMetadataFetchersForTypeHtml(availableTypeOptions, libraryOptionsForType) {
let html = ''; let html = '';
let plugins = availableTypeOptions.MetadataFetchers; let plugins = availableTypeOptions.MetadataFetchers;
@ -154,6 +169,41 @@ function getMetadataFetchersForTypeHtml(availableTypeOptions, libraryOptionsForT
return html; return html;
} }
function getMetadataResolversForTypeHtml(availableTypeOptions, libraryOptionsForType) {
let html = '';
let plugins = availableTypeOptions.MetadataResolvers;
plugins = getOrderedPlugins(plugins, libraryOptionsForType.MetadataResolverOrder || []);
if (!plugins.length) return html;
html += '<div class="metadataResolver" data-type="' + availableTypeOptions.Type + '">';
html += '<h3 class="checkboxListLabel">' + globalize.translate('LabelTypeMetadataResolvers', globalize.translate('TypeOptionPlural' + availableTypeOptions.Type)) + '</h3>';
html += '<div class="checkboxList paperList checkboxList-paperList">';
plugins.forEach((plugin, index) => {
html += '<div class="listItem metadataResolverItem sortableOption" data-pluginname="' + escapeHtml(plugin.Name) + '">';
const isChecked = libraryOptionsForType.MetadataResolvers ? libraryOptionsForType.MetadataResolvers.includes(plugin.Name) : plugin.DefaultEnabled;
const checkedHtml = isChecked ? ' checked="checked"' : '';
html += '<label class="listItemCheckboxContainer"><input type="checkbox" is="emby-checkbox" class="chkMetadataResolver" data-pluginname="' + escapeHtml(plugin.Name) + '" ' + checkedHtml + '><span></span></label>';
html += '<div class="listItemBody">';
html += '<h3 class="listItemBodyText">';
html += escapeHtml(plugin.Name);
html += '</h3>';
html += '</div>';
if (index > 0) {
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('Up') + '" class="btnSortableMoveUp btnSortable" data-pluginindex="' + index + '"><span class="material-icons keyboard_arrow_up" aria-hidden="true"></span></button>';
} else if (plugins.length > 1) {
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('Down') + '" class="btnSortableMoveDown btnSortable" data-pluginindex="' + index + '"><span class="material-icons keyboard_arrow_down" aria-hidden="true"></span></button>';
}
html += '</div>';
});
html += '</div>';
html += '<div class="fieldDescription">' + globalize.translate('LabelMetadataResolversHelp') + '</div>';
html += '</div>';
return html;
}
function getTypeOptions(allOptions, type) { function getTypeOptions(allOptions, type) {
const allTypeOptions = allOptions.TypeOptions || []; const allTypeOptions = allOptions.TypeOptions || [];
for (const typeOptions of allTypeOptions) { for (const typeOptions of allTypeOptions) {
@ -191,7 +241,7 @@ function renderSubtitleFetchers(page, availableOptions, libraryOptions) {
plugins = getOrderedPlugins(plugins, libraryOptions.SubtitleFetcherOrder || []); plugins = getOrderedPlugins(plugins, libraryOptions.SubtitleFetcherOrder || []);
if (!plugins.length) return html; if (!plugins.length) return html;
html += `<h3 class="checkboxListLabel">${globalize.translate('LabelSubtitleDownloaders')}</h3>`; html += `<h3 class="checkboxListLabel">${globalize.translate('LabelSubtitleResolvers')}</h3>`;
html += '<div class="checkboxList paperList checkboxList-paperList">'; html += '<div class="checkboxList paperList checkboxList-paperList">';
for (let i = 0; i < plugins.length; i++) { for (let i = 0; i < plugins.length; i++) {
const plugin = plugins[i]; const plugin = plugins[i];
@ -212,7 +262,7 @@ function renderSubtitleFetchers(page, availableOptions, libraryOptions) {
html += '</div>'; html += '</div>';
} }
html += '</div>'; html += '</div>';
html += `<div class="fieldDescription">${globalize.translate('SubtitleDownloadersHelp')}</div>`; html += `<div class="fieldDescription">${globalize.translate('SubtitleResolversHelp')}</div>`;
elem.innerHTML = html; elem.innerHTML = html;
} }
@ -349,6 +399,7 @@ function populateMetadataSettings(parent, contentType) {
currentAvailableOptions = availableOptions; currentAvailableOptions = availableOptions;
parent.availableOptions = availableOptions; parent.availableOptions = availableOptions;
renderMetadataSavers(parent, availableOptions.MetadataSavers); renderMetadataSavers(parent, availableOptions.MetadataSavers);
renderMetadataResolvers(parent, availableOptions.MetadataResolvers);
renderMetadataReaders(parent, availableOptions.MetadataReaders); renderMetadataReaders(parent, availableOptions.MetadataReaders);
renderMetadataFetchers(parent, availableOptions, {}); renderMetadataFetchers(parent, availableOptions, {});
renderSubtitleFetchers(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) { function setImageFetchersIntoOptions(parent, options) {
const sections = parent.querySelectorAll('.imageFetcher'); const sections = parent.querySelectorAll('.imageFetcher');
for (const section of sections) { for (const section of sections) {
@ -656,6 +730,16 @@ export function getLibraryOptions(parent) {
}), elem => { }), elem => {
return elem.getAttribute('data-pluginname'); 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: [] TypeOptions: []
}; };
@ -673,6 +757,7 @@ export function getLibraryOptions(parent) {
setLyricFetchersIntoOptions(parent, options); setLyricFetchersIntoOptions(parent, options);
setMediaSegmentProvidersIntoOptions(parent, options); setMediaSegmentProvidersIntoOptions(parent, options);
setMetadataFetchersIntoOptions(parent, options); setMetadataFetchersIntoOptions(parent, options);
setMetadataResolversIntoOptions(parent, options);
setImageFetchersIntoOptions(parent, options); setImageFetchersIntoOptions(parent, options);
setImageOptionsIntoOptions(options); setImageOptionsIntoOptions(options);
@ -723,6 +808,9 @@ export function setLibraryOptions(parent, options) {
Array.prototype.forEach.call(parent.querySelectorAll('.chkMetadataSaver'), elem => { Array.prototype.forEach.call(parent.querySelectorAll('.chkMetadataSaver'), elem => {
elem.checked = options.MetadataSavers ? options.MetadataSavers.includes(elem.getAttribute('data-pluginname')) : elem.getAttribute('data-defaultenabled') === 'true'; 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 => { Array.prototype.forEach.call(parent.querySelectorAll('.chkSubtitleLanguage'), elem => {
elem.checked = !!options.SubtitleDownloadLanguages && options.SubtitleDownloadLanguages.includes(elem.getAttribute('data-lang')); 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'); parent.querySelector('#tagDelimiterWhitelist').value = options.DelimiterWhitelist.filter(item => item.trim()).join('\n');
renderMetadataReaders(parent, getOrderedPlugins(parent.availableOptions.MetadataReaders, options.LocalMetadataReaderOrder || [])); renderMetadataReaders(parent, getOrderedPlugins(parent.availableOptions.MetadataReaders, options.LocalMetadataReaderOrder || []));
renderMetadataFetchers(parent, parent.availableOptions, options); renderMetadataFetchers(parent, parent.availableOptions, options);
renderMetadataResolvers(parent, parent.availableOptions, options);
renderImageFetchers(parent, parent.availableOptions, options); renderImageFetchers(parent, parent.availableOptions, options);
renderSubtitleFetchers(parent, parent.availableOptions, options); renderSubtitleFetchers(parent, parent.availableOptions, options);
renderLyricFetchers(parent, parent.availableOptions, options); renderLyricFetchers(parent, parent.availableOptions, options);

View file

@ -7,6 +7,9 @@
<div class="fieldDescription checkboxFieldDescription">${EnableLibraryHelp}</div> <div class="fieldDescription checkboxFieldDescription">${EnableLibraryHelp}</div>
</div> </div>
<div class="metadataResolvers advanced" style="margin-bottom: 2em;">
</div>
<div class="selectContainer fldMetadataLanguage hide"> <div class="selectContainer fldMetadataLanguage hide">
<select is="emby-select" id="selectLanguage" label="${LabelMetadataDownloadLanguage}"></select> <select is="emby-select" id="selectLanguage" label="${LabelMetadataDownloadLanguage}"></select>
</div> </div>

View file

@ -753,6 +753,7 @@
"LabelLanguage": "Language", "LabelLanguage": "Language",
"LabelLanNetworks": "LAN networks", "LabelLanNetworks": "LAN networks",
"LabelLevel": "Level", "LabelLevel": "Level",
"LabelLibraryScannerSelectionSetting": "Folder to Metadata Translaters",
"LabelLibraryPageSize": "Library page size", "LabelLibraryPageSize": "Library page size",
"LabelLibraryPageSizeHelp": "Set the amount of items to show on a library page. Set to 0 in order to disable paging.", "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'", "LabelMaxDaysForNextUp": "Max days in 'Next Up'",