diff --git a/Jellyfin.Plugin.TubeArchivistMetadata/Tasks/RebuildPlaylistSeasonsTask.cs b/Jellyfin.Plugin.TubeArchivistMetadata/Tasks/RebuildPlaylistSeasonsTask.cs index 7f7ab41..64d2764 100644 --- a/Jellyfin.Plugin.TubeArchivistMetadata/Tasks/RebuildPlaylistSeasonsTask.cs +++ b/Jellyfin.Plugin.TubeArchivistMetadata/Tasks/RebuildPlaylistSeasonsTask.cs @@ -41,6 +41,17 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Tasks /// There is no default trigger. Regrouping a library is disruptive and must be an explicit /// choice rather than a side effect of saving the settings page. /// + /// + /// Episodes are processed one at a time. Each refresh reaches TubeArchivist, so running them + /// concurrently would multiply the load on it and interleave badly with a scheduled library + /// scan. The cost is duration: expect roughly a second per episode. + /// + /// + /// On a library large enough to run longer than PlaylistCache's lifetime, the cache can + /// refresh part way through. If playlists changed in TubeArchivist during the run, episodes + /// handled before and after that point can be grouped against different playlist data. Running + /// the task again once TubeArchivist has settled resolves it. + /// /// public class RebuildPlaylistSeasonsTask : IScheduledTask { @@ -128,10 +139,19 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Tasks // Calling the injected manager rather than BaseItem.UpdateToRepositoryAsync, // which resolves the parent through the static BaseItem.LibraryManager. + // + // MetadataDownload, never MetadataEdit. ItemUpdateType is a [Flags] enum + // whose highest value is MetadataEdit, and ProviderManager treats + // "updateType >= MetadataEdit" as a manual edit: it then rewrites an .nfo + // beside the media whenever one already exists, even with local metadata + // saving switched off. That write would happen while ParentIndexNumber is + // still null, stripping from the user's file. Anything below + // MetadataEdit skips the savers, and persistence is unaffected either way + // because UpdateItemsAsync saves to the database regardless of the reason. await _libraryManager.UpdateItemAsync( episode, episode.GetParent(), - ItemUpdateType.MetadataEdit, + ItemUpdateType.MetadataDownload, cancellationToken).ConfigureAwait(false); cleared++; } diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 927766c..8adb567 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -137,6 +137,18 @@ seasons left behind. Jellyfin removes the now-empty old seasons by itself. Season *names* may briefly read "Season Unknown" immediately afterwards. That is a cached field on the episode and the next library refresh restores the correct name. +**If you keep `.nfo` files next to your media, they win.** An `.nfo` containing `` is a local +metadata source, and Jellyfin prefers it over anything this plugin supplies, so those episodes stay +where the file says regardless of the setting or the task. Measured: an episode with +`1` in its `.nfo` ignored the rebuild entirely, then moved correctly the moment the +file was removed. Either delete the `.nfo` files, remove their `` element, or disable the +"Nfo" metadata reader for the library. + +The task itself will **not** modify or create `.nfo` files. It saves below Jellyfin's "manual edit" +threshold precisely so the NFO savers stay out of the way — otherwise Jellyfin would rewrite any +existing `.nfo` while the season number was cleared, silently stripping `` from it. Verified +against a hand-written `.nfo`: byte-identical after a full run. + > **Deleting the seasons by hand does not work** — worth stating, because it is the obvious approach. > Jellyfin derives a season's item id deterministically from its series and index number, and > deleting a season does not clear its episodes' stored season number, so a rescan recreates exactly