mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-05-23 17:52:29 -04:00
Terminate at null char for audio tags (#14100)
This commit is contained in:
parent
fe2596dc0e
commit
9d601f8e9b
@ -181,10 +181,18 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
var trackTrackNumber = track.TrackNumber is null or 0 ? mediaInfo.IndexNumber : track.TrackNumber;
|
var trackTrackNumber = track.TrackNumber is null or 0 ? mediaInfo.IndexNumber : track.TrackNumber;
|
||||||
var trackDiscNumber = track.DiscNumber is null or 0 ? mediaInfo.ParentIndexNumber : track.DiscNumber;
|
var trackDiscNumber = track.DiscNumber is null or 0 ? mediaInfo.ParentIndexNumber : track.DiscNumber;
|
||||||
|
|
||||||
|
// Some users may use a misbehaved tag editor that writes a null character in the tag when not allowed by the standard.
|
||||||
|
trackTitle = GetSanitizedStringTag(trackTitle, audio.Path);
|
||||||
|
trackAlbum = GetSanitizedStringTag(trackAlbum, audio.Path);
|
||||||
|
var trackAlbumArtist = GetSanitizedStringTag(track.AlbumArtist, audio.Path);
|
||||||
|
var trackArist = GetSanitizedStringTag(track.Artist, audio.Path);
|
||||||
|
var trackComposer = GetSanitizedStringTag(track.Composer, audio.Path);
|
||||||
|
var trackGenre = GetSanitizedStringTag(track.Genre, audio.Path);
|
||||||
|
|
||||||
if (audio.SupportsPeople && !audio.LockedFields.Contains(MetadataField.Cast))
|
if (audio.SupportsPeople && !audio.LockedFields.Contains(MetadataField.Cast))
|
||||||
{
|
{
|
||||||
var people = new List<PersonInfo>();
|
var people = new List<PersonInfo>();
|
||||||
var albumArtists = string.IsNullOrEmpty(track.AlbumArtist) ? [] : track.AlbumArtist.Split(InternalValueSeparator);
|
var albumArtists = string.IsNullOrEmpty(trackAlbumArtist) ? [] : trackAlbumArtist.Split(InternalValueSeparator);
|
||||||
|
|
||||||
if (libraryOptions.UseCustomTagDelimiters)
|
if (libraryOptions.UseCustomTagDelimiters)
|
||||||
{
|
{
|
||||||
@ -206,7 +214,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
string[]? performers = null;
|
string[]? performers = null;
|
||||||
if (libraryOptions.PreferNonstandardArtistsTag)
|
if (libraryOptions.PreferNonstandardArtistsTag)
|
||||||
{
|
{
|
||||||
track.AdditionalFields.TryGetValue("ARTISTS", out var artistsTagString);
|
TryGetSanitizedAdditionalFields(track, "ARTISTS", out var artistsTagString);
|
||||||
if (artistsTagString is not null)
|
if (artistsTagString is not null)
|
||||||
{
|
{
|
||||||
performers = artistsTagString.Split(InternalValueSeparator);
|
performers = artistsTagString.Split(InternalValueSeparator);
|
||||||
@ -215,7 +223,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
|
|
||||||
if (performers is null || performers.Length == 0)
|
if (performers is null || performers.Length == 0)
|
||||||
{
|
{
|
||||||
performers = string.IsNullOrEmpty(track.Artist) ? [] : track.Artist.Split(InternalValueSeparator);
|
performers = string.IsNullOrEmpty(trackArist) ? [] : trackArist.Split(InternalValueSeparator);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (libraryOptions.UseCustomTagDelimiters)
|
if (libraryOptions.UseCustomTagDelimiters)
|
||||||
@ -235,15 +243,18 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var composer in track.Composer.Split(InternalValueSeparator))
|
if (!string.IsNullOrWhiteSpace(trackComposer))
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrWhiteSpace(composer))
|
foreach (var composer in trackComposer.Split(InternalValueSeparator))
|
||||||
{
|
{
|
||||||
PeopleHelper.AddPerson(people, new PersonInfo
|
if (!string.IsNullOrWhiteSpace(composer))
|
||||||
{
|
{
|
||||||
Name = composer.Trim(),
|
PeopleHelper.AddPerson(people, new PersonInfo
|
||||||
Type = PersonKind.Composer
|
{
|
||||||
});
|
Name = composer.Trim(),
|
||||||
|
Type = PersonKind.Composer
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,7 +331,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
|
|
||||||
if (!audio.LockedFields.Contains(MetadataField.Genres))
|
if (!audio.LockedFields.Contains(MetadataField.Genres))
|
||||||
{
|
{
|
||||||
var genres = string.IsNullOrEmpty(track.Genre) ? [] : track.Genre.Split(InternalValueSeparator).Distinct(StringComparer.OrdinalIgnoreCase).ToArray();
|
var genres = string.IsNullOrEmpty(trackGenre) ? [] : trackGenre.Split(InternalValueSeparator).Distinct(StringComparer.OrdinalIgnoreCase).ToArray();
|
||||||
|
|
||||||
if (libraryOptions.UseCustomTagDelimiters)
|
if (libraryOptions.UseCustomTagDelimiters)
|
||||||
{
|
{
|
||||||
@ -334,7 +345,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
: audio.Genres;
|
: audio.Genres;
|
||||||
}
|
}
|
||||||
|
|
||||||
track.AdditionalFields.TryGetValue("REPLAYGAIN_TRACK_GAIN", out var trackGainTag);
|
TryGetSanitizedAdditionalFields(track, "REPLAYGAIN_TRACK_GAIN", out var trackGainTag);
|
||||||
|
|
||||||
if (trackGainTag is not null)
|
if (trackGainTag is not null)
|
||||||
{
|
{
|
||||||
@ -351,8 +362,8 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
|
|
||||||
if (options.ReplaceAllMetadata || !audio.TryGetProviderId(MetadataProvider.MusicBrainzArtist, out _))
|
if (options.ReplaceAllMetadata || !audio.TryGetProviderId(MetadataProvider.MusicBrainzArtist, out _))
|
||||||
{
|
{
|
||||||
if ((track.AdditionalFields.TryGetValue("MUSICBRAINZ_ARTISTID", out var musicBrainzArtistTag)
|
if ((TryGetSanitizedAdditionalFields(track, "MUSICBRAINZ_ARTISTID", out var musicBrainzArtistTag)
|
||||||
|| track.AdditionalFields.TryGetValue("MusicBrainz Artist Id", out musicBrainzArtistTag))
|
|| TryGetSanitizedAdditionalFields(track, "MusicBrainz Artist Id", out musicBrainzArtistTag))
|
||||||
&& !string.IsNullOrEmpty(musicBrainzArtistTag))
|
&& !string.IsNullOrEmpty(musicBrainzArtistTag))
|
||||||
{
|
{
|
||||||
var id = GetFirstMusicBrainzId(musicBrainzArtistTag, libraryOptions.UseCustomTagDelimiters, libraryOptions.GetCustomTagDelimiters(), libraryOptions.DelimiterWhitelist);
|
var id = GetFirstMusicBrainzId(musicBrainzArtistTag, libraryOptions.UseCustomTagDelimiters, libraryOptions.GetCustomTagDelimiters(), libraryOptions.DelimiterWhitelist);
|
||||||
@ -362,8 +373,8 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
|
|
||||||
if (options.ReplaceAllMetadata || !audio.TryGetProviderId(MetadataProvider.MusicBrainzAlbumArtist, out _))
|
if (options.ReplaceAllMetadata || !audio.TryGetProviderId(MetadataProvider.MusicBrainzAlbumArtist, out _))
|
||||||
{
|
{
|
||||||
if ((track.AdditionalFields.TryGetValue("MUSICBRAINZ_ALBUMARTISTID", out var musicBrainzReleaseArtistIdTag)
|
if ((TryGetSanitizedAdditionalFields(track, "MUSICBRAINZ_ALBUMARTISTID", out var musicBrainzReleaseArtistIdTag)
|
||||||
|| track.AdditionalFields.TryGetValue("MusicBrainz Album Artist Id", out musicBrainzReleaseArtistIdTag))
|
|| TryGetSanitizedAdditionalFields(track, "MusicBrainz Album Artist Id", out musicBrainzReleaseArtistIdTag))
|
||||||
&& !string.IsNullOrEmpty(musicBrainzReleaseArtistIdTag))
|
&& !string.IsNullOrEmpty(musicBrainzReleaseArtistIdTag))
|
||||||
{
|
{
|
||||||
var id = GetFirstMusicBrainzId(musicBrainzReleaseArtistIdTag, libraryOptions.UseCustomTagDelimiters, libraryOptions.GetCustomTagDelimiters(), libraryOptions.DelimiterWhitelist);
|
var id = GetFirstMusicBrainzId(musicBrainzReleaseArtistIdTag, libraryOptions.UseCustomTagDelimiters, libraryOptions.GetCustomTagDelimiters(), libraryOptions.DelimiterWhitelist);
|
||||||
@ -373,8 +384,8 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
|
|
||||||
if (options.ReplaceAllMetadata || !audio.TryGetProviderId(MetadataProvider.MusicBrainzAlbum, out _))
|
if (options.ReplaceAllMetadata || !audio.TryGetProviderId(MetadataProvider.MusicBrainzAlbum, out _))
|
||||||
{
|
{
|
||||||
if ((track.AdditionalFields.TryGetValue("MUSICBRAINZ_ALBUMID", out var musicBrainzReleaseIdTag)
|
if ((TryGetSanitizedAdditionalFields(track, "MUSICBRAINZ_ALBUMID", out var musicBrainzReleaseIdTag)
|
||||||
|| track.AdditionalFields.TryGetValue("MusicBrainz Album Id", out musicBrainzReleaseIdTag))
|
|| TryGetSanitizedAdditionalFields(track, "MusicBrainz Album Id", out musicBrainzReleaseIdTag))
|
||||||
&& !string.IsNullOrEmpty(musicBrainzReleaseIdTag))
|
&& !string.IsNullOrEmpty(musicBrainzReleaseIdTag))
|
||||||
{
|
{
|
||||||
var id = GetFirstMusicBrainzId(musicBrainzReleaseIdTag, libraryOptions.UseCustomTagDelimiters, libraryOptions.GetCustomTagDelimiters(), libraryOptions.DelimiterWhitelist);
|
var id = GetFirstMusicBrainzId(musicBrainzReleaseIdTag, libraryOptions.UseCustomTagDelimiters, libraryOptions.GetCustomTagDelimiters(), libraryOptions.DelimiterWhitelist);
|
||||||
@ -384,8 +395,8 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
|
|
||||||
if (options.ReplaceAllMetadata || !audio.TryGetProviderId(MetadataProvider.MusicBrainzReleaseGroup, out _))
|
if (options.ReplaceAllMetadata || !audio.TryGetProviderId(MetadataProvider.MusicBrainzReleaseGroup, out _))
|
||||||
{
|
{
|
||||||
if ((track.AdditionalFields.TryGetValue("MUSICBRAINZ_RELEASEGROUPID", out var musicBrainzReleaseGroupIdTag)
|
if ((TryGetSanitizedAdditionalFields(track, "MUSICBRAINZ_RELEASEGROUPID", out var musicBrainzReleaseGroupIdTag)
|
||||||
|| track.AdditionalFields.TryGetValue("MusicBrainz Release Group Id", out musicBrainzReleaseGroupIdTag))
|
|| TryGetSanitizedAdditionalFields(track, "MusicBrainz Release Group Id", out musicBrainzReleaseGroupIdTag))
|
||||||
&& !string.IsNullOrEmpty(musicBrainzReleaseGroupIdTag))
|
&& !string.IsNullOrEmpty(musicBrainzReleaseGroupIdTag))
|
||||||
{
|
{
|
||||||
var id = GetFirstMusicBrainzId(musicBrainzReleaseGroupIdTag, libraryOptions.UseCustomTagDelimiters, libraryOptions.GetCustomTagDelimiters(), libraryOptions.DelimiterWhitelist);
|
var id = GetFirstMusicBrainzId(musicBrainzReleaseGroupIdTag, libraryOptions.UseCustomTagDelimiters, libraryOptions.GetCustomTagDelimiters(), libraryOptions.DelimiterWhitelist);
|
||||||
@ -395,8 +406,8 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
|
|
||||||
if (options.ReplaceAllMetadata || !audio.TryGetProviderId(MetadataProvider.MusicBrainzTrack, out _))
|
if (options.ReplaceAllMetadata || !audio.TryGetProviderId(MetadataProvider.MusicBrainzTrack, out _))
|
||||||
{
|
{
|
||||||
if ((track.AdditionalFields.TryGetValue("MUSICBRAINZ_RELEASETRACKID", out var trackMbId)
|
if ((TryGetSanitizedAdditionalFields(track, "MUSICBRAINZ_RELEASETRACKID", out var trackMbId)
|
||||||
|| track.AdditionalFields.TryGetValue("MusicBrainz Release Track Id", out trackMbId))
|
|| TryGetSanitizedAdditionalFields(track, "MusicBrainz Release Track Id", out trackMbId))
|
||||||
&& !string.IsNullOrEmpty(trackMbId))
|
&& !string.IsNullOrEmpty(trackMbId))
|
||||||
{
|
{
|
||||||
var id = GetFirstMusicBrainzId(trackMbId, libraryOptions.UseCustomTagDelimiters, libraryOptions.GetCustomTagDelimiters(), libraryOptions.DelimiterWhitelist);
|
var id = GetFirstMusicBrainzId(trackMbId, libraryOptions.UseCustomTagDelimiters, libraryOptions.GetCustomTagDelimiters(), libraryOptions.DelimiterWhitelist);
|
||||||
@ -406,13 +417,13 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
|
|
||||||
if (options.ReplaceAllMetadata || !audio.TryGetProviderId(MetadataProvider.MusicBrainzRecording, out _))
|
if (options.ReplaceAllMetadata || !audio.TryGetProviderId(MetadataProvider.MusicBrainzRecording, out _))
|
||||||
{
|
{
|
||||||
if ((track.AdditionalFields.TryGetValue("MUSICBRAINZ_TRACKID", out var recordingMbId)
|
if ((TryGetSanitizedAdditionalFields(track, "MUSICBRAINZ_TRACKID", out var recordingMbId)
|
||||||
|| track.AdditionalFields.TryGetValue("MusicBrainz Track Id", out recordingMbId))
|
|| TryGetSanitizedAdditionalFields(track, "MusicBrainz Track Id", out recordingMbId))
|
||||||
&& !string.IsNullOrEmpty(recordingMbId))
|
&& !string.IsNullOrEmpty(recordingMbId))
|
||||||
{
|
{
|
||||||
audio.TrySetProviderId(MetadataProvider.MusicBrainzRecording, recordingMbId);
|
audio.TrySetProviderId(MetadataProvider.MusicBrainzRecording, recordingMbId);
|
||||||
}
|
}
|
||||||
else if (track.AdditionalFields.TryGetValue("UFID", out var ufIdValue) && !string.IsNullOrEmpty(ufIdValue))
|
else if (TryGetSanitizedAdditionalFields(track, "UFID", out var ufIdValue) && !string.IsNullOrEmpty(ufIdValue))
|
||||||
{
|
{
|
||||||
// If tagged with MB Picard, the format is 'http://musicbrainz.org\0<recording MBID>'
|
// If tagged with MB Picard, the format is 'http://musicbrainz.org\0<recording MBID>'
|
||||||
if (ufIdValue.Contains("musicbrainz.org", StringComparison.OrdinalIgnoreCase))
|
if (ufIdValue.Contains("musicbrainz.org", StringComparison.OrdinalIgnoreCase))
|
||||||
@ -485,5 +496,28 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string? GetSanitizedStringTag(string? tag, string filePath)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(tag))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = tag.TruncateAtNull();
|
||||||
|
if (result.Length != tag.Length)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Audio file {File} contains a null character in its tag, but this is not allowed by its tagging standard. All characters after the null char will be discarded. Please fix your file", filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryGetSanitizedAdditionalFields(Track track, string field, out string? value)
|
||||||
|
{
|
||||||
|
var hasField = track.AdditionalFields.TryGetValue(field, out value);
|
||||||
|
value = GetSanitizedStringTag(value, track.Path);
|
||||||
|
return hasField;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,5 +135,18 @@ namespace Jellyfin.Extensions
|
|||||||
{
|
{
|
||||||
return values.Select(i => (i ?? string.Empty).Trim());
|
return values.Select(i => (i ?? string.Empty).Trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Truncates a string at the first null character ('\0').
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">The input string.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// The substring up to (but not including) the first null character,
|
||||||
|
/// or the original string if no null character is present.
|
||||||
|
/// </returns>
|
||||||
|
public static string TruncateAtNull(this string text)
|
||||||
|
{
|
||||||
|
return string.IsNullOrEmpty(text) ? text : text.AsSpan().LeftPart('\0').ToString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user