Changeset 165 for smplayer/trunk/src/youtube/retrieveyoutubeurl.cpp
- Timestamp:
- May 16, 2014, 9:51:55 AM (11 years ago)
- Location:
- smplayer/trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
smplayer/trunk
- Property svn:mergeinfo changed
/smplayer/vendor/current merged: 163
- Property svn:mergeinfo changed
-
smplayer/trunk/src/youtube/retrieveyoutubeurl.cpp
r156 r165 1 1 /* smplayer, GUI front-end for mplayer. 2 Copyright (C) 2006-201 3Ricardo Villalba <rvm@users.sourceforge.net>2 Copyright (C) 2006-2014 Ricardo Villalba <rvm@users.sourceforge.net> 3 3 Copyright (C) 2010 Ori Rejwan 4 4 … … 25 25 #include "ytsig.h" 26 26 27 #if QT_VERSION >= 0x050000 28 #include <QUrlQuery> 29 #endif 30 31 #define USE_PLAYER_NAME 32 33 QString RetrieveYoutubeUrl::user_agent; 34 27 35 RetrieveYoutubeUrl::RetrieveYoutubeUrl( QObject* parent ) : QObject(parent) 28 36 { 29 37 reply = 0; 30 38 manager = new QNetworkAccessManager(this); 31 connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(gotResponse(QNetworkReply*)));32 39 33 40 preferred_quality = FLV_360p; 34 user_agent = "Mozilla/5.0 (X11; Linux x86_64; rv:5.0.1) Gecko/20100101 Firefox/5.0.1";35 41 } 36 42 … … 39 45 40 46 void RetrieveYoutubeUrl::fetchPage(const QString & url) { 47 QString agent = user_agent; 48 if (agent.isEmpty()) agent = "Mozilla/5.0 (X11; Linux x86_64; rv:5.0.1) Gecko/20100101 Firefox/5.0.1"; 49 qDebug("RetrieveYoutubeUrl::fetchPage: user agent: %s", agent.toLatin1().constData()); 50 51 QNetworkRequest req(url); 52 req.setRawHeader("User-Agent", agent.toLatin1()); 53 reply = manager->get(req); 54 connect(reply, SIGNAL(finished()), this, SLOT(gotResponse())); 55 orig_url = url; 56 57 emit connecting(QUrl(url).host()); 58 59 #ifdef YT_GET_VIDEOINFO 60 video_id = getVideoID(url); 61 #endif 62 } 63 64 #ifdef YT_GET_VIDEOINFO 65 void RetrieveYoutubeUrl::fetchVideoInfoPage() { 66 QString url = QString("http://www.youtube.com/get_video_info?el=detailpage&ps=default&eurl=&gl=US&hl=en&video_id=%1").arg(video_id); 67 //qDebug("RetrieveYoutubeUrl::fetchVideoInfoPage: url: %s", url.toUtf8().constData()); 68 69 YTSig::check(url); 41 70 QNetworkRequest req(url); 42 71 req.setRawHeader("User-Agent", user_agent.toLatin1()); 43 72 reply = manager->get(req); 44 orig_url = url; 45 46 emit connecting(url); 47 } 73 connect(reply, SIGNAL(finished()), this, SLOT(gotVideoInfoResponse())); 74 75 emit connecting(QUrl(url).host()); 76 } 77 #endif 48 78 49 79 void RetrieveYoutubeUrl::close() { … … 51 81 } 52 82 53 void RetrieveYoutubeUrl::gotResponse(QNetworkReply* reply) { 83 void RetrieveYoutubeUrl::gotResponse() { 84 QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender()); 85 54 86 if (reply->error() == QNetworkReply::NoError) { 55 87 int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); … … 71 103 } 72 104 105 #ifdef YT_GET_VIDEOINFO 106 void RetrieveYoutubeUrl::gotVideoInfoResponse() { 107 qDebug("RetrieveYoutubeUrl::gotVideoInfoResponse"); 108 109 QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender()); 110 111 if (reply->error() != QNetworkReply::NoError) { 112 emit errorOcurred((int)reply->error(), reply->errorString()); 113 return; 114 } 115 parseVideoInfo(reply->readAll()); 116 } 117 #endif 118 73 119 void RetrieveYoutubeUrl::parse(QByteArray text) { 74 120 qDebug("RetrieveYoutubeUrl::parse"); … … 87 133 } 88 134 135 //qDebug("RetrieveYoutubeUrl::parse: replyString: %s",replyString.toLatin1().constData()); 136 137 QString player; 138 QRegExp rxplayer("html5player-([\\d,\\w,-]+)\\.js"); 139 if (rxplayer.indexIn(replyString) != -1) { 140 player = rxplayer.cap(1); 141 qDebug("RetrieveYoutubeUrl::parse: html5player: %s", player.toLatin1().constData()); 142 } 143 89 144 QRegExp regex("\\\"url_encoded_fmt_stream_map\\\"\\s*:\\s*\\\"([^\\\"]*)"); 90 145 regex.indexIn(replyString); … … 93 148 fmtArray.replace(QRegExp("\\\\(.)"), "\\1"); 94 149 95 bool signature_not_found = false; 150 #ifndef YT_GET_VIDEOINFO 151 bool failed_to_decrypt_signature = false; 152 #endif 153 154 #if QT_VERSION >= 0x050000 155 QUrlQuery * q = new QUrlQuery(); 156 #endif 96 157 97 158 QList<QByteArray> codeList = fmtArray.toLatin1().split(','); … … 101 162 102 163 QUrl line; 103 line.setEncodedQuery(code); 104 105 if (line.hasQueryItem("url")) { 106 QUrl url( line.queryItemValue("url") ); 164 #if QT_VERSION >= 0x050000 165 q->setQuery(code); 166 #else 167 QUrl * q = &line; 168 q->setEncodedQuery(code); 169 #endif 170 171 if (q->hasQueryItem("url")) { 172 QUrl url( q->queryItemValue("url") ); 107 173 line.setScheme(url.scheme()); 108 174 line.setHost(url.host()); 109 175 line.setPath(url.path()); 110 line.setEncodedQuery( line.encodedQuery() + "&" + url.encodedQuery() ); 111 line.removeQueryItem("url"); 112 113 if (line.hasQueryItem("sig")) { 114 line.addQueryItem("signature", line.queryItemValue("sig")); 115 line.removeQueryItem("sig"); 176 q->removeQueryItem("url"); 177 #if QT_VERSION >= 0x050000 178 q->setQuery( q->query(QUrl::FullyDecoded) + "&" + url.query(QUrl::FullyDecoded) ); 179 /* 180 QList < QPair < QString,QString > > l = q->queryItems(); 181 for (int n=0; n < l.count(); n++) { 182 qDebug("n: %d, %s = %s", n, l[n].first.toLatin1().constData(), l[n].second.toLatin1().constData()); 183 } 184 */ 185 #else 186 q->setEncodedQuery( q->encodedQuery() + "&" + url.encodedQuery() ); 187 /* 188 QList < QPair < QString,QString > > l = q->queryItems(); 189 for (int n=0; n < l.count(); n++) { 190 qDebug("n: %d, %s = %s", n, l[n].first.toLatin1().constData(), l[n].second.toLatin1().constData()); 191 } 192 */ 193 #endif 194 195 if (q->hasQueryItem("sig")) { 196 q->addQueryItem("signature", q->queryItemValue("sig")); 197 q->removeQueryItem("sig"); 116 198 } 117 199 else 118 if (line.hasQueryItem("s")) { 119 QString signature = YTSig::aclara(line.queryItemValue("s")); 200 if (q->hasQueryItem("s")) { 201 #ifdef USE_PLAYER_NAME 202 QString signature = YTSig::aclara(q->queryItemValue("s"), player); 203 #else 204 QString signature = YTSig::aclara(q->queryItemValue("s")); 205 #endif 120 206 if (!signature.isEmpty()) { 121 line.addQueryItem("signature", signature);207 q->addQueryItem("signature", signature); 122 208 } else { 123 signature_not_found = true; 209 #ifndef YT_GET_VIDEOINFO 210 failed_to_decrypt_signature = true; 211 #endif 124 212 } 125 line.removeQueryItem("s"); 126 } 127 line.removeAllQueryItems("fallback_host"); 128 line.removeAllQueryItems("type"); 129 if ((line.hasQueryItem("itag")) && (line.hasQueryItem("signature"))) { 130 QString itag = line.queryItemValue("itag"); 131 line.removeAllQueryItems("itag"); // Remove duplicated itag 132 line.addQueryItem("itag", itag); 213 q->removeQueryItem("s"); 214 } 215 q->removeAllQueryItems("fallback_host"); 216 q->removeAllQueryItems("type"); 217 218 if ((q->hasQueryItem("itag")) && (q->hasQueryItem("signature"))) { 219 QString itag = q->queryItemValue("itag"); 220 q->removeAllQueryItems("itag"); // Remove duplicated itag 221 q->addQueryItem("itag", itag); 222 #if QT_VERSION >= 0x050000 223 line.setQuery(q->query(QUrl::FullyDecoded)); 224 #endif 133 225 urlMap[itag.toInt()] = line.toString(); 134 226 //qDebug("line: %s", line.toString().toLatin1().constData()); … … 137 229 } 138 230 231 #if QT_VERSION >= 0x050000 232 delete q; 233 #endif 234 139 235 qDebug("RetrieveYoutubeUrl::parse: url count: %d", urlMap.count()); 140 236 141 if ((urlMap.count() == 0) && (signature_not_found)) { 237 #ifndef YT_GET_VIDEOINFO 238 if ((urlMap.count() == 0) && (failed_to_decrypt_signature)) { 142 239 qDebug("RetrieveYoutubeUrl::parse: no url found with valid signature"); 143 240 emit signatureNotFound(url_title); 144 241 return; 145 242 } 243 #else 244 if (urlMap.count() == 0) { 245 qDebug("RetrieveYoutubeUrl::parse: no url found with valid signature"); 246 fetchVideoInfoPage(); 247 return; 248 } 249 #endif 146 250 147 251 QString p_url = findPreferredUrl(); … … 155 259 } 156 260 } 261 262 QString RetrieveYoutubeUrl::getVideoID(QString video_url) { 263 if (video_url.contains("youtu.be/")) { 264 video_url.replace("youtu.be/", "youtube.com/watch?v="); 265 } 266 else 267 if (video_url.contains("y2u.be/")) { 268 video_url.replace("y2u.be/", "youtube.com/watch?v="); 269 } 270 else 271 if (video_url.contains("m.youtube.com")) { 272 video_url.replace("m.youtube.com", "www.youtube.com"); 273 } 274 275 if ((video_url.startsWith("youtube.com")) || (video_url.startsWith("www.youtube.com"))) video_url = "http://" + video_url; 276 277 //qDebug("RetrieveYoutubeUrl::getVideoID: video_url: %s", video_url.toLatin1().constData()); 278 279 QUrl url(video_url); 280 281 QString ID; 282 283 #if QT_VERSION >= 0x050000 284 QUrlQuery * q = new QUrlQuery(url); 285 #else 286 const QUrl * q = &url; 287 #endif 288 289 if ((url.host().contains("youtube")) && (url.path().contains("watch_videos"))) { 290 if (q->hasQueryItem("video_ids")) { 291 int index = 0; 292 if (q->hasQueryItem("index")) index = q->queryItemValue("index").toInt(); 293 QStringList list = q->queryItemValue("video_ids").split(","); 294 if (index < list.count()) ID = list[index]; 295 } 296 } 297 else 298 if ((url.host().contains("youtube")) && (url.path().contains("watch"))) { 299 if (q->hasQueryItem("v")) { 300 ID = q->queryItemValue("v"); 301 } 302 } 303 304 #if QT_VERSION >= 0x050000 305 delete q; 306 #endif 307 308 //qDebug("RetrieveYoutubeUrl::getVideoID: ID: %s", ID.toLatin1().constData()); 309 310 return ID; 311 } 312 313 bool RetrieveYoutubeUrl::isUrlSupported(const QString & url) { 314 return (!getVideoID(url).isEmpty()); 315 } 316 317 QString RetrieveYoutubeUrl::fullUrl(const QString & url) { 318 QString r; 319 QString ID = getVideoID(url); 320 if (!ID.isEmpty()) r = "http://www.youtube.com/watch?v=" + ID; 321 return r; 322 } 323 324 #ifdef YT_GET_VIDEOINFO 325 void RetrieveYoutubeUrl::parseVideoInfo(QByteArray text) { 326 urlMap.clear(); 327 328 #if QT_VERSION >= 0x050000 329 QUrlQuery all; 330 all.setQuery(text); 331 QByteArray fmtArray = all.queryItemValue("url_encoded_fmt_stream_map").toLatin1(); 332 #else 333 QUrl all; 334 all.setEncodedQuery(text); 335 QByteArray fmtArray = all.queryItemValue("url_encoded_fmt_stream_map").toLatin1(); 336 #endif 337 338 /* 339 qDebug("fmtArray: %s", fmtArray.constData()); 340 return; 341 */ 342 343 bool failed_to_decrypt_signature = false; 344 345 #if QT_VERSION >= 0x050000 346 QUrlQuery * q = new QUrlQuery(); 347 #endif 348 349 QList<QByteArray> codeList = fmtArray.split(','); 350 foreach(QByteArray code, codeList) { 351 code = QUrl::fromPercentEncoding(code).toLatin1(); 352 //qDebug("code: %s", code.constData()); 353 354 QUrl line; 355 #if QT_VERSION >= 0x050000 356 q->setQuery(code); 357 #else 358 QUrl * q = &line; 359 q->setEncodedQuery(code); 360 #endif 361 362 if (q->hasQueryItem("url")) { 363 QUrl url( q->queryItemValue("url") ); 364 line.setScheme(url.scheme()); 365 line.setHost(url.host()); 366 line.setPath(url.path()); 367 q->removeQueryItem("url"); 368 #if QT_VERSION >= 0x050000 369 q->setQuery( q->query(QUrl::FullyDecoded) + "&" + url.query(QUrl::FullyDecoded) ); 370 /* 371 QList < QPair < QString,QString > > l = q->queryItems(); 372 for (int n=0; n < l.count(); n++) { 373 qDebug("n: %d, %s = %s", n, l[n].first.toLatin1().constData(), l[n].second.toLatin1().constData()); 374 } 375 */ 376 #else 377 q->setEncodedQuery( q->encodedQuery() + "&" + url.encodedQuery() ); 378 /* 379 QList < QPair < QString,QString > > l = q->queryItems(); 380 for (int n=0; n < l.count(); n++) { 381 qDebug("n: %d, %s = %s", n, l[n].first.toLatin1().constData(), l[n].second.toLatin1().constData()); 382 } 383 */ 384 #endif 385 386 if (q->hasQueryItem("sig")) { 387 q->addQueryItem("signature", q->queryItemValue("sig")); 388 q->removeQueryItem("sig"); 389 } 390 else 391 if (q->hasQueryItem("s")) { 392 QString signature = YTSig::aclara(q->queryItemValue("s"), "", "aclara_f"); 393 if (!signature.isEmpty()) { 394 q->addQueryItem("signature", signature); 395 } else { 396 failed_to_decrypt_signature = true; 397 } 398 q->removeQueryItem("s"); 399 } 400 q->removeAllQueryItems("fallback_host"); 401 q->removeAllQueryItems("type"); 402 if ((q->hasQueryItem("itag")) && (q->hasQueryItem("signature"))) { 403 QString itag = q->queryItemValue("itag"); 404 q->removeAllQueryItems("itag"); // Remove duplicated itag 405 q->addQueryItem("itag", itag); 406 #if QT_VERSION >= 0x050000 407 line.setQuery(q->query(QUrl::FullyDecoded)); 408 #endif 409 urlMap[itag.toInt()] = line.toString(); 410 //qDebug("line: %s", line.toString().toLatin1().constData()); 411 } 412 } 413 } 414 415 #if QT_VERSION >= 0x050000 416 delete q; 417 #endif 418 419 qDebug("RetrieveYoutubeUrl::parseVideoInfo: url count: %d", urlMap.count()); 420 421 if ((urlMap.count() == 0) && (failed_to_decrypt_signature)) { 422 qDebug("RetrieveYoutubeUrl::parseVideoInfo: no url found with valid signature"); 423 emit signatureNotFound(url_title); 424 return; 425 } 426 427 QString p_url = findPreferredUrl(); 428 //qDebug("p_url: '%s'", p_url.toLatin1().constData()); 429 430 if (!p_url.isNull()) { 431 emit gotUrls(urlMap); 432 emit gotPreferredUrl(p_url); 433 } else { 434 emit gotEmptyList(); 435 } 436 } 437 #endif 157 438 158 439 QString RetrieveYoutubeUrl::findPreferredUrl() {
Note:
See TracChangeset
for help on using the changeset viewer.