diff --git a/StreamCinemaLib/API/Metadata.cs b/StreamCinemaLib/API/Metadata.cs index 2ef90ac..8f66d87 100644 --- a/StreamCinemaLib/API/Metadata.cs +++ b/StreamCinemaLib/API/Metadata.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Globalization; +using System.Net; using System.Net.Http.Json; using System.Text.Json; using System.Text.Json.Serialization; @@ -27,7 +28,7 @@ public class Metadata /// Maximum returned items count. /// Asynchronous cancellation. /// Response. - public static Task SearchAsync(string expression, ItemOrder order = ItemOrder.Descending, FilterSortBy sort = FilterSortBy.Score, ItemType type = ItemType.All, int offset = 0, int limit = 0, CancellationToken cancel = default) + public async static Task SearchAsync(string expression, ItemOrder order = ItemOrder.Descending, FilterSortBy sort = FilterSortBy.Score, ItemType type = ItemType.All, int offset = 0, int limit = 0, CancellationToken cancel = default) { if (expression == null) throw new ArgumentNullException(); @@ -39,7 +40,10 @@ public class Metadata UriBuilder uri = new UriBuilder(new Uri(ApiFilter, "search")); uri.Query = $"?access_token={AccessToken}&value={Uri.EscapeDataString(expression)}&order={ToString(order)}&sort={ToString(sort)}&type={ToString(type)}&from={offset.ToString()}&size={limit.ToString()}"; - return Program._http.GetFromJsonAsync(uri.Uri, CreateFilterJsonOptions(), cancel); + FilterResponse? result = await Program._http.GetFromJsonAsync(uri.Uri, CreateFilterJsonOptions(), cancel); + if (result != null) + result = FixFilterResponse(result); + return result; } /// @@ -49,7 +53,7 @@ public class Metadata /// Result ordering column. /// Asynchronous cancellation. /// Response. - public static Task ChildrenAsync(string parentId, FilterSortBy sort = FilterSortBy.Episode, CancellationToken cancel = default) + public async static Task ChildrenAsync(string parentId, FilterSortBy sort = FilterSortBy.Episode, CancellationToken cancel = default) { if (parentId == null) throw new ArgumentNullException(); @@ -57,7 +61,10 @@ public class Metadata UriBuilder uri = new UriBuilder(new Uri(ApiFilter, "parent")); uri.Query = $"?access_token={AccessToken}&value={parentId}&sort={ToString(sort)}&size={MaxPageLimit.ToString()}"; - return Program._http.GetFromJsonAsync(uri.Uri, CreateFilterJsonOptions(), cancel); + FilterResponse? result = await Program._http.GetFromJsonAsync(uri.Uri, CreateFilterJsonOptions(), cancel); + if (result != null) + result = FixFilterResponse(result); + return result; } /// @@ -85,14 +92,17 @@ public class Metadata /// Requested image height that may however get rounded or completely ignored. /// On success the thumbnail address. /// True if thumbnail url got calculated, false otherwise. - public static bool TryGetThumbnail(Uri imageUri, int suggestWidth, int suggestHeight, [NotNullWhen(true)] out Uri? thumbUri) { + public static bool TryGetThumbnail(Uri imageUri, int suggestWidth, int suggestHeight, [NotNullWhen(true)] out Uri? thumbUri) + { if (imageUri == null) throw new ArgumentNullException(); - - switch (imageUri.Host) { + + switch (imageUri.Host) + { case "image.tmdb.org": const string TmdbOrigPrefix = "/t/p/original/"; - if (imageUri.AbsolutePath.StartsWith(TmdbOrigPrefix)) { + if (imageUri.AbsolutePath.StartsWith(TmdbOrigPrefix)) + { UriBuilder ub = new UriBuilder(imageUri); ub.Path = "/t/p/w300_and_h450_bestv2/" + ub.Path.Substring(TmdbOrigPrefix.Length); thumbUri = ub.Uri; @@ -100,29 +110,69 @@ public class Metadata } break; - case "img.csfd.cz": - if (imageUri.AbsolutePath.StartsWith("/files/images/film/posters/")) { - // 140px, 280px, 420px - int w; - if (suggestWidth < 160) - w = 140; - else if (suggestWidth < 320) - w = 280; - else - w = 420; - UriBuilder ub = new UriBuilder(imageUri); - ub.Host = "image.pmgstatic.com"; - ub.Path = "/cache/resized/w" + w.ToString(CultureInfo.InvariantCulture) + ub.Path; - thumbUri = ub.Uri; - return true; - } - break; + case "img.csfd.cz": + if (imageUri.AbsolutePath.StartsWith("/files/images/film/posters/")) + { + // 140px, 280px, 420px + int w; + if (suggestWidth < 160) + w = 140; + else if (suggestWidth < 320) + w = 280; + else + w = 420; + UriBuilder ub = new UriBuilder(imageUri); + ub.Host = "image.pmgstatic.com"; + ub.Path = "/cache/resized/w" + w.ToString(CultureInfo.InvariantCulture) + ub.Path; + thumbUri = ub.Uri; + return true; + } + break; } thumbUri = null; return false; } + private static FilterResponse FixFilterResponse(FilterResponse res) + { + if (res == null) + throw new ArgumentNullException(); + + // Fix image URLs as they may miss the https scheme + if (res.hits != null && res.hits.hits != null) + foreach (MediaInfo i in res.hits.hits) + { + if (i._source == null) + continue; + + if (i._source.cast != null) + foreach (Cast j in i._source.cast) + j.thumbnail = FixImageUrl(j.thumbnail); + + if (i._source.i18n_info_labels != null) + foreach (InfoLabelI18n j in i._source.i18n_info_labels) { + if (j.art != null) { + j.art.poster = FixImageUrl(j.art.poster); + j.art.fanart = FixImageUrl(j.art.fanart); + } + } + } + + return res; + } + + private static string FixImageUrl(string url) + { + if (url != null && !url.StartsWith("http")) { + if (url.StartsWith("//")) + url = "https:" + url; + else + url = "https://" + url; + } + return url; + } + private static string ToString(ItemOrder value) { switch (value) @@ -171,7 +221,8 @@ public class Metadata } } - private static JsonSerializerOptions CreateFilterJsonOptions() { + private static JsonSerializerOptions CreateFilterJsonOptions() + { JsonSerializerOptions options = new JsonSerializerOptions(); options.Converters.Add(new CustomDateTimeConverter()); return options; diff --git a/StreamCinemaWeb/Layouts/BasicLayout.cs b/StreamCinemaWeb/Layouts/BasicLayout.cs index 777e137..bd137e2 100644 --- a/StreamCinemaWeb/Layouts/BasicLayout.cs +++ b/StreamCinemaWeb/Layouts/BasicLayout.cs @@ -41,9 +41,11 @@ public abstract class BasicLayout w.WriteLine("" + HttpUtility.HtmlEncode(title) + ""); w.WriteLine("