diff --git a/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs index bce4cf0093..81774b8735 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs @@ -208,6 +208,18 @@ namespace MediaBrowser.XbmcMetadata.Parsers break; } + case "showtitle": + { + var showtitle = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(showtitle)) + { + item.SeriesName = showtitle; + } + + break; + } + default: base.FetchDataFromXmlNode(reader, itemResult); break; diff --git a/MediaBrowser.XbmcMetadata/Savers/EpisodeNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/EpisodeNfoSaver.cs index ac2fbb8d24..5d3d17893a 100644 --- a/MediaBrowser.XbmcMetadata/Savers/EpisodeNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/EpisodeNfoSaver.cs @@ -56,6 +56,8 @@ namespace MediaBrowser.XbmcMetadata.Savers { var episode = (Episode)item; + writer.WriteElementString("showtitle", episode.SeriesName); + if (episode.IndexNumber.HasValue) { writer.WriteElementString("episode", episode.IndexNumber.Value.ToString(_usCulture)); @@ -122,7 +124,8 @@ namespace MediaBrowser.XbmcMetadata.Savers "airsbefore_episode", "airsbefore_season", "displayseason", - "displayepisode" + "displayepisode", + "showtitle" }); return list; diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/EpisodeNfoProviderTests.cs b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/EpisodeNfoProviderTests.cs new file mode 100644 index 0000000000..67b4b969a3 --- /dev/null +++ b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/EpisodeNfoProviderTests.cs @@ -0,0 +1,103 @@ +using System; +using System.Linq; +using System.Threading; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; +using MediaBrowser.XbmcMetadata.Parsers; +using Microsoft.Extensions.Logging.Abstractions; +using Moq; +using Xunit; + +#pragma warning disable CA5369 + +namespace Jellyfin.XbmcMetadata.Tests.Parsers +{ + public class EpisodeNfoProviderTests + { + private readonly EpisodeNfoParser _parser; + + public EpisodeNfoProviderTests() + { + var providerManager = new Mock(); + providerManager.Setup(x => x.GetExternalIdInfos(It.IsAny())) + .Returns(Enumerable.Empty()); + var config = new Mock(); + config.Setup(x => x.GetConfiguration(It.IsAny())) + .Returns(new XbmcMetadataOptions()); + _parser = new EpisodeNfoParser(new NullLogger(), config.Object, providerManager.Object); + } + + [Fact] + public void Fetch_Valid_Succes() + { + var result = new MetadataResult() + { + Item = new Episode() + }; + + _parser.Fetch(result, "Test Data/The Bone Orchard.nfo", CancellationToken.None); + + var item = result.Item; + Assert.Equal("The Bone Orchard", item.Name); + Assert.Equal("American Gods", item.SeriesName); + Assert.Equal(1, item.IndexNumber); + Assert.Equal(1, item.ParentIndexNumber); + Assert.Equal("When Shadow Moon is released from prison early after the death of his wife, he meets Mr. Wednesday and is recruited as his bodyguard. Shadow discovers that this may be more than he bargained for.", item.Overview); + Assert.Equal(0, item.RunTimeTicks); + Assert.Equal("16", item.OfficialRating); + Assert.Contains("Drama", item.Genres); + Assert.Contains("Mystery", item.Genres); + Assert.Contains("Sci-Fi & Fantasy", item.Genres); + Assert.Equal(new DateTime(2017, 4, 30), item.PremiereDate); + Assert.Equal(2017, item.ProductionYear); + Assert.Single(item.Studios); + Assert.Contains("Starz", item.Studios); + + // Credits + var writers = result.People.Where(x => x.Type == PersonType.Writer).ToArray(); + Assert.Equal(2, writers.Length); + Assert.Contains("Bryan Fuller", writers.Select(x => x.Name)); + Assert.Contains("Michael Green", writers.Select(x => x.Name)); + + // Direcotrs + var directors = result.People.Where(x => x.Type == PersonType.Director).ToArray(); + Assert.Single(directors); + Assert.Contains("David Slade", directors.Select(x => x.Name)); + + // Actors + var actors = result.People.Where(x => x.Type == PersonType.Actor).ToArray(); + Assert.Equal(11, actors.Length); + // Only test one actor + var shadow = actors.FirstOrDefault(x => x.Role.Equals("Shadow Moon", StringComparison.Ordinal)); + Assert.NotNull(shadow); + Assert.Equal("Ricky Whittle", shadow!.Name); + Assert.Equal(0, shadow!.SortOrder); + Assert.Equal("http://image.tmdb.org/t/p/original/cjeDbVfBp6Qvb3C74Dfy7BKDTQN.jpg", shadow!.ImageUrl); + + Assert.Equal(new DateTime(2017, 10, 7, 14, 25, 47), item.DateCreated); + } + + [Fact] + public void Fetch_WithNullItem_ThrowsArgumentException() + { + var result = new MetadataResult(); + + Assert.Throws(() => _parser.Fetch(result, "Test Data/The Bone Orchard.nfo", CancellationToken.None)); + } + + [Fact] + public void Fetch_NullResult_ThrowsArgumentException() + { + var result = new MetadataResult() + { + Item = new Episode() + }; + + Assert.Throws(() => _parser.Fetch(result, string.Empty, CancellationToken.None)); + } + } +} diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs index 7651653a1b..e1f50876fb 100644 --- a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs +++ b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs @@ -12,7 +12,7 @@ using Microsoft.Extensions.Logging.Abstractions; using Moq; using Xunit; -namespace Jellyfin.XbmcMetadata.Parsers.Tests +namespace Jellyfin.XbmcMetadata.Tests.Parsers { public class MovieNfoParserTests { diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MusicAlbumNfoProviderTests.cs b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MusicAlbumNfoProviderTests.cs new file mode 100644 index 0000000000..bdffea560c --- /dev/null +++ b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MusicAlbumNfoProviderTests.cs @@ -0,0 +1,72 @@ +#pragma warning disable CA5369 + +using System; +using System.Linq; +using System.Threading; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; +using MediaBrowser.XbmcMetadata.Parsers; +using Microsoft.Extensions.Logging.Abstractions; +using Moq; +using Xunit; + +namespace Jellyfin.XbmcMetadata.Tests.Parsers +{ + public class MusicAlbumNfoProviderTests + { + private readonly BaseNfoParser _parser; + + public MusicAlbumNfoProviderTests() + { + var providerManager = new Mock(); + providerManager.Setup(x => x.GetExternalIdInfos(It.IsAny())) + .Returns(Enumerable.Empty()); + var config = new Mock(); + config.Setup(x => x.GetConfiguration(It.IsAny())) + .Returns(new XbmcMetadataOptions()); + _parser = new BaseNfoParser(new NullLogger>(), config.Object, providerManager.Object); + } + + [Fact] + public void Fetch_Valid_Succes() + { + var result = new MetadataResult() + { + Item = new MusicAlbum() + }; + + _parser.Fetch(result, "Test Data/The Best of 1980-1990.nfo", CancellationToken.None); + var item = result.Item; + + Assert.Equal("The Best of 1980-1990", item.Name); + Assert.Equal(1989, item.ProductionYear); + Assert.Contains("Pop", item.Genres); + Assert.Single(item.Genres); + Assert.Contains("Rock/Pop", item.Tags); + Assert.Equal("The Best of 1980-1990 is the first greatest hits compilation by Irish rock band U2, released in November 1998. It mostly contains the group's hit singles from the eighties but also mixes in some live staples as well as one new recording, Sweetest Thing. In April 1999, a companion video (featuring music videos and live footage) was released. The album was followed by another compilation, The Best of 1990-2000, in 2002.\nA limited edition version containing a special B-sides disc was released on the same date as the single-disc version. At the time of release, the official word was that the 2-disc album would be available the first week the album went on sale, then pulled from the stores. While this threat never materialized, it did result in the 2-disc version being in very high demand. Both versions charted in the Billboard 200.\nThe boy on the cover is Peter Rowan, brother of Bono's friend Guggi (real name Derek Rowan) of the Virgin Prunes. He also appears on the covers of the early EP Three, two of the band's first three albums (Boy and War), and Early Demos.", item.Overview); + } + + [Fact] + public void Fetch_WithNullItem_ThrowsArgumentException() + { + var result = new MetadataResult(); + + Assert.Throws(() => _parser.Fetch(result, "Test Data/The Best of 1980-1990.nfo", CancellationToken.None)); + } + + [Fact] + public void Fetch_NullResult_ThrowsArgumentException() + { + var result = new MetadataResult() + { + Item = new MusicAlbum() + }; + + Assert.Throws(() => _parser.Fetch(result, string.Empty, CancellationToken.None)); + } + } +} diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MusicArtistNfoParserTests.cs b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MusicArtistNfoParserTests.cs index a8c6e5afd8..2a4d376c6b 100644 --- a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MusicArtistNfoParserTests.cs +++ b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MusicArtistNfoParserTests.cs @@ -12,7 +12,7 @@ using Microsoft.Extensions.Logging.Abstractions; using Moq; using Xunit; -namespace Jellyfin.XbmcMetadata.Parsers.Tests +namespace Jellyfin.XbmcMetadata.Tests.Parsers { public class MusicArtistNfoParserTests { diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/SeasonNfoProviderTests.cs b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/SeasonNfoProviderTests.cs new file mode 100644 index 0000000000..68b7239d22 --- /dev/null +++ b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/SeasonNfoProviderTests.cs @@ -0,0 +1,83 @@ +#pragma warning disable CA5369 + +using System; +using System.Linq; +using System.Threading; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; +using MediaBrowser.XbmcMetadata.Parsers; +using Microsoft.Extensions.Logging.Abstractions; +using Moq; +using Xunit; + +namespace Jellyfin.XbmcMetadata.Tests.Parsers +{ + public class SeasonNfoProviderTests + { + private readonly SeasonNfoParser _parser; + + public SeasonNfoProviderTests() + { + var providerManager = new Mock(); + providerManager.Setup(x => x.GetExternalIdInfos(It.IsAny())) + .Returns(Enumerable.Empty()); + var config = new Mock(); + config.Setup(x => x.GetConfiguration(It.IsAny())) + .Returns(new XbmcMetadataOptions()); + _parser = new SeasonNfoParser(new NullLogger(), config.Object, providerManager.Object); + } + + [Fact] + public void Fetch_Valid_Succes() + { + var result = new MetadataResult() + { + Item = new Season() + }; + + _parser.Fetch(result, "Test Data/Season 01.nfo", CancellationToken.None); + var item = result.Item; + + Assert.Equal("Season 1", item.Name); + Assert.Equal(1, item.IndexNumber); + Assert.False(item.IsLocked); + Assert.Equal(2019, item.ProductionYear); + Assert.Equal(new DateTime(2019, 11, 08), item.PremiereDate); + Assert.Equal(new DateTime(2020, 06, 14, 17, 26, 51), item.DateCreated); + + Assert.Equal(10, result.People.Count); + + Assert.True(result.People.All(x => x.Type == PersonType.Actor)); + + // Only test one actor + var nini = result.People.FirstOrDefault(x => x.Role.Equals("Nini", StringComparison.Ordinal)); + Assert.NotNull(nini); + Assert.Equal("Olivia Rodrigo", nini!.Name); + Assert.Equal(0, nini!.SortOrder); + Assert.Equal("/config/metadata/People/O/Olivia Rodrigo/poster.jpg", nini!.ImageUrl); + } + + [Fact] + public void Fetch_WithNullItem_ThrowsArgumentException() + { + var result = new MetadataResult(); + + Assert.Throws(() => _parser.Fetch(result, "Test Data/Season 01.nfo", CancellationToken.None)); + } + + [Fact] + public void Fetch_NullResult_ThrowsArgumentException() + { + var result = new MetadataResult() + { + Item = new Season() + }; + + Assert.Throws(() => _parser.Fetch(result, string.Empty, CancellationToken.None)); + } + } +} diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/SeriesNfoParserTests.cs b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/SeriesNfoParserTests.cs index 37ca0fd059..3bbfb66e3e 100644 --- a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/SeriesNfoParserTests.cs +++ b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/SeriesNfoParserTests.cs @@ -12,7 +12,7 @@ using Microsoft.Extensions.Logging.Abstractions; using Moq; using Xunit; -namespace Jellyfin.XbmcMetadata.Parsers.Tests +namespace Jellyfin.XbmcMetadata.Tests.Parsers { public class SeriesNfoParserTests { diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Test Data/Season 01.nfo b/tests/Jellyfin.XbmcMetadata.Tests/Test Data/Season 01.nfo new file mode 100644 index 0000000000..91f0392f4d --- /dev/null +++ b/tests/Jellyfin.XbmcMetadata.Tests/Test Data/Season 01.nfo @@ -0,0 +1,86 @@ + + + + + false + 2020-06-14 17:26:51 + Season 1 + 2019 + 359728 + 2019-11-08 + 2019-11-08 + + /media/Serien/High School Musical The Musical The Series (2019)/Season 1/Season 1.jpeg + + + Olivia Rodrigo + Nini + Actor + 0 + /config/metadata/People/O/Olivia Rodrigo/poster.jpg + + + Kate Reinders + Miss Jenn + Actor + 1 + /config/metadata/People/K/Kate Reinders/poster.jpg + + + Sofia Wylie + Gina + Actor + 2 + /config/metadata/People/S/Sofia Wylie/poster.jpg + + + Matt Cornett + E.J. + Actor + 3 + /config/metadata/People/M/Matt Cornett/poster.jpg + + + Dara Reneé + Kourtney + Actor + 4 + /config/metadata/People/D/Dara Reneé/poster.jpg + + + Julia Lester + Ashlyn + Actor + 5 + /config/metadata/People/J/Julia Lester/poster.jpg + + + Joshua Bassett + Ricky + Actor + 6 + /config/metadata/People/J/Joshua Bassett/poster.jpg + + + Frankie A. Rodriguez + Carlos + Actor + 7 + /config/metadata/People/F/Frankie A. Rodriguez/poster.jpg + + + Larry Saperstein + Big Red + Actor + 8 + /config/metadata/People/L/Larry Saperstein/poster.jpg + + + Mark St. Cyr + Mr. Mazzara + Actor + 9 + /config/metadata/People/M/Mark St. Cyr/poster.jpg + + 1 + diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Test Data/The Best of 1980-1990.nfo b/tests/Jellyfin.XbmcMetadata.Tests/Test Data/The Best of 1980-1990.nfo new file mode 100644 index 0000000000..4ab8400d31 --- /dev/null +++ b/tests/Jellyfin.XbmcMetadata.Tests/Test Data/The Best of 1980-1990.nfo @@ -0,0 +1,29 @@ + + + The Best of 1980-1990 + 59b5a40b-e2fd-3f18-a218-e8c9aae12ab5 + 6c301dbd-6ccb-3403-a6c4-6a22240a0297 + false + U2 + Pop + + Political + false + The Best of 1980-1990 is the first greatest hits compilation by Irish rock band U2, released in November 1998. It mostly contains the group's hit singles from the eighties but also mixes in some live staples as well as one new recording, Sweetest Thing. In April 1999, a companion video (featuring music videos and live footage) was released. The album was followed by another compilation, The Best of 1990-2000, in 2002. A limited edition version containing a special B-sides disc was released on the same date as the single-disc version. At the time of release, the official word was that the 2-disc album would be available the first week the album went on sale, then pulled from the stores. While this threat never materialized, it did result in the 2-disc version being in very high demand. Both versions charted in the Billboard 200. The boy on the cover is Peter Rowan, brother of Bono's friend Guggi (real name Derek Rowan) of the Virgin Prunes. He also appears on the covers of the early EP Three, two of the band's first three albums (Boy and War), and Early Demos. + album / compilation + + + https://assets.fanart.tv/fanart/music/a3cb23fc-acd3-4ce0-8f36-1e5aa6a18432/albumcover/the-best-of-1980-1990-4e43a22cab023.jpg + https://assets.fanart.tv/fanart/music/a3cb23fc-acd3-4ce0-8f36-1e5aa6a18432/albumcover/the-best-of-1980-1990-5bc4301068645.jpg + https://www.theaudiodb.com/images/media/album/thumb/the-best-of-1980-1990-4e43a22cab023.jpg + C:\KODI\Test- Music\U2\Best Of 1980-1990, The\ + -1.000000 + -1 + -1 + 1989 + + U2 + a3cb23fc-acd3-4ce0-8f36-1e5aa6a18432 + + album + diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Test Data/The Bone Orchard.nfo b/tests/Jellyfin.XbmcMetadata.Tests/Test Data/The Bone Orchard.nfo new file mode 100644 index 0000000000..e77c02a349 --- /dev/null +++ b/tests/Jellyfin.XbmcMetadata.Tests/Test Data/The Bone Orchard.nfo @@ -0,0 +1,111 @@ + + + The Bone Orchard + American Gods + + + 7.532000 + 31 + + + 0 + 0 + 1 + 1 + -1 + -1 + + When Shadow Moon is released from prison early after the death of his wife, he meets Mr. Wednesday and is recruited as his bodyguard. Shadow discovers that this may be more than he bargained for. + + 0 + http://image.tmdb.org/t/p/original/uvry4weK00pFLn7fxQ9M4m3Da2A.jpg + 16 + 0 + + 1276153 + 1276153 + Drama + Mystery + Sci-Fi & Fantasy + Bryan Fuller + Michael Green + David Slade + 2017-04-30 + 2017 + + + 2017-04-30 + Starz + + + Jonathan Tucker + 'Low Key' Lyesmith + 10 + http://image.tmdb.org/t/p/original/jvJpYDbwmUTACw7Yn7PKOP6CdlJ.jpg + + + Demore Barnes + Mr. Ibis + 11 + http://image.tmdb.org/t/p/original/4rEVzSIFPgiN14xYQnjKcKQ7tYE.jpg + + + Betty Gilpin + Audrey + 12 + http://image.tmdb.org/t/p/original/xFeqyem5i4Kf0nFjBZ4Oi9NM26k.jpg + + + Beth Grant + Jack + 13 + http://image.tmdb.org/t/p/original/zAT9GvzJE0ytL3C36L461cgKI9p.jpg + + + Joel Murray + Paunch + 14 + http://image.tmdb.org/t/p/original/t5syYfCgxbTC7XPrNeXhhhQULUf.jpg + + + Ricky Whittle + Shadow Moon + 0 + http://image.tmdb.org/t/p/original/cjeDbVfBp6Qvb3C74Dfy7BKDTQN.jpg + + + Ian McShane + Mr. Wednesday + 1 + http://image.tmdb.org/t/p/original/pY9ud4BJwHekNiO4MMItPbgkdAy.jpg + + + Emily Browning + Laura Moon + 2 + http://image.tmdb.org/t/p/original/fa1Kyj02wxwcdS6EHb2i27TNXvU.jpg + + + Pablo Schreiber + Mad Sweeney + 3 + http://image.tmdb.org/t/p/original/uo8YljeePz3pbj7gvWXdB4gOOW4.jpg + + + Bruce Langley + Technical Boy + 4 + http://image.tmdb.org/t/p/original/f4EOWUmznLqboq8Ce7jnlkHVK3Y.jpg + + + Yetide Badaki + Bilquis + 5 + http://image.tmdb.org/t/p/original/qfzkREHuI1JvMxBteIAjKX8qMEr.jpg + + + 0.000000 + 0.000000 + + 2017-10-07 14:25:47 +