From 58697496fac950cacf4aa880c2c0459d6b4a6850 Mon Sep 17 00:00:00 2001 From: Jason Dove Date: Fri, 4 Mar 2022 15:44:51 -0600 Subject: [PATCH] metadata stack trace improvements (#672) * improve stack traces from local metadata provider * more metadata line number fixes --- .../Metadata/LocalMetadataProvider.cs | 962 +++++++++--------- 1 file changed, 480 insertions(+), 482 deletions(-) diff --git a/ErsatzTV.Core/Metadata/LocalMetadataProvider.cs b/ErsatzTV.Core/Metadata/LocalMetadataProvider.cs index d2d3f2172..287fcf71f 100644 --- a/ErsatzTV.Core/Metadata/LocalMetadataProvider.cs +++ b/ErsatzTV.Core/Metadata/LocalMetadataProvider.cs @@ -70,18 +70,15 @@ public class LocalMetadataProvider : ILocalMetadataProvider maybeMetadata = await LoadTelevisionShowMetadata(nfoFileName); } - return maybeMetadata.Match( - metadata => - { - metadata.SortTitle = _fallbackMetadataProvider.GetSortTitle(metadata.Title); - return metadata; - }, - () => - { - ShowMetadata metadata = _fallbackMetadataProvider.GetFallbackMetadataForShow(showFolder); - metadata.SortTitle = _fallbackMetadataProvider.GetSortTitle(metadata.Title); - return metadata; - }); + foreach (ShowMetadata metadata in maybeMetadata) + { + metadata.SortTitle = _fallbackMetadataProvider.GetSortTitle(metadata.Title); + return metadata; + } + + ShowMetadata fallbackMetadata = _fallbackMetadataProvider.GetFallbackMetadataForShow(showFolder); + fallbackMetadata.SortTitle = _fallbackMetadataProvider.GetSortTitle(fallbackMetadata.Title); + return fallbackMetadata; } public async Task GetMetadataForArtist(string artistFolder) @@ -93,18 +90,15 @@ public class LocalMetadataProvider : ILocalMetadataProvider maybeMetadata = await LoadArtistMetadata(nfoFileName); } - return maybeMetadata.Match( - metadata => - { - metadata.SortTitle = _fallbackMetadataProvider.GetSortTitle(metadata.Title); - return metadata; - }, - () => - { - ArtistMetadata metadata = _fallbackMetadataProvider.GetFallbackMetadataForArtist(artistFolder); - metadata.SortTitle = _fallbackMetadataProvider.GetSortTitle(metadata.Title); - return metadata; - }); + foreach (ArtistMetadata metadata in maybeMetadata) + { + metadata.SortTitle = _fallbackMetadataProvider.GetSortTitle(metadata.Title); + return metadata; + } + + ArtistMetadata fallbackMetadata = _fallbackMetadataProvider.GetFallbackMetadataForArtist(artistFolder); + fallbackMetadata.SortTitle = _fallbackMetadataProvider.GetSortTitle(fallbackMetadata.Title); + return fallbackMetadata; } public Task RefreshSidecarMetadata(Movie movie, string nfoFileName) => @@ -173,8 +167,9 @@ public class LocalMetadataProvider : ILocalMetadataProvider { await using FileStream fileStream = File.Open(nfoFileName, FileMode.Open, FileAccess.Read); Option maybeNfo = MusicVideoSerializer.Deserialize(fileStream) as MusicVideoNfo; - return maybeNfo.Match>( - nfo => new MusicVideoMetadata + foreach (MusicVideoNfo nfo in maybeNfo) + { + return new MusicVideoMetadata { MetadataKind = MetadataKind.Sidecar, DateAdded = DateTime.UtcNow, @@ -187,8 +182,10 @@ public class LocalMetadataProvider : ILocalMetadataProvider Genres = nfo.Genres.Map(g => new Genre { Name = g }).ToList(), Tags = nfo.Tags.Map(t => new Tag { Name = t }).ToList(), Studios = nfo.Studios.Map(s => new Studio { Name = s }).ToList() - }, - None); + }; + } + + return None; } catch (Exception ex) { @@ -207,74 +204,74 @@ public class LocalMetadataProvider : ILocalMetadataProvider Either> maybeTags = await _localStatisticsProvider.GetFormatTags(ffprobePath, song); - return maybeTags.Match( - tags => + foreach (Dictionary tags in maybeTags.RightToSeq()) + { + Option maybeFallbackMetadata = + _fallbackMetadataProvider.GetFallbackMetadata(song); + + var result = new SongMetadata { - Option maybeFallbackMetadata = - _fallbackMetadataProvider.GetFallbackMetadata(song); - - var result = new SongMetadata - { - MetadataKind = MetadataKind.Embedded, - DateAdded = DateTime.UtcNow, - DateUpdated = File.GetLastWriteTimeUtc(path), - - Artwork = new List(), - Actors = new List(), - Genres = new List(), - Studios = new List(), - Tags = new List() - }; - - if (tags.TryGetValue(MetadataFormatTag.Album, out string album)) - { - result.Album = album; - } + MetadataKind = MetadataKind.Embedded, + DateAdded = DateTime.UtcNow, + DateUpdated = File.GetLastWriteTimeUtc(path), - if (tags.TryGetValue(MetadataFormatTag.Artist, out string artist)) - { - result.Artist = artist; - } + Artwork = new List(), + Actors = new List(), + Genres = new List(), + Studios = new List(), + Tags = new List() + }; - if (tags.TryGetValue(MetadataFormatTag.Date, out string date)) - { - result.Date = date; - } + if (tags.TryGetValue(MetadataFormatTag.Album, out string album)) + { + result.Album = album; + } - if (tags.TryGetValue(MetadataFormatTag.Genre, out string genre)) - { - result.Genres.AddRange(SplitGenres(genre).Map(n => new Genre { Name = n })); - } + if (tags.TryGetValue(MetadataFormatTag.Artist, out string artist)) + { + result.Artist = artist; + } - if (tags.TryGetValue(MetadataFormatTag.Title, out string title)) - { - result.Title = title; - } + if (tags.TryGetValue(MetadataFormatTag.Date, out string date)) + { + result.Date = date; + } + + if (tags.TryGetValue(MetadataFormatTag.Genre, out string genre)) + { + result.Genres.AddRange(SplitGenres(genre).Map(n => new Genre { Name = n })); + } + + if (tags.TryGetValue(MetadataFormatTag.Title, out string title)) + { + result.Title = title; + } + + if (tags.TryGetValue(MetadataFormatTag.Track, out string track)) + { + result.Track = track; + } - if (tags.TryGetValue(MetadataFormatTag.Track, out string track)) + foreach (SongMetadata fallbackMetadata in maybeFallbackMetadata) + { + if (string.IsNullOrWhiteSpace(result.Title)) { - result.Track = track; + result.Title = fallbackMetadata.Title; } - foreach (SongMetadata fallbackMetadata in maybeFallbackMetadata) + result.OriginalTitle = fallbackMetadata.OriginalTitle; + + // preserve folder tagging - maybe someone uses this + foreach (Tag tag in fallbackMetadata.Tags) { - if (string.IsNullOrWhiteSpace(result.Title)) - { - result.Title = fallbackMetadata.Title; - } - - result.OriginalTitle = fallbackMetadata.OriginalTitle; - - // preserve folder tagging - maybe someone uses this - foreach (Tag tag in fallbackMetadata.Tags) - { - result.Tags.Add(tag); - } + result.Tags.Add(tag); } + } - return result; - }, - _ => Option.None); + return result; + } + + return Option.None; } catch (Exception ex) { @@ -320,109 +317,8 @@ public class LocalMetadataProvider : ILocalMetadataProvider { Option maybeIncoming = episodeMetadata.Find(em => em.EpisodeNumber == existing.EpisodeNumber); - updated = await maybeIncoming.Match( - async metadata => - { - existing.Outline = metadata.Outline; - existing.Plot = metadata.Plot; - existing.Tagline = metadata.Tagline; - existing.Title = metadata.Title; - - if (existing.DateAdded == SystemTime.MinValueUtc) - { - existing.DateAdded = metadata.DateAdded; - } - - existing.DateUpdated = metadata.DateUpdated; - existing.MetadataKind = metadata.MetadataKind; - existing.OriginalTitle = metadata.OriginalTitle; - existing.ReleaseDate = metadata.ReleaseDate; - existing.Year = metadata.Year; - existing.SortTitle = string.IsNullOrWhiteSpace(metadata.SortTitle) - ? _fallbackMetadataProvider.GetSortTitle(metadata.Title) - : metadata.SortTitle; - - updated = await UpdateMetadataCollections( - existing, - metadata, - (_, _) => Task.FromResult(false), - (_, _) => Task.FromResult(false), - (_, _) => Task.FromResult(false), - _televisionRepository.AddActor) || updated; - - foreach (Director director in existing.Directors - .Filter(d => metadata.Directors.All(d2 => d2.Name != d.Name)).ToList()) - { - existing.Directors.Remove(director); - if (await _metadataRepository.RemoveDirector(director)) - { - updated = true; - } - } - - foreach (Director director in metadata.Directors - .Filter(d => existing.Directors.All(d2 => d2.Name != d.Name)).ToList()) - { - existing.Directors.Add(director); - if (await _televisionRepository.AddDirector(existing, director)) - { - updated = true; - } - } - - foreach (Writer writer in existing.Writers - .Filter(w => metadata.Writers.All(w2 => w2.Name != w.Name)).ToList()) - { - existing.Writers.Remove(writer); - if (await _metadataRepository.RemoveWriter(writer)) - { - updated = true; - } - } - - foreach (Writer writer in metadata.Writers - .Filter(w => existing.Writers.All(w2 => w2.Name != w.Name)).ToList()) - { - existing.Writers.Add(writer); - if (await _televisionRepository.AddWriter(existing, writer)) - { - updated = true; - } - } - - foreach (MetadataGuid guid in existing.Guids - .Filter(g => metadata.Guids.All(g2 => g2.Guid != g.Guid)).ToList()) - { - existing.Guids.Remove(guid); - if (await _metadataRepository.RemoveGuid(guid)) - { - updated = true; - } - } - - foreach (MetadataGuid guid in metadata.Guids - .Filter(g => existing.Guids.All(g2 => g2.Guid != g.Guid)).ToList()) - { - existing.Guids.Add(guid); - if (await _metadataRepository.AddGuid(existing, guid)) - { - updated = true; - } - } - - return await _metadataRepository.Update(existing) || updated; - }, - () => Task.FromResult(updated)) || updated; - } - - return updated; - } - - private Task ApplyMetadataUpdate(Movie movie, MovieMetadata metadata) => - Optional(movie.MovieMetadata).Flatten().HeadOrNone().Match( - async existing => + foreach (EpisodeMetadata metadata in maybeIncoming) { - existing.ContentRating = metadata.ContentRating; existing.Outline = metadata.Outline; existing.Plot = metadata.Plot; existing.Tagline = metadata.Tagline; @@ -442,13 +338,13 @@ public class LocalMetadataProvider : ILocalMetadataProvider ? _fallbackMetadataProvider.GetSortTitle(metadata.Title) : metadata.SortTitle; - bool updated = await UpdateMetadataCollections( + updated = await UpdateMetadataCollections( existing, metadata, - _movieRepository.AddGenre, - _movieRepository.AddTag, - _movieRepository.AddStudio, - _movieRepository.AddActor); + (_, _) => Task.FromResult(false), + (_, _) => Task.FromResult(false), + (_, _) => Task.FromResult(false), + _televisionRepository.AddActor) || updated; foreach (Director director in existing.Directors .Filter(d => metadata.Directors.All(d2 => d2.Name != d.Name)).ToList()) @@ -464,7 +360,7 @@ public class LocalMetadataProvider : ILocalMetadataProvider .Filter(d => existing.Directors.All(d2 => d2.Name != d.Name)).ToList()) { existing.Directors.Add(director); - if (await _movieRepository.AddDirector(existing, director)) + if (await _televisionRepository.AddDirector(existing, director)) { updated = true; } @@ -484,7 +380,7 @@ public class LocalMetadataProvider : ILocalMetadataProvider .Filter(w => existing.Writers.All(w2 => w2.Name != w.Name)).ToList()) { existing.Writers.Add(writer); - if (await _movieRepository.AddWriter(existing, writer)) + if (await _televisionRepository.AddWriter(existing, writer)) { updated = true; } @@ -511,301 +407,400 @@ public class LocalMetadataProvider : ILocalMetadataProvider } return await _metadataRepository.Update(existing) || updated; - }, - async () => + } + } + + return updated; + } + + private async Task ApplyMetadataUpdate(Movie movie, MovieMetadata metadata) + { + Option maybeMetadata = Optional(movie.MovieMetadata).Flatten().HeadOrNone(); + foreach (MovieMetadata existing in maybeMetadata) + { + existing.ContentRating = metadata.ContentRating; + existing.Outline = metadata.Outline; + existing.Plot = metadata.Plot; + existing.Tagline = metadata.Tagline; + existing.Title = metadata.Title; + + if (existing.DateAdded == SystemTime.MinValueUtc) { - metadata.SortTitle = string.IsNullOrWhiteSpace(metadata.SortTitle) - ? _fallbackMetadataProvider.GetSortTitle(metadata.Title) - : metadata.SortTitle; - metadata.MovieId = movie.Id; - movie.MovieMetadata = new List { metadata }; + existing.DateAdded = metadata.DateAdded; + } + + existing.DateUpdated = metadata.DateUpdated; + existing.MetadataKind = metadata.MetadataKind; + existing.OriginalTitle = metadata.OriginalTitle; + existing.ReleaseDate = metadata.ReleaseDate; + existing.Year = metadata.Year; + existing.SortTitle = string.IsNullOrWhiteSpace(metadata.SortTitle) + ? _fallbackMetadataProvider.GetSortTitle(metadata.Title) + : metadata.SortTitle; - return await _metadataRepository.Add(metadata); - }); + bool updated = await UpdateMetadataCollections( + existing, + metadata, + _movieRepository.AddGenre, + _movieRepository.AddTag, + _movieRepository.AddStudio, + _movieRepository.AddActor); - private Task ApplyMetadataUpdate(Show show, ShowMetadata metadata) => - Optional(show.ShowMetadata).Flatten().HeadOrNone().Match( - async existing => + foreach (Director director in existing.Directors + .Filter(d => metadata.Directors.All(d2 => d2.Name != d.Name)).ToList()) { - existing.ContentRating = metadata.ContentRating; - existing.Outline = metadata.Outline; - existing.Plot = metadata.Plot; - existing.Tagline = metadata.Tagline; - existing.Title = metadata.Title; + existing.Directors.Remove(director); + if (await _metadataRepository.RemoveDirector(director)) + { + updated = true; + } + } - if (existing.DateAdded == SystemTime.MinValueUtc) + foreach (Director director in metadata.Directors + .Filter(d => existing.Directors.All(d2 => d2.Name != d.Name)).ToList()) + { + existing.Directors.Add(director); + if (await _movieRepository.AddDirector(existing, director)) { - existing.DateAdded = metadata.DateAdded; + updated = true; } + } - existing.DateUpdated = metadata.DateUpdated; - existing.MetadataKind = metadata.MetadataKind; - existing.OriginalTitle = metadata.OriginalTitle; - existing.ReleaseDate = metadata.ReleaseDate; - existing.Year = metadata.Year; - existing.SortTitle = string.IsNullOrWhiteSpace(metadata.SortTitle) - ? _fallbackMetadataProvider.GetSortTitle(metadata.Title) - : metadata.SortTitle; + foreach (Writer writer in existing.Writers + .Filter(w => metadata.Writers.All(w2 => w2.Name != w.Name)).ToList()) + { + existing.Writers.Remove(writer); + if (await _metadataRepository.RemoveWriter(writer)) + { + updated = true; + } + } - bool updated = await UpdateMetadataCollections( - existing, - metadata, - _televisionRepository.AddGenre, - _televisionRepository.AddTag, - _televisionRepository.AddStudio, - _televisionRepository.AddActor); + foreach (Writer writer in metadata.Writers + .Filter(w => existing.Writers.All(w2 => w2.Name != w.Name)).ToList()) + { + existing.Writers.Add(writer); + if (await _movieRepository.AddWriter(existing, writer)) + { + updated = true; + } + } - foreach (MetadataGuid guid in existing.Guids - .Filter(g => metadata.Guids.All(g2 => g2.Guid != g.Guid)).ToList()) + foreach (MetadataGuid guid in existing.Guids + .Filter(g => metadata.Guids.All(g2 => g2.Guid != g.Guid)).ToList()) + { + existing.Guids.Remove(guid); + if (await _metadataRepository.RemoveGuid(guid)) { - existing.Guids.Remove(guid); - if (await _metadataRepository.RemoveGuid(guid)) - { - updated = true; - } + updated = true; } + } - foreach (MetadataGuid guid in metadata.Guids - .Filter(g => existing.Guids.All(g2 => g2.Guid != g.Guid)).ToList()) + foreach (MetadataGuid guid in metadata.Guids + .Filter(g => existing.Guids.All(g2 => g2.Guid != g.Guid)).ToList()) + { + existing.Guids.Add(guid); + if (await _metadataRepository.AddGuid(existing, guid)) { - existing.Guids.Add(guid); - if (await _metadataRepository.AddGuid(existing, guid)) - { - updated = true; - } + updated = true; } + } - return await _metadataRepository.Update(existing) || updated; - }, - async () => + return await _metadataRepository.Update(existing) || updated; + } + + metadata.SortTitle = string.IsNullOrWhiteSpace(metadata.SortTitle) + ? _fallbackMetadataProvider.GetSortTitle(metadata.Title) + : metadata.SortTitle; + metadata.MovieId = movie.Id; + movie.MovieMetadata = new List { metadata }; + + return await _metadataRepository.Add(metadata); + } + + private async Task ApplyMetadataUpdate(Show show, ShowMetadata metadata) + { + Option maybeMetadata = Optional(show.ShowMetadata).Flatten().HeadOrNone(); + foreach (ShowMetadata existing in maybeMetadata) + { + existing.ContentRating = metadata.ContentRating; + existing.Outline = metadata.Outline; + existing.Plot = metadata.Plot; + existing.Tagline = metadata.Tagline; + existing.Title = metadata.Title; + + if (existing.DateAdded == SystemTime.MinValueUtc) { - metadata.SortTitle = string.IsNullOrWhiteSpace(metadata.SortTitle) - ? _fallbackMetadataProvider.GetSortTitle(metadata.Title) - : metadata.SortTitle; - metadata.ShowId = show.Id; - show.ShowMetadata = new List { metadata }; + existing.DateAdded = metadata.DateAdded; + } - return await _metadataRepository.Add(metadata); - }); + existing.DateUpdated = metadata.DateUpdated; + existing.MetadataKind = metadata.MetadataKind; + existing.OriginalTitle = metadata.OriginalTitle; + existing.ReleaseDate = metadata.ReleaseDate; + existing.Year = metadata.Year; + existing.SortTitle = string.IsNullOrWhiteSpace(metadata.SortTitle) + ? _fallbackMetadataProvider.GetSortTitle(metadata.Title) + : metadata.SortTitle; - private Task ApplyMetadataUpdate(Artist artist, ArtistMetadata metadata) => - Optional(artist.ArtistMetadata).Flatten().HeadOrNone().Match( - async existing => + bool updated = await UpdateMetadataCollections( + existing, + metadata, + _televisionRepository.AddGenre, + _televisionRepository.AddTag, + _televisionRepository.AddStudio, + _televisionRepository.AddActor); + + foreach (MetadataGuid guid in existing.Guids + .Filter(g => metadata.Guids.All(g2 => g2.Guid != g.Guid)).ToList()) { - existing.Title = metadata.Title; - existing.Disambiguation = metadata.Disambiguation; - existing.Biography = metadata.Biography; + existing.Guids.Remove(guid); + if (await _metadataRepository.RemoveGuid(guid)) + { + updated = true; + } + } - if (existing.DateAdded == SystemTime.MinValueUtc) + foreach (MetadataGuid guid in metadata.Guids + .Filter(g => existing.Guids.All(g2 => g2.Guid != g.Guid)).ToList()) + { + existing.Guids.Add(guid); + if (await _metadataRepository.AddGuid(existing, guid)) { - existing.DateAdded = metadata.DateAdded; + updated = true; } + } - existing.DateUpdated = metadata.DateUpdated; - existing.MetadataKind = metadata.MetadataKind; - existing.SortTitle = string.IsNullOrWhiteSpace(metadata.SortTitle) - ? _fallbackMetadataProvider.GetSortTitle(metadata.Title) - : metadata.SortTitle; + return await _metadataRepository.Update(existing) || updated; + } + + metadata.SortTitle = string.IsNullOrWhiteSpace(metadata.SortTitle) + ? _fallbackMetadataProvider.GetSortTitle(metadata.Title) + : metadata.SortTitle; + metadata.ShowId = show.Id; + show.ShowMetadata = new List { metadata }; + + return await _metadataRepository.Add(metadata); + } + + private async Task ApplyMetadataUpdate(Artist artist, ArtistMetadata metadata) + { + Option maybeMetadata = Optional(artist.ArtistMetadata).Flatten().HeadOrNone(); + foreach (ArtistMetadata existing in maybeMetadata) + { + existing.Title = metadata.Title; + existing.Disambiguation = metadata.Disambiguation; + existing.Biography = metadata.Biography; - var updated = false; + if (existing.DateAdded == SystemTime.MinValueUtc) + { + existing.DateAdded = metadata.DateAdded; + } + + existing.DateUpdated = metadata.DateUpdated; + existing.MetadataKind = metadata.MetadataKind; + existing.SortTitle = string.IsNullOrWhiteSpace(metadata.SortTitle) + ? _fallbackMetadataProvider.GetSortTitle(metadata.Title) + : metadata.SortTitle; + + var updated = false; - foreach (Genre genre in existing.Genres.Filter(g => metadata.Genres.All(g2 => g2.Name != g.Name)) - .ToList()) + foreach (Genre genre in existing.Genres.Filter(g => metadata.Genres.All(g2 => g2.Name != g.Name)) + .ToList()) + { + existing.Genres.Remove(genre); + if (await _metadataRepository.RemoveGenre(genre)) { - existing.Genres.Remove(genre); - if (await _metadataRepository.RemoveGenre(genre)) - { - updated = true; - } + updated = true; } + } - foreach (Genre genre in metadata.Genres.Filter(g => existing.Genres.All(g2 => g2.Name != g.Name)) - .ToList()) + foreach (Genre genre in metadata.Genres.Filter(g => existing.Genres.All(g2 => g2.Name != g.Name)) + .ToList()) + { + existing.Genres.Add(genre); + if (await _artistRepository.AddGenre(existing, genre)) { - existing.Genres.Add(genre); - if (await _artistRepository.AddGenre(existing, genre)) - { - updated = true; - } + updated = true; } + } - foreach (Style style in existing.Styles.Filter(s => metadata.Styles.All(s2 => s2.Name != s.Name)) - .ToList()) + foreach (Style style in existing.Styles.Filter(s => metadata.Styles.All(s2 => s2.Name != s.Name)) + .ToList()) + { + existing.Styles.Remove(style); + if (await _metadataRepository.RemoveStyle(style)) { - existing.Styles.Remove(style); - if (await _metadataRepository.RemoveStyle(style)) - { - updated = true; - } + updated = true; } + } - foreach (Style style in metadata.Styles.Filter(s => existing.Styles.All(s2 => s2.Name != s.Name)) - .ToList()) + foreach (Style style in metadata.Styles.Filter(s => existing.Styles.All(s2 => s2.Name != s.Name)) + .ToList()) + { + existing.Styles.Add(style); + if (await _artistRepository.AddStyle(existing, style)) { - existing.Styles.Add(style); - if (await _artistRepository.AddStyle(existing, style)) - { - updated = true; - } + updated = true; } + } - foreach (Mood mood in existing.Moods.Filter(m => metadata.Moods.All(m2 => m2.Name != m.Name)) - .ToList()) + foreach (Mood mood in existing.Moods.Filter(m => metadata.Moods.All(m2 => m2.Name != m.Name)) + .ToList()) + { + existing.Moods.Remove(mood); + if (await _metadataRepository.RemoveMood(mood)) { - existing.Moods.Remove(mood); - if (await _metadataRepository.RemoveMood(mood)) - { - updated = true; - } + updated = true; } + } - foreach (Mood mood in metadata.Moods.Filter(s => existing.Moods.All(m2 => m2.Name != s.Name)) - .ToList()) + foreach (Mood mood in metadata.Moods.Filter(s => existing.Moods.All(m2 => m2.Name != s.Name)) + .ToList()) + { + existing.Moods.Add(mood); + if (await _artistRepository.AddMood(existing, mood)) { - existing.Moods.Add(mood); - if (await _artistRepository.AddMood(existing, mood)) - { - updated = true; - } + updated = true; } + } - return await _metadataRepository.Update(existing) || updated; - }, - async () => - { - metadata.SortTitle = string.IsNullOrWhiteSpace(metadata.SortTitle) - ? _fallbackMetadataProvider.GetSortTitle(metadata.Title) - : metadata.SortTitle; - metadata.ArtistId = artist.Id; - artist.ArtistMetadata = new List { metadata }; + return await _metadataRepository.Update(existing) || updated; + } + + metadata.SortTitle = string.IsNullOrWhiteSpace(metadata.SortTitle) + ? _fallbackMetadataProvider.GetSortTitle(metadata.Title) + : metadata.SortTitle; + metadata.ArtistId = artist.Id; + artist.ArtistMetadata = new List { metadata }; + + return await _metadataRepository.Add(metadata); + } - return await _metadataRepository.Add(metadata); - }); + private async Task ApplyMetadataUpdate(MusicVideo musicVideo, MusicVideoMetadata metadata) + { + Option maybeMetadata = Optional(musicVideo.MusicVideoMetadata).Flatten().HeadOrNone(); + foreach (MusicVideoMetadata existing in maybeMetadata) + { + existing.Title = metadata.Title; + existing.Year = metadata.Year; + existing.Plot = metadata.Plot; + existing.Album = metadata.Album; - private Task ApplyMetadataUpdate(MusicVideo musicVideo, MusicVideoMetadata metadata) => - Optional(musicVideo.MusicVideoMetadata).Flatten().HeadOrNone().Match( - async existing => + if (existing.DateAdded == SystemTime.MinValueUtc) { - existing.Title = metadata.Title; - existing.Year = metadata.Year; - existing.Plot = metadata.Plot; - existing.Album = metadata.Album; + existing.DateAdded = metadata.DateAdded; + } - if (existing.DateAdded == SystemTime.MinValueUtc) - { - existing.DateAdded = metadata.DateAdded; - } + existing.DateUpdated = metadata.DateUpdated; + existing.MetadataKind = metadata.MetadataKind; + existing.OriginalTitle = metadata.OriginalTitle; + existing.ReleaseDate = metadata.ReleaseDate; + existing.SortTitle = string.IsNullOrWhiteSpace(metadata.SortTitle) + ? _fallbackMetadataProvider.GetSortTitle(metadata.Title) + : metadata.SortTitle; - existing.DateUpdated = metadata.DateUpdated; - existing.MetadataKind = metadata.MetadataKind; - existing.OriginalTitle = metadata.OriginalTitle; - existing.ReleaseDate = metadata.ReleaseDate; - existing.SortTitle = string.IsNullOrWhiteSpace(metadata.SortTitle) - ? _fallbackMetadataProvider.GetSortTitle(metadata.Title) - : metadata.SortTitle; + bool updated = await UpdateMetadataCollections( + existing, + metadata, + _musicVideoRepository.AddGenre, + _musicVideoRepository.AddTag, + _musicVideoRepository.AddStudio, + (_, _) => Task.FromResult(false)); - bool updated = await UpdateMetadataCollections( - existing, - metadata, - _musicVideoRepository.AddGenre, - _musicVideoRepository.AddTag, - _musicVideoRepository.AddStudio, - (_, _) => Task.FromResult(false)); + return await _metadataRepository.Update(existing) || updated; + } - return await _metadataRepository.Update(existing) || updated; - }, - async () => - { - metadata.SortTitle = string.IsNullOrWhiteSpace(metadata.SortTitle) - ? _fallbackMetadataProvider.GetSortTitle(metadata.Title) - : metadata.SortTitle; - metadata.MusicVideoId = musicVideo.Id; - musicVideo.MusicVideoMetadata = new List { metadata }; + metadata.SortTitle = string.IsNullOrWhiteSpace(metadata.SortTitle) + ? _fallbackMetadataProvider.GetSortTitle(metadata.Title) + : metadata.SortTitle; + metadata.MusicVideoId = musicVideo.Id; + musicVideo.MusicVideoMetadata = new List { metadata }; - return await _metadataRepository.Add(metadata); - }); - - private Task ApplyMetadataUpdate(OtherVideo otherVideo, OtherVideoMetadata metadata) => - Optional(otherVideo.OtherVideoMetadata).Flatten().HeadOrNone().Match( - async existing => + return await _metadataRepository.Add(metadata); + } + + private async Task ApplyMetadataUpdate(OtherVideo otherVideo, OtherVideoMetadata metadata) + { + Option maybeMetadata = Optional(otherVideo.OtherVideoMetadata).Flatten().HeadOrNone(); + foreach (OtherVideoMetadata existing in maybeMetadata) + { + existing.Title = metadata.Title; + + if (existing.DateAdded == SystemTime.MinValueUtc) { - existing.Title = metadata.Title; + existing.DateAdded = metadata.DateAdded; + } - if (existing.DateAdded == SystemTime.MinValueUtc) - { - existing.DateAdded = metadata.DateAdded; - } + existing.DateUpdated = metadata.DateUpdated; + existing.MetadataKind = metadata.MetadataKind; + existing.SortTitle = string.IsNullOrWhiteSpace(metadata.SortTitle) + ? _fallbackMetadataProvider.GetSortTitle(metadata.Title) + : metadata.SortTitle; + existing.OriginalTitle = metadata.OriginalTitle; - existing.DateUpdated = metadata.DateUpdated; - existing.MetadataKind = metadata.MetadataKind; - existing.SortTitle = string.IsNullOrWhiteSpace(metadata.SortTitle) - ? _fallbackMetadataProvider.GetSortTitle(metadata.Title) - : metadata.SortTitle; - existing.OriginalTitle = metadata.OriginalTitle; + bool updated = await UpdateMetadataCollections( + existing, + metadata, + (_, _) => Task.FromResult(false), + _otherVideoRepository.AddTag, + (_, _) => Task.FromResult(false), + (_, _) => Task.FromResult(false)); - bool updated = await UpdateMetadataCollections( - existing, - metadata, - (_, _) => Task.FromResult(false), - _otherVideoRepository.AddTag, - (_, _) => Task.FromResult(false), - (_, _) => Task.FromResult(false)); + return await _metadataRepository.Update(existing) || updated; + } - return await _metadataRepository.Update(existing) || updated; - }, - async () => - { - metadata.SortTitle = string.IsNullOrWhiteSpace(metadata.SortTitle) - ? _fallbackMetadataProvider.GetSortTitle(metadata.Title) - : metadata.SortTitle; - metadata.OtherVideoId = otherVideo.Id; - otherVideo.OtherVideoMetadata = new List { metadata }; + metadata.SortTitle = string.IsNullOrWhiteSpace(metadata.SortTitle) + ? _fallbackMetadataProvider.GetSortTitle(metadata.Title) + : metadata.SortTitle; + metadata.OtherVideoId = otherVideo.Id; + otherVideo.OtherVideoMetadata = new List { metadata }; - return await _metadataRepository.Add(metadata); - }); - - private Task ApplyMetadataUpdate(Song song, SongMetadata metadata) => - Optional(song.SongMetadata).Flatten().HeadOrNone().Match( - async existing => + return await _metadataRepository.Add(metadata); + } + + private async Task ApplyMetadataUpdate(Song song, SongMetadata metadata) + { + Option maybeMetadata = Optional(song.SongMetadata).Flatten().HeadOrNone(); + foreach (SongMetadata existing in maybeMetadata) + { + existing.Title = metadata.Title; + existing.Artist = metadata.Artist; + existing.Album = metadata.Album; + existing.Date = metadata.Date; + existing.Track = metadata.Track; + + if (existing.DateAdded == SystemTime.MinValueUtc) { - existing.Title = metadata.Title; - existing.Artist = metadata.Artist; - existing.Album = metadata.Album; - existing.Date = metadata.Date; - existing.Track = metadata.Track; + existing.DateAdded = metadata.DateAdded; + } - if (existing.DateAdded == SystemTime.MinValueUtc) - { - existing.DateAdded = metadata.DateAdded; - } + existing.DateUpdated = metadata.DateUpdated; + existing.MetadataKind = metadata.MetadataKind; + existing.SortTitle = string.IsNullOrWhiteSpace(metadata.SortTitle) + ? _fallbackMetadataProvider.GetSortTitle(metadata.Title) + : metadata.SortTitle; + existing.OriginalTitle = metadata.OriginalTitle; - existing.DateUpdated = metadata.DateUpdated; - existing.MetadataKind = metadata.MetadataKind; - existing.SortTitle = string.IsNullOrWhiteSpace(metadata.SortTitle) - ? _fallbackMetadataProvider.GetSortTitle(metadata.Title) - : metadata.SortTitle; - existing.OriginalTitle = metadata.OriginalTitle; + bool updated = await UpdateMetadataCollections( + existing, + metadata, + _songRepository.AddGenre, + _songRepository.AddTag, + (_, _) => Task.FromResult(false), + (_, _) => Task.FromResult(false)); - bool updated = await UpdateMetadataCollections( - existing, - metadata, - _songRepository.AddGenre, - _songRepository.AddTag, - (_, _) => Task.FromResult(false), - (_, _) => Task.FromResult(false)); + return await _metadataRepository.Update(existing) || updated; + } - return await _metadataRepository.Update(existing) || updated; - }, - async () => - { - metadata.SortTitle = string.IsNullOrWhiteSpace(metadata.SortTitle) - ? _fallbackMetadataProvider.GetSortTitle(metadata.Title) - : metadata.SortTitle; - metadata.SongId = song.Id; - song.SongMetadata = new List { metadata }; + metadata.SortTitle = string.IsNullOrWhiteSpace(metadata.SortTitle) + ? _fallbackMetadataProvider.GetSortTitle(metadata.Title) + : metadata.SortTitle; + metadata.SongId = song.Id; + song.SongMetadata = new List { metadata }; - return await _metadataRepository.Add(metadata); - }); + return await _metadataRepository.Add(metadata); + } private async Task> LoadTelevisionShowMetadata(string nfoFileName) { @@ -813,34 +808,34 @@ public class LocalMetadataProvider : ILocalMetadataProvider { await using FileStream fileStream = File.Open(nfoFileName, FileMode.Open, FileAccess.Read); Option maybeNfo = TvShowSerializer.Deserialize(fileStream) as TvShowNfo; - return maybeNfo.Match>( - nfo => + foreach (TvShowNfo nfo in maybeNfo) + { + DateTime dateAdded = DateTime.UtcNow; + DateTime dateUpdated = File.GetLastWriteTimeUtc(nfoFileName); + + return new ShowMetadata { - DateTime dateAdded = DateTime.UtcNow; - DateTime dateUpdated = File.GetLastWriteTimeUtc(nfoFileName); + MetadataKind = MetadataKind.Sidecar, + DateAdded = dateAdded, + DateUpdated = dateUpdated, + Title = nfo.Title, + Plot = nfo.Plot, + Outline = nfo.Outline, + Tagline = nfo.Tagline, + ContentRating = nfo.ContentRating, + Year = GetYear(nfo.Year, nfo.Premiered), + ReleaseDate = GetAired(nfo.Year, nfo.Premiered), + Genres = nfo.Genres.Map(g => new Genre { Name = g }).ToList(), + Tags = nfo.Tags.Map(t => new Tag { Name = t }).ToList(), + Studios = nfo.Studios.Map(s => new Studio { Name = s }).ToList(), + Actors = Actors(nfo.Actors, dateAdded, dateUpdated), + Guids = nfo.UniqueIds + .Map(id => new MetadataGuid { Guid = $"{id.Type}://{id.Guid}" }) + .ToList() + }; + } - return new ShowMetadata - { - MetadataKind = MetadataKind.Sidecar, - DateAdded = dateAdded, - DateUpdated = dateUpdated, - Title = nfo.Title, - Plot = nfo.Plot, - Outline = nfo.Outline, - Tagline = nfo.Tagline, - ContentRating = nfo.ContentRating, - Year = GetYear(nfo.Year, nfo.Premiered), - ReleaseDate = GetAired(nfo.Year, nfo.Premiered), - Genres = nfo.Genres.Map(g => new Genre { Name = g }).ToList(), - Tags = nfo.Tags.Map(t => new Tag { Name = t }).ToList(), - Studios = nfo.Studios.Map(s => new Studio { Name = s }).ToList(), - Actors = Actors(nfo.Actors, dateAdded, dateUpdated), - Guids = nfo.UniqueIds - .Map(id => new MetadataGuid { Guid = $"{id.Type}://{id.Guid}" }) - .ToList() - }; - }, - None); + return None; } catch (Exception ex) { @@ -856,8 +851,9 @@ public class LocalMetadataProvider : ILocalMetadataProvider { await using FileStream fileStream = File.Open(nfoFileName, FileMode.Open, FileAccess.Read); Option maybeNfo = ArtistSerializer.Deserialize(fileStream) as ArtistNfo; - return maybeNfo.Match>( - nfo => new ArtistMetadata + foreach (ArtistNfo nfo in maybeNfo) + { + return new ArtistMetadata { MetadataKind = MetadataKind.Sidecar, DateAdded = DateTime.UtcNow, @@ -868,8 +864,10 @@ public class LocalMetadataProvider : ILocalMetadataProvider Genres = nfo.Genres.Map(g => new Genre { Name = g }).ToList(), Styles = nfo.Styles.Map(s => new Style { Name = s }).ToList(), Moods = nfo.Moods.Map(m => new Mood { Name = m }).ToList() - }, - None); + }; + } + + return None; } catch (Exception ex) { @@ -933,36 +931,36 @@ public class LocalMetadataProvider : ILocalMetadataProvider { await using FileStream fileStream = File.Open(nfoFileName, FileMode.Open, FileAccess.Read); Option maybeNfo = MovieSerializer.Deserialize(fileStream) as MovieNfo; - return maybeNfo.Match>( - nfo => + foreach (MovieNfo nfo in maybeNfo) + { + DateTime dateAdded = DateTime.UtcNow; + DateTime dateUpdated = File.GetLastWriteTimeUtc(nfoFileName); + + return new MovieMetadata { - DateTime dateAdded = DateTime.UtcNow; - DateTime dateUpdated = File.GetLastWriteTimeUtc(nfoFileName); + MetadataKind = MetadataKind.Sidecar, + DateAdded = dateAdded, + DateUpdated = dateUpdated, + Title = nfo.Title, + Year = nfo.Year, + ContentRating = nfo.ContentRating, + ReleaseDate = nfo.Premiered, + Plot = nfo.Plot, + Outline = nfo.Outline, + Tagline = nfo.Tagline, + Genres = nfo.Genres.Map(g => new Genre { Name = g }).ToList(), + Tags = nfo.Tags.Map(t => new Tag { Name = t }).ToList(), + Studios = nfo.Studios.Map(s => new Studio { Name = s }).ToList(), + Actors = Actors(nfo.Actors, dateAdded, dateUpdated), + Directors = nfo.Directors.Map(d => new Director { Name = d }).ToList(), + Writers = nfo.Writers.Map(w => new Writer { Name = w }).ToList(), + Guids = nfo.UniqueIds + .Map(id => new MetadataGuid { Guid = $"{id.Type}://{id.Guid}" }) + .ToList() + }; + } - return new MovieMetadata - { - MetadataKind = MetadataKind.Sidecar, - DateAdded = dateAdded, - DateUpdated = dateUpdated, - Title = nfo.Title, - Year = nfo.Year, - ContentRating = nfo.ContentRating, - ReleaseDate = nfo.Premiered, - Plot = nfo.Plot, - Outline = nfo.Outline, - Tagline = nfo.Tagline, - Genres = nfo.Genres.Map(g => new Genre { Name = g }).ToList(), - Tags = nfo.Tags.Map(t => new Tag { Name = t }).ToList(), - Studios = nfo.Studios.Map(s => new Studio { Name = s }).ToList(), - Actors = Actors(nfo.Actors, dateAdded, dateUpdated), - Directors = nfo.Directors.Map(d => new Director { Name = d }).ToList(), - Writers = nfo.Writers.Map(w => new Writer { Name = w }).ToList(), - Guids = nfo.UniqueIds - .Map(id => new MetadataGuid { Guid = $"{id.Type}://{id.Guid}" }) - .ToList() - }; - }, - None); + return None; } catch (Exception ex) {