ytparser: adjust to API changes (#12)

YouTube now enforces the HTML5 API for get_video_info, which
provides the stream info in a JSON object.
This commit is contained in:
Hendi48
2021-06-14 22:14:59 +02:00
committed by GitHub
parent 4d560da9be
commit 0999fa72f8

View File

@@ -424,7 +424,6 @@ bool cYTFeedParser::supportedFormat(int fmt)
bool cYTFeedParser::decodeVideoInfo(std::string &answer, cYTVideoInfo &vinfo)
{
bool ret = false;
decodeUrl(answer);
#if 0
std::string infofile = thumbnail_dir;
infofile += "/";
@@ -432,59 +431,79 @@ bool cYTFeedParser::decodeVideoInfo(std::string &answer, cYTVideoInfo &vinfo)
infofile += ".txt";
saveToFile(infofile.c_str(), answer);
#endif
if(answer.find("token=") == std::string::npos)
return ret;
//FIXME check expire
std::vector<std::string> ulist;
std::string::size_type fmt = answer.find("url_encoded_fmt_stream_map=");
if (fmt != std::string::npos) {
fmt = answer.find("=", fmt);
splitString(answer, ",", ulist, fmt+1);
for (unsigned i = 0; i < ulist.size(); i++) {
#if 0 // to decode all params
decodeUrl(ulist[i]);
printf("URL: %s\n", ulist[i].c_str());
#endif
std::map<std::string,std::string> smap;
std::vector<std::string> uparams;
splitString(ulist[i], "&", uparams);
if (uparams.size() < 3)
continue;
for (unsigned j = 0; j < uparams.size(); j++) {
decodeUrl(uparams[j]);
#ifdef DEBUG_PARSER
printf(" param: %s\n", uparams[j].c_str());
#endif
splitString(uparams[j], "=", smap);
}
#ifdef DEBUG_PARSER
printf("=========================================================\n");
#endif
cYTVideoUrl yurl;
yurl.url = smap["url"];
std::size_t sig = std::string::npos;
std::string::size_type ptr = smap["url"].find("signature=");
if (ptr != std::string::npos)
{
ptr = smap["url"].find("=", ptr);
smap["url"].erase(0,ptr+1);
if((ptr = smap["url"].find("&")) != std::string::npos)
yurl.sig = smap["url"].substr(0,ptr);
}else{
sig = smap["url"].find("&sig=");
}
// Extract player_response
std::string::size_type player_resp_start = answer.find("player_response=");
if (player_resp_start == std::string::npos) {
printf("player_response not found\n");
return false;
}
int id = atoi(smap["itag"].c_str());
if (supportedFormat(id) && !yurl.url.empty() && (!yurl.sig.empty() || (sig != std::string::npos))) {
yurl.quality = smap["quality"];
yurl.type = smap["type"];
vinfo.formats.insert(yt_urlmap_pair_t(id, yurl));
ret = true;
}
player_resp_start = answer.find("=", player_resp_start) + 1;
std::string::size_type player_resp_end = answer.find("&", player_resp_start);
if (player_resp_end == std::string::npos) {
player_resp_end = answer.length();
}
std::string player_response = answer.substr(player_resp_start, player_resp_end - player_resp_start);
decodeUrl(player_response);
// Load player_response as json
Json::Value root;
if (!parseJsonFromString(player_response, &root, NULL)) {
printf("Decoding player_response failed\n");
return false;
}
const Json::Value streamingData = root["streamingData"];
if (!streamingData) {
printf("streamingData element not present\n");
return false;
}
const Json::Value formats = streamingData["formats"];
if (!formats) {
printf("formats element not present\n");
return false;
}
for (auto it = formats.begin(); it != formats.end(); ++it) {
const Json::Value format = *it;
int id = format["itag"].asInt();
std::string quality = format["quality"].asString();
std::string url;
if (!format["url"].empty()) {
url = format["url"].asString();
} else if (!format["cipher"].empty()) {
// FIXME add support for cipher (is it still used or was it replaced by signatureCipher?)
printf("cipher unsupported: %s\n", format["cipher"].asCString());
continue;
} else if (!format["signatureCipher"].empty()) {
// FIXME add support for signatureCipher
printf("signatureCipher unsupported: %s\n", format["signatureCipher"].asCString());
continue;
} else {
printf("Unable to find url\n");
continue;
}
#ifdef DEBUG_PARSER
printf("%d: %s - %s\n", id, quality.c_str(), url.c_str());
#endif
cYTVideoUrl yurl;
if (supportedFormat(id) && !url.empty()) {
yurl.quality = quality;
yurl.url = url;
yurl.type = format["mimeType"].asString();
vinfo.formats.insert(yt_urlmap_pair_t(id, yurl));
ret = true;
}
}
return ret;
}
@@ -592,7 +611,7 @@ bool cYTFeedParser::ParseVideoInfo(cYTVideoInfo &vinfo, CURL *_curl_handle)
std::string vurl = "https://www.youtube.com/get_video_info?video_id=";
vurl += vinfo.id;
vurl += estr[i];
vurl += "&ps=default&eurl=&gl=US&hl=en";
vurl += "&ps=default&eurl=&gl=US&hl=en&html5=1";
printf("cYTFeedParser::ParseVideoInfo: get [%s]\n", vurl.c_str());
std::string answer;
if (!getUrl(vurl, answer, _curl_handle))