mirror of https://github.com/ErsatzTV/ErsatzTV.git
Browse Source
* 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 changelogpull/778/head
20 changed files with 1258 additions and 168 deletions
@ -0,0 +1,153 @@
@@ -0,0 +1,153 @@
|
||||
using System.Text; |
||||
using Bugsnag; |
||||
using ErsatzTV.Core.Metadata.Nfo; |
||||
using FluentAssertions; |
||||
using Moq; |
||||
using NUnit.Framework; |
||||
|
||||
namespace ErsatzTV.Core.Tests.Metadata.Nfo; |
||||
|
||||
[TestFixture] |
||||
public class ArtistNfoReaderTests |
||||
{ |
||||
[SetUp] |
||||
public void SetUp() => _artistNfoReader = new ArtistNfoReader(new Mock<IClient>().Object); |
||||
|
||||
private ArtistNfoReader _artistNfoReader; |
||||
|
||||
[Test] |
||||
public async Task ParsingNfo_Should_Return_Error() |
||||
{ |
||||
await using var stream = |
||||
new MemoryStream(Encoding.UTF8.GetBytes(@"https://www.themoviedb.org/movie/11-star-wars")); |
||||
|
||||
Either<BaseError, ArtistNfo> result = await _artistNfoReader.Read(stream); |
||||
|
||||
result.IsLeft.Should().BeTrue(); |
||||
} |
||||
|
||||
[Test] |
||||
public async Task MetadataNfo_Should_Return_Nfo() |
||||
{ |
||||
await using var stream = new MemoryStream(Encoding.UTF8.GetBytes(@"<artist></artist>")); |
||||
|
||||
Either<BaseError, ArtistNfo> result = await _artistNfoReader.Read(stream); |
||||
|
||||
result.IsRight.Should().BeTrue(); |
||||
} |
||||
|
||||
[Test] |
||||
public async Task CombinationNfo_Should_Return_Nfo() |
||||
{ |
||||
await using var stream = new MemoryStream( |
||||
Encoding.UTF8.GetBytes( |
||||
@"<artist></artist>
|
||||
https://www.themoviedb.org/movie/11-star-wars"));
|
||||
|
||||
Either<BaseError, ArtistNfo> result = await _artistNfoReader.Read(stream); |
||||
|
||||
result.IsRight.Should().BeTrue(); |
||||
} |
||||
|
||||
[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"" ?>
|
||||
<artist> |
||||
<name>Billy Joel</name> |
||||
<musicBrainzArtistID>64b94289-9474-4d43-8c93-918ccc1920d1</musicBrainzArtistID> |
||||
<sortname>Joel, Billy</sortname> |
||||
<type>Person</type> |
||||
<gender>Male</gender> |
||||
<disambiguation></disambiguation> |
||||
<genre>Pop/Rock</genre> |
||||
<style>Album Rock</style> |
||||
<style>Contemporary Pop/Rock</style> |
||||
<style>Singer/Songwriter</style> |
||||
<style>Soft Rock</style> |
||||
<style>Keyboard</style> |
||||
<mood>Amiable/Good-Natured</mood> |
||||
<mood>Autumnal</mood> |
||||
<mood>Nostalgic</mood> |
||||
<mood>Refined</mood> |
||||
<mood>Acerbic</mood> |
||||
<mood>Bittersweet</mood> |
||||
<mood>Brash</mood> |
||||
<mood>Cynical/Sarcastic</mood> |
||||
<mood>Earnest</mood> |
||||
<yearsactive>1960s - 2010s</yearsactive> |
||||
<born>1949-05-09</born> |
||||
<formed>1964</formed> |
||||
<biography>William Martin "Billy" Joel (born May 9, 1949, New York, USA) is an American pianist, singer-songwriter, and composer. Since releasing his first hit song, "Piano Man", in 1973, Joel has become the sixth-best-selling recording artist and the third-best-selling solo artist in the United States, according to the RIAA. His compilation album Greatest Hits Vol. 1 & 2 is the third-best-selling album in the United States by discs shipped.
Joel had Top 40 hits in the 1970s, 1980s, and 1990s, achieving 33 Top 40 hits in the United States, all of which he wrote himself. He is also a six-time Grammy Award winner, a 23-time Grammy nominee and one of the world's best-selling artists of all time, having sold over 150 million records worldwide. He was inducted into the Songwriter's Hall of Fame (1992), the Rock and Roll Hall of Fame (1999), and the Long Island Music Hall of Fame (2006). In 2008, Billboard magazine released a list of the Hot 100 All-Time Top Artists to celebrate the US singles chart's 50th anniversary, with Billy Joel positioned at No. 23. With the exception of the 2007 songs "All My Life" and "Christmas in Fallujah", Joel stopped writing and recording popular music after 1993's River of Dreams, but he continued to tour extensively until 2010. Joel was born in the Bronx, May 9, 1949 and raised in Hicksville, New York in a Levitt home. His father, Howard (born Helmuth), was born in Germany, the son of German merchant and manufacturer Karl Amson Joel, who, after the advent of the Nazi regime, emigrated to Switzerland and later to the United States. Billy Joel's mother, Rosalind Nyman, was born in England to Philip and Rebecca Nyman. Both of Joel's parents were Jewish. They divorced in 1960, and his father moved to Vienna, Austria. Billy has a sister, Judith Joel, and a half-brother, Alexander Joel, who is an acclaimed classical conductor in Europe and currently chief musical director of the Staatstheater Braunschweig.
Joel's father was an accomplished classical pianist. Billy reluctantly began piano lessons at an early age, at his mother's insistence; his teachers included the noted American pianist Morton Estrin and musician/songwriter Timothy Ford. His interest in music, rather than sports, was a source of teasing and bullying in his early years. (He has said in interviews that his piano instructor also taught ballet. Her name was Frances Neiman, and she was a Juilliard trained musician. She gave both classical piano and ballet lessons in the studio attached to the rear of her house, leading neighborhood bullies to mistakenly assume that he was learning to dance.) As a teenager, Joel took up boxing so that he would be able to defend himself. He boxed successfully on the amateur Golden Gloves circuit for a short time, winning twenty-two bouts, but abandoned the sport shortly after breaking his nose in his twenty-fourth boxing match.
Joel attended Hicksville High School in 1967, but he did not graduate with his class. He had been helping his single mother make ends meet by playing at a piano bar, which interfered with his school attendance. At the end of his senior year, Joel did not have enough credits to graduate. Rather than attend summer school to earn his diploma, however, Joel decided to immediately begin a career in music. Joel recounted, "I told them, 'To hell with it. If I'm not going to Columbia University, I'm going to Columbia Records, and you don't need a high school diploma over there'." Columbia did, in fact, become the label that eventually signed him. In 1992, he submitted essays to the school board and was awarded his diploma at Hicksville High's annual graduation ceremony, 25 years after he had left.</biography> |
||||
<died></died> |
||||
<disbanded></disbanded> |
||||
<thumb spoof="""" cache="""" aspect=""thumb"" preview=""https://assets.fanart.tv/preview/music/64b94289-9474-4d43-8c93-918ccc1920d1/artistthumb/joel-billy-541603848114c.jpg"">https://assets.fanart.tv/fanart/music/64b94289-9474-4d43-8c93-918ccc1920d1/artistthumb/joel-billy-541603848114c.jpg</thumb>
|
||||
<thumb spoof="""" cache="""" aspect=""thumb"" preview=""https://www.theaudiodb.com/images/media/artist/thumb/ttsxwr1425765041.jpg/preview"">https://www.theaudiodb.com/images/media/artist/thumb/ttsxwr1425765041.jpg</thumb>
|
||||
<thumb spoof="""" cache="""" aspect=""thumb"" preview=""https://rovimusic.rovicorp.com/image.jpg?c=73pC-Gp0OovlmiQL7Wp5Yd_M69_UI9rrJSVvWL2-yAg=&f=2"">https://rovimusic.rovicorp.com/image.jpg?c=73pC-Gp0OovlmiQL7Wp5Yd_M69_UI9rrJSVvWL2-yAg=&f=0</thumb>
|
||||
<thumb spoof="""" cache="""" aspect=""thumb"" preview=""https://img.discogs.com/J3bqAiLmdr2gXsetNgSQF2W-f6M=/150x150/smart/filters:strip_icc():format(jpeg):mode_rgb():quality(40)/discogs-images/A-137418-1143052539.jpeg.jpg"">https://img.discogs.com/u7cfC3lZo9JGRdukSttJTZKr9Go=/350x255/smart/filters:strip_icc():format(jpeg):mode_rgb():quality(90)/discogs-images/A-137418-1143052539.jpeg.jpg</thumb>
|
||||
<thumb spoof="""" cache="""" aspect=""clearlogo"" preview=""https://www.theaudiodb.com/images/media/artist/logo/tvqpys1367246337.png/preview"">https://www.theaudiodb.com/images/media/artist/logo/tvqpys1367246337.png</thumb>
|
||||
<thumb spoof="""" cache="""" aspect=""clearart"" preview=""https://www.theaudiodb.com/images/media/artist/clearart/yqpsuq1523892204.png/preview"">https://www.theaudiodb.com/images/media/artist/clearart/yqpsuq1523892204.png</thumb>
|
||||
<thumb spoof="""" cache="""" aspect=""landscape"" preview=""https://www.theaudiodb.com/images/media/artist/widethumb/tywpqx1530815867.jpg/preview"">https://www.theaudiodb.com/images/media/artist/widethumb/tywpqx1530815867.jpg</thumb>
|
||||
<thumb spoof="""" cache="""" aspect=""banner"" preview=""https://assets.fanart.tv/preview/music/64b94289-9474-4d43-8c93-918ccc1920d1/musicbanner/joel-billy-5914e7759bfcd.jpg"">https://assets.fanart.tv/fanart/music/64b94289-9474-4d43-8c93-918ccc1920d1/musicbanner/joel-billy-5914e7759bfcd.jpg</thumb>
|
||||
<thumb spoof="""" cache="""" aspect=""clearlogo"" preview=""https://assets.fanart.tv/preview/music/64b94289-9474-4d43-8c93-918ccc1920d1/hdmusiclogo/joel-billy-550b259604412.png"">https://assets.fanart.tv/fanart/music/64b94289-9474-4d43-8c93-918ccc1920d1/hdmusiclogo/joel-billy-550b259604412.png</thumb>
|
||||
<thumb spoof="""" cache="""" aspect=""fanart"" preview=""https://assets.fanart.tv/preview/music/64b94289-9474-4d43-8c93-918ccc1920d1/artistbackground/joel-billy-4fc0c2dad9ab7.jpg"">https://assets.fanart.tv/fanart/music/64b94289-9474-4d43-8c93-918ccc1920d1/artistbackground/joel-billy-4fc0c2dad9ab7.jpg</thumb>
|
||||
<thumb spoof="""" cache="""" aspect=""fanart"" preview=""https://www.theaudiodb.com/images/media/artist/fanart/uwqtup1521206367.jpg/preview"">https://www.theaudiodb.com/images/media/artist/fanart/uwqtup1521206367.jpg</thumb>
|
||||
<path>F:\Music\ArtistInfoKodi\Billy Joel</path> |
||||
</artist>"));
|
||||
|
||||
Either<BaseError, ArtistNfo> result = await _artistNfoReader.Read(stream); |
||||
|
||||
result.IsRight.Should().BeTrue(); |
||||
|
||||
foreach (ArtistNfo nfo in result.RightToSeq()) |
||||
{ |
||||
nfo.Name.Should().Be("Billy Joel"); |
||||
nfo.Disambiguation.Should().BeNullOrEmpty(); |
||||
nfo.Genres.Should().BeEquivalentTo(new List<string> { "Pop/Rock" }); |
||||
nfo.Styles.Should().BeEquivalentTo( |
||||
new List<string> |
||||
{ |
||||
"Album Rock", |
||||
"Contemporary Pop/Rock", |
||||
"Singer/Songwriter", |
||||
"Soft Rock", |
||||
"Keyboard" |
||||
}); |
||||
nfo.Moods.Should().BeEquivalentTo( |
||||
new List<string> |
||||
{ |
||||
"Amiable/Good-Natured", |
||||
"Autumnal", |
||||
"Nostalgic", |
||||
"Refined", |
||||
"Acerbic", |
||||
"Bittersweet", |
||||
"Brash", |
||||
"Cynical/Sarcastic", |
||||
"Earnest" |
||||
}); |
||||
nfo.Biography.Should().Be( |
||||
@"William Martin ""Billy"" Joel (born May 9, 1949, New York, USA) is an American pianist, singer-songwriter, and composer. Since releasing his first hit song, ""Piano Man"", in 1973, Joel has become the sixth-best-selling recording artist and the third-best-selling solo artist in the United States, according to the RIAA. His compilation album Greatest Hits Vol. 1 & 2 is the third-best-selling album in the United States by discs shipped.
|
||||
Joel had Top 40 hits in the 1970s, 1980s, and 1990s, achieving 33 Top 40 hits in the United States, all of which he wrote himself. He is also a six-time Grammy Award winner, a 23-time Grammy nominee and one of the world's best-selling artists of all time, having sold over 150 million records worldwide. He was inducted into the Songwriter's Hall of Fame (1992), the Rock and Roll Hall of Fame (1999), and the Long Island Music Hall of Fame (2006). In 2008, Billboard magazine released a list of the Hot 100 All-Time Top Artists to celebrate the US singles chart's 50th anniversary, with Billy Joel positioned at No. 23. With the exception of the 2007 songs ""All My Life"" and ""Christmas in Fallujah"", Joel stopped writing and recording popular music after 1993's River of Dreams, but he continued to tour extensively until 2010. Joel was born in the Bronx, May 9, 1949 and raised in Hicksville, New York in a Levitt home. His father, Howard (born Helmuth), was born in Germany, the son of German merchant and manufacturer Karl Amson Joel, who, after the advent of the Nazi regime, emigrated to Switzerland and later to the United States. Billy Joel's mother, Rosalind Nyman, was born in England to Philip and Rebecca Nyman. Both of Joel's parents were Jewish. They divorced in 1960, and his father moved to Vienna, Austria. Billy has a sister, Judith Joel, and a half-brother, Alexander Joel, who is an acclaimed classical conductor in Europe and currently chief musical director of the Staatstheater Braunschweig. |
||||
Joel's father was an accomplished classical pianist. Billy reluctantly began piano lessons at an early age, at his mother's insistence; his teachers included the noted American pianist Morton Estrin and musician/songwriter Timothy Ford. His interest in music, rather than sports, was a source of teasing and bullying in his early years. (He has said in interviews that his piano instructor also taught ballet. Her name was Frances Neiman, and she was a Juilliard trained musician. She gave both classical piano and ballet lessons in the studio attached to the rear of her house, leading neighborhood bullies to mistakenly assume that he was learning to dance.) As a teenager, Joel took up boxing so that he would be able to defend himself. He boxed successfully on the amateur Golden Gloves circuit for a short time, winning twenty-two bouts, but abandoned the sport shortly after breaking his nose in his twenty-fourth boxing match. |
||||
Joel attended Hicksville High School in 1967, but he did not graduate with his class. He had been helping his single mother make ends meet by playing at a piano bar, which interfered with his school attendance. At the end of his senior year, Joel did not have enough credits to graduate. Rather than attend summer school to earn his diploma, however, Joel decided to immediately begin a career in music. Joel recounted, ""I told them, 'To hell with it. If I'm not going to Columbia University, I'm going to Columbia Records, and you don't need a high school diploma over there'."" Columbia did, in fact, become the label that eventually signed him. In 1992, he submitted essays to the school board and was awarded his diploma at Hicksville High's annual graduation ceremony, 25 years after he had left.");
|
||||
} |
||||
} |
||||
|
||||
[Test] |
||||
public async Task MetadataNfo_With_Disambiguation_Should_Return_Nfo() |
||||
{ |
||||
await using var stream = new MemoryStream( |
||||
Encoding.UTF8.GetBytes(@"<artist><disambiguation>Test Disambiguation</disambiguation></artist>")); |
||||
|
||||
Either<BaseError, ArtistNfo> result = await _artistNfoReader.Read(stream); |
||||
|
||||
result.IsRight.Should().BeTrue(); |
||||
foreach (ArtistNfo nfo in result.RightToSeq()) |
||||
{ |
||||
nfo.Disambiguation.Should().Be("Test Disambiguation"); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,156 @@
@@ -0,0 +1,156 @@
|
||||
using System.Text; |
||||
using Bugsnag; |
||||
using ErsatzTV.Core.Metadata.Nfo; |
||||
using FluentAssertions; |
||||
using Moq; |
||||
using NUnit.Framework; |
||||
|
||||
namespace ErsatzTV.Core.Tests.Metadata.Nfo; |
||||
|
||||
[TestFixture] |
||||
public class MusicVideoNfoReaderTests |
||||
{ |
||||
[SetUp] |
||||
public void SetUp() => _musicVideoNfoReader = new MusicVideoNfoReader(new Mock<IClient>().Object); |
||||
|
||||
private MusicVideoNfoReader _musicVideoNfoReader; |
||||
|
||||
[Test] |
||||
public async Task ParsingNfo_Should_Return_Error() |
||||
{ |
||||
await using var stream = |
||||
new MemoryStream(Encoding.UTF8.GetBytes(@"https://www.themoviedb.org/movie/11-star-wars")); |
||||
|
||||
Either<BaseError, MusicVideoNfo> result = await _musicVideoNfoReader.Read(stream); |
||||
|
||||
result.IsLeft.Should().BeTrue(); |
||||
} |
||||
|
||||
[Test] |
||||
public async Task MetadataNfo_Should_Return_Nfo() |
||||
{ |
||||
await using var stream = new MemoryStream(Encoding.UTF8.GetBytes(@"<musicvideo></musicvideo>")); |
||||
|
||||
Either<BaseError, MusicVideoNfo> result = await _musicVideoNfoReader.Read(stream); |
||||
|
||||
result.IsRight.Should().BeTrue(); |
||||
} |
||||
|
||||
[Test] |
||||
public async Task CombinationNfo_Should_Return_Nfo() |
||||
{ |
||||
await using var stream = new MemoryStream( |
||||
Encoding.UTF8.GetBytes( |
||||
@"<musicvideo></musicvideo>
|
||||
https://www.themoviedb.org/movie/11-star-wars"));
|
||||
|
||||
Either<BaseError, MusicVideoNfo> result = await _musicVideoNfoReader.Read(stream); |
||||
|
||||
result.IsRight.Should().BeTrue(); |
||||
} |
||||
|
||||
[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"" ?>
|
||||
<musicvideo> |
||||
<title>Dancing Queen</title> |
||||
<userrating>0</userrating> |
||||
<top250>0</top250> |
||||
<track>-1</track> |
||||
<album>Arrival</album> |
||||
<outline></outline> |
||||
<plot>Dancing Queen est un des tubes emblématiques de l'ère disco produits par le groupe suédois ABBA en 1976. Ce tube connaît un regain de popularité en 1994 lors de la sortie de Priscilla, folle du désert, et fait « presque » partie de la distribution du film Muriel.
Le groupe a également enregistré une version espagnole de ce titre, La reina del baile, pour le marché d'Amérique latine. On peut retrouver ces versions en espagnol des succès de ABBA sur l'abum Oro. Le 18 juin 1976, ABBA a interprété cette chanson lors d'un spectacle télévisé organisé en l'honneur du roi Charles XVI Gustave de Suède, qui venait de se marier. Le titre sera repris en 2011 par Glee dans la saison 2, épisode 20.</plot> |
||||
<tagline></tagline> |
||||
<runtime>2</runtime> |
||||
<thumb preview=""https://www.theaudiodb.com/images/media/album/thumb/arrival-4ee244732bbde.jpg/preview"">https://www.theaudiodb.com/images/media/album/thumb/arrival-4ee244732bbde.jpg</thumb>
|
||||
<thumb preview=""https://assets.fanart.tv/preview/music/d87e52c5-bb8d-4da8-b941-9f4928627dc8/albumcover/arrival-548ab7a698b49.jpg"">https://assets.fanart.tv/fanart/music/d87e52c5-bb8d-4da8-b941-9f4928627dc8/albumcover/arrival-548ab7a698b49.jpg</thumb>
|
||||
<mpaa></mpaa> |
||||
<playcount>0</playcount> |
||||
<lastplayed></lastplayed> |
||||
<id></id> |
||||
<genre>Pop</genre> |
||||
<year>1976</year> |
||||
<status></status> |
||||
<director>Director 1</director> |
||||
<director>Director 2</director> |
||||
<director>Director 3</director> |
||||
<director>Director 4</director> |
||||
<code></code> |
||||
<aired></aired> |
||||
<trailer></trailer> |
||||
<fileinfo> |
||||
<streamdetails> |
||||
<video> |
||||
<codec>hevc</codec> |
||||
<aspect>1.792230</aspect> |
||||
<width>716</width> |
||||
<height>568</height> |
||||
<durationinseconds>143</durationinseconds> |
||||
<stereomode></stereomode> |
||||
</video> |
||||
<audio> |
||||
<codec>ac3</codec> |
||||
<language>eng</language> |
||||
<channels>2</channels> |
||||
</audio> |
||||
</streamdetails> |
||||
</fileinfo> |
||||
<artist>ABBA</artist> |
||||
<resume> |
||||
<position>0.000000</position> |
||||
<total>0.000000</total> |
||||
</resume> |
||||
<dateadded>2018-09-10 09:46:06</dateadded> |
||||
</musicvideo>"));
|
||||
|
||||
Either<BaseError, MusicVideoNfo> result = await _musicVideoNfoReader.Read(stream); |
||||
|
||||
result.IsRight.Should().BeTrue(); |
||||
|
||||
foreach (MusicVideoNfo nfo in result.RightToSeq()) |
||||
{ |
||||
nfo.Artist.Should().Be("ABBA"); |
||||
nfo.Title.Should().Be("Dancing Queen"); |
||||
nfo.Album.Should().Be("Arrival"); |
||||
nfo.Plot.Should().Be( |
||||
@"Dancing Queen est un des tubes emblématiques de l'ère disco produits par le groupe suédois ABBA en 1976. Ce tube connaît un regain de popularité en 1994 lors de la sortie de Priscilla, folle du désert, et fait « presque » partie de la distribution du film Muriel.
|
||||
Le groupe a également enregistré une version espagnole de ce titre, La reina del baile, pour le marché d'Amérique latine. On peut retrouver ces versions en espagnol des succès de ABBA sur l'abum Oro. Le 18 juin 1976, ABBA a interprété cette chanson lors d'un spectacle télévisé organisé en l'honneur du roi Charles XVI Gustave de Suède, qui venait de se marier. Le titre sera repris en 2011 par Glee dans la saison 2, épisode 20.");
|
||||
|
||||
nfo.Year.Should().Be(1976); |
||||
nfo.Genres.Should().BeEquivalentTo(new List<string> { "Pop" }); |
||||
} |
||||
} |
||||
|
||||
[Test] |
||||
public async Task MetadataNfo_With_Tags_Should_Return_Nfo() |
||||
{ |
||||
await using var stream = new MemoryStream( |
||||
Encoding.UTF8.GetBytes(@"<musicvideo><tag>Test Tag</tag></musicvideo>")); |
||||
|
||||
Either<BaseError, MusicVideoNfo> result = await _musicVideoNfoReader.Read(stream); |
||||
|
||||
result.IsRight.Should().BeTrue(); |
||||
foreach (MusicVideoNfo nfo in result.RightToSeq()) |
||||
{ |
||||
nfo.Tags.Should().BeEquivalentTo(new List<string> { "Test Tag" }); |
||||
} |
||||
} |
||||
|
||||
[Test] |
||||
public async Task MetadataNfo_With_Studios_Should_Return_Nfo() |
||||
{ |
||||
await using var stream = new MemoryStream( |
||||
Encoding.UTF8.GetBytes(@"<musicvideo><studio>Test Studio</studio></musicvideo>")); |
||||
|
||||
Either<BaseError, MusicVideoNfo> result = await _musicVideoNfoReader.Read(stream); |
||||
|
||||
result.IsRight.Should().BeTrue(); |
||||
foreach (MusicVideoNfo nfo in result.RightToSeq()) |
||||
{ |
||||
nfo.Studios.Should().BeEquivalentTo(new List<string> { "Test Studio" }); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,216 @@
@@ -0,0 +1,216 @@
|
||||
using System.Text; |
||||
using Bugsnag; |
||||
using ErsatzTV.Core.Metadata.Nfo; |
||||
using FluentAssertions; |
||||
using Moq; |
||||
using NUnit.Framework; |
||||
|
||||
namespace ErsatzTV.Core.Tests.Metadata.Nfo; |
||||
|
||||
[TestFixture] |
||||
public class TvShowNfoReaderTests |
||||
{ |
||||
[SetUp] |
||||
public void SetUp() => _tvShowNfoReader = new TvShowNfoReader(new Mock<IClient>().Object); |
||||
|
||||
private TvShowNfoReader _tvShowNfoReader; |
||||
|
||||
[Test] |
||||
public async Task ParsingNfo_Should_Return_Error() |
||||
{ |
||||
await using var stream = |
||||
new MemoryStream(Encoding.UTF8.GetBytes(@"https://www.themoviedb.org/movie/11-star-wars")); |
||||
|
||||
Either<BaseError, TvShowNfo> result = await _tvShowNfoReader.Read(stream); |
||||
|
||||
result.IsLeft.Should().BeTrue(); |
||||
} |
||||
|
||||
[Test] |
||||
public async Task MetadataNfo_Should_Return_Nfo() |
||||
{ |
||||
await using var stream = new MemoryStream(Encoding.UTF8.GetBytes(@"<tvshow></tvshow>")); |
||||
|
||||
Either<BaseError, TvShowNfo> result = await _tvShowNfoReader.Read(stream); |
||||
|
||||
result.IsRight.Should().BeTrue(); |
||||
} |
||||
|
||||
[Test] |
||||
public async Task CombinationNfo_Should_Return_Nfo() |
||||
{ |
||||
await using var stream = new MemoryStream( |
||||
Encoding.UTF8.GetBytes( |
||||
@"<tvshow></tvshow>
|
||||
https://www.themoviedb.org/movie/11-star-wars"));
|
||||
|
||||
Either<BaseError, TvShowNfo> result = await _tvShowNfoReader.Read(stream); |
||||
|
||||
result.IsRight.Should().BeTrue(); |
||||
} |
||||
|
||||
[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"" ?>
|
||||
<tvshow> |
||||
<title>WandaVision</title> |
||||
<originaltitle>WandaVision</originaltitle> |
||||
<showtitle>WandaVision</showtitle> |
||||
<ratings> |
||||
<rating name=""imdb"" max=""10"" default=""true""> |
||||
<value>8.200000</value> |
||||
<votes>105359</votes> |
||||
</rating> |
||||
<rating name=""tmdb"" max=""10""> |
||||
<value>8.500000</value> |
||||
<votes>7230</votes> |
||||
</rating> |
||||
<rating name=""trakt"" max=""10""> |
||||
<value>8.077950</value> |
||||
<votes>3284</votes> |
||||
</rating> |
||||
</ratings> |
||||
<userrating>0</userrating> |
||||
<top250>0</top250> |
||||
<season>1</season> |
||||
<episode>9</episode> |
||||
<displayseason>-1</displayseason> |
||||
<displayepisode>-1</displayepisode> |
||||
<outline></outline> |
||||
<plot>Wanda Maximoff and Vision—two super-powered beings living idealized suburban lives—begin to suspect that everything is not as it seems.</plot> |
||||
<tagline></tagline> |
||||
<runtime>0</runtime> |
||||
<thumb spoof="""" cache="""" aspect=""landscape"" preview=""https://image.tmdb.org/t/p/w780/dUWto4NaeJFrGx7jm8m3KLymUGf.jpg"">https://image.tmdb.org/t/p/original/dUWto4NaeJFrGx7jm8m3KLymUGf.jpg</thumb>
|
||||
<thumb spoof="""" cache="""" aspect=""poster"" preview=""https://image.tmdb.org/t/p/w780/8UsAB1hgwnd80eI2ociyppB6UXL.jpg"">https://image.tmdb.org/t/p/original/8UsAB1hgwnd80eI2ociyppB6UXL.jpg</thumb>
|
||||
<thumb spoof="""" cache="""" aspect=""poster"" preview=""https://assets.fanart.tv/preview/tv/362392/tvposter/wandavision-6009571d1ed1f.jpg"">https://assets.fanart.tv/fanart/tv/362392/tvposter/wandavision-6009571d1ed1f.jpg</thumb>
|
||||
<thumb spoof="""" cache="""" aspect=""clearlogo"" preview=""https://assets.fanart.tv/preview/tv/362392/hdtvlogo/marvels-wandavision-5f6ac3b1e9458.png"">https://assets.fanart.tv/fanart/tv/362392/hdtvlogo/marvels-wandavision-5f6ac3b1e9458.png</thumb>
|
||||
<thumb spoof="""" cache="""" aspect=""clearart"" preview=""https://assets.fanart.tv/preview/tv/362392/hdclearart/wandavision-6009b6875a285.png"">https://assets.fanart.tv/fanart/tv/362392/hdclearart/wandavision-6009b6875a285.png</thumb>
|
||||
<thumb spoof="""" cache="""" aspect=""landscape"" preview=""https://assets.fanart.tv/preview/tv/362392/tvthumb/wandavision-603032a5349b9.jpg"">https://assets.fanart.tv/fanart/tv/362392/tvthumb/wandavision-603032a5349b9.jpg</thumb>
|
||||
<thumb spoof="""" cache="""" season=""1"" type=""season"" aspect=""poster"" preview=""https://image.tmdb.org/t/p/w780/7u443QI5xNIfLgNzEsV43CYZCWX.jpg"">https://image.tmdb.org/t/p/original/7u443QI5xNIfLgNzEsV43CYZCWX.jpg</thumb>
|
||||
<fanart> |
||||
<thumb colors="""" preview="""">https://image.tmdb.org/t/p/original/57vVjteucIF3bGnZj6PmaoJRScw.jpg</thumb>
|
||||
<thumb colors="""" preview="""">https://assets.fanart.tv/fanart/tv/362392/showbackground/marvels-wandavision-5ff4fef387a43.jpg</thumb>
|
||||
</fanart> |
||||
<mpaa>Australia:M</mpaa> |
||||
<playcount>0</playcount> |
||||
<lastplayed>2021-03-29</lastplayed> |
||||
<id>85271</id> |
||||
<uniqueid type=""imdb"">tt9140560</uniqueid> |
||||
<uniqueid type=""tmdb"" default=""true"">85271</uniqueid> |
||||
<uniqueid type=""tvdb"">362392</uniqueid> |
||||
<genre>SuperHero</genre> |
||||
<premiered>2021-01-15</premiered> |
||||
<year>2021</year> |
||||
<status>Ended</status> |
||||
<code></code> |
||||
<aired></aired> |
||||
<studio>Disney+</studio> |
||||
<actor> |
||||
<name>Elizabeth Olsen</name> |
||||
<role>Wanda Maximoff / The Scarlet Witch</role> |
||||
<order>0</order> |
||||
<thumb>https://image.tmdb.org/t/p/original/wIU675y4dofIDVuhaNWPizJNtep.jpg</thumb>
|
||||
</actor> |
||||
<actor> |
||||
<name>Paul Bettany</name> |
||||
<role>Vision / The Vision</role> |
||||
<order>1</order> |
||||
<thumb>https://image.tmdb.org/t/p/original/vcAVrAOZrpqmi37qjFdztRAv1u9.jpg</thumb>
|
||||
</actor> |
||||
<namedseason number=""1"">Season 1</namedseason> |
||||
<resume> |
||||
<position>0.000000</position> |
||||
<total>0.000000</total> |
||||
</resume> |
||||
<dateadded>2021-03-12 06:15:51</dateadded> |
||||
</tvshow>"));
|
||||
|
||||
Either<BaseError, TvShowNfo> result = await _tvShowNfoReader.Read(stream); |
||||
|
||||
result.IsRight.Should().BeTrue(); |
||||
|
||||
foreach (TvShowNfo nfo in result.RightToSeq()) |
||||
{ |
||||
nfo.Title.Should().Be("WandaVision"); |
||||
nfo.Year.Should().Be(2021); |
||||
nfo.Plot.Should().Be( |
||||
"Wanda Maximoff and Vision—two super-powered beings living idealized suburban lives—begin to suspect that everything is not as it seems."); |
||||
nfo.ContentRating.Should().Be("Australia:M"); |
||||
nfo.Genres.Should().BeEquivalentTo(new List<string> { "SuperHero" }); |
||||
nfo.Studios.Should().BeEquivalentTo(new List<string> { "Disney+" }); |
||||
nfo.Actors.Should().BeEquivalentTo( |
||||
new List<ActorNfo> |
||||
{ |
||||
new() |
||||
{ |
||||
Name = "Elizabeth Olsen", Order = 0, Role = "Wanda Maximoff / The Scarlet Witch", |
||||
Thumb = "https://image.tmdb.org/t/p/original/wIU675y4dofIDVuhaNWPizJNtep.jpg" |
||||
}, |
||||
new() |
||||
{ |
||||
Name = "Paul Bettany", Order = 1, Role = "Vision / The Vision", |
||||
Thumb = "https://image.tmdb.org/t/p/original/vcAVrAOZrpqmi37qjFdztRAv1u9.jpg" |
||||
} |
||||
}); |
||||
nfo.UniqueIds.Should().BeEquivalentTo( |
||||
new List<UniqueIdNfo> |
||||
{ |
||||
new() { Type = "imdb", Guid = "tt9140560", Default = false }, |
||||
new() { Type = "tmdb", Guid = "85271", Default = true }, |
||||
new() { Type = "tvdb", Guid = "362392", Default = false } |
||||
}); |
||||
nfo.Premiered.IsSome.Should().BeTrue(); |
||||
foreach (DateTime premiered in nfo.Premiered) |
||||
{ |
||||
premiered.Should().Be(new DateTime(2021, 1, 15)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
[Test] |
||||
public async Task MetadataNfo_With_Outline_Should_Return_Nfo() |
||||
{ |
||||
await using var stream = |
||||
new MemoryStream(Encoding.UTF8.GetBytes(@"<tvshow><outline>Test Outline</outline></tvshow>")); |
||||
|
||||
Either<BaseError, TvShowNfo> result = await _tvShowNfoReader.Read(stream); |
||||
|
||||
result.IsRight.Should().BeTrue(); |
||||
foreach (TvShowNfo nfo in result.RightToSeq()) |
||||
{ |
||||
nfo.Outline.Should().Be("Test Outline"); |
||||
} |
||||
} |
||||
|
||||
[Test] |
||||
public async Task MetadataNfo_With_Tagline_Should_Return_Nfo() |
||||
{ |
||||
await using var stream = |
||||
new MemoryStream(Encoding.UTF8.GetBytes(@"<tvshow><tagline>Test Tagline</tagline></tvshow>")); |
||||
|
||||
Either<BaseError, TvShowNfo> result = await _tvShowNfoReader.Read(stream); |
||||
|
||||
result.IsRight.Should().BeTrue(); |
||||
foreach (TvShowNfo nfo in result.RightToSeq()) |
||||
{ |
||||
nfo.Tagline.Should().Be("Test Tagline"); |
||||
} |
||||
} |
||||
|
||||
[Test] |
||||
public async Task MetadataNfo_With_Tag_Should_Return_Nfo() |
||||
{ |
||||
await using var stream = new MemoryStream(Encoding.UTF8.GetBytes(@"<tvshow><tag>Test Tag</tag></tvshow>")); |
||||
|
||||
Either<BaseError, TvShowNfo> result = await _tvShowNfoReader.Read(stream); |
||||
|
||||
result.IsRight.Should().BeTrue(); |
||||
foreach (TvShowNfo nfo in result.RightToSeq()) |
||||
{ |
||||
nfo.Tags.Should().BeEquivalentTo(new List<string> { "Test Tag" }); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
|
||||
using ErsatzTV.Core.Metadata.Nfo; |
||||
|
||||
namespace ErsatzTV.Core.Interfaces.Metadata.Nfo; |
||||
|
||||
public interface IArtistNfoReader |
||||
{ |
||||
Task<Either<BaseError, ArtistNfo>> Read(Stream input); |
||||
} |
||||
@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
|
||||
using ErsatzTV.Core.Metadata.Nfo; |
||||
|
||||
namespace ErsatzTV.Core.Interfaces.Metadata.Nfo; |
||||
|
||||
public interface IMusicVideoNfoReader |
||||
{ |
||||
Task<Either<BaseError, MusicVideoNfo>> Read(Stream input); |
||||
} |
||||
@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
|
||||
using ErsatzTV.Core.Metadata.Nfo; |
||||
|
||||
namespace ErsatzTV.Core.Interfaces.Metadata.Nfo; |
||||
|
||||
public interface ITvShowNfoReader |
||||
{ |
||||
Task<Either<BaseError, TvShowNfo>> Read(Stream input); |
||||
} |
||||
@ -0,0 +1,83 @@
@@ -0,0 +1,83 @@
|
||||
using System.Xml; |
||||
using Bugsnag; |
||||
using ErsatzTV.Core.Errors; |
||||
using ErsatzTV.Core.Interfaces.Metadata.Nfo; |
||||
|
||||
namespace ErsatzTV.Core.Metadata.Nfo; |
||||
|
||||
public class ArtistNfoReader : NfoReader<ArtistNfo>, IArtistNfoReader |
||||
{ |
||||
private readonly IClient _client; |
||||
|
||||
public ArtistNfoReader(IClient client) => _client = client; |
||||
|
||||
public async Task<Either<BaseError, ArtistNfo>> Read(Stream input) |
||||
{ |
||||
try |
||||
{ |
||||
var settings = new XmlReaderSettings { Async = true, ConformanceLevel = ConformanceLevel.Fragment }; |
||||
using var reader = XmlReader.Create(input, settings); |
||||
ArtistNfo nfo = null; |
||||
var done = false; |
||||
|
||||
while (!done && await reader.ReadAsync()) |
||||
{ |
||||
switch (reader.NodeType) |
||||
{ |
||||
case XmlNodeType.Element: |
||||
switch (reader.Name.ToLowerInvariant()) |
||||
{ |
||||
case "artist": |
||||
nfo = new ArtistNfo |
||||
{ |
||||
Genres = new List<string>(), |
||||
Styles = new List<string>(), |
||||
Moods = new List<string>() |
||||
}; |
||||
break; |
||||
case "name": |
||||
await ReadStringContent(reader, nfo, (artist, name) => artist.Name = name); |
||||
break; |
||||
case "disambiguation": |
||||
await ReadStringContent( |
||||
reader, |
||||
nfo, |
||||
(artist, disambiguation) => artist.Disambiguation = disambiguation); |
||||
break; |
||||
case "genre": |
||||
await ReadStringContent(reader, nfo, (artist, genre) => artist.Genres.Add(genre)); |
||||
break; |
||||
case "style": |
||||
await ReadStringContent(reader, nfo, (artist, style) => artist.Styles.Add(style)); |
||||
break; |
||||
case "mood": |
||||
await ReadStringContent(reader, nfo, (artist, mood) => artist.Moods.Add(mood)); |
||||
break; |
||||
case "biography": |
||||
await ReadStringContent( |
||||
reader, |
||||
nfo, |
||||
(artist, biography) => artist.Biography = biography); |
||||
break; |
||||
} |
||||
|
||||
break; |
||||
case XmlNodeType.EndElement: |
||||
if (reader.Name == "artist") |
||||
{ |
||||
done = true; |
||||
} |
||||
|
||||
break; |
||||
} |
||||
} |
||||
|
||||
return Optional(nfo).ToEither((BaseError)new FailedToReadNfo()); |
||||
} |
||||
catch (Exception ex) |
||||
{ |
||||
_client.Notify(ex); |
||||
return new FailedToReadNfo(ex.ToString()); |
||||
} |
||||
} |
||||
} |
||||
@ -1,104 +1,115 @@
@@ -1,104 +1,115 @@
|
||||
using System.Xml; |
||||
using Bugsnag; |
||||
using ErsatzTV.Core.Errors; |
||||
using ErsatzTV.Core.Interfaces.Metadata.Nfo; |
||||
|
||||
namespace ErsatzTV.Core.Metadata.Nfo; |
||||
|
||||
public class EpisodeNfoReader : NfoReader<TvShowEpisodeNfo>, IEpisodeNfoReader |
||||
{ |
||||
public async Task<List<TvShowEpisodeNfo>> Read(Stream input) |
||||
{ |
||||
var result = new List<TvShowEpisodeNfo>(); |
||||
private readonly IClient _client; |
||||
|
||||
var settings = new XmlReaderSettings { Async = true, ConformanceLevel = ConformanceLevel.Fragment }; |
||||
using var reader = XmlReader.Create(input, settings); |
||||
TvShowEpisodeNfo nfo = null; |
||||
public EpisodeNfoReader(IClient client) => _client = client; |
||||
|
||||
while (await reader.ReadAsync()) |
||||
public async Task<Either<BaseError, List<TvShowEpisodeNfo>>> Read(Stream input) |
||||
{ |
||||
try |
||||
{ |
||||
switch (reader.NodeType) |
||||
var result = new List<TvShowEpisodeNfo>(); |
||||
|
||||
var settings = new XmlReaderSettings { Async = true, ConformanceLevel = ConformanceLevel.Fragment }; |
||||
using var reader = XmlReader.Create(input, settings); |
||||
TvShowEpisodeNfo nfo = null; |
||||
|
||||
while (await reader.ReadAsync()) |
||||
{ |
||||
case XmlNodeType.Element: |
||||
switch (reader.Name.ToLowerInvariant()) |
||||
{ |
||||
case "episodedetails": |
||||
nfo = new TvShowEpisodeNfo |
||||
{ |
||||
UniqueIds = new List<UniqueIdNfo>(), |
||||
Actors = new List<ActorNfo>(), |
||||
Writers = new List<string>(), |
||||
Directors = new List<string>() |
||||
}; |
||||
break; |
||||
case "title": |
||||
await ReadStringContent(reader, nfo, (episode, title) => episode.Title = title); |
||||
break; |
||||
case "showtitle": |
||||
await ReadStringContent(reader, nfo, (episode, showTitle) => episode.ShowTitle = showTitle); |
||||
break; |
||||
case "episode": |
||||
await ReadIntContent( |
||||
reader, |
||||
nfo, |
||||
(episode, episodeNumber) => episode.Episode = episodeNumber); |
||||
break; |
||||
case "season": |
||||
await ReadIntContent(reader, nfo, (episode, seasonNumber) => episode.Season = seasonNumber); |
||||
break; |
||||
case "uniqueid": |
||||
await ReadUniqueId(reader, nfo, (episode, uniqueId) => episode.UniqueIds.Add(uniqueId)); |
||||
break; |
||||
case "mpaa": |
||||
await ReadStringContent( |
||||
reader, |
||||
nfo, |
||||
(episode, contentRating) => episode.ContentRating = contentRating); |
||||
break; |
||||
case "aired": |
||||
// TODO: parse the date here
|
||||
await ReadAired(reader, nfo); |
||||
break; |
||||
case "plot": |
||||
await ReadStringContent(reader, nfo, (episode, plot) => episode.Plot = plot); |
||||
break; |
||||
case "actor": |
||||
ReadActor(reader, nfo, (episode, actor) => episode.Actors.Add(actor)); |
||||
break; |
||||
case "credits": |
||||
await ReadStringContent(reader, nfo, (episode, writer) => episode.Writers.Add(writer)); |
||||
break; |
||||
case "director": |
||||
await ReadStringContent( |
||||
reader, |
||||
nfo, |
||||
(episode, director) => episode.Directors.Add(director)); |
||||
break; |
||||
} |
||||
switch (reader.NodeType) |
||||
{ |
||||
case XmlNodeType.Element: |
||||
switch (reader.Name.ToLowerInvariant()) |
||||
{ |
||||
case "episodedetails": |
||||
nfo = new TvShowEpisodeNfo |
||||
{ |
||||
UniqueIds = new List<UniqueIdNfo>(), |
||||
Actors = new List<ActorNfo>(), |
||||
Writers = new List<string>(), |
||||
Directors = new List<string>() |
||||
}; |
||||
break; |
||||
case "title": |
||||
await ReadStringContent(reader, nfo, (episode, title) => episode.Title = title); |
||||
break; |
||||
case "showtitle": |
||||
await ReadStringContent( |
||||
reader, |
||||
nfo, |
||||
(episode, showTitle) => episode.ShowTitle = showTitle); |
||||
break; |
||||
case "episode": |
||||
await ReadIntContent( |
||||
reader, |
||||
nfo, |
||||
(episode, episodeNumber) => episode.Episode = episodeNumber); |
||||
break; |
||||
case "season": |
||||
await ReadIntContent( |
||||
reader, |
||||
nfo, |
||||
(episode, seasonNumber) => episode.Season = seasonNumber); |
||||
break; |
||||
case "uniqueid": |
||||
await ReadUniqueId(reader, nfo, (episode, uniqueId) => episode.UniqueIds.Add(uniqueId)); |
||||
break; |
||||
case "mpaa": |
||||
await ReadStringContent( |
||||
reader, |
||||
nfo, |
||||
(episode, contentRating) => episode.ContentRating = contentRating); |
||||
break; |
||||
case "aired": |
||||
await ReadDateTimeContent(reader, nfo, (episode, aired) => episode.Aired = aired); |
||||
break; |
||||
case "plot": |
||||
await ReadStringContent(reader, nfo, (episode, plot) => episode.Plot = plot); |
||||
break; |
||||
case "actor": |
||||
ReadActor(reader, nfo, (episode, actor) => episode.Actors.Add(actor)); |
||||
break; |
||||
case "credits": |
||||
await ReadStringContent(reader, nfo, (episode, writer) => episode.Writers.Add(writer)); |
||||
break; |
||||
case "director": |
||||
await ReadStringContent( |
||||
reader, |
||||
nfo, |
||||
(episode, director) => episode.Directors.Add(director)); |
||||
break; |
||||
} |
||||
|
||||
break; |
||||
case XmlNodeType.EndElement: |
||||
switch (reader.Name.ToLowerInvariant()) |
||||
{ |
||||
case "episodedetails": |
||||
if (nfo != null) |
||||
{ |
||||
result.Add(nfo); |
||||
} |
||||
break; |
||||
case XmlNodeType.EndElement: |
||||
switch (reader.Name.ToLowerInvariant()) |
||||
{ |
||||
case "episodedetails": |
||||
if (nfo != null) |
||||
{ |
||||
result.Add(nfo); |
||||
} |
||||
|
||||
break; |
||||
} |
||||
break; |
||||
} |
||||
|
||||
break; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
private static async Task ReadAired(XmlReader reader, TvShowEpisodeNfo nfo) |
||||
{ |
||||
if (nfo != null) |
||||
return result; |
||||
} |
||||
catch (Exception ex) |
||||
{ |
||||
nfo.Aired = await reader.ReadElementContentAsStringAsync(); |
||||
_client.Notify(ex); |
||||
return new FailedToReadNfo(ex.ToString()); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,92 @@
@@ -0,0 +1,92 @@
|
||||
using System.Xml; |
||||
using Bugsnag; |
||||
using ErsatzTV.Core.Errors; |
||||
using ErsatzTV.Core.Interfaces.Metadata.Nfo; |
||||
|
||||
namespace ErsatzTV.Core.Metadata.Nfo; |
||||
|
||||
public class MusicVideoNfoReader : NfoReader<MusicVideoNfo>, IMusicVideoNfoReader |
||||
{ |
||||
private readonly IClient _client; |
||||
|
||||
public MusicVideoNfoReader(IClient client) => _client = client; |
||||
|
||||
public async Task<Either<BaseError, MusicVideoNfo>> Read(Stream input) |
||||
{ |
||||
try |
||||
{ |
||||
var settings = new XmlReaderSettings { Async = true, ConformanceLevel = ConformanceLevel.Fragment }; |
||||
using var reader = XmlReader.Create(input, settings); |
||||
MusicVideoNfo nfo = null; |
||||
var done = false; |
||||
|
||||
while (!done && await reader.ReadAsync()) |
||||
{ |
||||
switch (reader.NodeType) |
||||
{ |
||||
case XmlNodeType.Element: |
||||
switch (reader.Name.ToLowerInvariant()) |
||||
{ |
||||
case "musicvideo": |
||||
nfo = new MusicVideoNfo |
||||
{ |
||||
Genres = new List<string>(), |
||||
Tags = new List<string>(), |
||||
Studios = new List<string>() |
||||
}; |
||||
break; |
||||
case "artist": |
||||
await ReadStringContent( |
||||
reader, |
||||
nfo, |
||||
(musicVideo, artist) => musicVideo.Artist = artist); |
||||
break; |
||||
case "title": |
||||
await ReadStringContent(reader, nfo, (musicVideo, title) => musicVideo.Title = title); |
||||
break; |
||||
case "album": |
||||
await ReadStringContent(reader, nfo, (musicVideo, album) => musicVideo.Album = album); |
||||
break; |
||||
case "plot": |
||||
await ReadStringContent(reader, nfo, (musicVideo, plot) => musicVideo.Plot = plot); |
||||
break; |
||||
case "year": |
||||
await ReadIntContent(reader, nfo, (musicVideo, year) => musicVideo.Year = year); |
||||
break; |
||||
case "genre": |
||||
await ReadStringContent( |
||||
reader, |
||||
nfo, |
||||
(musicVideo, genre) => musicVideo.Genres.Add(genre)); |
||||
break; |
||||
case "tag": |
||||
await ReadStringContent(reader, nfo, (musicVideo, tag) => musicVideo.Tags.Add(tag)); |
||||
break; |
||||
case "studio": |
||||
await ReadStringContent( |
||||
reader, |
||||
nfo, |
||||
(musicVideo, studio) => musicVideo.Studios.Add(studio)); |
||||
break; |
||||
} |
||||
|
||||
break; |
||||
case XmlNodeType.EndElement: |
||||
if (reader.Name == "musicvideo") |
||||
{ |
||||
done = true; |
||||
} |
||||
|
||||
break; |
||||
} |
||||
} |
||||
|
||||
return Optional(nfo).ToEither((BaseError)new FailedToReadNfo()); |
||||
} |
||||
catch (Exception ex) |
||||
{ |
||||
_client.Notify(ex); |
||||
return new FailedToReadNfo(ex.ToString()); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,100 @@
@@ -0,0 +1,100 @@
|
||||
using System.Xml; |
||||
using Bugsnag; |
||||
using ErsatzTV.Core.Errors; |
||||
using ErsatzTV.Core.Interfaces.Metadata.Nfo; |
||||
|
||||
namespace ErsatzTV.Core.Metadata.Nfo; |
||||
|
||||
public class TvShowNfoReader : NfoReader<TvShowNfo>, ITvShowNfoReader |
||||
{ |
||||
private readonly IClient _client; |
||||
|
||||
public TvShowNfoReader(IClient client) => _client = client; |
||||
|
||||
public async Task<Either<BaseError, TvShowNfo>> Read(Stream input) |
||||
{ |
||||
try |
||||
{ |
||||
var settings = new XmlReaderSettings { Async = true, ConformanceLevel = ConformanceLevel.Fragment }; |
||||
using var reader = XmlReader.Create(input, settings); |
||||
TvShowNfo nfo = null; |
||||
var done = false; |
||||
|
||||
while (!done && await reader.ReadAsync()) |
||||
{ |
||||
switch (reader.NodeType) |
||||
{ |
||||
case XmlNodeType.Element: |
||||
switch (reader.Name.ToLowerInvariant()) |
||||
{ |
||||
case "tvshow": |
||||
nfo = new TvShowNfo |
||||
{ |
||||
Genres = new List<string>(), |
||||
Tags = new List<string>(), |
||||
Studios = new List<string>(), |
||||
Actors = new List<ActorNfo>(), |
||||
UniqueIds = new List<UniqueIdNfo>() |
||||
}; |
||||
break; |
||||
case "title": |
||||
await ReadStringContent(reader, nfo, (show, title) => show.Title = title); |
||||
break; |
||||
case "year": |
||||
await ReadIntContent(reader, nfo, (show, year) => show.Year = year); |
||||
break; |
||||
case "plot": |
||||
await ReadStringContent(reader, nfo, (show, plot) => show.Plot = plot); |
||||
break; |
||||
case "outline": |
||||
await ReadStringContent(reader, nfo, (show, outline) => show.Outline = outline); |
||||
break; |
||||
case "tagline": |
||||
await ReadStringContent(reader, nfo, (show, tagline) => show.Tagline = tagline); |
||||
break; |
||||
case "mpaa": |
||||
await ReadStringContent( |
||||
reader, |
||||
nfo, |
||||
(show, contentRating) => show.ContentRating = contentRating); |
||||
break; |
||||
case "premiered": |
||||
await ReadDateTimeContent(reader, nfo, (show, premiered) => show.Premiered = premiered); |
||||
break; |
||||
case "genre": |
||||
await ReadStringContent(reader, nfo, (show, genre) => show.Genres.Add(genre)); |
||||
break; |
||||
case "tag": |
||||
await ReadStringContent(reader, nfo, (show, tag) => show.Tags.Add(tag)); |
||||
break; |
||||
case "studio": |
||||
await ReadStringContent(reader, nfo, (show, studio) => show.Studios.Add(studio)); |
||||
break; |
||||
case "actor": |
||||
ReadActor(reader, nfo, (episode, actor) => episode.Actors.Add(actor)); |
||||
break; |
||||
case "uniqueid": |
||||
await ReadUniqueId(reader, nfo, (episode, uniqueid) => episode.UniqueIds.Add(uniqueid)); |
||||
break; |
||||
} |
||||
|
||||
break; |
||||
case XmlNodeType.EndElement: |
||||
if (reader.Name == "tvshow") |
||||
{ |
||||
done = true; |
||||
} |
||||
|
||||
break; |
||||
} |
||||
} |
||||
|
||||
return Optional(nfo).ToEither((BaseError)new FailedToReadNfo()); |
||||
} |
||||
catch (Exception ex) |
||||
{ |
||||
_client.Notify(ex); |
||||
return new FailedToReadNfo(ex.ToString()); |
||||
} |
||||
} |
||||
} |
||||
Loading…
Reference in new issue