using System.Net; using System.Text; using Jellyfin.Plugin.Multilang.Services.Providers; using Jellyfin.Plugin.Multilang.Services.Refresh; namespace Jellyfin.Plugin.Multilang.Tests; public sealed class ProviderClientTests { [Fact] public async Task TmdbMetadataParsesMovieFieldsAndDeduplicatesGenres() { var factory = JsonFactory(""" { "title": "Finnish title", "overview": "Overview", "tagline": "Tagline", "original_title": "Original title", "original_language": "fi", "origin_country": ["FI", "FI"], "production_countries": [{"iso_3166_1":"FI"}], "spoken_languages": [{"iso_639_1":"fi"}, {"iso_639_1":"en"}], "genres": [{"id": 18, "name": "Drama"}, {"id": 18, "name": "Duplicate"}] } """); var client = new TmdbClient(factory); var result = await client.FetchMetadataAsync(Movie(), "fi-FI", "key", new FetchRateLimiter(TimeSpan.Zero), CancellationToken.None); Assert.NotNull(result); Assert.Equal("Finnish title", result.Title); Assert.Equal("Original title", result.OriginalTitle); Assert.Equal("fi", result.OriginalLanguage); Assert.Equal(["FI"], result.OriginCountries); Assert.Equal(["fi", "en"], result.SpokenLanguages); Assert.Equal([18], result.GenreIds); Assert.Contains("language=fi-FI", factory.Requests.Single()); } [Fact] public async Task TmdbImagesKeepTheFirstImageForEachLanguage() { var factory = JsonFactory(""" { "posters": [ {"iso_639_1":"fi", "file_path":"/first.jpg"}, {"iso_639_1":"fi", "file_path":"/second.jpg"}, {"iso_639_1":null, "file_path":"/none.jpg"} ], "logos": [{"iso_639_1":"sv", "file_path":"/logo.png"}], "backdrops": [{"iso_639_1":"en", "file_path":"/backdrop.jpg"}] } """); var client = new TmdbClient(factory); var result = await client.FetchImagesAsync(Movie(), "key", new FetchRateLimiter(TimeSpan.Zero), CancellationToken.None); Assert.NotNull(result); Assert.Equal("https://image.tmdb.org/t/p/original/first.jpg", result.Posters["fi"]); Assert.Equal("https://image.tmdb.org/t/p/original/logo.png", result.Logos["sv"]); Assert.Equal("https://image.tmdb.org/t/p/original/backdrop.jpg", result.Backdrops["en"]); } [Fact] public async Task TmdbNotFoundReturnsNoMetadata() { var factory = new TestHttpClientFactory(_ => new HttpResponseMessage(HttpStatusCode.NotFound)); var client = new TmdbClient(factory); var result = await client.FetchMetadataAsync(Movie(), "en", "key", new FetchRateLimiter(TimeSpan.Zero), CancellationToken.None); Assert.Null(result); } [Fact] public async Task FanartSelectsMostLikedArtworkAndUsesStandardLogoAsFallback() { var factory = JsonFactory(""" { "movieposter": [ {"lang":"fi", "url":"https://images/fi-low.jpg", "likes":"2"}, {"lang":"fi", "url":"https://images/fi-best.jpg", "likes":"8"}, {"lang":"00", "url":"https://images/no-language.jpg", "likes":"99"} ], "hdmovielogo": [{"lang":"sv", "url":"https://images/hd-logo.png", "likes":1}], "movielogo": [ {"lang":"sv", "url":"https://images/standard-sv.png", "likes":9}, {"lang":"fi", "url":"https://images/standard-fi.png", "likes":3} ], "moviebanner": [{"lang":"fi", "url":"https://images/banner.jpg", "likes":0}], "moviethumb": [{"lang":"fi", "url":"https://images/thumb.jpg", "likes":0}] } """); var client = new FanartClient(factory); var result = await client.FetchMovieImagesAsync("123", "key", CancellationToken.None); Assert.NotNull(result); Assert.Equal("https://images/fi-best.jpg", result.Posters["fi"]); Assert.Equal("https://images/hd-logo.png", result.Logos["sv"]); Assert.Equal("https://images/standard-fi.png", result.Logos["fi"]); Assert.Equal("https://images/banner.jpg", result.Banners["fi"]); Assert.Equal("https://images/thumb.jpg", result.Thumbs["fi"]); } private static RefreshItemInfo Movie() => new("11111111111111111111111111111111", "123", "movie", RefreshWorkClass.Movies, 0, 0, null, "Movie"); private static TestHttpClientFactory JsonFactory(string json) => new(_ => new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(json, Encoding.UTF8, "application/json") }); }