using System.Net; using Flaro.Core.Metadata; using Microsoft.Extensions.Logging.Abstractions; namespace Flaro.Metadata.Tests; /// Plakate von fanart.tv — der Quelle, bei der die Sprache mitsteht. /// /// /// Der Anlass. „365 Tage" stand mit polnischem Plakat da. Nachgesehen: /// TMDB hat zu diesem Film 26 Plakate und kein einziges deutsches. Die /// Auswahl im TMDB-Client nimmt seither das sprachlose statt des polnischen /// — erfinden kann sie ein deutsches nicht. Genau dafür gibt es diese zweite /// Quelle. /// public class FanartTests { private static FanartClient Client(Attrappe attrappe, string? schluessel = "ein-schluessel") => new(new HttpClient(attrappe) { BaseAddress = new Uri(FanartClient.BaseAddress) }, new FesterFanartSchluessel(schluessel), NullLogger.Instance); private const string Antwort = """ {"name":"Probe","tmdb_id":"500", "movieposter":[ {"id":"1","url":"https://assets.fanart.tv/de.jpg","lang":"de","likes":"3"}, {"id":"2","url":"https://assets.fanart.tv/en.jpg","lang":"en","likes":"9"}, {"id":"3","url":"https://assets.fanart.tv/ohne.jpg","lang":"00","likes":"5"}], "moviebackground":[ {"id":"4","url":"https://assets.fanart.tv/hg.jpg","lang":"","likes":"2"}]} """; [Test] public async Task Ohne_Schluessel_geht_keine_Anfrage_hinaus() { var attrappe = Attrappe.MitJson(Antwort); var bilder = await Client(attrappe, schluessel: null).BilderAsync("500"); Assert.Multiple(() => { Assert.That(bilder, Is.Empty); Assert.That(attrappe.Aufrufe, Is.Empty, "fanart.tv verlangt einen persönlichen Schlüssel — ohne ihn wird nicht gefragt"); }); } [Test] public async Task Die_Plakate_kommen_mit_ihrer_Sprache() { var bilder = await Client(Attrappe.MitJson(Antwort)).BilderAsync("500"); var plakate = bilder.Where(b => b.Kind == "poster").ToList(); Assert.Multiple(() => { Assert.That(plakate, Has.Count.EqualTo(3)); Assert.That(plakate.Select(p => p.Language), Is.EquivalentTo(new[] { "de", "en", null })); Assert.That(plakate.All(p => p.Quelle == "fanart"), Is.True); }); } /// „00" ist bei fanart.tv die Schreibweise für „ohne Sprache". /// /// /// Sie durchzureichen hiesse, ein sprachloses Plakat als Sprache „00" zu /// führen — und die gemeinsame Rangfolge setzte es damit hinter Englisch /// statt davor. /// [Test] public async Task Die_Null_Null_wird_zu_sprachlos() { var bilder = await Client(Attrappe.MitJson(Antwort)).BilderAsync("500"); Assert.That(bilder.Any(b => b.Language == "00"), Is.False); } /// Zu den meisten Filmen hat fanart.tv nichts — das ist kein Fehler. [Test] public async Task Ein_unbekannter_Film_ergibt_eine_leere_Liste() { var bilder = await Client(Attrappe.MitStatus(HttpStatusCode.NotFound)).BilderAsync("500"); Assert.That(bilder, Is.Empty); } /// Eine hakende fremde Quelle darf keinen Scan anhalten. [Test] public async Task Kein_Netz_ergibt_nichts_statt_eines_Absturzes() { var bilder = await Client(Attrappe.DieWirft(new HttpRequestException("weg"))).BilderAsync("500"); Assert.That(bilder, Is.Empty); } [Test] public async Task Der_Schluessel_steht_in_der_Anfrage() { var attrappe = Attrappe.MitJson(Antwort); await Client(attrappe).BilderAsync("500"); Assert.That(attrappe.Aufrufe[0], Does.Contain("movies/500").And.Contain("api_key=ein-schluessel")); } /// Ein deutsches Plakat von fanart.tv sticht ein sprachloses von TMDB. /// /// /// Das ist der ganze Zweck der zweiten Quelle, und die Rangfolge dafür /// liegt im Kern — sie muss für beide Quellen dieselbe sein, sonst kämen /// die Bilder zweier Anbieter in zwei Reihenfolgen zusammen. /// [Test] public async Task Die_gemeinsame_Rangfolge_stellt_das_deutsche_nach_vorn() { var vonFanart = await Client(Attrappe.MitJson(Antwort)).BilderAsync("500"); var vonTmdb = new[] { new Bildkandidat("poster", "tmdb-ohne.jpg", "t", null, 9.5), new Bildkandidat("poster", "tmdb-en.jpg", "t", "en", 9.9), }; var geordnet = Bildrang .Geordnet(vonTmdb.Concat(vonFanart.Where(b => b.Kind == "poster")), "de") .ToList(); Assert.Multiple(() => { Assert.That(geordnet[0].Url, Does.EndWith("de.jpg")); Assert.That(geordnet[0].Quelle, Is.EqualTo("fanart")); Assert.That(geordnet[1].Url, Does.Contain("ohne"), "dann das sprachlose, egal von wem"); }); } } public sealed record FesterFanartSchluessel(string? Wert) : IFanartSettingsSource { public Task SchluesselAsync(CancellationToken ct = default) => Task.FromResult(Wert); }