From 257d3445a1f022c8d1b43e9c1de195f2974743dd Mon Sep 17 00:00:00 2001 From: baliasnyifeliks Date: Tue, 13 Jan 2026 14:53:06 +0200 Subject: [PATCH] feat(season): implement dynamic season number extraction and episode loading - Add GetSeasonNumber method to extract season numbers from titles - Implement LoadMissingSeasonEpisodes to fetch episodes for seasons without them - Refactor season handling to use AddSeason method for consistency - Improve episode template generation with proper season numbering --- StarLight/Controller.cs | 15 ++++++- StarLight/StarLightInvoke.cs | 77 +++++++++++++++++++++++++++++++++++- 2 files changed, 89 insertions(+), 3 deletions(-) diff --git a/StarLight/Controller.cs b/StarLight/Controller.cs index 7e1ce59..71ce4bc 100644 --- a/StarLight/Controller.cs +++ b/StarLight/Controller.cs @@ -75,13 +75,15 @@ namespace StarLight.Controllers if (s < 0 || s >= project.Seasons.Count) return OnError("starlight", proxyManager); - string seasonSlug = project.Seasons[s].Slug; + var season = project.Seasons[s]; + string seasonSlug = season.Slug; var episodes = invoke.GetEpisodes(project, seasonSlug); if (episodes == null || episodes.Count == 0) return OnError("starlight", proxyManager); var episode_tpl = new EpisodeTpl(); int index = 1; + string seasonNumber = GetSeasonNumber(season, s); foreach (var ep in episodes) { if (string.IsNullOrEmpty(ep.Hash)) @@ -89,7 +91,7 @@ namespace StarLight.Controllers string episodeName = string.IsNullOrEmpty(ep.Title) ? $"Епізод {index}" : ep.Title; string callUrl = $"{host}/starlight/play?hash={HttpUtility.UrlEncode(ep.Hash)}&title={HttpUtility.UrlEncode(title ?? original_title)}"; - episode_tpl.Append(episodeName, title ?? original_title, (s + 1).ToString(), index.ToString("D2"), accsArgs(callUrl), "call"); + episode_tpl.Append(episodeName, title ?? original_title, seasonNumber, index.ToString("D2"), accsArgs(callUrl), "call"); index++; } @@ -132,5 +134,14 @@ namespace StarLight.Controllers string jsonResult = $"{{\"method\":\"play\",\"url\":\"{streamUrl}\",\"title\":\"{title ?? result.Name ?? ""}\"}}"; return Content(jsonResult, "application/json; charset=utf-8"); } + + private static string GetSeasonNumber(SeasonInfo season, int fallbackIndex) + { + if (season?.Title == null) + return (fallbackIndex + 1).ToString(); + + var digits = new string(season.Title.Where(char.IsDigit).ToArray()); + return string.IsNullOrEmpty(digits) ? (fallbackIndex + 1).ToString() : digits; + } } } diff --git a/StarLight/StarLightInvoke.cs b/StarLight/StarLightInvoke.cs index 771d853..82c1a91 100644 --- a/StarLight/StarLightInvoke.cs +++ b/StarLight/StarLightInvoke.cs @@ -125,13 +125,23 @@ namespace StarLight Channel = root.TryGetProperty("channelTitle", out var channelProp) ? channelProp.GetString() : null }; + if (root.TryGetProperty("seasons", out var seasonsListProp) && seasonsListProp.ValueKind == JsonValueKind.Array) + { + foreach (var season in seasonsListProp.EnumerateArray()) + { + string seasonTitle = season.TryGetProperty("title", out var sTitle) ? sTitle.GetString() : null; + string seasonSlug = season.TryGetProperty("seasonSlug", out var sSlug) ? sSlug.GetString() : null; + AddSeason(project, seasonTitle, seasonSlug); + } + } + if (root.TryGetProperty("seasonsGallery", out var seasonsProp) && seasonsProp.ValueKind == JsonValueKind.Array) { foreach (var season in seasonsProp.EnumerateArray()) { string seasonTitle = season.TryGetProperty("title", out var sTitle) ? sTitle.GetString() : null; string seasonSlug = season.TryGetProperty("seasonSlug", out var sSlug) ? sSlug.GetString() : null; - project.Seasons.Add(new SeasonInfo { Title = seasonTitle, Slug = seasonSlug }); + AddSeason(project, seasonTitle, seasonSlug); if (season.TryGetProperty("items", out var itemsProp) && itemsProp.ValueKind == JsonValueKind.Array) { @@ -150,6 +160,8 @@ namespace StarLight } } + await LoadMissingSeasonEpisodes(project, href, headers); + _hybridCache.Set(memKey, project, cacheTime(10, init: _init)); return project; } @@ -160,6 +172,69 @@ namespace StarLight } } + private async Task LoadMissingSeasonEpisodes(ProjectInfo project, string href, List headers) + { + if (project == null || string.IsNullOrEmpty(href)) + return; + + var missing = project.Seasons + .Where(s => !string.IsNullOrEmpty(s.Slug)) + .Where(s => !project.Episodes.Any(e => e.SeasonSlug == s.Slug)) + .ToList(); + + foreach (var season in missing) + { + string seasonUrl = $"{href}/{season.Slug}"; + try + { + _onLog?.Invoke($"StarLight season: {seasonUrl}"); + string payload = await Http.Get(seasonUrl, headers: headers, proxy: _proxyManager.Get()); + if (string.IsNullOrEmpty(payload)) + continue; + + using var document = JsonDocument.Parse(payload); + var root = document.RootElement; + + if (root.TryGetProperty("items", out var itemsProp) && itemsProp.ValueKind == JsonValueKind.Array) + { + foreach (var item in itemsProp.EnumerateArray()) + { + string hash = item.TryGetProperty("hash", out var eHash) ? eHash.GetString() : null; + if (string.IsNullOrEmpty(hash)) + continue; + + if (project.Episodes.Any(e => e.SeasonSlug == season.Slug && e.Hash == hash)) + continue; + + project.Episodes.Add(new EpisodeInfo + { + Title = item.TryGetProperty("title", out var eTitle) ? eTitle.GetString() : null, + Hash = hash, + VideoSlug = item.TryGetProperty("videoSlug", out var eSlug) ? eSlug.GetString() : null, + Date = item.TryGetProperty("dateOfBroadcast", out var eDate) ? eDate.GetString() : (item.TryGetProperty("timeUploadVideo", out var eDate2) ? eDate2.GetString() : null), + SeasonSlug = season.Slug + }); + } + } + } + catch (Exception ex) + { + _onLog?.Invoke($"StarLight season error: {ex.Message}"); + } + } + } + + private static void AddSeason(ProjectInfo project, string title, string slug) + { + if (project == null || string.IsNullOrEmpty(slug)) + return; + + if (project.Seasons.Any(s => s.Slug == slug)) + return; + + project.Seasons.Add(new SeasonInfo { Title = title, Slug = slug }); + } + public List GetEpisodes(ProjectInfo project, string seasonSlug) { if (project == null || project.Seasons.Count == 0)