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:
parent
2290a78adf
commit
3e52375da4
3 changed files with 95 additions and 2 deletions
|
@ -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);
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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'",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue