feat: support Miruro provider tracks, proxies, and native embeds
This commit is contained in:
+121
-53
@@ -94,90 +94,158 @@ struct StreamResolverChecks {
|
||||
try require(source.subtitles.count == 2 && source.subtitles[0].isDefault, "only external VTT retained with default")
|
||||
try require(source.subtitles[0].url.hasSuffix(".jpeg") && source.subtitles[1].label == "Spanish (Latin America)", "subtitle format and labels independent of file extension")
|
||||
try require(source.subtitles.allSatisfy { $0.headers == source.headers }, "verified Sun subtitle headers retained")
|
||||
let defaults = try MiruroResolver.decode(Data(fixture.utf8), mediaID: mediaID, episode: 1)
|
||||
let defaultSelection = try defaults.select()
|
||||
try require(defaults.videoProviders == ["sun"] && defaults.captionProviders == ["sun"], "menus contain usable native providers")
|
||||
try require(defaultSelection.videoProvider == "sun" && defaultSelection.captionProvider == "sun", "existing Sun defaults")
|
||||
let native: [String: Any] = ["player": "native", "proxy": false]
|
||||
var captionOnly = provider("bun")
|
||||
captionOnly["servers"] = [["headers": ["Referer": "https://bun.example/"],
|
||||
"streams": [], "embed": ["url": "https://bun.example/embed"]]]
|
||||
var missingVideo = provider("captions")
|
||||
missingVideo["servers"] = [["headers": ["Origin": "https://captions.example"]]]
|
||||
let independentCatalog = try catalog([
|
||||
"episodeNumber": 1,
|
||||
"config": ["sun": native, "bun": ["player": "iframe", "proxy": false]],
|
||||
"tracks": [["track": "ssub", "providers": [provider("sun"), captionOnly, missingVideo]]]
|
||||
])
|
||||
let independentCaptions = try independentCatalog.select(captionProvider: "bun:ssub")
|
||||
try require(independentCaptions.source.subtitles.first?.url == "https://bun.example/english.vtt" &&
|
||||
independentCaptions.source.subtitles.first?.headers == "Referer: https://bun.example/\r\n",
|
||||
"iframe-only provider captions are discovered independently of video eligibility")
|
||||
let unconfiguredCaptions = try independentCatalog.select(captionProvider: "captions")
|
||||
try require(unconfiguredCaptions.captionProvider == "captions:ssub" &&
|
||||
unconfiguredCaptions.source.subtitles.first?.headers == "Origin: https://captions.example\r\n",
|
||||
"captions without config or video streams retain their own server headers")
|
||||
let embedded = try independentCatalog.select(videoProvider: "bun:ssub")
|
||||
try require(independentCatalog.videoProviders == ["sun:ssub", "bun:ssub"] &&
|
||||
independentCatalog.captionProviders == ["sun:ssub", "bun:ssub", "captions:ssub"] &&
|
||||
embedded.source.url == "https://bun.example/embed" && embedded.source.requirements.embed,
|
||||
"iframe choices retain the embed URL and require asynchronous native preparation")
|
||||
let captionsOnly = try catalog([
|
||||
"episodeNumber": 1, "tracks": [["track": "ssub", "providers": [missingVideo]]]
|
||||
])
|
||||
try require(captionsOnly.videoProviders.isEmpty && captionsOnly.captionProviders == ["captions:ssub"],
|
||||
"caption discovery does not require any video candidate or config table")
|
||||
try reject("caption-only catalog playback") { _ = try captionsOnly.select() }
|
||||
var document: [String: Any] = [
|
||||
"episodeNumber": 1, "providerOrder": ["cloud", "river", "sun", "cloud", "missing"],
|
||||
"config": ["sun": native, "river": native, "cloud": native],
|
||||
"tracks": [["track": "ssub", "providers": [provider("river"), provider("sun"), provider("cloud")]]]
|
||||
]
|
||||
let choices = try catalog(document)
|
||||
try require(choices.videoProviders == ["cloud", "river", "sun"] &&
|
||||
choices.captionProviders == ["cloud", "river", "sun"], "runtime names follow deduplicated provider order")
|
||||
try require(choices.videoProviders == ["cloud:ssub", "river:ssub", "sun:ssub"] &&
|
||||
choices.captionProviders == ["cloud:ssub", "river:ssub", "sun:ssub"],
|
||||
"choices expose provider and track in deduplicated runtime provider order")
|
||||
let automatic = try choices.select()
|
||||
try require(automatic.videoProvider == "sun" && automatic.captionProvider == "sun", "Auto prefers usable Sun")
|
||||
let independent = try choices.select(videoProvider: "river", captionProvider: "cloud")
|
||||
try require(independent.videoProvider == "river" && independent.captionProvider == "cloud", "explicit independent choices")
|
||||
try require(independent.source.url == "https://river.example/master.m3u8" &&
|
||||
independent.source.headers == "Referer: https://river.example/\r\n", "selected host retains its URL and headers")
|
||||
try require(independent.source.subtitles.first?.url == "https://cloud.example/english.vtt" &&
|
||||
independent.source.subtitles.first?.headers == "Referer: https://cloud.example/\r\n", "captions retain their own provider headers")
|
||||
let sameHost = try choices.select(videoProvider: "river")
|
||||
try require(sameHost.captionProvider == "river", "Auto captions prefer chosen video provider")
|
||||
try require(automatic.videoProvider == "sun:ssub" && automatic.captionProvider == "sun:ssub",
|
||||
"Auto prefers usable Japanese Sun")
|
||||
let independent = try choices.select(videoProvider: "river", captionProvider: "cloud:ssub")
|
||||
try require(independent.videoProvider == "river:ssub" && independent.captionProvider == "cloud:ssub" &&
|
||||
independent.source.url == "https://river.example/master.m3u8" &&
|
||||
independent.source.headers == "Referer: https://river.example/\r\n" &&
|
||||
independent.source.subtitles.first?.headers == "Referer: https://cloud.example/\r\n",
|
||||
"bare provider preference and exact caption choice retain independent URLs and headers")
|
||||
let absent = try choices.select(videoProvider: "absent", captionProvider: "unsupported")
|
||||
let empty = try choices.select(videoProvider: "", captionProvider: "")
|
||||
try require(absent.videoProvider == "sun" && absent.captionProvider == "sun" &&
|
||||
empty.videoProvider == "sun" && empty.captionProvider == "sun", "absent and empty preferences fall back to Auto")
|
||||
document["tracks"] = [["track": "ssub", "providers": [provider("river"), provider("cloud")]]]
|
||||
let withoutSun = try catalog(document).select()
|
||||
try require(withoutSun.videoProvider == "cloud" && withoutSun.captionProvider == "cloud", "provider order applies without Sun")
|
||||
document["providerOrder"] = []
|
||||
let returnedOrder = try catalog(document).select()
|
||||
try require(returnedOrder.videoProvider == "river", "returned order is deterministic when no provider order applies")
|
||||
try require(absent.videoProvider == "sun:ssub" && absent.captionProvider == "sun:ssub" &&
|
||||
empty.videoProvider == "sun:ssub" && empty.captionProvider == "sun:ssub",
|
||||
"unavailable and empty preferences fall back to Japanese Auto")
|
||||
document["tracks"] = [["track": "ssub", "providers": [provider("river", captions: false), provider("cloud")]]]
|
||||
let withoutSun = try catalog(document).select()
|
||||
try require(withoutSun.videoProvider == "cloud:ssub" && withoutSun.captionProvider == "cloud:ssub",
|
||||
"provider order applies without Sun")
|
||||
document["providerOrder"] = []
|
||||
let otherCaptions = try catalog(document).select()
|
||||
try require(otherCaptions.videoProvider == "river" && otherCaptions.captionProvider == "cloud", "Auto captions fall back independently")
|
||||
try require(otherCaptions.videoProvider == "river:ssub" && otherCaptions.captionProvider == "cloud:ssub",
|
||||
"response order is retained and captions fall back independently")
|
||||
document["tracks"] = [["track": "sub", "providers": [provider("river", captions: false)]]]
|
||||
let noCaptions = try catalog(document)
|
||||
let bare = try noCaptions.select(captionProvider: "cloud")
|
||||
try require(noCaptions.captionProviders.isEmpty && bare.captionProvider == nil && bare.source.subtitles.isEmpty, "Japanese sub without captions remains playable")
|
||||
var soft = provider("river")
|
||||
soft["servers"] = [["streams": [["url": "https://soft.example/master.m3u8", "format": "m3u8"]]]]
|
||||
document["tracks"] = [["track": "sub", "providers": [provider("river")]],
|
||||
["track": "ssub", "providers": [soft]],
|
||||
["track": "dub", "providers": [provider("cloud")]]]
|
||||
let preferredVariant = try catalog(document)
|
||||
let preferredSelection = try preferredVariant.select()
|
||||
try require(preferredVariant.videoProviders == ["river"] &&
|
||||
preferredSelection.source.url == "https://soft.example/master.m3u8", "ssub wins per provider without dub fallback")
|
||||
var mixedConfigs: [String: Any] = ["river": native, "proxy": ["player": "native", "proxy": ["segments": true]],
|
||||
"iframe": ["player": "iframe", "proxy": false], "broken": ["player": 42], "bad name": native]
|
||||
mixedConfigs["rewrite"] = ["player": "native", "proxy": false, "hls": ["query": ["enabled": true]]]
|
||||
document["config"] = mixedConfigs
|
||||
try require(noCaptions.captionProviders.isEmpty && bare.captionProvider == nil && bare.source.subtitles.isEmpty,
|
||||
"Japanese sub without captions remains playable")
|
||||
document["tracks"] = [
|
||||
["track": "ssub", "providers": [provider("river")]],
|
||||
["track": "dub", "providers": [provider("river"), provider("sun")]],
|
||||
["track": "sub", "providers": [provider("river")]]]
|
||||
document["config"] = ["sun": native, "river": ["player": "native", "proxy": false,
|
||||
"variantOrder": ["dub", "sub", "sub", "ssub"]]]
|
||||
let variants = try catalog(document)
|
||||
let preferredVariant = try variants.select(videoProvider: "river")
|
||||
let dubbed = try variants.select(videoProvider: "river:dub", captionProvider: "river:dub")
|
||||
try require(variants.videoProviders == ["river:dub", "river:sub", "river:ssub", "sun:dub"] &&
|
||||
preferredVariant.videoProvider == "river:sub" && preferredVariant.captionProvider == "river:sub" &&
|
||||
dubbed.videoProvider == "river:dub" && dubbed.captionProvider == "river:dub",
|
||||
"all tracks remain selectable; bare provider uses variantOrder without implicit dub")
|
||||
document["tracks"] = [["track": "dub", "providers": [provider("sun")]]]
|
||||
let dubOnly = try catalog(document)
|
||||
try reject("automatic dub fallback") { _ = try dubOnly.select() }
|
||||
try reject("bare provider dub fallback") { _ = try dubOnly.select(videoProvider: "sun") }
|
||||
let explicitDub = try dubOnly.select(videoProvider: "sun:dub")
|
||||
try require(explicitDub.videoProvider == "sun:dub",
|
||||
"dub-only catalog remains available for an explicit track choice")
|
||||
let processed: [String: Any] = ["player": "native", "proxy": ["rotate": true, "segments": true],
|
||||
"hls": ["segments": ["enabled": true, "origin": "https://segments.example"],
|
||||
"query": ["enabled": true, "params": ["skip": "opaque", "token": "secret"]]]]
|
||||
document["config"] = ["river": native, "bee": processed]
|
||||
document["tracks"] = [["track": "ssub", "providers": [provider("river"), provider("bee")]]]
|
||||
let processing = try catalog(document).select(videoProvider: "bee", captionProvider: "bee")
|
||||
try require(processing.source.url == "https://bee.example/master.m3u8" &&
|
||||
processing.source.requirements.proxy?.rotate == true &&
|
||||
processing.source.requirements.proxy?.segments == true &&
|
||||
processing.source.requirements.segmentOrigin == "https://segments.example" &&
|
||||
processing.source.requirements.playlistQuery == ["skip": "opaque", "token": "secret"] &&
|
||||
processing.source.subtitles.first?.proxy?.segments == true &&
|
||||
!processing.source.requirements.embed,
|
||||
"selection preserves native proxy/HLS requirements and caption proxy independently")
|
||||
let parent = provider("bee")
|
||||
var embeddedCaptions = provider("bun")
|
||||
embeddedCaptions["subtitles"] = parent["subtitles"]
|
||||
embeddedCaptions["servers"] = [["streams": [], "embed": ["url": "https://megaplay.buzz/videojs/stream/example"]]]
|
||||
document["config"] = ["river": native, "bee": processed,
|
||||
"bun": ["player": "iframe", "proxy": false, "parent": "bee"]]
|
||||
document["tracks"] = [["track": "ssub", "providers": [provider("river"), parent, embeddedCaptions]]]
|
||||
let sharedCaptions = try catalog(document).select(captionProvider: "bun:ssub")
|
||||
try require(sharedCaptions.captionProvider == "bun:ssub" &&
|
||||
sharedCaptions.source.subtitles.first?.headers == "Referer: https://bee.example/\r\n" &&
|
||||
sharedCaptions.source.subtitles.first?.proxy?.segments == true,
|
||||
"identical iframe caption resources use their parent's known request transport")
|
||||
embeddedCaptions["subtitles"] = provider("bun")["subtitles"]
|
||||
document["tracks"] = [["track": "ssub", "providers": [provider("river"), parent, embeddedCaptions]]]
|
||||
let distinctCaptions = try catalog(document).select(captionProvider: "bun:ssub")
|
||||
try require(distinctCaptions.source.subtitles.first?.proxy == nil &&
|
||||
distinctCaptions.source.subtitles.first?.headers.isEmpty == true,
|
||||
"parent credentials and routing never propagate to different caption resources")
|
||||
var unsafeHLS = processed
|
||||
unsafeHLS["hls"] = ["segments": ["enabled": true, "origin": "file:///secret"]]
|
||||
document["config"] = ["river": native, "bee": unsafeHLS]
|
||||
let captionDespiteHLS = try catalog(document).select(videoProvider: "river", captionProvider: "bee:ssub")
|
||||
try require(captionDespiteHLS.captionProvider == "bee:ssub" &&
|
||||
captionDespiteHLS.source.subtitles.first?.proxy?.segments == true,
|
||||
"unsupported video processing does not hide valid independent captions")
|
||||
var resilient = provider("river")
|
||||
resilient["servers"] = [
|
||||
["streams": [["url": "https://embed.example/master.m3u8", "format": "hls"]], "embed": ["url": "https://embed.example/"]],
|
||||
["streams": [42, ["url": "file:///secret", "format": "hls"],
|
||||
["url": "https://river.example/master.m3u8", "format": "application/vnd.apple.mpegurl"]] as [Any],
|
||||
"headers": ["Referer": "https://river.example/"]]] as [[String: Any]]
|
||||
"headers": ["Referer": "https://river.example/"]]]
|
||||
document["config"] = ["river": native, "broken": ["player": 42], "bad name": native]
|
||||
document["tracks"] = [["track": "ssub", "providers": [
|
||||
42, ["provider": "broken", "servers": "invalid"], provider("proxy"), provider("iframe"),
|
||||
provider("rewrite"), provider("bad name"), resilient] as [Any]]]
|
||||
42, ["provider": "broken", "servers": "invalid"], provider("bad name"), resilient] as [Any]]]
|
||||
let resilientSources = try catalog(document)
|
||||
let resilientChoice = try resilientSources.select(videoProvider: "proxy", captionProvider: "iframe")
|
||||
try require(resilientSources.videoProviders == ["river"] && resilientSources.captionProviders == ["river"] &&
|
||||
resilientChoice.source.url == "https://river.example/master.m3u8", "malformed and unsupported entries do not poison usable alternatives")
|
||||
try require(resilientSources.videoProviders == ["river:ssub"] &&
|
||||
resilientSources.captionProviders == ["river:ssub"],
|
||||
"malformed neighboring entries do not poison usable provider tracks")
|
||||
for (old, replacement) in [
|
||||
("https://vault.example/english.jpeg", "https://user:secret@vault.example/english.jpeg"),
|
||||
("\"default\": false", "\"default\": true")
|
||||
] {
|
||||
let safeVideo = try project(fixture.replacingOccurrences(of: old, with: replacement))
|
||||
try require(safeVideo.url == source.url && safeVideo.subtitles.isEmpty, "unsafe caption sets are excluded without losing safe video")
|
||||
try require(safeVideo.url == source.url && safeVideo.subtitles.isEmpty,
|
||||
"unsafe caption sets are excluded without losing safe video")
|
||||
}
|
||||
let renewed = try project(fixture.replacingOccurrences(of: "token=secret", with: "token=renewed"))
|
||||
try require(renewed.identity == source.identity && renewed.url != source.url, "token rotation does not change stable identity")
|
||||
try require(renewed.identity == source.identity && renewed.url != source.url,
|
||||
"token rotation does not change stable identity")
|
||||
for (old, replacement) in [
|
||||
("\"episodeNumber\": 1", "\"episodeNumber\": 49"),
|
||||
("\"proxy\": false", "\"proxy\": true"),
|
||||
("\"enabled\": false", "\"enabled\": true"),
|
||||
("\"player\": \"native\"", "\"player\": \"iframe\""),
|
||||
("\"track\": \"ssub\"", "\"track\": \"dub\""),
|
||||
("\"proxy\": false", "\"proxy\": {\"segments\": true}"),
|
||||
("\"format\": \"hls\"", "\"format\": \"mp4\""),
|
||||
("\"embed\": null", "\"embed\": {\"url\": \"https://embed.example/secret\"}"),
|
||||
("https://vault.example/master.m3u8?token=secret", "file:///secret"),
|
||||
("\"embed\": null", "\"embed\": false"),
|
||||
("https://ultracloud.cc/\"", "https://ultracloud.cc/\\r\\nX-Injected: secret\""),
|
||||
@@ -204,7 +272,7 @@ struct StreamResolverChecks {
|
||||
_ = try await cancelled.value
|
||||
throw Failure(message: "Cancelled resolution was accepted")
|
||||
} catch is CancellationError {}
|
||||
print("PASS: streaming URL security, runtime native providers, independent captions, bounded responses and cancellation")
|
||||
print("PASS: streaming URL security, provider/track choices, proxy/HLS requirements, independent captions, bounded responses and cancellation")
|
||||
}
|
||||
|
||||
static func main() async {
|
||||
|
||||
Reference in New Issue
Block a user