mirror of https://github.com/ErsatzTV/ErsatzTV.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
498 lines
16 KiB
498 lines
16 KiB
using System.Text; |
|
using Bugsnag; |
|
using ErsatzTV.Core; |
|
using ErsatzTV.Scanner.Core.Metadata.Nfo; |
|
using FluentAssertions; |
|
using Microsoft.Extensions.Logging; |
|
using Microsoft.IO; |
|
using NSubstitute; |
|
using NUnit.Framework; |
|
using Serilog; |
|
|
|
namespace ErsatzTV.Scanner.Tests.Core.Metadata.Nfo; |
|
|
|
[TestFixture] |
|
public class EpisodeNfoReaderTests |
|
{ |
|
[SetUp] |
|
public void SetUp() => _episodeNfoReader = new EpisodeNfoReader( |
|
new RecyclableMemoryStreamManager(), |
|
Substitute.For<IClient>(), |
|
_logger); |
|
|
|
private readonly ILogger<EpisodeNfoReader> _logger; |
|
|
|
public EpisodeNfoReaderTests() |
|
{ |
|
Log.Logger = new LoggerConfiguration() |
|
.MinimumLevel.Debug() |
|
.WriteTo.Console() |
|
.CreateLogger(); |
|
|
|
ILoggerFactory loggerFactory = new LoggerFactory().AddSerilog(Log.Logger); |
|
|
|
_logger = loggerFactory.CreateLogger<EpisodeNfoReader>(); |
|
} |
|
|
|
private EpisodeNfoReader _episodeNfoReader; |
|
|
|
[Test] |
|
public async Task One() |
|
{ |
|
var stream = new MemoryStream( |
|
Encoding.UTF8.GetBytes( |
|
@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?> |
|
<!--created on whatever - comment--> |
|
<episodedetails> |
|
</episodedetails>")); |
|
|
|
Either<BaseError, List<EpisodeNfo>> result = await _episodeNfoReader.Read(stream); |
|
|
|
result.IsRight.Should().BeTrue(); |
|
foreach (List<EpisodeNfo> list in result.RightToSeq()) |
|
{ |
|
list.Count.Should().Be(1); |
|
} |
|
} |
|
|
|
[Test] |
|
public async Task Two() |
|
{ |
|
var stream = new MemoryStream( |
|
Encoding.UTF8.GetBytes( |
|
@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?> |
|
<!--created on whatever - comment--> |
|
<episodedetails> |
|
<showtitle>show</showtitle> |
|
<title>episode-one</title> |
|
<episode>1</episode> |
|
<season>1</season> |
|
</episodedetails> |
|
<episodedetails> |
|
<showtitle>show</showtitle> |
|
<title>episode-two</title> |
|
<episode>2</episode> |
|
<season>1</season> |
|
</episodedetails>")); |
|
|
|
Either<BaseError, List<EpisodeNfo>> result = await _episodeNfoReader.Read(stream); |
|
|
|
result.IsRight.Should().BeTrue(); |
|
foreach (List<EpisodeNfo> 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 stream = new MemoryStream( |
|
Encoding.UTF8.GetBytes( |
|
@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?> |
|
<!--created on whatever - comment--> |
|
<episodedetails> |
|
<uniqueid default=""true"" type=""tvdb"">12345</uniqueid> |
|
<uniqueid default=""false"" type=""imdb"">tt54321</uniqueid> |
|
</episodedetails>")); |
|
|
|
Either<BaseError, List<EpisodeNfo>> result = await _episodeNfoReader.Read(stream); |
|
|
|
result.IsRight.Should().BeTrue(); |
|
foreach (List<EpisodeNfo> 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 stream = new MemoryStream( |
|
Encoding.UTF8.GetBytes( |
|
@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?> |
|
<!--created on whatever - comment--> |
|
<episodedetails> |
|
<mpaa/> |
|
</episodedetails>")); |
|
|
|
Either<BaseError, List<EpisodeNfo>> result = await _episodeNfoReader.Read(stream); |
|
|
|
result.IsRight.Should().BeTrue(); |
|
foreach (List<EpisodeNfo> list in result.RightToSeq()) |
|
{ |
|
list.Count.Should().Be(1); |
|
list[0].ContentRating.Should().BeNullOrEmpty(); |
|
} |
|
} |
|
|
|
[Test] |
|
public async Task ContentRating() |
|
{ |
|
var stream = new MemoryStream( |
|
Encoding.UTF8.GetBytes( |
|
@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?> |
|
<!--created on whatever - comment--> |
|
<episodedetails> |
|
<mpaa>US:Something</mpaa> |
|
</episodedetails> |
|
<episodedetails> |
|
<mpaa>US:Something / US:SomethingElse</mpaa> |
|
</episodedetails>")); |
|
|
|
Either<BaseError, List<EpisodeNfo>> result = await _episodeNfoReader.Read(stream); |
|
|
|
result.IsRight.Should().BeTrue(); |
|
foreach (List<EpisodeNfo> 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 stream = new MemoryStream( |
|
Encoding.UTF8.GetBytes( |
|
@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?> |
|
<!--created on whatever - comment--> |
|
<episodedetails> |
|
<plot/> |
|
</episodedetails>")); |
|
|
|
Either<BaseError, List<EpisodeNfo>> result = await _episodeNfoReader.Read(stream); |
|
|
|
result.IsRight.Should().BeTrue(); |
|
foreach (List<EpisodeNfo> list in result.RightToSeq()) |
|
{ |
|
list.Count.Should().Be(1); |
|
list[0].Plot.Should().BeNullOrEmpty(); |
|
} |
|
} |
|
|
|
[Test] |
|
public async Task Plot() |
|
{ |
|
var stream = new MemoryStream( |
|
Encoding.UTF8.GetBytes( |
|
@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?> |
|
<!--created on whatever - comment--> |
|
<episodedetails> |
|
<plot>Some Plot</plot> |
|
</episodedetails>")); |
|
|
|
Either<BaseError, List<EpisodeNfo>> result = await _episodeNfoReader.Read(stream); |
|
|
|
result.IsRight.Should().BeTrue(); |
|
foreach (List<EpisodeNfo> list in result.RightToSeq()) |
|
{ |
|
list.Count.Should().Be(1); |
|
list[0].Plot.Should().Be("Some Plot"); |
|
} |
|
} |
|
|
|
[Test] |
|
public async Task Actors() |
|
{ |
|
var stream = new MemoryStream( |
|
Encoding.UTF8.GetBytes( |
|
@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?> |
|
<!--created on whatever - comment--> |
|
<episodedetails> |
|
<actor> |
|
<name>Name 1</name> |
|
<role>Role 1</role> |
|
<thumb>Thumb 1</thumb> |
|
</actor> |
|
<actor> |
|
<name>Name 2</name> |
|
<role>Role 2</role> |
|
<thumb>Thumb 2</thumb> |
|
</actor> |
|
</episodedetails>")); |
|
|
|
Either<BaseError, List<EpisodeNfo>> result = await _episodeNfoReader.Read(stream); |
|
|
|
result.IsRight.Should().BeTrue(); |
|
foreach (List<EpisodeNfo> 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 stream = new MemoryStream( |
|
Encoding.UTF8.GetBytes( |
|
@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?> |
|
<!--created on whatever - comment--> |
|
<episodedetails> |
|
<credits>Writer 1</credits> |
|
</episodedetails> |
|
<episodedetails> |
|
<credits>Writer 2</credits> |
|
<credits>Writer 3</credits> |
|
</episodedetails>")); |
|
|
|
Either<BaseError, List<EpisodeNfo>> result = await _episodeNfoReader.Read(stream); |
|
|
|
result.IsRight.Should().BeTrue(); |
|
foreach (List<EpisodeNfo> 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 stream = new MemoryStream( |
|
Encoding.UTF8.GetBytes( |
|
@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?> |
|
<!--created on whatever - comment--> |
|
<episodedetails> |
|
<director>Director 1</director> |
|
</episodedetails> |
|
<episodedetails> |
|
<director>Director 2</director> |
|
<director>Director 3</director> |
|
</episodedetails>")); |
|
|
|
Either<BaseError, List<EpisodeNfo>> result = await _episodeNfoReader.Read(stream); |
|
|
|
result.IsRight.Should().BeTrue(); |
|
foreach (List<EpisodeNfo> 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 Genres() |
|
{ |
|
var stream = new MemoryStream( |
|
Encoding.UTF8.GetBytes( |
|
@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?> |
|
<!--created on whatever - comment--> |
|
<episodedetails> |
|
<genre>Genre 1</genre> |
|
</episodedetails> |
|
<episodedetails> |
|
<genre>Genre 2</genre> |
|
<genre>Genre 3</genre> |
|
</episodedetails>")); |
|
|
|
Either<BaseError, List<EpisodeNfo>> result = await _episodeNfoReader.Read(stream); |
|
|
|
result.IsRight.Should().BeTrue(); |
|
foreach (List<EpisodeNfo> list in result.RightToSeq()) |
|
{ |
|
list.Count.Should().Be(2); |
|
list.Count(nfo => nfo.Genres is ["Genre 1"]).Should().Be(1); |
|
list.Count(nfo => nfo.Genres is ["Genre 2", "Genre 3"]).Should().Be(1); |
|
} |
|
} |
|
|
|
[Test] |
|
public async Task Tags() |
|
{ |
|
var stream = new MemoryStream( |
|
Encoding.UTF8.GetBytes( |
|
@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?> |
|
<!--created on whatever - comment--> |
|
<episodedetails> |
|
<tag>Tag 1</tag> |
|
</episodedetails> |
|
<episodedetails> |
|
<tag>Tag 2</tag> |
|
<tag>Tag 3</tag> |
|
</episodedetails>")); |
|
|
|
Either<BaseError, List<EpisodeNfo>> result = await _episodeNfoReader.Read(stream); |
|
|
|
result.IsRight.Should().BeTrue(); |
|
foreach (List<EpisodeNfo> list in result.RightToSeq()) |
|
{ |
|
list.Count.Should().Be(2); |
|
list.Count(nfo => nfo.Tags is ["Tag 1"]).Should().Be(1); |
|
list.Count(nfo => nfo.Tags is ["Tag 2", "Tag 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<EpisodeNfo>> result = await _episodeNfoReader.Read(stream); |
|
|
|
result.IsRight.Should().BeTrue(); |
|
|
|
foreach (EpisodeNfo 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 } |
|
}); |
|
} |
|
} |
|
|
|
[Test] |
|
public async Task Invalid_Characters_Should_Abort_And_Return_Nfo() |
|
{ |
|
string sourceFile = Path.Combine( |
|
TestContext.CurrentContext.TestDirectory, |
|
"Resources", |
|
"Nfo", |
|
"EpisodeInvalidCharacters.nfo"); |
|
Either<BaseError, List<EpisodeNfo>> result = await _episodeNfoReader.ReadFromFile(sourceFile); |
|
|
|
result.IsRight.Should().BeTrue(); |
|
foreach (List<EpisodeNfo> list in result.RightToSeq()) |
|
{ |
|
list.Count.Should().Be(1); |
|
list[0].Title.Should().Be("Test Title"); |
|
} |
|
} |
|
}
|
|
|