more local metadata parsing improvements (#776)
* extract remaining nfo xml serializers * add artist nfo tests * add music video nfo tests * add tv show nfo reader tests * custom artist nfo reader * custom music video nfo reader * custom tv show nfo reader * local metadata parsing cleanup * update changelog
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
using System.Text;
|
||||
using Bugsnag;
|
||||
using ErsatzTV.Core.Metadata.Nfo;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace ErsatzTV.Core.Tests.Metadata.Nfo;
|
||||
@@ -8,10 +10,14 @@ namespace ErsatzTV.Core.Tests.Metadata.Nfo;
|
||||
[TestFixture]
|
||||
public class EpisodeNfoReaderTests
|
||||
{
|
||||
[SetUp]
|
||||
public void SetUp() => _episodeNfoReader = new EpisodeNfoReader(new Mock<IClient>().Object);
|
||||
|
||||
private EpisodeNfoReader _episodeNfoReader;
|
||||
|
||||
[Test]
|
||||
public async Task One()
|
||||
{
|
||||
var reader = new EpisodeNfoReader();
|
||||
var stream = new MemoryStream(
|
||||
Encoding.UTF8.GetBytes(
|
||||
@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
|
||||
@@ -19,15 +25,18 @@ public class EpisodeNfoReaderTests
|
||||
<episodedetails>
|
||||
</episodedetails>"));
|
||||
|
||||
List<TvShowEpisodeNfo> result = await reader.Read(stream);
|
||||
Either<BaseError, List<TvShowEpisodeNfo>> result = await _episodeNfoReader.Read(stream);
|
||||
|
||||
result.Count.Should().Be(1);
|
||||
result.IsRight.Should().BeTrue();
|
||||
foreach (List<TvShowEpisodeNfo> list in result.RightToSeq())
|
||||
{
|
||||
list.Count.Should().Be(1);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Two()
|
||||
{
|
||||
var reader = new EpisodeNfoReader();
|
||||
var stream = new MemoryStream(
|
||||
Encoding.UTF8.GetBytes(
|
||||
@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
|
||||
@@ -45,19 +54,22 @@ public class EpisodeNfoReaderTests
|
||||
<season>1</season>
|
||||
</episodedetails>"));
|
||||
|
||||
List<TvShowEpisodeNfo> result = await reader.Read(stream);
|
||||
Either<BaseError, List<TvShowEpisodeNfo>> result = await _episodeNfoReader.Read(stream);
|
||||
|
||||
result.Count.Should().Be(2);
|
||||
result.All(nfo => nfo.ShowTitle == "show").Should().BeTrue();
|
||||
result.All(nfo => nfo.Season == 1).Should().BeTrue();
|
||||
result.Count(nfo => nfo.Title == "episode-one" && nfo.Episode == 1).Should().Be(1);
|
||||
result.Count(nfo => nfo.Title == "episode-two" && nfo.Episode == 2).Should().Be(1);
|
||||
result.IsRight.Should().BeTrue();
|
||||
foreach (List<TvShowEpisodeNfo> list in result.RightToSeq())
|
||||
{
|
||||
list.Count.Should().Be(2);
|
||||
list.All(nfo => nfo.ShowTitle == "show").Should().BeTrue();
|
||||
list.All(nfo => nfo.Season == 1).Should().BeTrue();
|
||||
list.Count(nfo => nfo.Title == "episode-one" && nfo.Episode == 1).Should().Be(1);
|
||||
list.Count(nfo => nfo.Title == "episode-two" && nfo.Episode == 2).Should().Be(1);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task UniqueIds()
|
||||
{
|
||||
var reader = new EpisodeNfoReader();
|
||||
var stream = new MemoryStream(
|
||||
Encoding.UTF8.GetBytes(
|
||||
@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
|
||||
@@ -67,18 +79,21 @@ public class EpisodeNfoReaderTests
|
||||
<uniqueid default=""false"" type=""imdb"">tt54321</uniqueid>
|
||||
</episodedetails>"));
|
||||
|
||||
List<TvShowEpisodeNfo> result = await reader.Read(stream);
|
||||
Either<BaseError, List<TvShowEpisodeNfo>> result = await _episodeNfoReader.Read(stream);
|
||||
|
||||
result.Count.Should().Be(1);
|
||||
result[0].UniqueIds.Count.Should().Be(2);
|
||||
result[0].UniqueIds.Count(id => id.Default && id.Type == "tvdb" && id.Guid == "12345").Should().Be(1);
|
||||
result[0].UniqueIds.Count(id => !id.Default && id.Type == "imdb" && id.Guid == "tt54321").Should().Be(1);
|
||||
result.IsRight.Should().BeTrue();
|
||||
foreach (List<TvShowEpisodeNfo> list in result.RightToSeq())
|
||||
{
|
||||
list.Count.Should().Be(1);
|
||||
list[0].UniqueIds.Count.Should().Be(2);
|
||||
list[0].UniqueIds.Count(id => id.Default && id.Type == "tvdb" && id.Guid == "12345").Should().Be(1);
|
||||
list[0].UniqueIds.Count(id => !id.Default && id.Type == "imdb" && id.Guid == "tt54321").Should().Be(1);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task No_ContentRating()
|
||||
{
|
||||
var reader = new EpisodeNfoReader();
|
||||
var stream = new MemoryStream(
|
||||
Encoding.UTF8.GetBytes(
|
||||
@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
|
||||
@@ -87,16 +102,19 @@ public class EpisodeNfoReaderTests
|
||||
<mpaa/>
|
||||
</episodedetails>"));
|
||||
|
||||
List<TvShowEpisodeNfo> result = await reader.Read(stream);
|
||||
Either<BaseError, List<TvShowEpisodeNfo>> result = await _episodeNfoReader.Read(stream);
|
||||
|
||||
result.Count.Should().Be(1);
|
||||
result[0].ContentRating.Should().BeNullOrEmpty();
|
||||
result.IsRight.Should().BeTrue();
|
||||
foreach (List<TvShowEpisodeNfo> list in result.RightToSeq())
|
||||
{
|
||||
list.Count.Should().Be(1);
|
||||
list[0].ContentRating.Should().BeNullOrEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ContentRating()
|
||||
{
|
||||
var reader = new EpisodeNfoReader();
|
||||
var stream = new MemoryStream(
|
||||
Encoding.UTF8.GetBytes(
|
||||
@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
|
||||
@@ -108,17 +126,20 @@ public class EpisodeNfoReaderTests
|
||||
<mpaa>US:Something / US:SomethingElse</mpaa>
|
||||
</episodedetails>"));
|
||||
|
||||
List<TvShowEpisodeNfo> result = await reader.Read(stream);
|
||||
Either<BaseError, List<TvShowEpisodeNfo>> result = await _episodeNfoReader.Read(stream);
|
||||
|
||||
result.Count.Should().Be(2);
|
||||
result.Count(nfo => nfo.ContentRating == "US:Something").Should().Be(1);
|
||||
result.Count(nfo => nfo.ContentRating == "US:Something / US:SomethingElse").Should().Be(1);
|
||||
result.IsRight.Should().BeTrue();
|
||||
foreach (List<TvShowEpisodeNfo> list in result.RightToSeq())
|
||||
{
|
||||
list.Count.Should().Be(2);
|
||||
list.Count(nfo => nfo.ContentRating == "US:Something").Should().Be(1);
|
||||
list.Count(nfo => nfo.ContentRating == "US:Something / US:SomethingElse").Should().Be(1);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task No_Plot()
|
||||
{
|
||||
var reader = new EpisodeNfoReader();
|
||||
var stream = new MemoryStream(
|
||||
Encoding.UTF8.GetBytes(
|
||||
@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
|
||||
@@ -127,16 +148,19 @@ public class EpisodeNfoReaderTests
|
||||
<plot/>
|
||||
</episodedetails>"));
|
||||
|
||||
List<TvShowEpisodeNfo> result = await reader.Read(stream);
|
||||
Either<BaseError, List<TvShowEpisodeNfo>> result = await _episodeNfoReader.Read(stream);
|
||||
|
||||
result.Count.Should().Be(1);
|
||||
result[0].Plot.Should().BeNullOrEmpty();
|
||||
result.IsRight.Should().BeTrue();
|
||||
foreach (List<TvShowEpisodeNfo> list in result.RightToSeq())
|
||||
{
|
||||
list.Count.Should().Be(1);
|
||||
list[0].Plot.Should().BeNullOrEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Plot()
|
||||
{
|
||||
var reader = new EpisodeNfoReader();
|
||||
var stream = new MemoryStream(
|
||||
Encoding.UTF8.GetBytes(
|
||||
@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
|
||||
@@ -145,16 +169,19 @@ public class EpisodeNfoReaderTests
|
||||
<plot>Some Plot</plot>
|
||||
</episodedetails>"));
|
||||
|
||||
List<TvShowEpisodeNfo> result = await reader.Read(stream);
|
||||
Either<BaseError, List<TvShowEpisodeNfo>> result = await _episodeNfoReader.Read(stream);
|
||||
|
||||
result.Count.Should().Be(1);
|
||||
result[0].Plot.Should().Be("Some Plot");
|
||||
result.IsRight.Should().BeTrue();
|
||||
foreach (List<TvShowEpisodeNfo> list in result.RightToSeq())
|
||||
{
|
||||
list.Count.Should().Be(1);
|
||||
list[0].Plot.Should().Be("Some Plot");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Actors()
|
||||
{
|
||||
var reader = new EpisodeNfoReader();
|
||||
var stream = new MemoryStream(
|
||||
Encoding.UTF8.GetBytes(
|
||||
@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
|
||||
@@ -172,20 +199,23 @@ public class EpisodeNfoReaderTests
|
||||
</actor>
|
||||
</episodedetails>"));
|
||||
|
||||
List<TvShowEpisodeNfo> result = await reader.Read(stream);
|
||||
Either<BaseError, List<TvShowEpisodeNfo>> result = await _episodeNfoReader.Read(stream);
|
||||
|
||||
result.Count.Should().Be(1);
|
||||
result[0].Actors.Count.Should().Be(2);
|
||||
result[0].Actors.Count(a => a.Name == "Name 1" && a.Role == "Role 1" && a.Thumb == "Thumb 1")
|
||||
.Should().Be(1);
|
||||
result[0].Actors.Count(a => a.Name == "Name 2" && a.Role == "Role 2" && a.Thumb == "Thumb 2")
|
||||
.Should().Be(1);
|
||||
result.IsRight.Should().BeTrue();
|
||||
foreach (List<TvShowEpisodeNfo> list in result.RightToSeq())
|
||||
{
|
||||
list.Count.Should().Be(1);
|
||||
list[0].Actors.Count.Should().Be(2);
|
||||
list[0].Actors.Count(a => a.Name == "Name 1" && a.Role == "Role 1" && a.Thumb == "Thumb 1")
|
||||
.Should().Be(1);
|
||||
list[0].Actors.Count(a => a.Name == "Name 2" && a.Role == "Role 2" && a.Thumb == "Thumb 2")
|
||||
.Should().Be(1);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Writers()
|
||||
{
|
||||
var reader = new EpisodeNfoReader();
|
||||
var stream = new MemoryStream(
|
||||
Encoding.UTF8.GetBytes(
|
||||
@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
|
||||
@@ -198,18 +228,21 @@ public class EpisodeNfoReaderTests
|
||||
<credits>Writer 3</credits>
|
||||
</episodedetails>"));
|
||||
|
||||
List<TvShowEpisodeNfo> result = await reader.Read(stream);
|
||||
Either<BaseError, List<TvShowEpisodeNfo>> result = await _episodeNfoReader.Read(stream);
|
||||
|
||||
result.Count.Should().Be(2);
|
||||
result.Count(nfo => nfo.Writers.Count == 1 && nfo.Writers[0] == "Writer 1").Should().Be(1);
|
||||
result.Count(nfo => nfo.Writers.Count == 2 && nfo.Writers[0] == "Writer 2" && nfo.Writers[1] == "Writer 3")
|
||||
.Should().Be(1);
|
||||
result.IsRight.Should().BeTrue();
|
||||
foreach (List<TvShowEpisodeNfo> list in result.RightToSeq())
|
||||
{
|
||||
list.Count.Should().Be(2);
|
||||
list.Count(nfo => nfo.Writers.Count == 1 && nfo.Writers[0] == "Writer 1").Should().Be(1);
|
||||
list.Count(nfo => nfo.Writers.Count == 2 && nfo.Writers[0] == "Writer 2" && nfo.Writers[1] == "Writer 3")
|
||||
.Should().Be(1);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Directors()
|
||||
{
|
||||
var reader = new EpisodeNfoReader();
|
||||
var stream = new MemoryStream(
|
||||
Encoding.UTF8.GetBytes(
|
||||
@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
|
||||
@@ -222,13 +255,153 @@ public class EpisodeNfoReaderTests
|
||||
<director>Director 3</director>
|
||||
</episodedetails>"));
|
||||
|
||||
List<TvShowEpisodeNfo> result = await reader.Read(stream);
|
||||
Either<BaseError, List<TvShowEpisodeNfo>> result = await _episodeNfoReader.Read(stream);
|
||||
|
||||
result.Count.Should().Be(2);
|
||||
result.Count(nfo => nfo.Directors.Count == 1 && nfo.Directors[0] == "Director 1").Should().Be(1);
|
||||
result.Count(
|
||||
nfo => nfo.Directors.Count == 2 && nfo.Directors[0] == "Director 2" &&
|
||||
nfo.Directors[1] == "Director 3")
|
||||
.Should().Be(1);
|
||||
result.IsRight.Should().BeTrue();
|
||||
foreach (List<TvShowEpisodeNfo> list in result.RightToSeq())
|
||||
{
|
||||
list.Count.Should().Be(2);
|
||||
list.Count(nfo => nfo.Directors.Count == 1 && nfo.Directors[0] == "Director 1").Should().Be(1);
|
||||
list.Count(
|
||||
nfo => nfo.Directors.Count == 2 && nfo.Directors[0] == "Director 2" &&
|
||||
nfo.Directors[1] == "Director 3")
|
||||
.Should().Be(1);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task FullSample_Should_Return_Nfo()
|
||||
{
|
||||
await using var stream = new MemoryStream(
|
||||
Encoding.UTF8.GetBytes(
|
||||
@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes"" ?>
|
||||
<episodedetails>
|
||||
<title>Filmed Before a Live Studio Audience</title>
|
||||
<showtitle>WandaVision</showtitle>
|
||||
<ratings>
|
||||
<rating name=""imdb"" max=""10"" default=""true"">
|
||||
<value>7.500000</value>
|
||||
<votes>18766</votes>
|
||||
</rating>
|
||||
<rating name=""tmdb"" max=""10"">
|
||||
<value>7.500000</value>
|
||||
<votes>42</votes>
|
||||
</rating>
|
||||
<rating name=""trakt"" max=""10"">
|
||||
<value>6.952780</value>
|
||||
<votes>3621</votes>
|
||||
</rating>
|
||||
</ratings>
|
||||
<userrating>0</userrating>
|
||||
<top250>0</top250>
|
||||
<season>1</season>
|
||||
<episode>1</episode>
|
||||
<displayseason>-1</displayseason>
|
||||
<displayepisode>-1</displayepisode>
|
||||
<outline></outline>
|
||||
<plot>Wanda and Vision struggle to conceal their powers during dinner with Vision’s boss and his wife.</plot>
|
||||
<tagline></tagline>
|
||||
<runtime>26</runtime>
|
||||
<thumb spoof="""" cache="""" aspect=""thumb"" preview=""https://image.tmdb.org/t/p/w780/cbe8l0Hnbvu07ePgoOopyWYrcdL.jpg"">https://image.tmdb.org/t/p/original/cbe8l0Hnbvu07ePgoOopyWYrcdL.jpg</thumb>
|
||||
<thumb spoof="""" cache="""" aspect=""thumb"" preview=""https://image.tmdb.org/t/p/w780/oNCzeCXFanVEWNpzRzyffhLLfZs.jpg"">https://image.tmdb.org/t/p/original/oNCzeCXFanVEWNpzRzyffhLLfZs.jpg</thumb>
|
||||
<mpaa>Australia:TV-14</mpaa>
|
||||
<playcount>1</playcount>
|
||||
<lastplayed>2021-03-27</lastplayed>
|
||||
<id>1830976</id>
|
||||
<uniqueid type=""imdb"">tt9601584</uniqueid>
|
||||
<uniqueid type=""tmdb"" default=""true"">1830976</uniqueid>
|
||||
<uniqueid type=""tvdb"">8042515</uniqueid>
|
||||
<genre>Sci-Fi & Fantasy</genre>
|
||||
<genre>Mystery</genre>
|
||||
<genre>Drama</genre>
|
||||
<credits>Jac Schaeffer</credits>
|
||||
<director>Matt Shakman</director>
|
||||
<premiered>2021-01-15</premiered>
|
||||
<year>2021</year>
|
||||
<status></status>
|
||||
<code></code>
|
||||
<aired>2021-01-15</aired>
|
||||
<studio>Disney+ (US)</studio>
|
||||
<trailer></trailer>
|
||||
<fileinfo>
|
||||
<streamdetails>
|
||||
<video>
|
||||
<codec>h264</codec>
|
||||
<aspect>1.777778</aspect>
|
||||
<width>1280</width>
|
||||
<height>720</height>
|
||||
<durationinseconds>1593</durationinseconds>
|
||||
<stereomode></stereomode>
|
||||
</video>
|
||||
<audio>
|
||||
<codec>aac</codec>
|
||||
<language>eng</language>
|
||||
<channels>2</channels>
|
||||
</audio>
|
||||
</streamdetails>
|
||||
</fileinfo>
|
||||
<actor>
|
||||
<name>Randall Park</name>
|
||||
<role>Jimmy Woo</role>
|
||||
<order>4</order>
|
||||
<thumb>https://image.tmdb.org/t/p/original/1QJ4cBQZoOaLR8Hc3V2NgBLvB0f.jpg</thumb>
|
||||
</actor>
|
||||
<actor>
|
||||
<name>Kat Dennings</name>
|
||||
<role>Darcy Lewis / The Escape Artist</role>
|
||||
<order>5</order>
|
||||
<thumb>https://image.tmdb.org/t/p/original/rrfyo9z1wW5nY9ZsFlj1Ozfj9g2.jpg</thumb>
|
||||
</actor>
|
||||
<resume>
|
||||
<position>0.000000</position>
|
||||
<total>0.000000</total>
|
||||
</resume>
|
||||
<dateadded>2021-02-02 11:57:44</dateadded>
|
||||
</episodedetails>"));
|
||||
|
||||
Either<BaseError, List<TvShowEpisodeNfo>> result = await _episodeNfoReader.Read(stream);
|
||||
|
||||
result.IsRight.Should().BeTrue();
|
||||
|
||||
foreach (TvShowEpisodeNfo nfo in result.RightToSeq().Flatten())
|
||||
{
|
||||
nfo.ShowTitle.Should().Be("WandaVision");
|
||||
nfo.Title.Should().Be("Filmed Before a Live Studio Audience");
|
||||
nfo.Episode.Should().Be(1);
|
||||
nfo.Season.Should().Be(1);
|
||||
nfo.ContentRating.Should().Be("Australia:TV-14");
|
||||
|
||||
nfo.Aired.IsSome.Should().BeTrue();
|
||||
foreach (DateTime aired in nfo.Aired)
|
||||
{
|
||||
aired.Should().Be(new DateTime(2021, 01, 15));
|
||||
}
|
||||
|
||||
nfo.Plot.Should().Be(
|
||||
"Wanda and Vision struggle to conceal their powers during dinner with Vision’s boss and his wife.");
|
||||
nfo.Actors.Should().BeEquivalentTo(
|
||||
new List<ActorNfo>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "Randall Park", Order = 4, Role = "Jimmy Woo",
|
||||
Thumb = "https://image.tmdb.org/t/p/original/1QJ4cBQZoOaLR8Hc3V2NgBLvB0f.jpg"
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "Kat Dennings", Order = 5, Role = "Darcy Lewis / The Escape Artist",
|
||||
Thumb = "https://image.tmdb.org/t/p/original/rrfyo9z1wW5nY9ZsFlj1Ozfj9g2.jpg"
|
||||
}
|
||||
});
|
||||
nfo.Writers.Should().BeEquivalentTo(new List<string> { "Jac Schaeffer" });
|
||||
nfo.Directors.Should().BeEquivalentTo(new List<string> { "Matt Shakman" });
|
||||
nfo.UniqueIds.Should().BeEquivalentTo(
|
||||
new List<UniqueIdNfo>
|
||||
{
|
||||
new() { Type = "imdb", Guid = "tt9601584", Default = false },
|
||||
new() { Type = "tmdb", Guid = "1830976", Default = true },
|
||||
new() { Type = "tvdb", Guid = "8042515", Default = false }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user