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
This commit is contained in:
baliasnyifeliks 2026-01-13 14:53:06 +02:00
parent cd67ea1639
commit 257d3445a1
2 changed files with 89 additions and 3 deletions

View File

@ -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;
}
}
}

View File

@ -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<HeadersModel> 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<EpisodeInfo> GetEpisodes(ProjectInfo project, string seasonSlug)
{
if (project == null || project.Seasons.Count == 0)