feat: add headless Zoko source checks
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
import Foundation
|
||||
|
||||
// Deliberately separate from launch: no configuration, application, player or state APIs.
|
||||
enum SourceCheck {
|
||||
enum Status: String, Sendable, CaseIterable {
|
||||
case available, unavailable, failed
|
||||
|
||||
var json: String {
|
||||
"{\"version\":1,\"provider\":\"zokoanime\",\"track\":\"sub\",\"status\":\"\(rawValue)\"}"
|
||||
}
|
||||
}
|
||||
|
||||
static func run(
|
||||
mediaID: String, episode: Int, timeout: Duration = .seconds(15),
|
||||
resolve: @escaping @Sendable (String, Int) async throws -> ResolvedSource = {
|
||||
try await ZokoResolver.resolve(mediaID: $0, episode: $1, enrichTitle: false)
|
||||
},
|
||||
validate: @escaping @Sendable (ResolvedSource) async throws -> Void = {
|
||||
try await MiruroTransport.checkZokoRoot($0)
|
||||
}
|
||||
) async -> Status {
|
||||
await withTaskGroup(of: Status.self) { group in
|
||||
group.addTask {
|
||||
let source: ResolvedSource
|
||||
do {
|
||||
try Task.checkCancellation()
|
||||
source = try await resolve(mediaID, episode)
|
||||
try Task.checkCancellation()
|
||||
} catch ZokoError.unavailable {
|
||||
return Task.isCancelled ? .failed : .unavailable
|
||||
} catch {
|
||||
return .failed
|
||||
}
|
||||
do {
|
||||
try await validate(source)
|
||||
try Task.checkCancellation()
|
||||
return .available
|
||||
} catch {
|
||||
// A manifest 404, protection page or other resource failure is
|
||||
// not evidence of the provider's explicit missing-episode page.
|
||||
return .failed
|
||||
}
|
||||
}
|
||||
group.addTask {
|
||||
try? await Task.sleep(for: timeout)
|
||||
return .failed
|
||||
}
|
||||
let result = await group.next() ?? .failed
|
||||
group.cancelAll()
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user