diff --git a/LME.UAKino/Controller.cs b/LME.UAKino/Controller.cs index ef65682..0315d5d 100644 --- a/LME.UAKino/Controller.cs +++ b/LME.UAKino/Controller.cs @@ -118,10 +118,14 @@ namespace LME.UAKino.Controllers } else { - string resolvedUrl = await invoke.ResolveAshdiVod(fallbackUrl); - string streamUrl = BuildStreamUrl(init, resolvedUrl); - var movie_tpl = new MovieTpl(title, original_title); - movie_tpl.Append("Фільм", streamUrl); + var resolvedStreams = await invoke.ResolveAshdiVodAll(fallbackUrl); + var movie_tpl = new MovieTpl(title, original_title, resolvedStreams.Count); + foreach (var (file, label) in resolvedStreams) + { + string displayLabel = !string.IsNullOrEmpty(label) ? label : "Фільм"; + string streamUrl = BuildStreamUrl(init, file); + movie_tpl.Append(displayLabel, streamUrl); + } return rjson ? Content(movie_tpl.ToJson(), "application/json; charset=utf-8") : Content(movie_tpl.ToHtml(), "text/html; charset=utf-8"); diff --git a/LME.UAKino/UAKinoInvoke.cs b/LME.UAKino/UAKinoInvoke.cs index 24ce2c6..f334078 100644 --- a/LME.UAKino/UAKinoInvoke.cs +++ b/LME.UAKino/UAKinoInvoke.cs @@ -270,6 +270,78 @@ namespace LME.UAKino } } + /// + /// Резолв Ashdi VOD з ?multivoice: повертає ВСІ стріми з JSON масиву + /// + public async Task> ResolveAshdiVodAll(string vodUrl) + { + var result = new List<(string file, string title)>(); + + if (string.IsNullOrEmpty(vodUrl) || !ApnHelper.IsAshdiUrl(vodUrl)) + { + if (!string.IsNullOrEmpty(vodUrl)) + result.Add((vodUrl, null)); + return result; + } + + try + { + _onLog?.Invoke($"UAKino resolve Ashdi all: {vodUrl}"); + + var headers = new List() + { + new HeadersModel("User-Agent", Http.UserAgent), + new HeadersModel("Referer", "https://ashdi.vip/") + }; + + string fetchUrl = vodUrl; + if (ApnHelper.IsEnabled(_init) && string.IsNullOrWhiteSpace(_init.webcorshost)) + fetchUrl = ApnHelper.WrapUrl(_init, fetchUrl); + + string html = await HttpGet(fetchUrl, headers); + if (string.IsNullOrEmpty(html)) + { + result.Add((vodUrl, null)); + return result; + } + + int arrayStart = FindAshdiJsonArray(html); + if (arrayStart >= 0) + { + string jsonArray = ExtractBalancedBrackets(html, arrayStart); + if (!string.IsNullOrEmpty(jsonArray)) + { + try + { + using var arr = JsonDocument.Parse(jsonArray); + if (arr.RootElement.ValueKind == JsonValueKind.Array) + { + foreach (var item in arr.RootElement.EnumerateArray()) + { + string file = item.GetProperty("file").GetString(); + string title = item.TryGetProperty("title", out var t) ? t.GetString() : null; + if (!string.IsNullOrEmpty(file)) + result.Add((file, title?.Trim())); + } + } + } + catch { } + } + } + + if (result.Count == 0) + result.Add((vodUrl, null)); + + return result; + } + catch (Exception ex) + { + _onLog?.Invoke($"UAKino resolve Ashdi all error: {ex.Message}"); + result.Add((vodUrl, null)); + return result; + } + } + /// /// Знайти позицію JSON масиву `[{...}]` після `file:'` ///