feat: add headless Zoko source checks
This commit is contained in:
@@ -31,7 +31,7 @@ enum ZokoResolver {
|
||||
completionHandler: @escaping (URLRequest?) -> Void) { completionHandler(nil) }
|
||||
}
|
||||
|
||||
private static func fetch(_ request: URLRequest) async throws -> (Data, HTTPURLResponse) {
|
||||
private static func fetch(_ request: URLRequest, allowMissingPage: Bool = false) async throws -> (Data, HTTPURLResponse) {
|
||||
let configuration = URLSessionConfiguration.ephemeral
|
||||
configuration.httpShouldSetCookies = false
|
||||
configuration.httpCookieStorage = nil
|
||||
@@ -46,7 +46,7 @@ enum ZokoResolver {
|
||||
guard let response = response as? HTTPURLResponse, response.url == request.url else { throw ZokoError.transport }
|
||||
guard response.expectedContentLength <= bodyLimit else { throw ZokoError.malformed }
|
||||
if response.statusCode == 403 || response.statusCode == 429 || response.statusCode == 503 { throw ZokoError.protection }
|
||||
guard response.statusCode == 200 else { throw ZokoError.transport }
|
||||
guard response.statusCode == 200 || (allowMissingPage && response.statusCode == 404) else { throw ZokoError.transport }
|
||||
var data = Data()
|
||||
if response.expectedContentLength > 0 { data.reserveCapacity(Int(response.expectedContentLength)) }
|
||||
for try await byte in bytes {
|
||||
@@ -62,14 +62,16 @@ enum ZokoResolver {
|
||||
}
|
||||
}
|
||||
|
||||
static func resolve(mediaID: String, episode: Int) async throws -> ResolvedSource {
|
||||
static func resolve(mediaID: String, episode: Int, enrichTitle: Bool = true) async throws -> ResolvedSource {
|
||||
guard ResolvedSource.validAniListIdentity(mediaID: mediaID, episode: episode) else { throw ZokoError.malformed }
|
||||
var request = URLRequest(url: URL(string: "https://zokoanime.video/stream/ani/\(mediaID)/\(episode)/sub")!)
|
||||
request.timeoutInterval = 20
|
||||
request.setValue("text/html", forHTTPHeaderField: "Accept")
|
||||
let (data, response) = try await fetch(request)
|
||||
let (data, response) = try await fetch(request, allowMissingPage: true)
|
||||
guard response.mimeType == "text/html", let page = String(data: data, encoding: .utf8) else { throw ZokoError.malformed }
|
||||
let source = try parse(page: page, mediaID: mediaID, episode: episode)
|
||||
guard response.statusCode == 200 else { throw ZokoError.transport }
|
||||
guard enrichTitle else { return source }
|
||||
let title = (try? await Self.title(mediaID: mediaID, episode: episode)) ?? source.title
|
||||
try Task.checkCancellation()
|
||||
return ResolvedSource(url: source.url, headers: source.headers, identity: source.identity,
|
||||
@@ -85,9 +87,9 @@ enum ZokoResolver {
|
||||
guard !page.contains("window.__P") else { throw ZokoError.malformed }
|
||||
let lower = page.lowercased()
|
||||
let visible = lower.replacingOccurrences(of: "<[^>]*>", with: " ", options: .regularExpression)
|
||||
if visible.contains("error"), visible.contains("404"), visible.contains("couldn't find anything to play here") { throw ZokoError.unavailable }
|
||||
if lower.contains("cf-chl-") || lower.contains("challenge-platform") || lower.contains("just a moment") ||
|
||||
lower.contains("captcha") || lower.contains("sorry, you have been blocked") { throw ZokoError.protection }
|
||||
if visible.contains("error"), visible.contains("404"), visible.contains("couldn't find anything to play here") { throw ZokoError.unavailable }
|
||||
throw ZokoError.malformed
|
||||
}
|
||||
guard var decoded = Data(base64Encoded: String(page[range])), !decoded.isEmpty else { throw ZokoError.malformed }
|
||||
|
||||
Reference in New Issue
Block a user