mirror of
https://github.com/lampame/lampac-ukraine.git
synced 2026-06-17 12:08:54 +00:00
Усі модулі тепер коректно передають об'єкт SubtitleTpl у шаблони Lampac, що дозволяє відображати субтитри в інтерфейсі плеєра.
This commit is contained in:
parent
ce58434c31
commit
04bb7d48b5
1
.gitignore
vendored
1
.gitignore
vendored
@ -17,3 +17,4 @@ obj
|
|||||||
.vscode/settings.json
|
.vscode/settings.json
|
||||||
.qwen
|
.qwen
|
||||||
log
|
log
|
||||||
|
.kilo
|
||||||
@ -4,6 +4,7 @@ using System.Threading.Tasks;
|
|||||||
using Shared;
|
using Shared;
|
||||||
using Shared.Models.Online.Settings;
|
using Shared.Models.Online.Settings;
|
||||||
using Shared.Models;
|
using Shared.Models;
|
||||||
|
using Shared.Models.Templates;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@ -14,6 +15,13 @@ using Shared.Engine;
|
|||||||
|
|
||||||
namespace LME.AnimeON
|
namespace LME.AnimeON
|
||||||
{
|
{
|
||||||
|
public class AshdiStream
|
||||||
|
{
|
||||||
|
public string Title { get; set; }
|
||||||
|
public string Link { get; set; }
|
||||||
|
public SubtitleTpl Subtitles { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public class AnimeONInvoke
|
public class AnimeONInvoke
|
||||||
{
|
{
|
||||||
private static readonly Regex Quality4kRegex = new Regex(@"(^|[^0-9])(2160p?)([^0-9]|$)|\b4k\b|\buhd\b", RegexOptions.IgnoreCase);
|
private static readonly Regex Quality4kRegex = new Regex(@"(^|[^0-9])(2160p?)([^0-9]|$)|\b4k\b|\buhd\b", RegexOptions.IgnoreCase);
|
||||||
@ -192,12 +200,12 @@ namespace LME.AnimeON
|
|||||||
public async Task<string> ParseAshdiPage(string url, bool disableAshdiMultivoiceForVod = false)
|
public async Task<string> ParseAshdiPage(string url, bool disableAshdiMultivoiceForVod = false)
|
||||||
{
|
{
|
||||||
var streams = await ParseAshdiPageStreams(url, disableAshdiMultivoiceForVod);
|
var streams = await ParseAshdiPageStreams(url, disableAshdiMultivoiceForVod);
|
||||||
return streams?.FirstOrDefault().link;
|
return streams?.FirstOrDefault()?.Link;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<(string title, string link)>> ParseAshdiPageStreams(string url, bool disableAshdiMultivoiceForVod = false)
|
public async Task<List<AshdiStream>> ParseAshdiPageStreams(string url, bool disableAshdiMultivoiceForVod = false)
|
||||||
{
|
{
|
||||||
var streams = new List<(string title, string link)>();
|
var streams = new List<AshdiStream>();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var headers = new List<HeadersModel>()
|
var headers = new List<HeadersModel>()
|
||||||
@ -234,7 +242,12 @@ namespace LME.AnimeON
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
string rawTitle = item.TryGetProperty("title", out var titleProp) ? titleProp.GetString() : null;
|
string rawTitle = item.TryGetProperty("title", out var titleProp) ? titleProp.GetString() : null;
|
||||||
streams.Add((BuildDisplayTitle(rawTitle, file, index), file));
|
streams.Add(new AshdiStream
|
||||||
|
{
|
||||||
|
Title = BuildDisplayTitle(rawTitle, file, index),
|
||||||
|
Link = file,
|
||||||
|
Subtitles = ApnHelper.ParseSubtitles(item.TryGetProperty("subtitle", out var subtitleProp) ? subtitleProp.GetString() : null)
|
||||||
|
});
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,7 +260,12 @@ namespace LME.AnimeON
|
|||||||
if (match.Success)
|
if (match.Success)
|
||||||
{
|
{
|
||||||
string file = match.Groups[1].Value;
|
string file = match.Groups[1].Value;
|
||||||
streams.Add((BuildDisplayTitle("Основне джерело", file, 1), file));
|
streams.Add(new AshdiStream
|
||||||
|
{
|
||||||
|
Title = BuildDisplayTitle("Основне джерело", file, 1),
|
||||||
|
Link = file,
|
||||||
|
Subtitles = ApnHelper.ParseSubtitles(ApnHelper.ExtractPlayerSubtitle(html))
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|||||||
@ -247,14 +247,17 @@ namespace LME.AnimeON.Controllers
|
|||||||
if (streamLink.Contains("ashdi.vip/vod", StringComparison.OrdinalIgnoreCase))
|
if (streamLink.Contains("ashdi.vip/vod", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var ashdiStreams = await invoke.ParseAshdiPageStreams(streamLink);
|
var ashdiStreams = await invoke.ParseAshdiPageStreams(streamLink);
|
||||||
if (ashdiStreams != null && ashdiStreams.Count > 0)
|
if (ashdiStreams != null && ashdiStreams.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var ashdiStream in ashdiStreams)
|
||||||
{
|
{
|
||||||
foreach (var ashdiStream in ashdiStreams)
|
string optionName = $"{translationName} {ashdiStream.Title}";
|
||||||
{
|
string subtitlesParam = ashdiStream.Subtitles != null ? $"&subtitles={HttpUtility.UrlEncode(JsonSerializer.Serialize(ashdiStream.Subtitles.ToObject()))}" : string.Empty;
|
||||||
string optionName = $"{translationName} {ashdiStream.title}";
|
string callUrl = $"{host}/lite/lme_animeon/play?url={HttpUtility.UrlEncode(ashdiStream.Link)}{subtitlesParam}";
|
||||||
string callUrl = $"{host}/lite/lme_animeon/play?url={HttpUtility.UrlEncode(ashdiStream.link)}";
|
movieTpl.Append(optionName, accsArgs(callUrl), "call");
|
||||||
tpl.Append(optionName, accsArgs(callUrl), "call");
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -375,7 +378,7 @@ namespace LME.AnimeON.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("lite/lme_animeon/play")]
|
[HttpGet("lite/lme_animeon/play")]
|
||||||
public async Task<ActionResult> Play(string url, int episode_id = 0, string title = null, int serial = 0)
|
public async Task<ActionResult> Play(string url, int episode_id = 0, string title = null, int serial = 0, string subtitles = null)
|
||||||
{
|
{
|
||||||
await UpdateService.ConnectAsync(host);
|
await UpdateService.ConnectAsync(host);
|
||||||
|
|
||||||
@ -421,10 +424,25 @@ namespace LME.AnimeON.Controllers
|
|||||||
forceProxy = true;
|
forceProxy = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SubtitleTpl subtitleTpl = null;
|
||||||
|
if (!string.IsNullOrEmpty(subtitles))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var subtitleDtos = JsonSerializer.Deserialize<List<SubtitleDto>>(subtitles);
|
||||||
|
if (subtitleDtos != null && subtitleDtos.Count > 0)
|
||||||
|
{
|
||||||
|
subtitleTpl = new SubtitleTpl(subtitleDtos.Count);
|
||||||
|
foreach (var sub in subtitleDtos)
|
||||||
|
subtitleTpl.Append(sub.label, sub.url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
string streamUrl = BuildStreamUrl(init, streamLink, streamHeaders, forceProxy);
|
string streamUrl = BuildStreamUrl(init, streamLink, streamHeaders, forceProxy);
|
||||||
string jsonResult = $"{{\"method\":\"play\",\"url\":\"{streamUrl}\",\"title\":\"{title ?? string.Empty}\"}}";
|
|
||||||
OnLog("AnimeON Play: return call JSON");
|
OnLog("AnimeON Play: return call JSON");
|
||||||
return UpdateService.Validate(Content(jsonResult, "application/json; charset=utf-8"));
|
return UpdateService.Validate(Content(VideoTpl.ToJson("play", streamUrl, title ?? string.Empty, subtitles: subtitleTpl), "application/json; charset=utf-8"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string StripLampacArgs(string url)
|
private static string StripLampacArgs(string url)
|
||||||
|
|||||||
@ -166,7 +166,7 @@ namespace LME.KlonFUN.Controllers
|
|||||||
: $"Серія {episode.Number}";
|
: $"Серія {episode.Number}";
|
||||||
|
|
||||||
string streamUrl = BuildStreamUrl(init, episode.Link);
|
string streamUrl = BuildStreamUrl(init, episode.Link);
|
||||||
episodeTpl.Append(episodeTitle, contentTitle, s.ToString(), episode.Number.ToString("D2"), streamUrl);
|
episodeTpl.Append(episodeTitle, contentTitle, s.ToString(), episode.Number.ToString("D2"), streamUrl, subtitles: episode.Subtitles);
|
||||||
}
|
}
|
||||||
|
|
||||||
episodeTpl.Append(voiceTpl);
|
episodeTpl.Append(voiceTpl);
|
||||||
@ -190,7 +190,7 @@ namespace LME.KlonFUN.Controllers
|
|||||||
: $"Варіант {i + 1}";
|
: $"Варіант {i + 1}";
|
||||||
|
|
||||||
string streamUrl = BuildStreamUrl(init, stream.Link);
|
string streamUrl = BuildStreamUrl(init, stream.Link);
|
||||||
movieTpl.Append(label, streamUrl);
|
movieTpl.Append(label, streamUrl, subtitles: stream.Subtitles);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rjson
|
return rjson
|
||||||
|
|||||||
@ -206,7 +206,8 @@ namespace LME.KlonFUN
|
|||||||
streams.Add(new MovieStream
|
streams.Add(new MovieStream
|
||||||
{
|
{
|
||||||
Title = voiceTitle,
|
Title = voiceTitle,
|
||||||
Link = link
|
Link = link,
|
||||||
|
Subtitles = ApnHelper.ParseSubtitles(item.Value<string>("subtitle"))
|
||||||
});
|
});
|
||||||
|
|
||||||
index++;
|
index++;
|
||||||
@ -221,7 +222,8 @@ namespace LME.KlonFUN
|
|||||||
streams.Add(new MovieStream
|
streams.Add(new MovieStream
|
||||||
{
|
{
|
||||||
Title = FormatMovieTitle("Основне джерело", directMatch.Groups["url"].Value, 1),
|
Title = FormatMovieTitle("Основне джерело", directMatch.Groups["url"].Value, 1),
|
||||||
Link = directMatch.Groups["url"].Value
|
Link = directMatch.Groups["url"].Value,
|
||||||
|
Subtitles = ApnHelper.ParseSubtitles(ApnHelper.ExtractPlayerSubtitle(playerHtml))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -310,7 +312,8 @@ namespace LME.KlonFUN
|
|||||||
{
|
{
|
||||||
Number = episodeNumber,
|
Number = episodeNumber,
|
||||||
Title = string.IsNullOrWhiteSpace(episodeTitle) ? $"Серія {episodeNumber}" : episodeTitle,
|
Title = string.IsNullOrWhiteSpace(episodeTitle) ? $"Серія {episodeNumber}" : episodeTitle,
|
||||||
Link = link
|
Link = link,
|
||||||
|
Subtitles = ApnHelper.ParseSubtitles(episodeObj.Value<string>("subtitle"))
|
||||||
});
|
});
|
||||||
|
|
||||||
episodeFallback++;
|
episodeFallback++;
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Shared.Models.Templates;
|
||||||
|
|
||||||
namespace LME.KlonFUN.Models
|
namespace LME.KlonFUN.Models
|
||||||
{
|
{
|
||||||
@ -47,6 +48,7 @@ namespace LME.KlonFUN.Models
|
|||||||
{
|
{
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
public string Link { get; set; }
|
public string Link { get; set; }
|
||||||
|
public SubtitleTpl Subtitles { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SerialEpisode
|
public class SerialEpisode
|
||||||
@ -54,6 +56,7 @@ namespace LME.KlonFUN.Models
|
|||||||
public int Number { get; set; }
|
public int Number { get; set; }
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
public string Link { get; set; }
|
public string Link { get; set; }
|
||||||
|
public SubtitleTpl Subtitles { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SerialVoice
|
public class SerialVoice
|
||||||
|
|||||||
@ -107,7 +107,7 @@ namespace LME.Makhno
|
|||||||
if (play)
|
if (play)
|
||||||
return UpdateService.Validate(Redirect(streamUrl));
|
return UpdateService.Validate(Redirect(streamUrl));
|
||||||
|
|
||||||
return UpdateService.Validate(Content(VideoTpl.ToJson("play", streamUrl, episodeTitle), "application/json; charset=utf-8"));
|
return UpdateService.Validate(Content(VideoTpl.ToJson("play", streamUrl, episodeTitle, subtitles: episode.Subtitles), "application/json; charset=utf-8"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +150,7 @@ namespace LME.Makhno
|
|||||||
if (play)
|
if (play)
|
||||||
return UpdateService.Validate(Redirect(streamUrl));
|
return UpdateService.Validate(Redirect(streamUrl));
|
||||||
|
|
||||||
return UpdateService.Validate(Content(VideoTpl.ToJson("play", streamUrl, title ?? original_title), "application/json; charset=utf-8"));
|
return UpdateService.Validate(Content(VideoTpl.ToJson("play", streamUrl, title ?? original_title, subtitles: playerData.Subtitles ?? playerData.Movies?.FirstOrDefault(m => m.File == playerData.File)?.Subtitles), "application/json; charset=utf-8"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<ActionResult> HandleMovie(string playUrl, string imdb_id, string title, string original_title, int year, bool rjson, MakhnoInvoke invoke)
|
private async Task<ActionResult> HandleMovie(string playUrl, string imdb_id, string title, string original_title, int year, bool rjson, MakhnoInvoke invoke)
|
||||||
@ -171,7 +171,8 @@ namespace LME.Makhno
|
|||||||
{
|
{
|
||||||
File = playerData.File,
|
File = playerData.File,
|
||||||
Title = "Основне джерело",
|
Title = "Основне джерело",
|
||||||
Quality = "auto"
|
Quality = "auto",
|
||||||
|
Subtitles = playerData.Subtitles
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,7 +190,7 @@ namespace LME.Makhno
|
|||||||
? stream.Title
|
? stream.Title
|
||||||
: $"Варіант {index}";
|
: $"Варіант {index}";
|
||||||
|
|
||||||
tpl.Append(label, BuildStreamUrl(init, stream.File));
|
tpl.Append(label, BuildStreamUrl(init, stream.File), subtitles: stream.Subtitles);
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,13 +391,15 @@ namespace LME.Makhno
|
|||||||
if (!string.IsNullOrEmpty(episode.File))
|
if (!string.IsNullOrEmpty(episode.File))
|
||||||
{
|
{
|
||||||
string streamUrl = BuildStreamUrl(init, episode.File);
|
string streamUrl = BuildStreamUrl(init, episode.File);
|
||||||
episode_tpl.Append(
|
episode_tpl.Append(
|
||||||
episode.Title,
|
episode.Title,
|
||||||
title ?? original_title,
|
title ?? original_title,
|
||||||
requestedSeason.ToString(),
|
requestedSeason.ToString(),
|
||||||
(i + 1).ToString("D2"),
|
(i + 1).ToString("D2"),
|
||||||
streamUrl
|
streamUrl,
|
||||||
);
|
subtitles: episode.Subtitles
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -114,18 +114,22 @@ namespace LME.Makhno
|
|||||||
{
|
{
|
||||||
string file = fileMatch.Groups[1].Value;
|
string file = fileMatch.Groups[1].Value;
|
||||||
var posterMatch = Regex.Match(html, @"poster:[""']([^""']+)[""']", RegexOptions.IgnoreCase);
|
var posterMatch = Regex.Match(html, @"poster:[""']([^""']+)[""']", RegexOptions.IgnoreCase);
|
||||||
|
var subtitles = ApnHelper.ParseSubtitles(ApnHelper.ExtractPlayerSubtitle(html));
|
||||||
|
|
||||||
return new PlayerData
|
return new PlayerData
|
||||||
{
|
{
|
||||||
File = file,
|
File = file,
|
||||||
Poster = posterMatch.Success ? posterMatch.Groups[1].Value : null,
|
Poster = posterMatch.Success ? posterMatch.Groups[1].Value : null,
|
||||||
Voices = new List<Voice>(),
|
Voices = new List<Voice>(),
|
||||||
|
Subtitles = subtitles,
|
||||||
Movies = new List<MovieVariant>()
|
Movies = new List<MovieVariant>()
|
||||||
{
|
{
|
||||||
new MovieVariant
|
new MovieVariant
|
||||||
{
|
{
|
||||||
File = file,
|
File = file,
|
||||||
Quality = DetectQualityTag(file) ?? "auto",
|
Quality = DetectQualityTag(file) ?? "auto",
|
||||||
Title = BuildMovieTitle("Основне джерело", file, 1)
|
Title = BuildMovieTitle("Основне джерело", file, 1),
|
||||||
|
Subtitles = subtitles
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -238,7 +242,8 @@ namespace LME.Makhno
|
|||||||
Title = episode["title"]?.ToString(),
|
Title = episode["title"]?.ToString(),
|
||||||
File = episode["file"]?.ToString(),
|
File = episode["file"]?.ToString(),
|
||||||
Poster = episode["poster"]?.ToString(),
|
Poster = episode["poster"]?.ToString(),
|
||||||
Subtitle = episode["subtitle"]?.ToString()
|
Subtitle = episode["subtitle"]?.ToString(),
|
||||||
|
Subtitles = ApnHelper.ParseSubtitles(episode["subtitle"]?.ToString())
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -289,7 +294,8 @@ namespace LME.Makhno
|
|||||||
{
|
{
|
||||||
File = file,
|
File = file,
|
||||||
Quality = DetectQualityTag($"{rawTitle} {file}") ?? "auto",
|
Quality = DetectQualityTag($"{rawTitle} {file}") ?? "auto",
|
||||||
Title = BuildMovieTitle(rawTitle, file, index)
|
Title = BuildMovieTitle(rawTitle, file, index),
|
||||||
|
Subtitles = ApnHelper.ParseSubtitles(item["subtitle"]?.ToString())
|
||||||
});
|
});
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Shared.Models.Templates;
|
||||||
|
|
||||||
namespace LME.Makhno.Models
|
namespace LME.Makhno.Models
|
||||||
{
|
{
|
||||||
@ -9,6 +10,7 @@ namespace LME.Makhno.Models
|
|||||||
public List<Voice> Voices { get; set; }
|
public List<Voice> Voices { get; set; }
|
||||||
public List<Season> Seasons { get; set; }
|
public List<Season> Seasons { get; set; }
|
||||||
public List<MovieVariant> Movies { get; set; }
|
public List<MovieVariant> Movies { get; set; }
|
||||||
|
public SubtitleTpl Subtitles { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Voice
|
public class Voice
|
||||||
@ -30,6 +32,7 @@ namespace LME.Makhno.Models
|
|||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
public string Poster { get; set; }
|
public string Poster { get; set; }
|
||||||
public string Subtitle { get; set; }
|
public string Subtitle { get; set; }
|
||||||
|
public SubtitleTpl Subtitles { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MovieVariant
|
public class MovieVariant
|
||||||
@ -37,5 +40,6 @@ namespace LME.Makhno.Models
|
|||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
public string File { get; set; }
|
public string File { get; set; }
|
||||||
public string Quality { get; set; }
|
public string Quality { get; set; }
|
||||||
|
public SubtitleTpl Subtitles { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
@ -177,10 +178,13 @@ namespace LME.Mikai.Controllers
|
|||||||
{
|
{
|
||||||
foreach (var ashdiStream in ashdiStreams)
|
foreach (var ashdiStream in ashdiStreams)
|
||||||
{
|
{
|
||||||
string optionName = $"{voice.DisplayName} {ashdiStream.title}";
|
string optionName = $"{voice.DisplayName} {ashdiStream.Title}";
|
||||||
string ashdiCallUrl = $"{host}/lite/lme_mikai/play?url={HttpUtility.UrlEncode(ashdiStream.link)}&title={HttpUtility.UrlEncode(displayTitle)}";
|
string subtitlesParam = ashdiStream.Subtitles != null ? $"&subtitles={HttpUtility.UrlEncode(JsonSerializer.Serialize(ashdiStream.Subtitles.ToObject()))}" : string.Empty;
|
||||||
|
string ashdiCallUrl = $"{host}/lite/lme_mikai/play?url={HttpUtility.UrlEncode(ashdiStream.Link)}&title={HttpUtility.UrlEncode(displayTitle)}{subtitlesParam}";
|
||||||
movieTpl.Append(optionName, accsArgs(ashdiCallUrl), "call");
|
movieTpl.Append(optionName, accsArgs(ashdiCallUrl), "call");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -204,7 +208,7 @@ namespace LME.Mikai.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("lite/lme_mikai/play")]
|
[HttpGet("lite/lme_mikai/play")]
|
||||||
public async Task<ActionResult> Play(string url, string title = null, int serial = 0)
|
public async Task<ActionResult> Play(string url, string title = null, int serial = 0, string subtitles = null)
|
||||||
{
|
{
|
||||||
await UpdateService.ConnectAsync(host);
|
await UpdateService.ConnectAsync(host);
|
||||||
|
|
||||||
@ -235,9 +239,24 @@ namespace LME.Mikai.Controllers
|
|||||||
forceProxy = true;
|
forceProxy = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SubtitleTpl subtitleTpl = null;
|
||||||
|
if (!string.IsNullOrEmpty(subtitles))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var subtitleDtos = JsonSerializer.Deserialize<List<SubtitleDto>>(subtitles);
|
||||||
|
if (subtitleDtos != null && subtitleDtos.Count > 0)
|
||||||
|
{
|
||||||
|
subtitleTpl = new SubtitleTpl(subtitleDtos.Count);
|
||||||
|
foreach (var sub in subtitleDtos)
|
||||||
|
subtitleTpl.Append(sub.label, sub.url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
string streamUrl = BuildStreamUrl(init, streamLink, streamHeaders, forceProxy);
|
string streamUrl = BuildStreamUrl(init, streamLink, streamHeaders, forceProxy);
|
||||||
string jsonResult = $"{{\"method\":\"play\",\"url\":\"{streamUrl}\",\"title\":\"{title ?? string.Empty}\"}}";
|
return UpdateService.Validate(Content(VideoTpl.ToJson("play", streamUrl, title ?? string.Empty, subtitles: subtitleTpl), "application/json; charset=utf-8"));
|
||||||
return UpdateService.Validate(Content(jsonResult, "application/json; charset=utf-8"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<List<MikaiAnime>> CollectSeasonDetails(MikaiAnime details, MikaiInvoke invoke)
|
private async Task<List<MikaiAnime>> CollectSeasonDetails(MikaiAnime details, MikaiInvoke invoke)
|
||||||
|
|||||||
@ -11,9 +11,17 @@ using Shared;
|
|||||||
using Shared.Engine;
|
using Shared.Engine;
|
||||||
using Shared.Models;
|
using Shared.Models;
|
||||||
using Shared.Models.Online.Settings;
|
using Shared.Models.Online.Settings;
|
||||||
|
using Shared.Models.Templates;
|
||||||
|
|
||||||
namespace LME.Mikai
|
namespace LME.Mikai
|
||||||
{
|
{
|
||||||
|
public class AshdiStream
|
||||||
|
{
|
||||||
|
public string Title { get; set; }
|
||||||
|
public string Link { get; set; }
|
||||||
|
public SubtitleTpl Subtitles { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public class MikaiInvoke
|
public class MikaiInvoke
|
||||||
{
|
{
|
||||||
private static readonly Regex Quality4kRegex = new Regex(@"(^|[^0-9])(2160p?)([^0-9]|$)|\b4k\b|\buhd\b", RegexOptions.IgnoreCase);
|
private static readonly Regex Quality4kRegex = new Regex(@"(^|[^0-9])(2160p?)([^0-9]|$)|\b4k\b|\buhd\b", RegexOptions.IgnoreCase);
|
||||||
@ -176,12 +184,12 @@ namespace LME.Mikai
|
|||||||
public async Task<string> ParseAshdiPage(string url, bool disableAshdiMultivoiceForVod = false)
|
public async Task<string> ParseAshdiPage(string url, bool disableAshdiMultivoiceForVod = false)
|
||||||
{
|
{
|
||||||
var streams = await ParseAshdiPageStreams(url, disableAshdiMultivoiceForVod);
|
var streams = await ParseAshdiPageStreams(url, disableAshdiMultivoiceForVod);
|
||||||
return streams?.FirstOrDefault().link;
|
return streams?.FirstOrDefault()?.Link;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<(string title, string link)>> ParseAshdiPageStreams(string url, bool disableAshdiMultivoiceForVod = false)
|
public async Task<List<AshdiStream>> ParseAshdiPageStreams(string url, bool disableAshdiMultivoiceForVod = false)
|
||||||
{
|
{
|
||||||
var streams = new List<(string title, string link)>();
|
var streams = new List<AshdiStream>();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var headers = new List<HeadersModel>()
|
var headers = new List<HeadersModel>()
|
||||||
@ -218,7 +226,12 @@ namespace LME.Mikai
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
string rawTitle = item.TryGetProperty("title", out var titleProp) ? titleProp.GetString() : null;
|
string rawTitle = item.TryGetProperty("title", out var titleProp) ? titleProp.GetString() : null;
|
||||||
streams.Add((BuildDisplayTitle(rawTitle, file, index), file));
|
streams.Add(new AshdiStream
|
||||||
|
{
|
||||||
|
Title = BuildDisplayTitle(rawTitle, file, index),
|
||||||
|
Link = file,
|
||||||
|
Subtitles = ApnHelper.ParseSubtitles(item.TryGetProperty("subtitle", out var subtitleProp) ? subtitleProp.GetString() : null)
|
||||||
|
});
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,7 +244,12 @@ namespace LME.Mikai
|
|||||||
if (match.Success)
|
if (match.Success)
|
||||||
{
|
{
|
||||||
string file = match.Groups[1].Value;
|
string file = match.Groups[1].Value;
|
||||||
streams.Add((BuildDisplayTitle("Основне джерело", file, 1), file));
|
streams.Add(new AshdiStream
|
||||||
|
{
|
||||||
|
Title = BuildDisplayTitle("Основне джерело", file, 1),
|
||||||
|
Link = file,
|
||||||
|
Subtitles = ApnHelper.ParseSubtitles(ApnHelper.ExtractPlayerSubtitle(html))
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using Shared.Models.Base;
|
using Shared.Models.Base;
|
||||||
|
using Shared.Models.Templates;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
|
|
||||||
namespace Shared.Engine
|
namespace Shared.Engine
|
||||||
@ -9,6 +12,8 @@ namespace Shared.Engine
|
|||||||
{
|
{
|
||||||
public const string DefaultHost = "https://tut.im/proxy.php?url={encodeurl}";
|
public const string DefaultHost = "https://tut.im/proxy.php?url={encodeurl}";
|
||||||
|
|
||||||
|
private static readonly Regex SubtitleLineRegex = new Regex(@"\[([^\]]+)\]([^,]+)", RegexOptions.Compiled);
|
||||||
|
|
||||||
public static bool TryGetInitConf(JObject conf, out bool enabled, out string host)
|
public static bool TryGetInitConf(JObject conf, out bool enabled, out string host)
|
||||||
{
|
{
|
||||||
enabled = false;
|
enabled = false;
|
||||||
@ -120,6 +125,40 @@ namespace Shared.Engine
|
|||||||
return $"{host.TrimEnd('/')}/{url}";
|
return $"{host.TrimEnd('/')}/{url}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static SubtitleTpl ParseSubtitles(string subtitleValue)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(subtitleValue))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var subtitles = new SubtitleTpl();
|
||||||
|
string normalized = WebUtility.HtmlDecode(subtitleValue)
|
||||||
|
.Replace("\\/", "/")
|
||||||
|
.Replace("\\'", "'")
|
||||||
|
.Replace("\\\"", "\"");
|
||||||
|
|
||||||
|
foreach (Match match in SubtitleLineRegex.Matches(normalized))
|
||||||
|
{
|
||||||
|
string label = WebUtility.HtmlDecode(match.Groups[1].Value).Trim();
|
||||||
|
string url = WebUtility.HtmlDecode(match.Groups[2].Value).Trim();
|
||||||
|
if (!string.IsNullOrWhiteSpace(label) && !string.IsNullOrWhiteSpace(url))
|
||||||
|
subtitles.Append(label, url);
|
||||||
|
}
|
||||||
|
|
||||||
|
return subtitles.IsEmpty ? null : subtitles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ExtractPlayerSubtitle(string html)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(html))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var match = Regex.Match(html, @"subtitle\s*:\s*['""]([^'""']+)['""]", RegexOptions.IgnoreCase);
|
||||||
|
if (!match.Success)
|
||||||
|
match = Regex.Match(html, @"subtitle['""]?\s*:\s*['""]([^'""']+)['""]", RegexOptions.IgnoreCase);
|
||||||
|
|
||||||
|
return match.Success ? match.Groups[1].Value : null;
|
||||||
|
}
|
||||||
|
|
||||||
private static string NormalizeHost(string host)
|
private static string NormalizeHost(string host)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(host))
|
if (string.IsNullOrWhiteSpace(host))
|
||||||
|
|||||||
@ -104,9 +104,10 @@ namespace LME.Uaflix.Controllers
|
|||||||
{
|
{
|
||||||
// Повертаємо JSON з інформацією про стрім для методу 'play'
|
// Повертаємо JSON з інформацією про стрім для методу 'play'
|
||||||
string streamUrl = BuildStreamUrl(init, playResult.streams.First().link);
|
string streamUrl = BuildStreamUrl(init, playResult.streams.First().link);
|
||||||
string jsonResult = $"{{\"method\":\"play\",\"url\":\"{streamUrl}\",\"title\":\"{title ?? original_title}\"}}";
|
var subtitles = playResult.subtitles ?? playResult.streams.FirstOrDefault(s => s.subtitles != null)?.subtitles;
|
||||||
|
|
||||||
OnLog($"=== RETURN: call method JSON for episode_url ===");
|
OnLog($"=== RETURN: call method JSON for episode_url ===");
|
||||||
return UpdateService.Validate(Content(jsonResult, "application/json; charset=utf-8"));
|
return UpdateService.Validate(Content(VideoTpl.ToJson("play", streamUrl, title ?? original_title, subtitles: subtitles), "application/json; charset=utf-8"));
|
||||||
}
|
}
|
||||||
|
|
||||||
OnLog("=== RETURN: call method no streams ===");
|
OnLog("=== RETURN: call method no streams ===");
|
||||||
@ -284,7 +285,8 @@ namespace LME.Uaflix.Controllers
|
|||||||
e: ep.Number.ToString(),
|
e: ep.Number.ToString(),
|
||||||
link: accsArgs(callUrl),
|
link: accsArgs(callUrl),
|
||||||
method: "call",
|
method: "call",
|
||||||
streamlink: accsArgs($"{callUrl}&play=true")
|
streamlink: accsArgs($"{callUrl}&play=true"),
|
||||||
|
subtitles: ApnHelper.ParseSubtitles(ep.Subtitle)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -296,7 +298,8 @@ namespace LME.Uaflix.Controllers
|
|||||||
title: title,
|
title: title,
|
||||||
s: s.ToString(),
|
s: s.ToString(),
|
||||||
e: ep.Number.ToString(),
|
e: ep.Number.ToString(),
|
||||||
link: playUrl
|
link: playUrl,
|
||||||
|
subtitles: ApnHelper.ParseSubtitles(ep.Subtitle)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,7 +354,7 @@ namespace LME.Uaflix.Controllers
|
|||||||
? stream.title
|
? stream.title
|
||||||
: $"Варіант {index}";
|
: $"Варіант {index}";
|
||||||
|
|
||||||
tpl.Append(label, BuildStreamUrl(init, stream.link));
|
tpl.Append(label, BuildStreamUrl(init, stream.link), subtitles: stream.subtitles ?? playResult.subtitles);
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -15,5 +15,6 @@ namespace LME.Uaflix.Models
|
|||||||
public string link { get; set; }
|
public string link { get; set; }
|
||||||
public string quality { get; set; }
|
public string quality { get; set; }
|
||||||
public string title { get; set; }
|
public string title { get; set; }
|
||||||
|
public SubtitleTpl? subtitles { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -582,7 +582,8 @@ namespace LME.Uaflix
|
|||||||
{
|
{
|
||||||
link = fileUrl,
|
link = fileUrl,
|
||||||
quality = DetectQualityTag($"{rawTitle} {fileUrl}") ?? "auto",
|
quality = DetectQualityTag($"{rawTitle} {fileUrl}") ?? "auto",
|
||||||
title = BuildDisplayTitle(rawTitle, fileUrl, index)
|
title = BuildDisplayTitle(rawTitle, fileUrl, index),
|
||||||
|
subtitles = ApnHelper.ParseSubtitles(item?["subtitle"]?.ToString())
|
||||||
});
|
});
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
@ -605,7 +606,8 @@ namespace LME.Uaflix
|
|||||||
{
|
{
|
||||||
link = fallbackFile,
|
link = fallbackFile,
|
||||||
quality = DetectQualityTag(fallbackFile) ?? "auto",
|
quality = DetectQualityTag(fallbackFile) ?? "auto",
|
||||||
title = BuildDisplayTitle(ExtractVoiceFromUrl(fallbackFile), fallbackFile, 1)
|
title = BuildDisplayTitle(ExtractVoiceFromUrl(fallbackFile), fallbackFile, 1),
|
||||||
|
subtitles = ApnHelper.ParseSubtitles(ApnHelper.ExtractPlayerSubtitle(html))
|
||||||
});
|
});
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -2050,19 +2052,7 @@ namespace LME.Uaflix
|
|||||||
string url = $"https://ashdi.vip/vod/{id}";
|
string url = $"https://ashdi.vip/vod/{id}";
|
||||||
var html = await GetHtml(AshdiRequestUrl(url), new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", "https://ashdi.vip/") });
|
var html = await GetHtml(AshdiRequestUrl(url), new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", "https://ashdi.vip/") });
|
||||||
string subtitle = new Regex("subtitle(\")?:\"([^\"]+)\"").Match(html).Groups[2].Value;
|
string subtitle = new Regex("subtitle(\")?:\"([^\"]+)\"").Match(html).Groups[2].Value;
|
||||||
if (!string.IsNullOrEmpty(subtitle))
|
return ApnHelper.ParseSubtitles(subtitle);
|
||||||
{
|
|
||||||
var match = new Regex("\\[([^\\]]+)\\](https?://[^\\,]+)").Match(subtitle);
|
|
||||||
var st = new Shared.Models.Templates.SubtitleTpl();
|
|
||||||
while (match.Success)
|
|
||||||
{
|
|
||||||
st.Append(match.Groups[1].Value, match.Groups[2].Value);
|
|
||||||
match = match.NextMatch();
|
|
||||||
}
|
|
||||||
if (st.data != null && st.data.Count > 0)
|
|
||||||
return st;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string WithAshdiMultivoice(string url)
|
private static string WithAshdiMultivoice(string url)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user