mirror of
https://github.com/lidarr/lidarr.git
synced 2025-08-19 04:59:35 -07:00
Fixed: Some bugs in new metadata writing (#677)
* Fixed: Don't fail reading m4a files when no 'day' tag set * Fixed: Make sure Quality and MediaInfo are set if tag reading failed * Add more tests for AudioTagService
This commit is contained in:
parent
24737baee6
commit
d552770da9
2 changed files with 117 additions and 17 deletions
|
@ -11,6 +11,7 @@ using System.Collections;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using NzbDrone.Test.Common;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Test.MediaFiles.AudioTagServiceFixture
|
namespace NzbDrone.Core.Test.MediaFiles.AudioTagServiceFixture
|
||||||
{
|
{
|
||||||
|
@ -141,7 +142,11 @@ namespace NzbDrone.Core.Test.MediaFiles.AudioTagServiceFixture
|
||||||
{
|
{
|
||||||
var val1 = (IEnumerable) property.GetValue(a, null);
|
var val1 = (IEnumerable) property.GetValue(a, null);
|
||||||
var val2 = (IEnumerable) property.GetValue(b, null);
|
var val2 = (IEnumerable) property.GetValue(b, null);
|
||||||
val1.Should().BeEquivalentTo(val2, $"{property.Name} should be equal");
|
|
||||||
|
if (val1 != null || val2 != null)
|
||||||
|
{
|
||||||
|
val1.Should().BeEquivalentTo(val2, $"{property.Name} should be equal");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -208,5 +213,71 @@ namespace NzbDrone.Core.Test.MediaFiles.AudioTagServiceFixture
|
||||||
tag.MusicBrainzAlbumComment.Should().BeNull();
|
tag.MusicBrainzAlbumComment.Should().BeNull();
|
||||||
tag.MusicBrainzReleaseTrackId.Should().BeNull();
|
tag.MusicBrainzReleaseTrackId.Should().BeNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test, TestCaseSource(typeof(TestCaseFactory), "TestCases")]
|
||||||
|
public void should_read_audiotag_from_file_with_no_tags(string filename, string[] skipProperties)
|
||||||
|
{
|
||||||
|
GivenFileCopy(filename);
|
||||||
|
var path = copiedFile;
|
||||||
|
|
||||||
|
Subject.RemoveAllTags(path);
|
||||||
|
|
||||||
|
var tag = Subject.ReadAudioTag(path);
|
||||||
|
var expected = new AudioTag() {
|
||||||
|
Performers = new string[0],
|
||||||
|
AlbumArtists = new string[0]
|
||||||
|
};
|
||||||
|
|
||||||
|
VerifySame(tag, expected, skipProperties);
|
||||||
|
tag.Quality.Should().NotBeNull();
|
||||||
|
tag.MediaInfo.Should().NotBeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test, TestCaseSource(typeof(TestCaseFactory), "TestCases")]
|
||||||
|
public void should_read_parsedtrackinfo_from_file_with_no_tags(string filename, string[] skipProperties)
|
||||||
|
{
|
||||||
|
GivenFileCopy(filename);
|
||||||
|
var path = copiedFile;
|
||||||
|
|
||||||
|
Subject.RemoveAllTags(path);
|
||||||
|
|
||||||
|
var tag = Subject.ReadTags(path);
|
||||||
|
|
||||||
|
tag.Quality.Should().NotBeNull();
|
||||||
|
tag.MediaInfo.Should().NotBeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test, TestCaseSource(typeof(TestCaseFactory), "TestCases")]
|
||||||
|
public void should_set_quality_and_mediainfo_for_corrupt_file(string filename, string[] skipProperties)
|
||||||
|
{
|
||||||
|
// use missing to simulate corrupt
|
||||||
|
var tag = Subject.ReadAudioTag(filename.Replace("nin", "missing"));
|
||||||
|
var expected = new AudioTag();
|
||||||
|
|
||||||
|
VerifySame(tag, expected, skipProperties);
|
||||||
|
tag.Quality.Should().NotBeNull();
|
||||||
|
tag.MediaInfo.Should().NotBeNull();
|
||||||
|
|
||||||
|
ExceptionVerification.ExpectedErrors(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test, TestCaseSource(typeof(TestCaseFactory), "TestCases")]
|
||||||
|
public void should_read_file_with_only_title_tag(string filename, string[] ignored)
|
||||||
|
{
|
||||||
|
GivenFileCopy(filename);
|
||||||
|
var path = copiedFile;
|
||||||
|
|
||||||
|
Subject.RemoveAllTags(path);
|
||||||
|
|
||||||
|
var nametag = new AudioTag();
|
||||||
|
nametag.Title = "test";
|
||||||
|
nametag.Write(path);
|
||||||
|
|
||||||
|
var tag = Subject.ReadTags(path);
|
||||||
|
tag.Title.Should().Be("test");
|
||||||
|
|
||||||
|
tag.Quality.Should().NotBeNull();
|
||||||
|
tag.MediaInfo.Should().NotBeNull();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,7 +150,7 @@ namespace NzbDrone.Core.MediaFiles
|
||||||
{
|
{
|
||||||
var appletag = (TagLib.Mpeg4.AppleTag) file.GetTag(TagTypes.Apple);
|
var appletag = (TagLib.Mpeg4.AppleTag) file.GetTag(TagTypes.Apple);
|
||||||
Media = appletag.GetDashBox("com.apple.iTunes", "MEDIA");
|
Media = appletag.GetDashBox("com.apple.iTunes", "MEDIA");
|
||||||
Date = DateTime.TryParse(appletag.DataBoxes(FixAppleId("day")).First().Text, out tempDate) ? tempDate : default(DateTime?);
|
Date = DateTime.TryParse(appletag.DataBoxes(FixAppleId("day")).FirstOrDefault()?.Text, out tempDate) ? tempDate : default(DateTime?);
|
||||||
OriginalReleaseDate = DateTime.TryParse(appletag.GetDashBox("com.apple.iTunes", "Original Date"), out tempDate) ? tempDate : default(DateTime?);
|
OriginalReleaseDate = DateTime.TryParse(appletag.GetDashBox("com.apple.iTunes", "Original Date"), out tempDate) ? tempDate : default(DateTime?);
|
||||||
MusicBrainzAlbumComment = appletag.GetDashBox("com.apple.iTunes", "MusicBrainz Album Comment");
|
MusicBrainzAlbumComment = appletag.GetDashBox("com.apple.iTunes", "MusicBrainz Album Comment");
|
||||||
MusicBrainzReleaseTrackId = appletag.GetDashBox("com.apple.iTunes", "MusicBrainz Release Track Id");
|
MusicBrainzReleaseTrackId = appletag.GetDashBox("com.apple.iTunes", "MusicBrainz Release Track Id");
|
||||||
|
@ -168,11 +168,7 @@ namespace NzbDrone.Core.MediaFiles
|
||||||
if (bitrate == 0)
|
if (bitrate == 0)
|
||||||
{
|
{
|
||||||
// Taglib can't read bitrate for Opus.
|
// Taglib can't read bitrate for Opus.
|
||||||
// Taglib File.Length is unreliable so use System.IO
|
bitrate = EstimateBitrate(file, path);
|
||||||
var size = new System.IO.FileInfo(path).Length;
|
|
||||||
var duration = file.Properties.Duration.TotalSeconds;
|
|
||||||
bitrate = (int) ((size * 8L) / (duration * 1024));
|
|
||||||
Logger.Trace($"Estimating bitrate. Size: {size} Duration: {duration} Bitrate: {bitrate}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.Debug("Audio Properties: " + acodec.Description + ", Bitrate: " + bitrate + ", Sample Size: " +
|
Logger.Debug("Audio Properties: " + acodec.Description + ", Bitrate: " + bitrate + ", Sample Size: " +
|
||||||
|
@ -193,17 +189,22 @@ namespace NzbDrone.Core.MediaFiles
|
||||||
|
|
||||||
IsValid = true;
|
IsValid = true;
|
||||||
}
|
}
|
||||||
catch (CorruptFileException ex)
|
|
||||||
{
|
|
||||||
Logger.Warn(ex, $"Tag reading failed for {path}. File is corrupt");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.Warn()
|
if (ex is CorruptFileException)
|
||||||
.Exception(ex)
|
{
|
||||||
.Message($"Tag reading failed for {path}")
|
Logger.Warn(ex, $"Tag reading failed for {path}. File is corrupt");
|
||||||
.WriteSentryWarn("Tag reading failed")
|
}
|
||||||
.Write();
|
else
|
||||||
|
{
|
||||||
|
// Log as error so it goes to sentry with correct fingerprint
|
||||||
|
Logger.Error(ex, "Tag reading failed for {0}", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure these are initialized to avoid errors later on
|
||||||
|
Quality = QualityParser.ParseQuality(path, null, EstimateBitrate(file, path));
|
||||||
|
Logger.Debug($"Quality parsed: {Quality}, Source: {Quality.QualityDetectionSource}");
|
||||||
|
MediaInfo = new MediaInfoModel();
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
@ -211,6 +212,25 @@ namespace NzbDrone.Core.MediaFiles
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int EstimateBitrate(TagLib.File file, string path)
|
||||||
|
{
|
||||||
|
int bitrate = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Taglib File.Length is unreliable so use System.IO
|
||||||
|
var size = new System.IO.FileInfo(path).Length;
|
||||||
|
var duration = file.Properties.Duration.TotalSeconds;
|
||||||
|
bitrate = (int) ((size * 8L) / (duration * 1024));
|
||||||
|
|
||||||
|
Logger.Trace($"Estimating bitrate. Size: {size} Duration: {duration} Bitrate: {bitrate}");
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
return bitrate;
|
||||||
|
}
|
||||||
|
|
||||||
private DateTime? ReadId3Date(TagLib.Id3v2.Tag tag, string dateTag)
|
private DateTime? ReadId3Date(TagLib.Id3v2.Tag tag, string dateTag)
|
||||||
{
|
{
|
||||||
string date = tag.GetTextAsString(dateTag);
|
string date = tag.GetTextAsString(dateTag);
|
||||||
|
@ -300,6 +320,11 @@ namespace NzbDrone.Core.MediaFiles
|
||||||
public void Write(string path)
|
public void Write(string path)
|
||||||
{
|
{
|
||||||
Logger.Debug($"Starting tag write for {path}");
|
Logger.Debug($"Starting tag write for {path}");
|
||||||
|
|
||||||
|
// patch up any null fields to work around TagLib exception for
|
||||||
|
// WMA with null performers/albumartists
|
||||||
|
Performers = Performers ?? new string[0];
|
||||||
|
AlbumArtists = AlbumArtists ?? new string[0];
|
||||||
|
|
||||||
TagLib.File file = null;
|
TagLib.File file = null;
|
||||||
try
|
try
|
||||||
|
@ -544,7 +569,11 @@ namespace NzbDrone.Core.MediaFiles
|
||||||
{
|
{
|
||||||
if (!tag.IsValid)
|
if (!tag.IsValid)
|
||||||
{
|
{
|
||||||
return new ParsedTrackInfo { Language = Language.English };
|
return new ParsedTrackInfo {
|
||||||
|
Language = Language.English,
|
||||||
|
Quality = tag.Quality ?? new QualityModel { Quality = NzbDrone.Core.Qualities.Quality.Unknown },
|
||||||
|
MediaInfo = tag.MediaInfo ?? new MediaInfoModel()
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
var artist = tag.AlbumArtists?.FirstOrDefault();
|
var artist = tag.AlbumArtists?.FirstOrDefault();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue