feat: resolve AniList episodes through ZokoAnime
This commit is contained in:
@@ -563,7 +563,7 @@ struct Player {
|
||||
status = PLAYER_OPENING;
|
||||
publish();
|
||||
if (network) {
|
||||
const bool resolved = command.mediaURL.starts_with("miruro:");
|
||||
const bool resolved = command.mediaURL.starts_with("miruro:") || command.mediaURL.starts_with("anilist:");
|
||||
auto *primary = openNetworkInput(0, command.path, command.videoHeaders, command.live, resolved);
|
||||
format = primary->format;
|
||||
openTrack(1, format, primary, AVMEDIA_TYPE_VIDEO, -1);
|
||||
|
||||
@@ -60,7 +60,7 @@ typedef struct PlayerNetworkSource {
|
||||
double duration;
|
||||
bool is_live;
|
||||
// Original HTTP(S) video URL (canonical for YouTube), or stable
|
||||
// miruro:<base64url media_id>:<positive episode> identity, never an extracted CDN URL.
|
||||
// miruro:<opaque media_id>:<episode> or anilist:<decimal ID>:<episode> identity, never an extracted CDN URL.
|
||||
// NULL/empty means no reporting for this source.
|
||||
const char *media_url;
|
||||
// Initial restored position, applied before publishing ready state. Zero
|
||||
|
||||
@@ -93,12 +93,20 @@ bool ProgressReporter::validMediaURL(std::string_view url) noexcept {
|
||||
|
||||
bool ProgressReporter::validMediaIdentity(std::string_view identity) noexcept {
|
||||
if (validMediaURL(identity)) return true;
|
||||
constexpr std::string_view prefix = "miruro:";
|
||||
if (identity.substr(0, prefix.size()) != prefix) return false;
|
||||
const bool anilist = identity.starts_with("anilist:");
|
||||
const std::string_view prefix = anilist ? "anilist:" : "miruro:";
|
||||
if (!identity.starts_with(prefix)) return false;
|
||||
const auto separator = identity.find(':', prefix.size());
|
||||
if (separator == std::string_view::npos) return false;
|
||||
const auto id = identity.substr(prefix.size(), separator - prefix.size());
|
||||
if (id.empty() || id.size() > 512) return false;
|
||||
if (anilist) {
|
||||
if (id.front() < '1' || id.front() > '9') return false;
|
||||
for (char c : id) if (c < '0' || c > '9') return false;
|
||||
int value = 0;
|
||||
const auto parsed = std::from_chars(id.data(), id.data() + id.size(), value);
|
||||
if (parsed.ec != std::errc{} || parsed.ptr != id.data() + id.size() || value <= 0) return false;
|
||||
}
|
||||
for (char c : id) {
|
||||
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
|
||||
(c >= '0' && c <= '9') || c == '-' || c == '_')) return false;
|
||||
@@ -186,13 +194,17 @@ bool ProgressReporter::emit(const char *event) noexcept {
|
||||
try {
|
||||
std::string record;
|
||||
record.reserve(256);
|
||||
const bool miruro = mediaURL.compare(0, 7, "miruro:") == 0;
|
||||
record += miruro ? "{\"version\":2,\"event\":\"" : "{\"version\":1,\"event\":\"";
|
||||
const bool anilist = mediaURL.starts_with("anilist:");
|
||||
const bool resolved = anilist || mediaURL.starts_with("miruro:");
|
||||
record += resolved ? "{\"version\":2,\"event\":\"" : "{\"version\":1,\"event\":\"";
|
||||
record += event;
|
||||
if (miruro) {
|
||||
const auto separator = mediaURL.find(':', 7);
|
||||
record += "\",\"media_identity\":{\"provider\":\"miruro\",\"media_id\":\"";
|
||||
record.append(mediaURL, 7, separator - 7);
|
||||
if (resolved) {
|
||||
const size_t prefix = anilist ? 8 : 7;
|
||||
const auto separator = mediaURL.find(':', prefix);
|
||||
record += "\",\"media_identity\":{\"provider\":\"";
|
||||
record += anilist ? "anilist" : "miruro";
|
||||
record += "\",\"media_id\":\"";
|
||||
record.append(mediaURL, prefix, separator - prefix);
|
||||
record += "\",\"episode\":";
|
||||
record.append(mediaURL, separator + 1, std::string::npos);
|
||||
record += "},\"position_seconds\":";
|
||||
|
||||
Reference in New Issue
Block a user