private static string Artwork( Metadata metadata, ArtworkKind artworkKind, Option <JellyfinMediaSource> maybeJellyfin, Option <EmbyMediaSource> maybeEmby) { string artwork = Optional(metadata.Artwork.FirstOrDefault(a => a.ArtworkKind == artworkKind)) .Match(a => a.Path, string.Empty); if (maybeJellyfin.IsSome && artwork.StartsWith("jellyfin://")) { Url url = JellyfinUrl.RelativeProxyForArtwork(artwork); if (artworkKind is ArtworkKind.Poster or ArtworkKind.Thumbnail) { url.SetQueryParam("fillHeight", 440); } artwork = url; } else if (maybeEmby.IsSome && artwork.StartsWith("emby://")) { Url url = EmbyUrl.RelativeProxyForArtwork(artwork); if (artworkKind is ArtworkKind.Poster or ArtworkKind.Thumbnail) { url.SetQueryParam("maxHeight", 440); } artwork = url; } return(artwork); }
private string GetArtworkUrl(Artwork artwork, ArtworkKind artworkKind) { string artworkPath = artwork.Path; int height = artworkKind switch { ArtworkKind.Thumbnail => 220, _ => 440 }; if (artworkPath.StartsWith("jellyfin://")) { artworkPath = JellyfinUrl.ProxyForArtwork(_scheme, _host, artworkPath, artworkKind) .SetQueryParam("fillHeight", height); } else if (artworkPath.StartsWith("emby://")) { artworkPath = EmbyUrl.ProxyForArtwork(_scheme, _host, artworkPath, artworkKind) .SetQueryParam("maxHeight", height); } else { string artworkFolder = artworkKind switch { ArtworkKind.Thumbnail => "thumbnails", _ => "posters" }; artworkPath = $"{_scheme}://{_host}/iptv/artwork/{artworkFolder}/{artwork.Path}.jpg"; } return(artworkPath); }
private Option <string> LocateArtwork(Movie movie, ArtworkKind artworkKind) { string segment = artworkKind switch { ArtworkKind.Poster => "poster", ArtworkKind.FanArt => "fanart", _ => throw new ArgumentOutOfRangeException(nameof(artworkKind)) }; string path = movie.MediaVersions.Head().MediaFiles.Head().Path; string folder = Path.GetDirectoryName(path) ?? string.Empty; IEnumerable <string> possibleMoviePosters = ImageFileExtensions.Collect( ext => new[] { $"{segment}.{ext}", Path.GetFileNameWithoutExtension(path) + $"-{segment}.{ext}" }) .Map(f => Path.Combine(folder, f)); Option <string> result = possibleMoviePosters.Filter(p => _localFileSystem.FileExists(p)).HeadOrNone(); if (result.IsNone && artworkKind == ArtworkKind.Poster) { IEnumerable <string> possibleFolderPosters = ImageFileExtensions.Collect( ext => new[] { $"folder.{ext}" }) .Map(f => Path.Combine(folder, f)); result = possibleFolderPosters.Filter(p => _localFileSystem.FileExists(p)).HeadOrNone(); } return(result); } }
private Option <string> LocateArtworkForArtist(string artistFolder, ArtworkKind artworkKind) { string segment = artworkKind switch { ArtworkKind.Thumbnail => "thumb", ArtworkKind.FanArt => "fanart", _ => throw new ArgumentOutOfRangeException(nameof(artworkKind)) }; return(ImageFileExtensions .Map(ext => $"{segment}.{ext}") .Map(f => Path.Combine(artistFolder, f)) .Filter(s => _localFileSystem.FileExists(s)) .HeadOrNone()); }
private Option <string> LocateArtworkForShow(string showFolder, ArtworkKind artworkKind) { string[] segments = artworkKind switch { ArtworkKind.Poster => new[] { "poster", "folder" }, ArtworkKind.FanArt => new[] { "fanart" }, _ => throw new ArgumentOutOfRangeException(nameof(artworkKind)) }; return(ImageFileExtensions .Map(ext => segments.Map(segment => $"{segment}.{ext}")) .Flatten() .Map(f => Path.Combine(showFolder, f)) .Filter(s => _localFileSystem.FileExists(s)) .HeadOrNone()); }
protected async Task <bool> UpdateArtworkIfNeeded( Domain.Metadata existingMetadata, Domain.Metadata incomingMetadata, ArtworkKind artworkKind) { if (incomingMetadata.DateUpdated > existingMetadata.DateUpdated) { Option <Artwork> maybeIncomingArtwork = Optional(incomingMetadata.Artwork).Flatten() .Find(a => a.ArtworkKind == artworkKind); if (maybeIncomingArtwork.IsNone) { existingMetadata.Artwork ??= new List <Artwork>(); existingMetadata.Artwork.RemoveAll(a => a.ArtworkKind == artworkKind); await _metadataRepository.RemoveArtwork(existingMetadata, artworkKind); } foreach (Artwork incomingArtwork in maybeIncomingArtwork) { _logger.LogDebug("Refreshing Plex {Attribute} from {Path}", artworkKind, incomingArtwork.Path); Option <Artwork> maybeExistingArtwork = Optional(existingMetadata.Artwork).Flatten() .Find(a => a.ArtworkKind == artworkKind); if (maybeExistingArtwork.IsNone) { existingMetadata.Artwork ??= new List <Artwork>(); existingMetadata.Artwork.Add(incomingArtwork); await _metadataRepository.AddArtwork(existingMetadata, incomingArtwork); } foreach (Artwork existingArtwork in maybeExistingArtwork) { existingArtwork.Path = incomingArtwork.Path; existingArtwork.DateUpdated = incomingArtwork.DateUpdated; await _metadataRepository.UpdateArtworkPath(existingArtwork); } } return(true); } return(false); }
public static Url ProxyForArtwork(string scheme, string host, string artwork, ArtworkKind artworkKind) { string[] split = artwork.Replace("jellyfin://", string.Empty).Split('?'); if (split.Length != 2) { return(artwork); } string pathSegment = split[0]; QueryParamCollection query = Url.ParseQueryParams(split[1]); string artworkFolder = artworkKind switch { ArtworkKind.Thumbnail => "thumbnails", _ => "posters" }; return(Url.Parse($"{scheme}://{host}/iptv/artwork/{artworkFolder}/jellyfin") .AppendPathSegment(pathSegment) .SetQueryParams(query)); }
private async Task <Either <BaseError, MediaItemScanResult <Movie> > > UpdateArtwork( MediaItemScanResult <Movie> result, ArtworkKind artworkKind) { try { Movie movie = result.Item; await LocateArtwork(movie, artworkKind).IfSomeAsync( async posterFile => { MovieMetadata metadata = movie.MovieMetadata.Head(); await RefreshArtwork(posterFile, metadata, artworkKind); }); return(result); } catch (Exception ex) { return(BaseError.New(ex.ToString())); } }
private async Task <Either <BaseError, MediaItemScanResult <Show> > > UpdateArtworkForShow( MediaItemScanResult <Show> result, string showFolder, ArtworkKind artworkKind) { try { Show show = result.Item; await LocateArtworkForShow(showFolder, artworkKind).IfSomeAsync( async posterFile => { ShowMetadata metadata = show.ShowMetadata.Head(); await RefreshArtwork(posterFile, metadata, artworkKind); }); return(result); } catch (Exception ex) { return(BaseError.New(ex.ToString())); } }
private async Task <Either <BaseError, MediaItemScanResult <Movie> > > UpdateArtwork( MediaItemScanResult <Movie> result, ArtworkKind artworkKind, CancellationToken cancellationToken) { try { Movie movie = result.Item; Option <string> maybeArtwork = LocateArtwork(movie, artworkKind); foreach (string posterFile in maybeArtwork) { MovieMetadata metadata = movie.MovieMetadata.Head(); await RefreshArtwork(posterFile, metadata, artworkKind, None, None, cancellationToken); } return(result); } catch (Exception ex) { _client.Notify(ex); return(BaseError.New(ex.ToString())); } }
private async Task <Either <BaseError, MediaItemScanResult <Show> > > UpdateArtworkForShow( MediaItemScanResult <Show> result, string showFolder, ArtworkKind artworkKind, CancellationToken cancellationToken) { try { Show show = result.Item; Option <string> maybeArtwork = LocateArtworkForShow(showFolder, artworkKind); foreach (string artworkFile in maybeArtwork) { ShowMetadata metadata = show.ShowMetadata.Head(); await RefreshArtwork(artworkFile, metadata, artworkKind, None, None, cancellationToken); } return(result); } catch (Exception ex) { _client.Notify(ex); return(BaseError.New(ex.ToString())); } }
private async Task <Either <BaseError, MediaItemScanResult <Artist> > > UpdateArtworkForArtist( MediaItemScanResult <Artist> result, string artistFolder, ArtworkKind artworkKind, CancellationToken cancellationToken) { try { Artist artist = result.Item; await LocateArtworkForArtist(artistFolder, artworkKind).IfSomeAsync( async artworkFile => { ArtistMetadata metadata = artist.ArtistMetadata.Head(); await RefreshArtwork(artworkFile, metadata, artworkKind, None, None, cancellationToken); }); return(result); } catch (Exception ex) { _client.Notify(ex); return(BaseError.New(ex.ToString())); } }
private static string Artwork(Metadata metadata, ArtworkKind artworkKind) => Optional(metadata.Artwork.FirstOrDefault(a => a.ArtworkKind == artworkKind)) .Match(a => a.Path, string.Empty);