using System; using System.Linq; using ErsatzTV.Core.Domain; using LanguageExt; using static LanguageExt.Prelude; namespace ErsatzTV.Application.MediaCards { internal static class Mapper { internal static TelevisionShowCardViewModel ProjectToViewModel( ShowMetadata showMetadata, Option maybeJellyfin) => new( showMetadata.ShowId, showMetadata.Title, showMetadata.Year?.ToString(), showMetadata.SortTitle, GetPoster(showMetadata, maybeJellyfin)); internal static TelevisionSeasonCardViewModel ProjectToViewModel( Season season, Option maybeJellyfin) => new( season.Show.ShowMetadata.HeadOrNone().Match(m => m.Title ?? string.Empty, () => string.Empty), season.Id, season.SeasonNumber, GetSeasonName(season.SeasonNumber), string.Empty, GetSeasonName(season.SeasonNumber), season.SeasonMetadata.HeadOrNone().Map(sm => GetPoster(sm, maybeJellyfin)).IfNone(string.Empty), season.SeasonNumber == 0 ? "S" : season.SeasonNumber.ToString()); internal static TelevisionEpisodeCardViewModel ProjectToViewModel( EpisodeMetadata episodeMetadata, Option maybeJellyfin) => new( episodeMetadata.EpisodeId, episodeMetadata.ReleaseDate ?? DateTime.MinValue, episodeMetadata.Episode.Season.Show.ShowMetadata.HeadOrNone().Match( m => m.Title ?? string.Empty, () => string.Empty), episodeMetadata.Episode.Season.ShowId, episodeMetadata.Episode.SeasonId, episodeMetadata.Episode.EpisodeNumber, episodeMetadata.Title, episodeMetadata.Episode.EpisodeMetadata.HeadOrNone().Match( em => em.Plot ?? string.Empty, () => string.Empty), GetThumbnail(episodeMetadata, maybeJellyfin)); internal static MovieCardViewModel ProjectToViewModel( MovieMetadata movieMetadata, Option maybeJellyfin) => new( movieMetadata.MovieId, movieMetadata.Title, movieMetadata.Year?.ToString(), movieMetadata.SortTitle, GetPoster(movieMetadata, maybeJellyfin)); internal static MusicVideoCardViewModel ProjectToViewModel(MusicVideoMetadata musicVideoMetadata) => new( musicVideoMetadata.MusicVideoId, musicVideoMetadata.Title, musicVideoMetadata.MusicVideo.Artist.ArtistMetadata.Head().Title, musicVideoMetadata.SortTitle, musicVideoMetadata.Plot, GetThumbnail(musicVideoMetadata, None)); internal static ArtistCardViewModel ProjectToViewModel(ArtistMetadata artistMetadata) => new( artistMetadata.ArtistId, artistMetadata.Title, artistMetadata.Disambiguation, artistMetadata.SortTitle, GetThumbnail(artistMetadata, None)); internal static CollectionCardResultsViewModel ProjectToViewModel(Collection collection, Option maybeJellyfin) => new( collection.Name, collection.MediaItems.OfType().Map( m => ProjectToViewModel(m.MovieMetadata.Head(), maybeJellyfin) with { CustomIndex = GetCustomIndex(collection, m.Id) }).ToList(), collection.MediaItems.OfType().Map(s => ProjectToViewModel(s.ShowMetadata.Head(), maybeJellyfin)) .ToList(), collection.MediaItems.OfType().Map(s => ProjectToViewModel(s, maybeJellyfin)).ToList(), collection.MediaItems.OfType() .Map(e => ProjectToViewModel(e.EpisodeMetadata.Head(), maybeJellyfin)) .ToList(), collection.MediaItems.OfType().Map(a => ProjectToViewModel(a.ArtistMetadata.Head())).ToList(), collection.MediaItems.OfType().Map(mv => ProjectToViewModel(mv.MusicVideoMetadata.Head())) .ToList()) { UseCustomPlaybackOrder = collection.UseCustomPlaybackOrder }; internal static ActorCardViewModel ProjectToViewModel(Actor actor, Option maybeJellyfin) { string artwork = actor.Artwork?.Path ?? string.Empty; if (maybeJellyfin.IsSome && artwork.StartsWith("jellyfin://")) { string address = maybeJellyfin.Map(ms => ms.Connections.HeadOrNone().Map(c => c.Address)) .Flatten() .IfNone("jellyfin://"); artwork = artwork.Replace("jellyfin://", address) + "&fillheight=440"; } return new ActorCardViewModel(actor.Id, actor.Name, actor.Role, artwork); } private static int GetCustomIndex(Collection collection, int mediaItemId) => Optional(collection.CollectionItems.Find(ci => ci.MediaItemId == mediaItemId)) .Map(ci => ci.CustomIndex ?? 0) .IfNone(0); private static string GetSeasonName(int number) => number == 0 ? "Specials" : $"Season {number}"; private static string GetPoster(Metadata metadata, Option maybeJellyfin) { string poster = Optional(metadata.Artwork.FirstOrDefault(a => a.ArtworkKind == ArtworkKind.Poster)) .Match(a => a.Path, string.Empty); if (maybeJellyfin.IsSome && poster.StartsWith("jellyfin://")) { string address = maybeJellyfin.Map(ms => ms.Connections.HeadOrNone().Map(c => c.Address)) .Flatten() .IfNone("jellyfin://"); poster = poster.Replace("jellyfin://", address) + "&fillHeight=440"; } return poster; } private static string GetThumbnail(Metadata metadata, Option maybeJellyfin) { string thumb = Optional(metadata.Artwork.FirstOrDefault(a => a.ArtworkKind == ArtworkKind.Thumbnail)) .Match(a => a.Path, string.Empty); if (maybeJellyfin.IsSome && thumb.StartsWith("jellyfin://")) { string address = maybeJellyfin.Map(ms => ms.Connections.HeadOrNone().Map(c => c.Address)) .Flatten() .IfNone("jellyfin://"); thumb = thumb.Replace("jellyfin://", address) + "&fillHeight=220"; // TODO: this height is optimized for episode } return thumb; } } }