Switch to opt-in

This commit is contained in:
Shadowghost
2026-08-02 18:02:22 +02:00
parent b94ba9d409
commit 4c812c9ba4
4 changed files with 34 additions and 42 deletions
@@ -58,12 +58,12 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
/// <summary>
/// Gets or sets the ids (the "N" formatted GUIDs from <c>VirtualFolderInfo.ItemId</c>) of the
/// libraries for which the unaired/missing episode provider is disabled. Whether episodes are
/// imported at all, and how, is still controlled by the global toggles above; this list only
/// opts individual libraries out. Libraries not listed here are enabled, so the global toggles
/// apply to every library unless it is explicitly opted out.
/// libraries for which the unaired/missing episode provider is enabled. Whether episodes are
/// imported at all, and how, is still controlled by the global toggles above; those toggles only
/// apply to the libraries listed here. Libraries not listed, including newly added ones, are
/// never processed, so an empty list disables the feature entirely.
/// </summary>
public string[] DisabledMissingEpisodeLibraries { get; set; } = [];
public string[] EnabledMissingEpisodeLibraries { get; set; } = [];
/// <summary>
/// Gets or sets how often, in days, the scheduled task re-checks TMDb for newly announced
@@ -56,7 +56,7 @@
</div>
<div class="verticalSection">
<h2>Libraries</h2>
<div class="fieldDescription" style="margin-bottom:1em;">Choose which TV libraries the unaired/missing episode options above apply to. The settings above are global; this only controls which libraries they run for. New libraries are enabled by default.</div>
<div class="fieldDescription" style="margin-bottom:1em;">Choose which TV libraries the unaired/missing episode options above apply to. The settings above are global; this only controls which libraries they run for. Libraries are opted in individually, so newly added libraries are not processed until they are enabled here.</div>
<div id="missingEpisodeLibraries"></div>
</div>
<div class="verticalSection">
@@ -119,7 +119,7 @@
Dashboard.showLoadingMsg();
var clientConfig, pluginConfig;
var populateMissingEpisodeLibraries = function (disabledLibraries) {
var populateMissingEpisodeLibraries = function (enabledLibraries) {
var container = document.querySelector('#missingEpisodeLibraries');
ApiClient.getVirtualFolders().then(function (folders) {
// Series only live in TV libraries (and mixed-content libraries, which report
@@ -134,7 +134,7 @@
}
container.innerHTML = tvLibraries.map(function (folder) {
var checked = disabledLibraries.indexOf(folder.ItemId) === -1 ? ' checked' : '';
var checked = enabledLibraries.indexOf(folder.ItemId) === -1 ? '' : ' checked';
return '<label class="checkboxContainer">'
+ '<input is="emby-checkbox" type="checkbox" class="missingEpisodeLibrary" data-library-id="' + folder.ItemId + '"' + checked + ' />'
+ '<span>' + folder.Name + '</span>'
@@ -216,7 +216,7 @@
document.querySelector('#hideMissingCastMembers').checked = config.HideMissingCastMembers;
document.querySelector('#hideMissingCrewMembers').checked = config.HideMissingCrewMembers;
populateMissingEpisodeLibraries(config.DisabledMissingEpisodeLibraries || []);
populateMissingEpisodeLibraries(config.EnabledMissingEpisodeLibraries || []);
var maxCastMembers = document.querySelector('#maxCastMembers');
maxCastMembers.value = config.MaxCastMembers;
@@ -258,9 +258,12 @@
config.ImportSpecials = document.querySelector('#importSpecials').checked;
config.MissingEpisodeRefreshIntervalDays = parseInt(document.querySelector('#missingEpisodeRefreshIntervalDays').value, 10);
config.UpcomingEpisodeGracePeriodDays = parseInt(document.querySelector('#upcomingEpisodeGracePeriodDays').value, 10);
config.DisabledMissingEpisodeLibraries = Array.prototype.map.call(
document.querySelectorAll('.missingEpisodeLibrary:not(:checked)'),
function (checkbox) { return checkbox.getAttribute('data-library-id'); });
var libraryCheckboxes = document.querySelectorAll('.missingEpisodeLibrary');
if (libraryCheckboxes.length > 0) {
config.EnabledMissingEpisodeLibraries = Array.prototype.filter
.call(libraryCheckboxes, function (checkbox) { return checkbox.checked; })
.map(function (checkbox) { return checkbox.getAttribute('data-library-id'); });
}
config.MaxCastMembers = document.querySelector('#maxCastMembers').value;
config.MaxCrewMembers = document.querySelector('#maxCrewMembers').value;
config.HideMissingCastMembers = document.querySelector('#hideMissingCastMembers').checked;
@@ -75,8 +75,8 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
var importMissing = (configuration?.ImportMissingEpisodes).GetValueOrDefault();
// The provider is inactive for this series when both global imports are off, or the series'
// library has been opted out. In either case remove every virtual episode (unaired and missing
// alike) it previously created, so disabling the feature cleans up on the next library scan.
// library has not been opted in. In either case remove every virtual episode (unaired and
// missing alike) it previously created, so disabling the feature cleans up on the next scan.
if ((!importUnaired && !importMissing) || !IsEnabledForLibrary(item))
{
if (!PruneAllVirtualEpisodes(item))
@@ -352,22 +352,16 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
private bool IsEnabledForLibrary(BaseItem item)
{
var disabledLibraries = Plugin.Instance?.Configuration.DisabledMissingEpisodeLibraries;
if (disabledLibraries is null || disabledLibraries.Length == 0)
var enabledLibraries = Plugin.Instance?.Configuration.EnabledMissingEpisodeLibraries;
if (enabledLibraries is null || enabledLibraries.Length == 0)
{
return true;
return false;
}
// A series can live under more than one collection folder; treat it as disabled only when
// every containing library is opted out.
var collectionFolders = _libraryManager.GetCollectionFolders(item);
if (collectionFolders.Count == 0)
{
return true;
}
return collectionFolders.Any(folder =>
!disabledLibraries.Contains(folder.Id.ToString("N", CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase));
// A series can live under more than one collection folder; opting in any one of them is
// enough. An item that belongs to no collection folder cannot be opted in at all.
return _libraryManager.GetCollectionFolders(item).Any(folder =>
enabledLibraries.Contains(folder.Id.ToString("N", CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase));
}
private (HashSet<(int Season, int Episode)> Keys, Dictionary<(int Season, int Episode), Episode> Updatable) GetExistingEpisodes(Series series, bool pruneAgedOut, DateTime today, int gracePeriodDays, bool importSpecials, out bool pruned)
@@ -85,14 +85,15 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
// The feature is fully disabled: remove every virtual episode (and now-empty virtual season)
// this provider previously created, across all libraries, then stop.
if (!configuration.ImportUnairedEpisodes && !configuration.ImportMissingEpisodes)
if ((!configuration.ImportUnairedEpisodes && !configuration.ImportMissingEpisodes)
|| configuration.EnabledMissingEpisodeLibraries.Length == 0)
{
RemoveAllVirtualItems(progress, cancellationToken);
return;
}
// Process non-ended series (they may have gained episodes) plus any series in a library that
// has been opted out (regardless of status) so the provider can prune the virtual episodes it
// is not opted in (regardless of status) so the provider can prune the virtual episodes it
// previously created there. Ended series in enabled libraries cannot change, so they're skipped.
var series = _libraryManager.GetItemList(new InternalItemsQuery
{
@@ -142,22 +143,16 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
private bool IsEnabledForLibrary(BaseItem item)
{
var disabledLibraries = Plugin.Instance?.Configuration.DisabledMissingEpisodeLibraries;
if (disabledLibraries is null || disabledLibraries.Length == 0)
var enabledLibraries = Plugin.Instance?.Configuration.EnabledMissingEpisodeLibraries;
if (enabledLibraries is null || enabledLibraries.Length == 0)
{
return true;
return false;
}
// A series can live under more than one collection folder; treat it as disabled only when
// every containing library is opted out.
var collectionFolders = _libraryManager.GetCollectionFolders(item);
if (collectionFolders.Count == 0)
{
return true;
}
return collectionFolders.Any(folder =>
!disabledLibraries.Contains(folder.Id.ToString("N", CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase));
// A series can live under more than one collection folder; opting in any one of them is
// enough. An item that belongs to no collection folder cannot be opted in at all.
return _libraryManager.GetCollectionFolders(item).Any(folder =>
enabledLibraries.Contains(folder.Id.ToString("N", CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase));
}
/// <summary>