XCDYouTubeKit
XCDYouTubeKit copied to clipboard
Error XCDYouTubeVideoErrorDomain -2 when i try open video
when i try to open any video it returns an error XCDYouTubeVideoErrorDomain, Code: -2
Before that, other tips from other discussions helped, but now something new :(
This brunch helped me
pod 'XCDYouTubeKit', :git => 'https://github.com/dpwilhelmsen/XCDYouTubeKit', :branch => 'hotfix/fix-get-video-info-error', submodules: true
But i just replace 2 files https://github.com/dpwilhelmsen/XCDYouTubeKit/blob/hotfix/fix-get-video-info-error/XCDYouTubeKit/XCDYouTubeVideoOperation.m
https://github.com/dpwilhelmsen/XCDYouTubeKit/blob/hotfix/fix-get-video-info-error/XCDYouTubeKit/XCDYouTubeVideoWebpage.m
It's working one time, now not work
yes, it does not work anymore
And now what i can do? :)
I'm seeing the same issue here.
When using a VPN to the US, videos still play. Maybe it's related to the consent cookie tweak we've had to implement before? That only affected non-US clients I believe.
Ah shit, here we go again
Maybe this can help: https://stackoverflow.com/questions/67615278/get-video-info-youtube-endpoint-suddenly-returning-404-not-found/67629882#67629882
There's a new answer named UPDATE (July 2021)
POST: https://youtubei.googleapis.com/youtubei/v1/player?key=AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8
with the body :
{ "context": { "client": { "hl": "en", "clientName": "WEB", "clientVersion": "2.20210721.00.00", "mainAppWebInfo": { "graftUrl": "/watch?v={VIDEO_ID}" } } }, "videoId": "{VIDEO_ID}" }
the above mentioned fix seems to work checkout #545
the innertube api key is hardcoded and we don't know how long it will last so it is recommended to scrap the api key from youtube and set it via XCDYouTubeClient.setInnertubeApiKey
func scrapInnertubeApiKey(){
let link = "https://www.youtube.com"
Alamofire.request(link).responseString { (response) in // network lib https://github.com/Alamofire/Alamofire
if let html = response.value {
if let doc = try? HTML(html: html, encoding: .utf8) { // HTML parser https://github.com/tid-kijyun/Kanna
if let text = doc.xpath("//script[contains(., 'INNERTUBE_API_KEY')]/text()").first?.text {
if let results = text.match("ytcfg.set\\((\\{.*?\\})\\)").last?.last {
if let data = results.data(using: .utf8), let model = try? JSONDecoder().decode(InnertubeScrap.self, from: data) {
let key = model.INNERTUBE_API_KEY
XCDYouTubeClient.setInnertubeApiKey(key)
}
}
}
}
}
}
}
struct InnertubeScrap : Codable {
let INNERTUBE_API_KEY : String
}
extension String {
func match(_ regex: String) -> [[String]] {
let nsString = self as NSString
return (try? NSRegularExpression(pattern: regex, options: []))?.matches(in: self, options: [], range: NSMakeRange(0, nsString.length)).map { match in
(0..<match.numberOfRanges).map { match.range(at: $0).location == NSNotFound ? "" : nsString.substring(with: match.range(at: $0)) }
} ?? []
}
}
I can confirm the post method works, but the response schema is different than the current get_video_info. So, I think there are some meaningful changes required to get this working from within XCDYouTubeKit. In case it helps anyone in the short-term, here's snippet from my swift app. But I started needing to re-implement some of the signature stuff inside XCDYouTubeKit, and decided to slow my roll.
Note that postToUrl is a shared helper which is pretty simple, so left out here for brevity.
func getVideoUrl(videoId: String, completion: @escaping ([UInt:String]) -> Void) {
let infoParams: [String: Any] = [
"graftUrl": "/watch?v=\(videoId)"
]
let clientParams: [String: Any] = [
"hl": "en",
"clientName": "WEB",
"clientVersion": "2.20210721.00.00",
"mainAppWebInfo": infoParams
]
let contextParams: [String: Any] = [
"client": clientParams
]
let parameters: [String: Any] = [
"context": contextParams,
"videoId": videoId
]
postToUrl(urlStr: "https://youtubei.googleapis.com/youtubei/v1/player?key=AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8", parameters: parameters, commandCompletion: { (data, response, error) in
var streamURLs: [UInt:String] = [:]
//let dataString = String(decoding: data!, as: UTF8.self)
//STLog(logStr: dataString)
if let data = data,
let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
let streamingData = json["streamingData"] as? [String: Any],
let formats = streamingData["formats"] as? [[String: Any]] {
for format in formats
{
if let itag = format["itag"] as? UInt
{
if let url = format["url"] as? String {
streamURLs[itag] = url
}
else if let signatureCipher = format["signatureCipher"] as? String,
let queryDict = signatureCipher.queryDictionary,
let url = queryDict["url"],
let sig = queryDict["s"] {
// TODO: twiddle the signature, should likely do this in XCDYouTubeKit
streamURLs[itag] = url
}
}
}
}
completion(streamURLs)
})
}
Note that postToUrl is a shared helper which is pretty simple, so left out here for brevity.
Return error "Precondition check failed" :(
the above mentioned fix seems to work checkout #545
the innertube api key is hardcoded and we don't know how long it will last so it is recommended to scrap the api key from youtube and set it via XCDYouTubeClient.setInnertubeApiKey
func scrapInnertubeApiKey(){ let link = "https://www.youtube.com" Alamofire.request(link).responseString { (response) in // network lib https://github.com/Alamofire/Alamofire if let html = response.value { if let doc = try? HTML(html: html, encoding: .utf8) { // HTML parser https://github.com/tid-kijyun/Kanna if let text = doc.xpath("//script[contains(., 'INNERTUBE_API_KEY')]/text()").first?.text { if let results = text.match("ytcfg.set\\((\\{.*?\\})\\)").last?.last { if let data = results.data(using: .utf8), let model = try? JSONDecoder().decode(InnertubeScrap.self, from: data) { let key = model.INNERTUBE_API_KEY XCDYouTubeClient.setInnertubeApiKey(key) } } } } } } } struct InnertubeScrap : Codable { let INNERTUBE_API_KEY : String } extension String { func match(_ regex: String) -> [[String]] { let nsString = self as NSString return (try? NSRegularExpression(pattern: regex, options: []))?.matches(in: self, options: [], range: NSMakeRange(0, nsString.length)).map { match in (0..<match.numberOfRanges).map { match.range(at: $0).location == NSNotFound ? "" : nsString.substring(with: match.range(at: $0)) } } ?? [] } }
Looks good, but the problem is that at my stage if let text = doc.xpath("//script[contains(., 'INNERTUBE_API_KEY')]/text()").first?.text { does not return anything, and a screen with the YouTube privacy policy is displayed in the doc. content
But i tested key "AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8" - he is work, but Privacy Policy blocked all and video not returned(
When i try get video info, google return this:
<NSHTTPURLResponse: 0x283dae420> { URL: https://youtubei.googleapis.com/youtubei/v1/player?key=AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8 } { Status Code: 404, Headers { "Alt-Svc" = ( "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-Q050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\"" ); "Content-Encoding" = ( br ); "Content-Length" = ( 138 ); "Content-Type" = ( "application/json; charset=UTF-8" ); Date = ( "Sun, 25 Jul 2021 21:16:49 GMT" ); Server = ( ESF ); Vary = ( Origin, "X-Origin", Referer ); "x-content-type-options" = ( nosniff ); "x-frame-options" = ( SAMEORIGIN ); "x-xss-protection" = ( 0 ); } }
Note that postToUrl is a shared helper which is pretty simple, so left out here for brevity.
Return error "Precondition check failed" :(
I saw that, you need to make sure that the content type is application/json and you don't percent encode it.
Note that postToUrl is a shared helper which is pretty simple, so left out here for brevity.
Return error "Precondition check failed" :(
I saw that, you need to make sure that the content type is application/json and you don't percent encode it.
It's... work...
I hope this doesn't sound weird, but I love you, thank you very much! :) You helped a lot, because the application in the store began to pour out, users complained and real hell began for me ... You really saved me, thanks!
I followed the code in #545, but still getting XCDYouTubeVideoErrorDomain -2 for upcoming live stream video. This is no doubt that if the problem solved, this will be the perfect fix. Any idea for this? Thanks.
@Kiu212 +1 Addition. This problem is specific to the European Region
After combining #545 with the changes I already had locally (consent cookie etc), it started playing videos again in europe.
When I try a livestream however, the POST works but youtubekit fails to play the stream. The log eventually notifies that a request went timeout. Anyone else seeing this?
The timeout error:
[XCDYouTubeKit] URL GET operation finished with error: The request timed out. Domain: NSURLErrorDomain Code: -1001 User Info: { NSErrorFailingURLKey = "https://r9---sn-uxaxoxu-cg0r.googlevideo.com/videoplayback?expire=1627321020&ei=XJ7-YIKUIYKx1wK-2pCADw&ip=2a02%3A1810%3Aa418%3Af700%3A38fc%3Aa27c%3Aa8bc%3A63e6&id=DWcJFNfaw9c.3&itag=243&aitags=133%2C134%2C135%2C136%2C137%2C160%2C242%2C243%2C244%2C247%2C248%2C278&source=yt_live_broadcast&requiressl=yes&mh=Ms&mm=44%2C29&mn=sn-uxaxoxu-cg0r%2Csn-5hnekn7d&ms=lva%2Crdu&mv=u&mvi=9&pl=45&pcm2=yes&vprv=1&live=1&hang=1&noclen=1&mime=video%2Fwebm&ns=EtxyS696fTkFieyGVFLQZrAG&gir=yes&mt=1627298950&fvip=4&keepalive=yes&fexp=24001373%2C24007246&beids=9466588&c=WEB&n=FSF8yu_YZ5HouZ&sparams=expire%2Cei%2Cip%2Cid%2Caitags%2Csource%2Crequiressl%2Cpcm2%2Cvprv%2Clive%2Chang%2Cnoclen%2Cmime%2Cns%2Cgir&sig=AOq0QJ8wRQIhAKPUVg1BS0dny9J4cVDhB57s1VBGBrZw2NppdaL-APesAiAU8b2kXbeM9iV-Yt_s4qMftNiJhNKDitq8M0FD6ESGMg%3D%3D&lsparams=mh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl&lsig=AG3C_xAwRgIhAI8vIV-EqXsXq0Y5zwdqvYYlrTKy3TqHoGRy0l4rXNJ5AiEAyspZ6SOPFDdQ-CnjDvqHl55kOAVMenro0IxH-jFdcoA%3D&ratebypass=yes"; NSErrorFailingURLStringKey = "https://r9---sn-uxaxoxu-cg0r.googlevideo.com/videoplayback?expire=1627321020&ei=XJ7-YIKUIYKx1wK-2pCADw&ip=2a02%3A1810%3Aa418%3Af700%3A38fc%3Aa27c%3Aa8bc%3A63e6&id=DWcJFNfaw9c.3&itag=243&aitags=133%2C134%2C135%2C136%2C137%2C160%2C242%2C243%2C244%2C247%2C248%2C278&source=yt_live_broadcast&requiressl=yes&mh=Ms&mm=44%2C29&mn=sn-uxaxoxu-cg0r%2Csn-5hnekn7d&ms=lva%2Crdu&mv=u&mvi=9&pl=45&pcm2=yes&vprv=1&live=1&hang=1&noclen=1&mime=video%2Fwebm&ns=EtxyS696fTkFieyGVFLQZrAG&gir=yes&mt=1627298950&fvip=4&keepalive=yes&fexp=24001373%2C24007246&beids=9466588&c=WEB&n=FSF8yu_YZ5HouZ&sparams=expire%2Cei%2Cip%2Cid%2Caitags%2Csource%2Crequiressl%2Cpcm2%2Cvprv%2Clive%2Chang%2Cnoclen%2Cmime%2Cns%2Cgir&sig=AOq0QJ8wRQIhAKPUVg1BS0dny9J4cVDhB57s1VBGBrZw2NppdaL-APesAiAU8b2kXbeM9iV-Yt_s4qMftNiJhNKDitq8M0FD6ESGMg%3D%3D&lsparams=mh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl&lsig=AG3C_xAwRgIhAI8vIV-EqXsXq0Y5zwdqvYYlrTKy3TqHoGRy0l4rXNJ5AiEAyspZ6SOPFDdQ-CnjDvqHl55kOAVMenro0IxH-jFdcoA%3D&ratebypass=yes"; NSLocalizedDescription = "The request timed out."; NSUnderlyingError = "Error Domain=kCFErrorDomainCFNetwork Code=-1001 \"(null)\" UserInfo={_kCFStreamErrorCodeKey=-2102, _kCFStreamErrorDomainKey=4}"; "_NSURLErrorFailingURLSessionTaskErrorKey" = "LocalDataTask <2272A8E5-2351-4FC3-942F-980D3DCBAEC5>.<1>"; "_NSURLErrorRelatedURLSessionTaskErrorKey" = ( "LocalDataTask <2272A8E5-2351-4FC3-942F-980D3DCBAEC5>.<1>" ); "_kCFStreamErrorCodeKey" = "-2102"; "_kCFStreamErrorDomainKey" = 4; }
I have same error... If someone have solution - pls share... Thanks.
need a fix :'(
Well damn, it seems I didn't apply one of the previous fixes and it came back to bite me.
The only missing code I needed was near line 173 in XCDYoutubeVideo.m:
if (httpLiveStream.length == 0) { httpLiveStream = info[@"streamingData"][@"hlsManifestUrl"]; }
Now both livestreams and past broadcasts are working for me.
no of the fixes works anymore (for me). it looks like it will only play videos randomly.
anyone got the solution ??
Hello guys, someone got the solution?
I was getting this error when I tried to pass the video url instead of the video id.