From 1cbd48cea010b0eca7d55e60b8b84c5dd9bef382 Mon Sep 17 00:00:00 2001 From: Jason Dove <1695733+jasongdove@users.noreply.github.com> Date: Sat, 19 Jul 2025 02:22:06 +0000 Subject: [PATCH] log nfo file name with nfo parsing errors (#2168) --- .../Core/Metadata/Nfo/ArtistNfoReaderTests.cs | 10 +-- .../Metadata/Nfo/EpisodeNfoReaderTests.cs | 26 ++++---- .../Core/Metadata/Nfo/MovieNfoReaderTests.cs | 12 ++-- .../Metadata/Nfo/MusicVideoNfoReaderTests.cs | 16 ++--- .../Metadata/Nfo/OtherVideoNfoReaderTests.cs | 12 ++-- .../Core/Metadata/Nfo/ShowNfoReaderTests.cs | 14 ++-- .../Core/Metadata/Nfo/ArtistNfoReader.cs | 36 ++++++---- .../Core/Metadata/Nfo/EpisodeNfoReader.cs | 57 +++++++++++----- .../Core/Metadata/Nfo/MovieNfoReader.cs | 65 +++++++++++++------ .../Core/Metadata/Nfo/MusicVideoNfoReader.cs | 60 ++++++++++++----- .../Core/Metadata/Nfo/NfoReader.cs | 20 +++--- .../Core/Metadata/Nfo/OtherVideoNfoReader.cs | 64 ++++++++++++------ .../Core/Metadata/Nfo/ShowNfoReader.cs | 55 +++++++++++----- 13 files changed, 294 insertions(+), 153 deletions(-) diff --git a/ErsatzTV.Scanner.Tests/Core/Metadata/Nfo/ArtistNfoReaderTests.cs b/ErsatzTV.Scanner.Tests/Core/Metadata/Nfo/ArtistNfoReaderTests.cs index 96ec2ad4..c526cb40 100644 --- a/ErsatzTV.Scanner.Tests/Core/Metadata/Nfo/ArtistNfoReaderTests.cs +++ b/ErsatzTV.Scanner.Tests/Core/Metadata/Nfo/ArtistNfoReaderTests.cs @@ -42,7 +42,7 @@ public class ArtistNfoReaderTests await using var stream = new MemoryStream(Encoding.UTF8.GetBytes(@"https://www.themoviedb.org/movie/11-star-wars")); - Either result = await _artistNfoReader.Read(stream); + Either result = await _artistNfoReader.Read(stream, string.Empty); result.IsLeft.ShouldBeTrue(); } @@ -52,7 +52,7 @@ public class ArtistNfoReaderTests { await using var stream = new MemoryStream(Encoding.UTF8.GetBytes(@"")); - Either result = await _artistNfoReader.Read(stream); + Either result = await _artistNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); } @@ -65,7 +65,7 @@ public class ArtistNfoReaderTests @" https://www.themoviedb.org/movie/11-star-wars")); - Either result = await _artistNfoReader.Read(stream); + Either result = await _artistNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); } @@ -119,7 +119,7 @@ https://www.themoviedb.org/movie/11-star-wars")); F:\Music\ArtistInfoKodi\Billy Joel "))); - Either result = await _artistNfoReader.Read(stream); + Either result = await _artistNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); @@ -165,7 +165,7 @@ Joel attended Hicksville High School in 1967, but he did not graduate with his c await using var stream = new MemoryStream( Encoding.UTF8.GetBytes(@"Test Disambiguation")); - Either result = await _artistNfoReader.Read(stream); + Either result = await _artistNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); foreach (ArtistNfo nfo in result.RightToSeq()) diff --git a/ErsatzTV.Scanner.Tests/Core/Metadata/Nfo/EpisodeNfoReaderTests.cs b/ErsatzTV.Scanner.Tests/Core/Metadata/Nfo/EpisodeNfoReaderTests.cs index 2f9dfd5b..2545bff5 100644 --- a/ErsatzTV.Scanner.Tests/Core/Metadata/Nfo/EpisodeNfoReaderTests.cs +++ b/ErsatzTV.Scanner.Tests/Core/Metadata/Nfo/EpisodeNfoReaderTests.cs @@ -46,7 +46,7 @@ public class EpisodeNfoReaderTests ")); - Either> result = await _episodeNfoReader.Read(stream); + Either> result = await _episodeNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); foreach (List list in result.RightToSeq()) @@ -75,7 +75,7 @@ public class EpisodeNfoReaderTests 1 ")); - Either> result = await _episodeNfoReader.Read(stream); + Either> result = await _episodeNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); foreach (List list in result.RightToSeq()) @@ -100,7 +100,7 @@ public class EpisodeNfoReaderTests tt54321 ")); - Either> result = await _episodeNfoReader.Read(stream); + Either> result = await _episodeNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); foreach (List list in result.RightToSeq()) @@ -123,7 +123,7 @@ public class EpisodeNfoReaderTests ")); - Either> result = await _episodeNfoReader.Read(stream); + Either> result = await _episodeNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); foreach (List list in result.RightToSeq()) @@ -147,7 +147,7 @@ public class EpisodeNfoReaderTests US:Something / US:SomethingElse ")); - Either> result = await _episodeNfoReader.Read(stream); + Either> result = await _episodeNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); foreach (List list in result.RightToSeq()) @@ -169,7 +169,7 @@ public class EpisodeNfoReaderTests ")); - Either> result = await _episodeNfoReader.Read(stream); + Either> result = await _episodeNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); foreach (List list in result.RightToSeq()) @@ -190,7 +190,7 @@ public class EpisodeNfoReaderTests Some Plot ")); - Either> result = await _episodeNfoReader.Read(stream); + Either> result = await _episodeNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); foreach (List list in result.RightToSeq()) @@ -220,7 +220,7 @@ public class EpisodeNfoReaderTests ")); - Either> result = await _episodeNfoReader.Read(stream); + Either> result = await _episodeNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); foreach (List list in result.RightToSeq()) @@ -249,7 +249,7 @@ public class EpisodeNfoReaderTests Writer 3 ")); - Either> result = await _episodeNfoReader.Read(stream); + Either> result = await _episodeNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); foreach (List list in result.RightToSeq()) @@ -276,7 +276,7 @@ public class EpisodeNfoReaderTests Director 3 ")); - Either> result = await _episodeNfoReader.Read(stream); + Either> result = await _episodeNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); foreach (List list in result.RightToSeq()) @@ -304,7 +304,7 @@ public class EpisodeNfoReaderTests Genre 3 ")); - Either> result = await _episodeNfoReader.Read(stream); + Either> result = await _episodeNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); foreach (List list in result.RightToSeq()) @@ -330,7 +330,7 @@ public class EpisodeNfoReaderTests Tag 3 ")); - Either> result = await _episodeNfoReader.Read(stream); + Either> result = await _episodeNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); foreach (List list in result.RightToSeq()) @@ -431,7 +431,7 @@ public class EpisodeNfoReaderTests 2021-02-02 11:57:44 ")); - Either> result = await _episodeNfoReader.Read(stream); + Either> result = await _episodeNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); diff --git a/ErsatzTV.Scanner.Tests/Core/Metadata/Nfo/MovieNfoReaderTests.cs b/ErsatzTV.Scanner.Tests/Core/Metadata/Nfo/MovieNfoReaderTests.cs index b378971f..6342cb8c 100644 --- a/ErsatzTV.Scanner.Tests/Core/Metadata/Nfo/MovieNfoReaderTests.cs +++ b/ErsatzTV.Scanner.Tests/Core/Metadata/Nfo/MovieNfoReaderTests.cs @@ -27,7 +27,7 @@ public class MovieNfoReaderTests await using var stream = new MemoryStream(Encoding.UTF8.GetBytes(@"https://www.themoviedb.org/movie/11-star-wars")); - Either result = await _movieNfoReader.Read(stream); + Either result = await _movieNfoReader.Read(stream, string.Empty); result.IsLeft.ShouldBeTrue(); } @@ -37,7 +37,7 @@ public class MovieNfoReaderTests { await using var stream = new MemoryStream(Encoding.UTF8.GetBytes(@"")); - Either result = await _movieNfoReader.Read(stream); + Either result = await _movieNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); } @@ -50,7 +50,7 @@ public class MovieNfoReaderTests @" https://www.themoviedb.org/movie/11-star-wars")); - Either result = await _movieNfoReader.Read(stream); + Either result = await _movieNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); } @@ -168,7 +168,7 @@ https://www.themoviedb.org/movie/11-star-wars")); 2021-03-26 11:35:50 ")); - Either result = await _movieNfoReader.Read(stream); + Either result = await _movieNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); @@ -227,7 +227,7 @@ https://www.themoviedb.org/movie/11-star-wars")); { await using var stream = new MemoryStream(Encoding.UTF8.GetBytes(@"Test Tag")); - Either result = await _movieNfoReader.Read(stream); + Either result = await _movieNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); foreach (MovieNfo nfo in result.RightToSeq()) @@ -242,7 +242,7 @@ https://www.themoviedb.org/movie/11-star-wars")); await using var stream = new MemoryStream(Encoding.UTF8.GetBytes(@"Test Outline")); - Either result = await _movieNfoReader.Read(stream); + Either result = await _movieNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); foreach (MovieNfo nfo in result.RightToSeq()) diff --git a/ErsatzTV.Scanner.Tests/Core/Metadata/Nfo/MusicVideoNfoReaderTests.cs b/ErsatzTV.Scanner.Tests/Core/Metadata/Nfo/MusicVideoNfoReaderTests.cs index a7071fcc..a4f76261 100644 --- a/ErsatzTV.Scanner.Tests/Core/Metadata/Nfo/MusicVideoNfoReaderTests.cs +++ b/ErsatzTV.Scanner.Tests/Core/Metadata/Nfo/MusicVideoNfoReaderTests.cs @@ -27,7 +27,7 @@ public class MusicVideoNfoReaderTests await using var stream = new MemoryStream(Encoding.UTF8.GetBytes(@"https://www.themoviedb.org/movie/11-star-wars")); - Either result = await _musicVideoNfoReader.Read(stream); + Either result = await _musicVideoNfoReader.Read(stream, string.Empty); result.IsLeft.ShouldBeTrue(); } @@ -37,7 +37,7 @@ public class MusicVideoNfoReaderTests { await using var stream = new MemoryStream(Encoding.UTF8.GetBytes(@"")); - Either result = await _musicVideoNfoReader.Read(stream); + Either result = await _musicVideoNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); } @@ -50,7 +50,7 @@ public class MusicVideoNfoReaderTests @" https://www.themoviedb.org/movie/11-star-wars")); - Either result = await _musicVideoNfoReader.Read(stream); + Either result = await _musicVideoNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); } @@ -113,7 +113,7 @@ https://www.themoviedb.org/movie/11-star-wars")); 2018-09-10 09:46:06 "))); - Either result = await _musicVideoNfoReader.Read(stream); + Either result = await _musicVideoNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); @@ -140,7 +140,7 @@ Le groupe a également enregistré une version espagnole de ce titre, La reina d await using var stream = new MemoryStream( Encoding.UTF8.GetBytes(@"Test Tag")); - Either result = await _musicVideoNfoReader.Read(stream); + Either result = await _musicVideoNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); foreach (MusicVideoNfo nfo in result.RightToSeq()) @@ -155,7 +155,7 @@ Le groupe a également enregistré une version espagnole de ce titre, La reina d await using var stream = new MemoryStream( Encoding.UTF8.GetBytes(@"2022-02-03")); - Either result = await _musicVideoNfoReader.Read(stream); + Either result = await _musicVideoNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); foreach (MusicVideoNfo nfo in result.RightToSeq()) @@ -174,7 +174,7 @@ Le groupe a également enregistré une version espagnole de ce titre, La reina d await using var stream = new MemoryStream( Encoding.UTF8.GetBytes(@"Test Studio")); - Either result = await _musicVideoNfoReader.Read(stream); + Either result = await _musicVideoNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); foreach (MusicVideoNfo nfo in result.RightToSeq()) @@ -189,7 +189,7 @@ Le groupe a également enregistré une version espagnole de ce titre, La reina d await using var stream = new MemoryStream( Encoding.UTF8.GetBytes(@"Test Director")); - Either result = await _musicVideoNfoReader.Read(stream); + Either result = await _musicVideoNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); foreach (MusicVideoNfo nfo in result.RightToSeq()) diff --git a/ErsatzTV.Scanner.Tests/Core/Metadata/Nfo/OtherVideoNfoReaderTests.cs b/ErsatzTV.Scanner.Tests/Core/Metadata/Nfo/OtherVideoNfoReaderTests.cs index 4a376ddc..19ef7a7e 100644 --- a/ErsatzTV.Scanner.Tests/Core/Metadata/Nfo/OtherVideoNfoReaderTests.cs +++ b/ErsatzTV.Scanner.Tests/Core/Metadata/Nfo/OtherVideoNfoReaderTests.cs @@ -27,7 +27,7 @@ public class OtherVideoNfoReaderTests await using var stream = new MemoryStream(Encoding.UTF8.GetBytes(@"https://www.themoviedb.org/movie/11-star-wars")); - Either result = await _otherVideoNfoReader.Read(stream); + Either result = await _otherVideoNfoReader.Read(stream, string.Empty); result.IsLeft.ShouldBeTrue(); } @@ -40,7 +40,7 @@ public class OtherVideoNfoReaderTests { await using var stream = new MemoryStream(Encoding.UTF8.GetBytes(@$"<{topLevel}>")); - Either result = await _otherVideoNfoReader.Read(stream); + Either result = await _otherVideoNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); } @@ -56,7 +56,7 @@ public class OtherVideoNfoReaderTests @$"<{topLevel}> https://www.themoviedb.org/movie/11-star-wars")); - Either result = await _otherVideoNfoReader.Read(stream); + Either result = await _otherVideoNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); } @@ -177,7 +177,7 @@ https://www.themoviedb.org/movie/11-star-wars")); 2021-03-26 11:35:50 ")); - Either result = await _otherVideoNfoReader.Read(stream); + Either result = await _otherVideoNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); @@ -240,7 +240,7 @@ https://www.themoviedb.org/movie/11-star-wars")); await using var stream = new MemoryStream(Encoding.UTF8.GetBytes(@$"<{topLevel}>Test Tag")); - Either result = await _otherVideoNfoReader.Read(stream); + Either result = await _otherVideoNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); foreach (OtherVideoNfo nfo in result.RightToSeq()) @@ -258,7 +258,7 @@ https://www.themoviedb.org/movie/11-star-wars")); await using var stream = new MemoryStream(Encoding.UTF8.GetBytes(@$"<{topLevel}>Test Outline")); - Either result = await _otherVideoNfoReader.Read(stream); + Either result = await _otherVideoNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); foreach (OtherVideoNfo nfo in result.RightToSeq()) diff --git a/ErsatzTV.Scanner.Tests/Core/Metadata/Nfo/ShowNfoReaderTests.cs b/ErsatzTV.Scanner.Tests/Core/Metadata/Nfo/ShowNfoReaderTests.cs index 8a649a36..21448725 100644 --- a/ErsatzTV.Scanner.Tests/Core/Metadata/Nfo/ShowNfoReaderTests.cs +++ b/ErsatzTV.Scanner.Tests/Core/Metadata/Nfo/ShowNfoReaderTests.cs @@ -27,7 +27,7 @@ public class ShowNfoReaderTests await using var stream = new MemoryStream(Encoding.UTF8.GetBytes(@"https://www.themoviedb.org/movie/11-star-wars")); - Either result = await _showNfoReader.Read(stream); + Either result = await _showNfoReader.Read(stream, string.Empty); result.IsLeft.ShouldBeTrue(); } @@ -37,7 +37,7 @@ public class ShowNfoReaderTests { await using var stream = new MemoryStream(Encoding.UTF8.GetBytes(@"")); - Either result = await _showNfoReader.Read(stream); + Either result = await _showNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); } @@ -50,7 +50,7 @@ public class ShowNfoReaderTests @" https://www.themoviedb.org/movie/11-star-wars")); - Either result = await _showNfoReader.Read(stream); + Either result = await _showNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); } @@ -153,7 +153,7 @@ https://www.themoviedb.org/movie/11-star-wars")); ")); - Either result = await _showNfoReader.Read(stream); + Either result = await _showNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); @@ -201,7 +201,7 @@ https://www.themoviedb.org/movie/11-star-wars")); await using var stream = new MemoryStream(Encoding.UTF8.GetBytes(@"Test Outline")); - Either result = await _showNfoReader.Read(stream); + Either result = await _showNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); foreach (ShowNfo nfo in result.RightToSeq()) @@ -216,7 +216,7 @@ https://www.themoviedb.org/movie/11-star-wars")); await using var stream = new MemoryStream(Encoding.UTF8.GetBytes(@"Test Tagline")); - Either result = await _showNfoReader.Read(stream); + Either result = await _showNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); foreach (ShowNfo nfo in result.RightToSeq()) @@ -230,7 +230,7 @@ https://www.themoviedb.org/movie/11-star-wars")); { await using var stream = new MemoryStream(Encoding.UTF8.GetBytes(@"Test Tag")); - Either result = await _showNfoReader.Read(stream); + Either result = await _showNfoReader.Read(stream, string.Empty); result.IsRight.ShouldBeTrue(); foreach (ShowNfo nfo in result.RightToSeq()) diff --git a/ErsatzTV.Scanner/Core/Metadata/Nfo/ArtistNfoReader.cs b/ErsatzTV.Scanner/Core/Metadata/Nfo/ArtistNfoReader.cs index f3fbef99..d028954e 100644 --- a/ErsatzTV.Scanner/Core/Metadata/Nfo/ArtistNfoReader.cs +++ b/ErsatzTV.Scanner/Core/Metadata/Nfo/ArtistNfoReader.cs @@ -28,11 +28,11 @@ public class ArtistNfoReader : NfoReader, IArtistNfoReader // ReSharper disable once ConvertToUsingDeclaration await using (Stream s = await SanitizedStreamForFile(fileName)) { - return await Read(s); + return await Read(s, fileName); } } - internal async Task> Read(Stream input) + internal async Task> Read(Stream input, string fileName) { ArtistNfo? nfo = null; @@ -53,28 +53,42 @@ public class ArtistNfoReader : NfoReader, IArtistNfoReader nfo = new ArtistNfo(); break; case "name": - await ReadStringContent(reader, nfo, (artist, name) => artist.Name = name); + await ReadStringContent(reader, nfo, (artist, name) => artist.Name = name, fileName); break; case "disambiguation": await ReadStringContent( reader, nfo, - (artist, disambiguation) => artist.Disambiguation = disambiguation); + (artist, disambiguation) => artist.Disambiguation = disambiguation, + fileName); break; case "genre": - await ReadStringContent(reader, nfo, (artist, genre) => artist.Genres.Add(genre)); + await ReadStringContent( + reader, + nfo, + (artist, genre) => artist.Genres.Add(genre), + fileName); break; case "style": - await ReadStringContent(reader, nfo, (artist, style) => artist.Styles.Add(style)); + await ReadStringContent( + reader, + nfo, + (artist, style) => artist.Styles.Add(style), + fileName); break; case "mood": - await ReadStringContent(reader, nfo, (artist, mood) => artist.Moods.Add(mood)); + await ReadStringContent( + reader, + nfo, + (artist, mood) => artist.Moods.Add(mood), + fileName); break; case "biography": await ReadStringContent( reader, nfo, - (artist, biography) => artist.Biography = biography); + (artist, biography) => artist.Biography = biography, + fileName); break; } @@ -89,12 +103,12 @@ public class ArtistNfoReader : NfoReader, IArtistNfoReader } } - return Optional(nfo).ToEither((BaseError)new FailedToReadNfo()); + return Optional(nfo).ToEither(new FailedToReadNfo()); } catch (XmlException) { - _logger.LogWarning("Invalid XML detected; returning incomplete metadata"); - return Optional(nfo).ToEither((BaseError)new FailedToReadNfo()); + _logger.LogWarning("Invalid XML detected in file {FileName}; returning incomplete metadata", fileName); + return Optional(nfo).ToEither(new FailedToReadNfo()); } catch (Exception ex) { diff --git a/ErsatzTV.Scanner/Core/Metadata/Nfo/EpisodeNfoReader.cs b/ErsatzTV.Scanner/Core/Metadata/Nfo/EpisodeNfoReader.cs index d433ec37..d8cec3fd 100644 --- a/ErsatzTV.Scanner/Core/Metadata/Nfo/EpisodeNfoReader.cs +++ b/ErsatzTV.Scanner/Core/Metadata/Nfo/EpisodeNfoReader.cs @@ -28,11 +28,11 @@ public class EpisodeNfoReader : NfoReader, IEpisodeNfoReader // ReSharper disable once ConvertToUsingDeclaration await using (Stream s = await SanitizedStreamForFile(fileName)) { - return await Read(s); + return await Read(s, fileName); } } - internal async Task>> Read(Stream input) + internal async Task>> Read(Stream input, string fileName) { var result = new List(); @@ -54,58 +54,83 @@ public class EpisodeNfoReader : NfoReader, IEpisodeNfoReader result.Add(nfo); break; case "title": - await ReadStringContent(reader, nfo, (episode, title) => episode.Title = title); + await ReadStringContent( + reader, + nfo, + (episode, title) => episode.Title = title, + fileName); break; case "showtitle": await ReadStringContent( reader, nfo, - (episode, showTitle) => episode.ShowTitle = showTitle); + (episode, showTitle) => episode.ShowTitle = showTitle, + fileName); break; case "episode": await ReadIntContent( reader, nfo, - (episode, episodeNumber) => episode.Episode = episodeNumber); + (episode, episodeNumber) => episode.Episode = episodeNumber, + fileName); break; case "season": await ReadIntContent( reader, nfo, - (episode, seasonNumber) => episode.Season = seasonNumber); + (episode, seasonNumber) => episode.Season = seasonNumber, + fileName); break; case "uniqueid": - await ReadUniqueId(reader, nfo, (episode, uniqueId) => episode.UniqueIds.Add(uniqueId)); + await ReadUniqueId( + reader, + nfo, + (episode, uniqueId) => episode.UniqueIds.Add(uniqueId), + fileName); break; case "mpaa": await ReadStringContent( reader, nfo, - (episode, contentRating) => episode.ContentRating = contentRating); + (episode, contentRating) => episode.ContentRating = contentRating, + fileName); break; case "aired": - await ReadDateTimeContent(reader, nfo, (episode, aired) => episode.Aired = aired); + await ReadDateTimeContent( + reader, + nfo, + (episode, aired) => episode.Aired = aired, + fileName); break; case "plot": - await ReadStringContent(reader, nfo, (episode, plot) => episode.Plot = plot); + await ReadStringContent(reader, nfo, (episode, plot) => episode.Plot = plot, fileName); break; case "genre": - await ReadStringContent(reader, nfo, (episode, genre) => episode.Genres.Add(genre)); + await ReadStringContent( + reader, + nfo, + (episode, genre) => episode.Genres.Add(genre), + fileName); break; case "tag": - await ReadStringContent(reader, nfo, (episode, tag) => episode.Tags.Add(tag)); + await ReadStringContent(reader, nfo, (episode, tag) => episode.Tags.Add(tag), fileName); break; case "actor": - ReadActor(reader, nfo, (episode, actor) => episode.Actors.Add(actor)); + ReadActor(reader, nfo, (episode, actor) => episode.Actors.Add(actor), fileName); break; case "credits": - await ReadStringContent(reader, nfo, (episode, writer) => episode.Writers.Add(writer)); + await ReadStringContent( + reader, + nfo, + (episode, writer) => episode.Writers.Add(writer), + fileName); break; case "director": await ReadStringContent( reader, nfo, - (episode, director) => episode.Directors.Add(director)); + (episode, director) => episode.Directors.Add(director), + fileName); break; } @@ -117,7 +142,7 @@ public class EpisodeNfoReader : NfoReader, IEpisodeNfoReader } catch (XmlException) { - _logger.LogWarning("Invalid XML detected; returning incomplete metadata"); + _logger.LogWarning("Invalid XML detected in file {FileName}; returning incomplete metadata", fileName); return result; } catch (Exception ex) diff --git a/ErsatzTV.Scanner/Core/Metadata/Nfo/MovieNfoReader.cs b/ErsatzTV.Scanner/Core/Metadata/Nfo/MovieNfoReader.cs index 01ee1520..ba9d3b5f 100644 --- a/ErsatzTV.Scanner/Core/Metadata/Nfo/MovieNfoReader.cs +++ b/ErsatzTV.Scanner/Core/Metadata/Nfo/MovieNfoReader.cs @@ -28,11 +28,11 @@ public class MovieNfoReader : NfoReader, IMovieNfoReader // ReSharper disable once ConvertToUsingDeclaration await using (Stream s = await SanitizedStreamForFile(fileName)) { - return await Read(s); + return await Read(s, fileName); } } - internal async Task> Read(Stream input) + internal async Task> Read(Stream input, string fileName) { MovieNfo? nfo = null; @@ -53,55 +53,82 @@ public class MovieNfoReader : NfoReader, IMovieNfoReader nfo = new MovieNfo(); break; case "title": - await ReadStringContent(reader, nfo, (movie, title) => movie.Title = title); + await ReadStringContent(reader, nfo, (movie, title) => movie.Title = title, fileName); break; case "sorttitle": - await ReadStringContent(reader, nfo, (movie, sortTitle) => movie.SortTitle = sortTitle); + await ReadStringContent( + reader, + nfo, + (movie, sortTitle) => movie.SortTitle = sortTitle, + fileName); break; case "outline": - await ReadStringContent(reader, nfo, (movie, outline) => movie.Outline = outline); + await ReadStringContent( + reader, + nfo, + (movie, outline) => movie.Outline = outline, + fileName); break; case "year": - await ReadIntContent(reader, nfo, (movie, year) => movie.Year = year); + await ReadIntContent(reader, nfo, (movie, year) => movie.Year = year, fileName); break; case "mpaa": await ReadStringContent( reader, nfo, - (movie, contentRating) => movie.ContentRating = contentRating); + (movie, contentRating) => movie.ContentRating = contentRating, + fileName); break; case "premiered": await ReadDateTimeContent( reader, nfo, - (movie, premiered) => movie.Premiered = premiered); + (movie, premiered) => movie.Premiered = premiered, + fileName); break; case "plot": - await ReadStringContent(reader, nfo, (movie, plot) => movie.Plot = plot); + await ReadStringContent(reader, nfo, (movie, plot) => movie.Plot = plot, fileName); break; case "genre": - await ReadStringContent(reader, nfo, (movie, genre) => movie.Genres.Add(genre)); + await ReadStringContent( + reader, + nfo, + (movie, genre) => movie.Genres.Add(genre), + fileName); break; case "tag": - await ReadStringContent(reader, nfo, (movie, tag) => movie.Tags.Add(tag)); + await ReadStringContent(reader, nfo, (movie, tag) => movie.Tags.Add(tag), fileName); break; case "studio": - await ReadStringContent(reader, nfo, (movie, studio) => movie.Studios.Add(studio)); + await ReadStringContent( + reader, + nfo, + (movie, studio) => movie.Studios.Add(studio), + fileName); break; case "actor": - ReadActor(reader, nfo, (movie, actor) => movie.Actors.Add(actor)); + ReadActor(reader, nfo, (movie, actor) => movie.Actors.Add(actor), fileName); break; case "credits": - await ReadStringContent(reader, nfo, (movie, writer) => movie.Writers.Add(writer)); + await ReadStringContent( + reader, + nfo, + (movie, writer) => movie.Writers.Add(writer), + fileName); break; case "director": await ReadStringContent( reader, nfo, - (movie, director) => movie.Directors.Add(director)); + (movie, director) => movie.Directors.Add(director), + fileName); break; case "uniqueid": - await ReadUniqueId(reader, nfo, (movie, uniqueid) => movie.UniqueIds.Add(uniqueid)); + await ReadUniqueId( + reader, + nfo, + (movie, uniqueid) => movie.UniqueIds.Add(uniqueid), + fileName); break; } @@ -116,12 +143,12 @@ public class MovieNfoReader : NfoReader, IMovieNfoReader } } - return Optional(nfo).ToEither((BaseError)new FailedToReadNfo()); + return Optional(nfo).ToEither(new FailedToReadNfo()); } catch (XmlException) { - _logger.LogWarning("Invalid XML detected; returning incomplete metadata"); - return Optional(nfo).ToEither((BaseError)new FailedToReadNfo()); + _logger.LogWarning("Invalid XML detected in file {FileName}; returning incomplete metadata", fileName); + return Optional(nfo).ToEither(new FailedToReadNfo()); } catch (Exception ex) { diff --git a/ErsatzTV.Scanner/Core/Metadata/Nfo/MusicVideoNfoReader.cs b/ErsatzTV.Scanner/Core/Metadata/Nfo/MusicVideoNfoReader.cs index f39c7992..66a4161b 100644 --- a/ErsatzTV.Scanner/Core/Metadata/Nfo/MusicVideoNfoReader.cs +++ b/ErsatzTV.Scanner/Core/Metadata/Nfo/MusicVideoNfoReader.cs @@ -28,11 +28,11 @@ public class MusicVideoNfoReader : NfoReader, IMusicVideoNfoReade // ReSharper disable once ConvertToUsingDeclaration await using (Stream s = await SanitizedStreamForFile(fileName)) { - return await Read(s); + return await Read(s, fileName); } } - internal async Task> Read(Stream input) + internal async Task> Read(Stream input, string fileName) { MusicVideoNfo? nfo = null; @@ -56,46 +56,74 @@ public class MusicVideoNfoReader : NfoReader, IMusicVideoNfoReade await ReadStringContent( reader, nfo, - (musicVideo, artist) => musicVideo.Artists.Add(artist)); + (musicVideo, artist) => musicVideo.Artists.Add(artist), + fileName); break; case "title": - await ReadStringContent(reader, nfo, (musicVideo, title) => musicVideo.Title = title); + await ReadStringContent( + reader, + nfo, + (musicVideo, title) => musicVideo.Title = title, + fileName); break; case "album": - await ReadStringContent(reader, nfo, (musicVideo, album) => musicVideo.Album = album); + await ReadStringContent( + reader, + nfo, + (musicVideo, album) => musicVideo.Album = album, + fileName); break; case "plot": - await ReadStringContent(reader, nfo, (musicVideo, plot) => musicVideo.Plot = plot); + await ReadStringContent( + reader, + nfo, + (musicVideo, plot) => musicVideo.Plot = plot, + fileName); break; case "track": - await ReadIntContent(reader, nfo, (musicVideo, track) => musicVideo.Track = track); + await ReadIntContent( + reader, + nfo, + (musicVideo, track) => musicVideo.Track = track, + fileName); break; case "year": - await ReadIntContent(reader, nfo, (musicVideo, year) => musicVideo.Year = year); + await ReadIntContent( + reader, + nfo, + (musicVideo, year) => musicVideo.Year = year, + fileName); break; case "aired": - await ReadDateTimeContent(reader, nfo, (show, aired) => show.Aired = aired); + await ReadDateTimeContent(reader, nfo, (show, aired) => show.Aired = aired, fileName); break; case "genre": await ReadStringContent( reader, nfo, - (musicVideo, genre) => musicVideo.Genres.Add(genre)); + (musicVideo, genre) => musicVideo.Genres.Add(genre), + fileName); break; case "tag": - await ReadStringContent(reader, nfo, (musicVideo, tag) => musicVideo.Tags.Add(tag)); + await ReadStringContent( + reader, + nfo, + (musicVideo, tag) => musicVideo.Tags.Add(tag), + fileName); break; case "studio": await ReadStringContent( reader, nfo, - (musicVideo, studio) => musicVideo.Studios.Add(studio)); + (musicVideo, studio) => musicVideo.Studios.Add(studio), + fileName); break; case "director": await ReadStringContent( reader, nfo, - (musicVideo, director) => musicVideo.Directors.Add(director)); + (musicVideo, director) => musicVideo.Directors.Add(director), + fileName); break; } @@ -110,12 +138,12 @@ public class MusicVideoNfoReader : NfoReader, IMusicVideoNfoReade } } - return Optional(nfo).ToEither((BaseError)new FailedToReadNfo()); + return Optional(nfo).ToEither(new FailedToReadNfo()); } catch (XmlException) { - _logger.LogWarning("Invalid XML detected; returning incomplete metadata"); - return Optional(nfo).ToEither((BaseError)new FailedToReadNfo()); + _logger.LogWarning("Invalid XML detected in file {FileName}; returning incomplete metadata", fileName); + return Optional(nfo).ToEither(new FailedToReadNfo()); } catch (Exception ex) { diff --git a/ErsatzTV.Scanner/Core/Metadata/Nfo/NfoReader.cs b/ErsatzTV.Scanner/Core/Metadata/Nfo/NfoReader.cs index 69ae5de3..afc00c78 100644 --- a/ErsatzTV.Scanner/Core/Metadata/Nfo/NfoReader.cs +++ b/ErsatzTV.Scanner/Core/Metadata/Nfo/NfoReader.cs @@ -37,7 +37,7 @@ public abstract class NfoReader : NfoReaderBase return ms; } - protected async Task ReadStringContent(XmlReader reader, T? nfo, Action action) + protected async Task ReadStringContent(XmlReader reader, T? nfo, Action action, string fileName) { try { @@ -49,11 +49,11 @@ public abstract class NfoReader : NfoReaderBase } catch (XmlException ex) { - _logger.LogWarning(ex, "Error reading string content from NFO {ElementName}", reader.Name); + _logger.LogWarning(ex, "Error reading string content from NFO {ElementName} file {FileName}", reader.Name, fileName); } } - protected async Task ReadIntContent(XmlReader reader, T? nfo, Action action) + protected async Task ReadIntContent(XmlReader reader, T? nfo, Action action, string fileName) { try { @@ -64,11 +64,11 @@ public abstract class NfoReader : NfoReaderBase } catch (XmlException ex) { - _logger.LogWarning(ex, "Error reading int content from NFO {ElementName}", reader.Name); + _logger.LogWarning(ex, "Error reading int content from NFO {ElementName} file {FileName}", reader.Name, fileName); } } - protected async Task ReadDateTimeContent(XmlReader reader, T? nfo, Action action) + protected async Task ReadDateTimeContent(XmlReader reader, T? nfo, Action action, string fileName) { try { @@ -81,11 +81,11 @@ public abstract class NfoReader : NfoReaderBase } catch (XmlException ex) { - _logger.LogWarning(ex, "Error reading date content from NFO {ElementName}", reader.Name); + _logger.LogWarning(ex, "Error reading date content from NFO {ElementName} file {FileName}", reader.Name, fileName); } } - protected void ReadActor(XmlReader reader, T? nfo, Action action) + protected void ReadActor(XmlReader reader, T? nfo, Action action, string fileName) { try { @@ -123,11 +123,11 @@ public abstract class NfoReader : NfoReaderBase } catch (XmlException ex) { - _logger.LogWarning(ex, "Error reading actor content from NFO {ElementName}", reader.Name); + _logger.LogWarning(ex, "Error reading actor content from NFO {ElementName} file {FileName}", reader.Name, fileName); } } - protected async Task ReadUniqueId(XmlReader reader, T? nfo, Action action) + protected async Task ReadUniqueId(XmlReader reader, T? nfo, Action action, string fileName) { try { @@ -146,7 +146,7 @@ public abstract class NfoReader : NfoReaderBase } catch (XmlException ex) { - _logger.LogWarning(ex, "Error reading uniqueid content from NFO {ElementName}", reader.Name); + _logger.LogWarning(ex, "Error reading uniqueid content from NFO {ElementName} file {FileName}", reader.Name, fileName); } } } diff --git a/ErsatzTV.Scanner/Core/Metadata/Nfo/OtherVideoNfoReader.cs b/ErsatzTV.Scanner/Core/Metadata/Nfo/OtherVideoNfoReader.cs index 52f1d571..b8181543 100644 --- a/ErsatzTV.Scanner/Core/Metadata/Nfo/OtherVideoNfoReader.cs +++ b/ErsatzTV.Scanner/Core/Metadata/Nfo/OtherVideoNfoReader.cs @@ -28,11 +28,11 @@ public class OtherVideoNfoReader : NfoReader, IOtherVideoNfoReade // ReSharper disable once ConvertToUsingDeclaration await using (Stream s = await SanitizedStreamForFile(fileName)) { - return await Read(s); + return await Read(s, fileName); } } - internal async Task> Read(Stream input) + internal async Task> Read(Stream input, string fileName) { OtherVideoNfo? nfo = null; @@ -60,55 +60,81 @@ public class OtherVideoNfoReader : NfoReader, IOtherVideoNfoReade nfo = new OtherVideoNfo(); break; case "title": - await ReadStringContent(reader, nfo, (movie, title) => movie.Title = title); + await ReadStringContent(reader, nfo, (movie, title) => movie.Title = title, fileName); break; case "sorttitle": - await ReadStringContent(reader, nfo, (movie, sortTitle) => movie.SortTitle = sortTitle); + await ReadStringContent( + reader, + nfo, + (movie, sortTitle) => movie.SortTitle = sortTitle, + fileName); break; case "outline": - await ReadStringContent(reader, nfo, (movie, outline) => movie.Outline = outline); + await ReadStringContent( + reader, + nfo, + (movie, outline) => movie.Outline = outline, + fileName); break; case "year": - await ReadIntContent(reader, nfo, (movie, year) => movie.Year = year); + await ReadIntContent(reader, nfo, (movie, year) => movie.Year = year, fileName); break; case "mpaa": await ReadStringContent( reader, nfo, - (movie, contentRating) => movie.ContentRating = contentRating); + (movie, contentRating) => movie.ContentRating = contentRating, fileName); break; case "premiered": await ReadDateTimeContent( reader, nfo, - (movie, premiered) => movie.Premiered = premiered); + (movie, premiered) => movie.Premiered = premiered, + fileName); break; case "plot": - await ReadStringContent(reader, nfo, (movie, plot) => movie.Plot = plot); + await ReadStringContent(reader, nfo, (movie, plot) => movie.Plot = plot, fileName); break; case "genre": - await ReadStringContent(reader, nfo, (movie, genre) => movie.Genres.Add(genre)); + await ReadStringContent( + reader, + nfo, + (movie, genre) => movie.Genres.Add(genre), + fileName); break; case "tag": - await ReadStringContent(reader, nfo, (movie, tag) => movie.Tags.Add(tag)); + await ReadStringContent(reader, nfo, (movie, tag) => movie.Tags.Add(tag), fileName); break; case "studio": - await ReadStringContent(reader, nfo, (movie, studio) => movie.Studios.Add(studio)); + await ReadStringContent( + reader, + nfo, + (movie, studio) => movie.Studios.Add(studio), + fileName); break; case "actor": - ReadActor(reader, nfo, (movie, actor) => movie.Actors.Add(actor)); + ReadActor(reader, nfo, (movie, actor) => movie.Actors.Add(actor), fileName); break; case "credits": - await ReadStringContent(reader, nfo, (movie, writer) => movie.Writers.Add(writer)); + await ReadStringContent( + reader, + nfo, + (movie, writer) => movie.Writers.Add(writer), + fileName); break; case "director": await ReadStringContent( reader, nfo, - (movie, director) => movie.Directors.Add(director)); + (movie, director) => movie.Directors.Add(director), + fileName); break; case "uniqueid": - await ReadUniqueId(reader, nfo, (movie, uniqueid) => movie.UniqueIds.Add(uniqueid)); + await ReadUniqueId( + reader, + nfo, + (movie, uniqueid) => movie.UniqueIds.Add(uniqueid), + fileName); break; } @@ -123,12 +149,12 @@ public class OtherVideoNfoReader : NfoReader, IOtherVideoNfoReade } } - return Optional(nfo).ToEither((BaseError)new FailedToReadNfo()); + return Optional(nfo).ToEither(new FailedToReadNfo()); } catch (XmlException) { - _logger.LogWarning("Invalid XML detected; returning incomplete metadata"); - return Optional(nfo).ToEither((BaseError)new FailedToReadNfo()); + _logger.LogWarning("Invalid XML detected in file {FileName}; returning incomplete metadata", fileName); + return Optional(nfo).ToEither(new FailedToReadNfo()); } catch (Exception ex) { diff --git a/ErsatzTV.Scanner/Core/Metadata/Nfo/ShowNfoReader.cs b/ErsatzTV.Scanner/Core/Metadata/Nfo/ShowNfoReader.cs index 5d1c6d58..93bafe3f 100644 --- a/ErsatzTV.Scanner/Core/Metadata/Nfo/ShowNfoReader.cs +++ b/ErsatzTV.Scanner/Core/Metadata/Nfo/ShowNfoReader.cs @@ -28,11 +28,11 @@ public class ShowNfoReader : NfoReader, IShowNfoReader // ReSharper disable once ConvertToUsingDeclaration await using (Stream s = await SanitizedStreamForFile(fileName)) { - return await Read(s); + return await Read(s, fileName); } } - internal async Task> Read(Stream input) + internal async Task> Read(Stream input, string fileName) { ShowNfo? nfo = null; @@ -57,45 +57,66 @@ public class ShowNfoReader : NfoReader, IShowNfoReader case "title": if (reader.Depth == showDepth + 1) { - await ReadStringContent(reader, nfo, (show, title) => show.Title = title); + await ReadStringContent(reader, nfo, (show, title) => show.Title = title, fileName); } break; case "year": - await ReadIntContent(reader, nfo, (show, year) => show.Year = year); + await ReadIntContent(reader, nfo, (show, year) => show.Year = year, fileName); break; case "plot": - await ReadStringContent(reader, nfo, (show, plot) => show.Plot = plot); + await ReadStringContent(reader, nfo, (show, plot) => show.Plot = plot, fileName); break; case "outline": - await ReadStringContent(reader, nfo, (show, outline) => show.Outline = outline); + await ReadStringContent( + reader, + nfo, + (show, outline) => show.Outline = outline, + fileName); break; case "tagline": - await ReadStringContent(reader, nfo, (show, tagline) => show.Tagline = tagline); + await ReadStringContent( + reader, + nfo, + (show, tagline) => show.Tagline = tagline, + fileName); break; case "mpaa": await ReadStringContent( reader, nfo, - (show, contentRating) => show.ContentRating = contentRating); + (show, contentRating) => show.ContentRating = contentRating, + fileName); break; case "premiered": - await ReadDateTimeContent(reader, nfo, (show, premiered) => show.Premiered = premiered); + await ReadDateTimeContent( + reader, + nfo, + (show, premiered) => show.Premiered = premiered, + fileName); break; case "genre": - await ReadStringContent(reader, nfo, (show, genre) => show.Genres.Add(genre)); + await ReadStringContent(reader, nfo, (show, genre) => show.Genres.Add(genre), fileName); break; case "tag": - await ReadStringContent(reader, nfo, (show, tag) => show.Tags.Add(tag)); + await ReadStringContent(reader, nfo, (show, tag) => show.Tags.Add(tag), fileName); break; case "studio": - await ReadStringContent(reader, nfo, (show, studio) => show.Studios.Add(studio)); + await ReadStringContent( + reader, + nfo, + (show, studio) => show.Studios.Add(studio), + fileName); break; case "actor": - ReadActor(reader, nfo, (episode, actor) => episode.Actors.Add(actor)); + ReadActor(reader, nfo, (episode, actor) => episode.Actors.Add(actor), fileName); break; case "uniqueid": - await ReadUniqueId(reader, nfo, (episode, uniqueid) => episode.UniqueIds.Add(uniqueid)); + await ReadUniqueId( + reader, + nfo, + (episode, uniqueid) => episode.UniqueIds.Add(uniqueid), + fileName); break; } @@ -110,12 +131,12 @@ public class ShowNfoReader : NfoReader, IShowNfoReader } } - return Optional(nfo).ToEither((BaseError)new FailedToReadNfo()); + return Optional(nfo).ToEither(new FailedToReadNfo()); } catch (XmlException) { - _logger.LogWarning("Invalid XML detected; returning incomplete metadata"); - return Optional(nfo).ToEither((BaseError)new FailedToReadNfo()); + _logger.LogWarning("Invalid XML detected in file {FileName}; returning incomplete metadata", fileName); + return Optional(nfo).ToEither(new FailedToReadNfo()); } catch (Exception ex) {