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