nfo saver makes unneccesary disk writes during library scan #6432

Closed
opened 2026-02-07 03:37:54 +03:00 by OVERLORD · 5 comments
Owner

Originally created by @srosorcxisto on GitHub (Nov 6, 2024).

This issue respects the following points:

  • This is a bug, not a question or a configuration issue; Please visit our forum or chat rooms first to troubleshoot with volunteers, before creating a report. The links can be found here.
  • This issue is not already reported on GitHub (I've searched it).
  • I'm using an up to date version of Jellyfin Server stable, unstable or master; We generally do not support previous older versions. If possible, please update to the latest version before opening an issue.
  • I agree to follow Jellyfin's Code of Conduct.
  • This report addresses only a single issue; If you encounter multiple issues, kindly create separate reports for each one.

Description of the bug

When re-scanning a library using the .nfo saver, all .nfo files are updated even if there were no changes.

While mostly benign, this does result in unnecessary disk writes and cause some backup software and software-based raid systems (like SnapRAID) to treat the file as new because of the changed timestamp. I am not sure if this is a bug for feature request, so apologies if it is misfiled.

I believe this operation is being handled by SaveToFileAsync () on line 204 of jellyfin/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs

I am not a C# programmer, nor am I familiar with the codebase and am therefore uncomfortable submitting a pull request on my own, but believe that this could be improved without noticeably impacting scan performance by adding a simple CRC32 hash to compare the stream with the existing file before writing.

Here is my attempt at a patch if helpful, I am not confident that it will work as written, but hate pointing out problems without at least suggesting a solution:

         private async Task SaveToFileAsync(Stream stream, string path)
         {
             var directory = Path.GetDirectoryName(path) ?? throw new ArgumentException($"Provided path ({path}) is not valid.", nameof(path));
             Directory.CreateDirectory(directory);
+		// Compare metadata hashes before proceeding
+		if (File.Exists(path))
+		{
+			byte[] existingFileHash;
+			using (var existingFileStream = File.OpenRead(path))
+			{
+				existingFileHash = new Crc32().ComputeHash(existingFileStream);
+			}
+
+			byte[] newContentHash;
+			using (var crc32 = new Crc32())
+			{
+				newContentHash = crc32.ComputeHash(stream);
+			}
+
+			stream.Position = 0;
+
+			if (existingFileHash.SequenceEqual(newContentHash))
+			{
+				return; // Don't save since .nfo is unchanged
+			}
+		}
+
            // On Windows, saving the file will fail if the file is hidden or readonly
            FileSystem.SetAttributes(path, false, false);

            var fileStreamOptions = new FileStreamOptions()
            {
                Mode = FileMode.Create,
                Access = FileAccess.Write,
                Share = FileShare.None,
                PreallocationSize = stream.Length,
                Options = FileOptions.Asynchronous
            };

            var filestream = new FileStream(path, fileStreamOptions);
            await using (filestream.ConfigureAwait(false))
            {
                await stream.CopyToAsync(filestream).ConfigureAwait(false);
            }

            if (ConfigurationManager.Configuration.SaveMetadataHidden)
            {
                SetHidden(path, true);
            }
        }

Reproduction steps

  1. Monitor the filesystem for changes (for example using auditd or inotifywait on Linux). Alternatively, just look at the timestamps for .nfo files before and after a library scan.
  2. Ensure that .nfo saver is for the library and that it has previously saved files
  3. Wait for a scheduled library scan or manually kickoff the job
  4. Observe that all .nfo get re-saved with new timestamps

What is the current bug behavior?

After each library scan with nfo saver on, all .nfo files are recreated regardless of changes to the metadata.

What is the expected correct behavior?

That only new and changed .nfo files are added to the filesystem.

Jellyfin Server version

10.10.0+

Specify commit id

No response

Specify unstable release number

No response

Specify version number

No response

Specify the build version

10.10.1

Environment

  • OS: Debian bookworm
  • Linux Kernel: 6.1.0-20
  • Virtualization: Docker (lscr.io/linuxserver/jellyfin:latest)
  • Clients: All
  • Browser: All
  • FFmpeg Version:
  • Playback Method:
  • Hardware Acceleration: No
  • GPU Model:
  • Plugins:
  • Reverse Proxy: nginx
  • Base URL:
  • Networking: Docker internal network
  • Storage: EXT4 using Docker bind

Jellyfin logs

None relevant

FFmpeg logs

None relevant

Client / Browser logs

None relevant

Relevant screenshots or videos

None relevant

Additional information

Originally created by @srosorcxisto on GitHub (Nov 6, 2024). ### This issue respects the following points: - [x] This is a **bug**, not a question or a configuration issue; Please visit our forum or chat rooms first to troubleshoot with volunteers, before creating a report. The links can be found [here](https://jellyfin.org/contact/). - [x] This issue is **not** already reported on [GitHub](https://github.com/jellyfin/jellyfin/issues?q=is%3Aopen+is%3Aissue) _(I've searched it)_. - [x] I'm using an up to date version of Jellyfin Server stable, unstable or master; We generally do not support previous older versions. If possible, please update to the latest version before opening an issue. - [x] I agree to follow Jellyfin's [Code of Conduct](https://jellyfin.org/docs/general/community-standards.html#code-of-conduct). - [x] This report addresses only a single issue; If you encounter multiple issues, kindly create separate reports for each one. ### Description of the bug When re-scanning a library using the .nfo saver, all .nfo files are updated even if there were no changes. While mostly benign, this does result in unnecessary disk writes and cause some backup software and software-based raid systems (like SnapRAID) to treat the file as new because of the changed timestamp. I am not sure if this is a bug for feature request, so apologies if it is misfiled. I believe this operation is being handled by SaveToFileAsync () on [line 204 of jellyfin/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs](https://github.com/jellyfin/jellyfin/blob/bf00899f92881c987f019ad7d20f0cef42d4e3e7/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs#L204) I am not a C# programmer, nor am I familiar with the codebase and am therefore uncomfortable submitting a pull request on my own, but believe that this could be improved without noticeably impacting scan performance by adding a simple CRC32 hash to compare the stream with the existing file before writing. Here is my attempt at a patch if helpful, I am not confident that it will work as written, but hate pointing out problems without at least suggesting a solution: ```diff private async Task SaveToFileAsync(Stream stream, string path) { var directory = Path.GetDirectoryName(path) ?? throw new ArgumentException($"Provided path ({path}) is not valid.", nameof(path)); Directory.CreateDirectory(directory); + // Compare metadata hashes before proceeding + if (File.Exists(path)) + { + byte[] existingFileHash; + using (var existingFileStream = File.OpenRead(path)) + { + existingFileHash = new Crc32().ComputeHash(existingFileStream); + } + + byte[] newContentHash; + using (var crc32 = new Crc32()) + { + newContentHash = crc32.ComputeHash(stream); + } + + stream.Position = 0; + + if (existingFileHash.SequenceEqual(newContentHash)) + { + return; // Don't save since .nfo is unchanged + } + } + // On Windows, saving the file will fail if the file is hidden or readonly FileSystem.SetAttributes(path, false, false); var fileStreamOptions = new FileStreamOptions() { Mode = FileMode.Create, Access = FileAccess.Write, Share = FileShare.None, PreallocationSize = stream.Length, Options = FileOptions.Asynchronous }; var filestream = new FileStream(path, fileStreamOptions); await using (filestream.ConfigureAwait(false)) { await stream.CopyToAsync(filestream).ConfigureAwait(false); } if (ConfigurationManager.Configuration.SaveMetadataHidden) { SetHidden(path, true); } } ``` ### Reproduction steps 1. Monitor the filesystem for changes (for example using auditd or inotifywait on Linux). Alternatively, just look at the timestamps for .nfo files before and after a library scan. 2. Ensure that .nfo saver is for the library and that it has previously saved files 3. Wait for a scheduled library scan or manually kickoff the job 4. Observe that all .nfo get re-saved with new timestamps ### What is the current _bug_ behavior? After each library scan with nfo saver on, all .nfo files are recreated regardless of changes to the metadata. ### What is the expected _correct_ behavior? That only new and changed .nfo files are added to the filesystem. ### Jellyfin Server version 10.10.0+ ### Specify commit id _No response_ ### Specify unstable release number _No response_ ### Specify version number _No response_ ### Specify the build version 10.10.1 ### Environment - OS: Debian bookworm - Linux Kernel: 6.1.0-20 - Virtualization: Docker (lscr.io/linuxserver/jellyfin:latest) - Clients: All - Browser: All - FFmpeg Version: - Playback Method: - Hardware Acceleration: No - GPU Model: - Plugins: - Reverse Proxy: nginx - Base URL: - Networking: Docker internal network - Storage: EXT4 using Docker bind ### Jellyfin logs None relevant ### FFmpeg logs None relevant ### Client / Browser logs None relevant ### Relevant screenshots or videos None relevant ### Additional information
OVERLORD added the bugstale labels 2026-02-07 03:37:54 +03:00
Author
Owner

@felix920506 commented on GitHub (Nov 6, 2024):

Please submit a PR if you have a fix.

@felix920506 commented on GitHub (Nov 6, 2024): Please submit a PR if you have a fix.
Author
Owner

@srosorcxisto commented on GitHub (Nov 7, 2024):

I have the outline of a fix, but am not familiar enough with C# to test or fully implement in a PR.

@srosorcxisto commented on GitHub (Nov 7, 2024): I have the outline of a fix, but am not familiar enough with C# to test or fully implement in a PR.
Author
Owner

@IDisposable commented on GitHub (Feb 12, 2025):

I created PR #13547 for this.

@IDisposable commented on GitHub (Feb 12, 2025): I created PR #13547 for this.
Author
Owner

@jellyfin-bot commented on GitHub (Jun 12, 2025):

This issue has gone 120 days without an update and will be closed within 21 days if there is no new activity. To prevent this issue from being closed, please confirm the issue has not already been fixed by providing updated examples or logs.

If you have any questions you can use one of several ways to contact us.

@jellyfin-bot commented on GitHub (Jun 12, 2025): This issue has gone 120 days without an update and will be closed within 21 days if there is no new activity. To prevent this issue from being closed, please confirm the issue has not already been fixed by providing updated examples or logs. If you have any questions you can use one of several ways to [contact us](https://jellyfin.org/contact).
Author
Owner

@jellyfin-bot commented on GitHub (Jul 3, 2025):

This issue was closed due to inactivity.

@jellyfin-bot commented on GitHub (Jul 3, 2025): This issue was closed due to inactivity.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/jellyfin#6432