Changeset 176 for smplayer/trunk/src/youtube
- Timestamp:
- May 3, 2016, 5:25:45 PM (9 years ago)
- Location:
- smplayer/trunk
- Files:
-
- 7 edited
- 4 copied
Legend:
- Unmodified
- Added
- Removed
-
smplayer/trunk
- Property svn:mergeinfo changed
/smplayer/vendor/current merged: 175
- Property svn:mergeinfo changed
-
smplayer/trunk/src/youtube/codedownloader.cpp
r165 r176 1 1 /* smplayer, GUI front-end for mplayer. 2 Copyright (C) 2006-201 4Ricardo Villalba <rvm@users.sourceforge.net>2 Copyright (C) 2006-2013 Ricardo Villalba <rvm@users.sourceforge.net> 3 3 4 4 This program is free software; you can redistribute it and/or modify … … 113 113 114 114 void CodeDownloader::updateDataReadProgress(qint64 bytes_read, qint64 total_bytes) { 115 #ifndef QT_NO_DEBUG_OUTPUT 115 116 qDebug() << "CodeDownloader::updateDataReadProgress: " << bytes_read << " " << total_bytes; 117 #endif 116 118 if (total_bytes > -1) { 117 119 setMaximum(total_bytes); -
smplayer/trunk/src/youtube/codedownloader.h
r165 r176 1 1 /* smplayer, GUI front-end for mplayer. 2 Copyright (C) 2006-201 4Ricardo Villalba <rvm@users.sourceforge.net>2 Copyright (C) 2006-2016 Ricardo Villalba <rvm@users.sourceforge.net> 3 3 4 4 This program is free software; you can redistribute it and/or modify -
smplayer/trunk/src/youtube/retrieveyoutubeurl.cpp
r170 r176 1 1 /* smplayer, GUI front-end for mplayer. 2 Copyright (C) 2006-2014 Ricardo Villalba <rvm@users.sourceforge.net> 3 Copyright (C) 2010 Ori Rejwan 2 Copyright (C) 2006-2016 Ricardo Villalba <rvm@users.sourceforge.net> 4 3 5 4 This program is free software; you can redistribute it and/or modify … … 19 18 20 19 #include "retrieveyoutubeurl.h" 20 #include "loadpage.h" 21 21 22 #include <QUrl> 23 #include <QDebug> 22 24 #include <QRegExp> 23 25 #include <QStringList> 24 #include <QFile> 26 #include <QSslSocket> 27 28 #ifdef YT_USE_YTSIG 25 29 #include "ytsig.h" 30 #endif 26 31 27 32 #if QT_VERSION >= 0x050000 … … 29 34 #endif 30 35 31 #define USE_PLAYER_NAME 32 33 QString RetrieveYoutubeUrl::user_agent; 34 bool RetrieveYoutubeUrl::use_https_main = false; 35 bool RetrieveYoutubeUrl::use_https_vi = false; 36 37 RetrieveYoutubeUrl::RetrieveYoutubeUrl( QObject* parent ) : QObject(parent) 36 37 RetrieveYoutubeUrl::RetrieveYoutubeUrl(QObject* parent) 38 : QObject(parent) 39 #ifdef YT_USE_SIG 40 , set(0) 41 #endif 42 , preferred_quality(MP4_360p) 43 , use_https_main(false) 44 , use_https_vi(false) 38 45 { 39 reply = 0;40 46 manager = new QNetworkAccessManager(this); 41 47 42 preferred_quality = FLV_360p; 48 dl_video_page = new LoadPage(manager, this); 49 connect(dl_video_page, SIGNAL(pageLoaded(QByteArray)), this, SLOT(videoPageLoaded(QByteArray))); 50 connect(dl_video_page, SIGNAL(errorOcurred(int, QString)), this, SIGNAL(errorOcurred(int, QString))); 51 52 #ifdef YT_GET_VIDEOINFO 53 dl_video_info_page = new LoadPage(manager, this); 54 connect(dl_video_info_page, SIGNAL(pageLoaded(QByteArray)), this, SLOT(videoInfoPageLoaded(QByteArray))); 55 connect(dl_video_info_page, SIGNAL(errorOcurred(int, QString)), this, SIGNAL(errorOcurred(int, QString))); 56 #endif 57 58 #ifdef YT_USE_SIG 59 dl_player_page = new LoadPage(manager, this); 60 connect(dl_player_page, SIGNAL(pageLoaded(QByteArray)), this, SLOT(playerPageLoaded(QByteArray))); 61 connect(dl_player_page, SIGNAL(errorOcurred(int, QString)), this, SIGNAL(errorOcurred(int, QString))); 62 #endif 63 64 #ifdef YT_LIVE_STREAM 65 dl_stream_page = new LoadPage(manager, this); 66 connect(dl_stream_page, SIGNAL(pageLoaded(QByteArray)), this, SLOT(streamPageLoaded(QByteArray))); 67 connect(dl_stream_page, SIGNAL(errorOcurred(int, QString)), this, SIGNAL(errorOcurred(int, QString))); 68 #endif 43 69 } 44 70 … … 46 72 } 47 73 74 #ifdef YT_USE_SIG 75 void RetrieveYoutubeUrl::setSettings(QSettings * settings) { 76 set = settings; 77 sig.load(set); 78 } 79 #endif 80 81 bool RetrieveYoutubeUrl::isUrlSupported(const QString & url) { 82 return (!getVideoID(url).isEmpty()); 83 } 84 85 QString RetrieveYoutubeUrl::fullUrl(const QString & url) { 86 QString r; 87 QString ID = getVideoID(url); 88 if (!ID.isEmpty()) { 89 QString scheme = use_https_main ? "https" : "http"; 90 r = scheme + "://www.youtube.com/watch?v=" + ID; 91 } 92 return r; 93 } 94 95 QString RetrieveYoutubeUrl::getVideoID(QString video_url) { 96 //qDebug() << "RetrieveYoutubeUrl::getVideoID: video_url:" << video_url; 97 98 if (video_url.contains("m.youtube.com")) { 99 video_url.replace("m.youtube.com", "www.youtube.com"); 100 } 101 102 if (video_url.startsWith("youtube.com") || video_url.startsWith("www.youtube.com") || 103 video_url.startsWith("youtu.be") || video_url.startsWith("www.youtu.be") || 104 video_url.startsWith("y2u.be") || video_url.startsWith("www.y2u.be")) 105 { 106 video_url = "http://" + video_url; 107 } 108 109 //qDebug() << "RetrieveYoutubeUrl::getVideoID: fixed url:" << video_url; 110 111 QUrl url(video_url); 112 113 QString ID; 114 115 #if QT_VERSION >= 0x050000 116 QUrlQuery * q = new QUrlQuery(url); 117 #else 118 const QUrl * q = &url; 119 #endif 120 121 /* 122 qDebug() << "host:" << url.host(); 123 qDebug() << "path:" << url.path(); 124 */ 125 126 if (url.host() == "youtu.be" || url.host() == "y2u.be") { 127 ID = url.path(); 128 if (ID.startsWith("/")) ID = ID.mid(1); 129 } 130 else 131 if ((url.host().contains("youtube")) && (url.path().contains("watch_videos"))) { 132 if (q->hasQueryItem("video_ids")) { 133 int index = 0; 134 if (q->hasQueryItem("index")) index = q->queryItemValue("index").toInt(); 135 QStringList list = q->queryItemValue("video_ids").split(","); 136 if (index < list.count()) ID = list[index]; 137 } 138 } 139 else 140 if ((url.host().contains("youtube")) && (url.path().contains("watch"))) { 141 if (q->hasQueryItem("v")) { 142 ID = q->queryItemValue("v"); 143 } 144 } 145 146 #if QT_VERSION >= 0x050000 147 delete q; 148 #endif 149 150 qDebug() << "RetrieveYoutubeUrl::getVideoID: ID:" << ID; 151 152 return ID; 153 } 154 48 155 void RetrieveYoutubeUrl::fetchPage(const QString & url) { 49 qDebug("RetrieveYoutubeUrl::fetchPage: url: %s", url.toUtf8().constData()); 50 qDebug("RetrieveYoutubeUrl::fetchPage: user agent: '%s'", user_agent.toLatin1().constData()); 51 52 QNetworkRequest req(url); 53 req.setRawHeader("User-Agent", user_agent.toLatin1()); 54 req.setRawHeader("Accept-Language", "en-us,en;q=0.5"); 55 reply = manager->get(req); 56 connect(reply, SIGNAL(finished()), this, SLOT(gotResponse())); 57 orig_url = url; 156 yt_url = url; 157 fetchVideoPage(url); 158 //fetchVideoInfoPage(url); 159 } 160 161 void RetrieveYoutubeUrl::fetchVideoPage(const QString & url) { 162 qDebug() << "RetrieveYoutubeUrl::fetchVideoPage: url:" << url; 163 164 if (url.toLower().startsWith("https") && !QSslSocket::supportsSsl()) { 165 qDebug() << "RetrieveYoutubeUrl::fetchVideoPage: no support for ssl"; 166 emit noSslSupport(); 167 return; 168 } 169 170 dl_video_page->fetchPage(url); 58 171 59 172 emit connecting(QUrl(url).host()); 173 }; 60 174 61 175 #ifdef YT_GET_VIDEOINFO 176 void RetrieveYoutubeUrl::fetchVideoInfoPage(const QString & url) { 62 177 video_id = getVideoID(url); 63 #endif 64 } 65 66 #ifdef YT_GET_VIDEOINFO 67 void RetrieveYoutubeUrl::fetchVideoInfoPage(QString url) { 68 if (url.isEmpty()) { 69 QString scheme = use_https_vi ? "https" : "http"; 70 url = QString("%2://www.youtube.com/get_video_info?el=detailpage&ps=default&eurl=&gl=US&hl=en&video_id=%1").arg(video_id).arg(scheme); 71 } 72 qDebug("RetrieveYoutubeUrl::fetchVideoInfoPage: url: %s...", url.left(20).toUtf8().constData()); 73 74 qDebug("RetrieveYoutubeUrl::fetchPage: user agent: '%s'", user_agent.toLatin1().constData()); 75 76 YTSig::check(url); 77 QNetworkRequest req(url); 78 req.setRawHeader("User-Agent", user_agent.toLatin1()); 79 req.setRawHeader("Accept-Language", "en-us,en;q=0.5"); 80 reply = manager->get(req); 81 connect(reply, SIGNAL(finished()), this, SLOT(gotVideoInfoResponse())); 82 83 emit connecting(QUrl(url).host()); 84 } 85 #endif 86 87 void RetrieveYoutubeUrl::close() { 88 if (reply) reply->abort(); 89 } 90 91 void RetrieveYoutubeUrl::gotResponse() { 92 qDebug("RetrieveYoutubeUrl::gotResponse"); 93 94 QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender()); 95 96 if (reply->error() == QNetworkReply::NoError) { 97 int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); 98 qDebug("RetrieveYoutubeUrl::gotResponse: status: %d", status); 99 switch (status) { 100 case 301: 101 case 302: 102 case 307: 103 QString r_url = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl().toString(); 104 qDebug("RetrieveYoutubeUrl::gotResponse: redirected: %s", r_url.toLatin1().constData()); 105 fetchPage(r_url); 106 return; 107 } 108 } else { 109 qDebug("RetrieveYoutubeUrl::gotResponse: error %d: '%s'", (int)reply->error(), reply->errorString().toUtf8().constData()); 110 emit errorOcurred((int)reply->error(), reply->errorString()); 178 179 QString scheme = use_https_vi ? "https" : "http"; 180 QString u = QString("%2://www.youtube.com/get_video_info?video_id=%1&el=vevo&ps=default&eurl=&gl=US&hl=en").arg(video_id).arg(scheme); 181 182 qDebug() << "RetrieveYoutubeUrl::fetchVideoInfoPage: url:" << url.left(20); 183 184 if (u.toLower().startsWith("https") && !QSslSocket::supportsSsl()) { 185 qDebug() << "RetrieveYoutubeUrl::fetchVideoInfoPage: no support for ssl"; 186 emit noSslSupport(); 111 187 return; 112 188 } 113 parse(reply->readAll()); 114 } 115 116 #ifdef YT_GET_VIDEOINFO 117 void RetrieveYoutubeUrl::gotVideoInfoResponse() { 118 qDebug("RetrieveYoutubeUrl::gotVideoInfoResponse"); 119 120 QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender()); 121 122 if (reply->error() == QNetworkReply::NoError) { 123 int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); 124 qDebug("RetrieveYoutubeUrl::gotVideoInfoResponse: status: %d", status); 125 switch (status) { 126 case 301: 127 case 302: 128 case 307: 129 QString r_url = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl().toString(); 130 //qDebug("RetrieveYoutubeUrl::gotVideoInfoResponse: redirected: %s", r_url.toLatin1().constData()); 131 fetchVideoInfoPage(r_url); 132 return; 133 } 134 } else { 135 qDebug("RetrieveYoutubeUrl::gotVideoInfoResponse: error %d: '%s'", (int)reply->error(), reply->errorString().toUtf8().constData()); 136 emit errorOcurred((int)reply->error(), reply->errorString()); 137 return; 138 } 139 parseVideoInfo(reply->readAll()); 140 } 141 #endif 142 143 void RetrieveYoutubeUrl::parse(QByteArray text) { 144 qDebug("RetrieveYoutubeUrl::parse"); 145 146 urlMap.clear(); 147 148 QString replyString = QString::fromUtf8(text); 189 190 #if defined(YT_USE_YTSIG) && !defined(YT_USE_SIG) 191 YTSig::check(u); 192 #endif 193 194 #ifdef YT_USE_SIG 195 if (!sig.sts.isEmpty()) { 196 u = u + "&sts=" + sig.sts; 197 } 198 #ifdef YT_USE_YTSIG 199 else { 200 YTSig::check(u); 201 } 202 #endif 203 #endif 204 205 dl_video_info_page->fetchPage(u); 206 207 emit connecting(QUrl(u).host()); 208 } 209 #endif 210 211 #ifdef YT_USE_SIG 212 void RetrieveYoutubeUrl::fetchPlayerPage(const QString & player_name) { 213 qDebug() << "RetrieveYoutubeUrl::fetchPlayerPage:" << player_name; 214 215 if (!player_name.isEmpty()) { 216 QString url; 217 /* 218 if (player_name.startsWith("new-")) { 219 url = QString("http://s.ytimg.com/yts/jsbin/html5player-%1/html5player-new.js").arg(player_name); 220 } else { 221 url = QString("http://s.ytimg.com/yts/jsbin/html5player-%1/html5player.js").arg(player_name); 222 } 223 */ 224 url = QString("http://s.ytimg.com/yts/jsbin/player-%1/base.js").arg(player_name); 225 qDebug() << "RetrieveYoutubeUrl::fetchPlayerPage: url:" << url; 226 dl_player_page->fetchPage(url); 227 } 228 } 229 #endif 230 231 #ifdef YT_LIVE_STREAM 232 void RetrieveYoutubeUrl::fetchStreamPage(const QString & url) { 233 qDebug() << "RetrieveYoutubeUrl::fetchStreamPage:" << url; 234 dl_stream_page->fetchPage(url); 235 } 236 #endif 237 238 void RetrieveYoutubeUrl::videoPageLoaded(QByteArray page) { 239 qDebug() << "RetrieveYoutubeUrl::videoPageLoaded"; 240 241 QString replyString = QString::fromUtf8(page); 149 242 150 243 QRegExp rx_title(".*<title>(.*)</title>.*"); 151 244 if (rx_title.indexIn(replyString) != -1) { 152 245 url_title = rx_title.cap(1).simplified(); 153 url_title = QString(url_title).replace("&","&").replace(">", ">").replace("<", "<").replace(""","\"").replace("'","'") /*.replace(" - YouTube", "")*/;154 qDebug( "RetrieveYoutubeUrl::parse: title '%s'", url_title.toUtf8().constData());246 url_title = QString(url_title).replace("&","&").replace(">", ">").replace("<", "<").replace(""","\"").replace("'","'"); 247 qDebug() << "RetrieveYoutubeUrl::videoPageLoaded: title:" << url_title; 155 248 } else { 156 url_title = "Youtube video"; 157 } 158 159 //qDebug("RetrieveYoutubeUrl::parse: replyString: %s",replyString.toLatin1().constData()); 160 161 QString player; 162 QRegExp rxplayer("html5player-([\\d,\\w,-]+)\\\\"); 249 url_title = "YouTube video"; 250 } 251 252 #ifdef YT_USE_SIG 253 QString html5_player; 254 #endif 255 //QRegExp rxplayer("player-([\\d,\\w,-]+)\\\\"); 256 QRegExp rxplayer("jsbin\\/player-([\\d\\w-]+)\\/base\\.js"); 163 257 if (rxplayer.indexIn(replyString) != -1) { 164 player = rxplayer.cap(1); 165 qDebug("RetrieveYoutubeUrl::parse: html5player: %s", player.toLatin1().constData()); 166 } 258 html5_player = rxplayer.cap(1); 259 qDebug() << "RetrieveYoutubeUrl::videoPageLoaded: html5player:" << html5_player; 260 } 261 262 video_page = replyString; 263 264 #ifdef YT_USE_SIG 265 if (!html5_player.isEmpty() && html5_player != sig.html5_player) { 266 sig.clear(); 267 sig.html5_player = html5_player; 268 fetchPlayerPage(html5_player); 269 } else { 270 processVideoPage(); 271 } 272 #else 273 processVideoPage(); 274 #endif 275 } 276 277 void RetrieveYoutubeUrl::processVideoPage() { 278 QString replyString = video_page; 279 280 #ifdef YT_LIVE_STREAM 281 QRegExp rxhlsvp("\"hlsvp\":\"([a-zA-Z0-9\\\\\\/_%\\+:\\.-]+)\""); 282 if (rxhlsvp.indexIn(replyString) != -1) { 283 QString hlsvp = QUrl::fromPercentEncoding(rxhlsvp.cap(1).toLatin1()).replace("\\/", "/"); 284 qDebug() << "RetrieveYoutubeUrl::processVideoPage: hlsvp:" << hlsvp; 285 286 if (!hlsvp.isEmpty()) { 287 fetchStreamPage(hlsvp); 288 return; 289 } 290 } 291 #endif 167 292 168 293 QString fmtArray; … … 172 297 } 173 298 174 #ifdef YT_DASH_SUPPORT299 #ifdef YT_DASH_SUPPORT 175 300 QRegExp regex2("\\\"adaptive_fmts\\\"\\s*:\\s*\\\"([^\\\"]*)"); 176 301 if (regex2.indexIn(replyString) != -1) { … … 178 303 fmtArray += regex2.cap(1); 179 304 } 180 #endif305 #endif 181 306 182 307 fmtArray = sanitizeForUnicodePoint(fmtArray); 183 308 fmtArray.replace(QRegExp("\\\\(.)"), "\\1"); 184 309 185 #ifndef YT_GET_VIDEOINFO 186 bool failed_to_decrypt_signature = false; 187 #endif 310 //qDebug() << "RetrieveYoutubeUrl::videoPageLoaded: fmtArray:" << fmtArray; 311 312 #ifdef YT_DISCARD_HTTPS 313 bool allow_https = false; 314 #else 315 bool allow_https = true; 316 #endif 317 318 UrlMap url_map = extractURLs(fmtArray, allow_https, true); 319 #ifdef YT_GET_VIDEOINFO 320 if (url_map.isEmpty()) { 321 fetchVideoInfoPage(yt_url); 322 } else { 323 finish(url_map); 324 } 325 #else 326 finish(url_map); 327 #endif 328 } 329 330 #ifdef YT_GET_VIDEOINFO 331 void RetrieveYoutubeUrl::videoInfoPageLoaded(QByteArray page) { 332 qDebug() << "RetrieveYoutubeUrl::videoInfoPageLoaded"; 333 334 #if QT_VERSION >= 0x050000 335 QUrlQuery all; 336 all.setQuery(page); 337 #else 338 QUrl all; 339 all.setEncodedQuery(page); 340 #endif 341 342 QByteArray fmtArray; 343 #if QT_VERSION >= 0x050000 344 fmtArray = all.queryItemValue("url_encoded_fmt_stream_map", QUrl::FullyDecoded).toLatin1(); 345 #else 346 fmtArray = all.queryItemValue("url_encoded_fmt_stream_map").toLatin1(); 347 #endif 348 349 #ifdef YT_DASH_SUPPORT 350 if (!fmtArray.isEmpty()) fmtArray += ","; 351 #if QT_VERSION >= 0x050000 352 fmtArray += all.queryItemValue("adaptive_fmts", QUrl::FullyDecoded).toLatin1(); 353 #else 354 fmtArray += all.queryItemValue("adaptive_fmts").toLatin1(); 355 #endif 356 #endif 357 358 //qDebug() <<"RetrieveYoutubeUrl::videoInfoPageLoaded: fmtArray:" << fmtArray; 359 360 UrlMap url_map = extractURLs(fmtArray, true, false); 361 362 if ((url_map.count() == 0) && (failed_to_decrypt_signature)) { 363 qDebug() << "RetrieveYoutubeUrl::videoInfoPageLoaded: no url found with valid signature"; 364 emit signatureNotFound(url_title); 365 return; 366 } 367 368 finish(url_map); 369 } 370 #endif 371 372 #ifdef YT_USE_SIG 373 void RetrieveYoutubeUrl::playerPageLoaded(QByteArray page) { 374 qDebug() << "RetrieveYoutubeUrl::playerPageLoaded"; 375 376 QString replyString = QString::fromUtf8(page); 377 QString signature_code = sig.findFunctions(replyString); 378 qDebug() << "RetrieveYoutubeUrl::playerPageLoaded: signature_code:" << signature_code; 379 380 if (!signature_code.isEmpty() && set) sig.save(set); 381 382 processVideoPage(); 383 } 384 #endif 385 386 #ifdef YT_LIVE_STREAM 387 void RetrieveYoutubeUrl::streamPageLoaded(QByteArray page) { 388 qDebug() << "RetrieveYoutubeUrl::streamPageLoaded"; 389 390 //qDebug() << "RetrieveYoutubeUrl::streamPageLoaded: page:" << page; 391 392 QRegExp rx("#EXT-X-STREAM-INF:.*RESOLUTION=\\d+x(\\d+)"); 393 394 QMap<int, QString> url_map; 395 int best_resolution = 0; 396 int res_height = 0; 397 398 QTextStream stream(page); 399 QString line; 400 do { 401 line = stream.readLine(); 402 if (!line.isEmpty()) { 403 //qDebug() << "RetrieveYoutubeUrl::streamPageLoaded: line:" << line; 404 if (rx.indexIn(line) != -1) { 405 res_height = rx.cap(1).toInt(); 406 qDebug() << "RetrieveYoutubeUrl::streamPageLoaded: height:" << res_height; 407 if (res_height > best_resolution) best_resolution = res_height; 408 } 409 else 410 if (!line.startsWith("#") && res_height != 0) { 411 url_map[res_height] = line; 412 res_height = 0; 413 } 414 } 415 } while (!line.isNull()); 416 417 qDebug() << "RetrieveYoutubeUrl::streamPageLoaded: best_resolution:" << best_resolution; 418 419 // Try to find a URL with the user's preferred quality 420 qDebug() << "RetrieveYoutubeUrl::streamPageLoaded: preferred_quality:" << preferred_quality; 421 422 int selected_quality = 0; 423 int q = preferred_quality; 424 425 if (q == WEBM_1080p || q == MP4_1080p) { 426 if (url_map.contains(1080)) { 427 selected_quality = 1080; 428 } else q = MP4_720p; 429 } 430 431 if (q == WEBM_720p || q == MP4_720p) { 432 if (url_map.contains(720)) { 433 selected_quality = 720; 434 } else q = WEBM_480p; 435 } 436 437 if (q == WEBM_480p || q == FLV_480p) { 438 if (url_map.contains(480)) { 439 selected_quality = 480; 440 } else q = MP4_360p; 441 } 442 443 if (q == WEBM_360p || q == FLV_360p || q == MP4_360p) { 444 if (url_map.contains(360)) { 445 selected_quality = 360; 446 } else q = FLV_240p; 447 } 448 449 if (q == FLV_240p) { 450 if (url_map.contains(240)) { 451 selected_quality = 240; 452 } 453 } 454 455 qDebug() << "RetrieveYoutubeUrl::streamPageLoaded: selected_quality:" << selected_quality; 456 457 if (selected_quality == 0) selected_quality = best_resolution; 458 459 if (url_map.contains(selected_quality)) { 460 QString p_url = url_map.value(selected_quality); 461 qDebug() << "RetrieveYoutubeUrl::streamPageLoaded: p_url:" << p_url; 462 emit gotPreferredUrl(p_url, 0); 463 latest_preferred_url = p_url; 464 } else { 465 emit gotEmptyList(); 466 } 467 } 468 #endif 469 470 void RetrieveYoutubeUrl::finish(const UrlMap & url_map) { 471 qDebug() << "RetrieveYoutubeUrl::finish"; 472 473 int itag = findPreferredUrl(url_map, preferred_quality); 474 475 QString p_url; 476 if (itag != -1) p_url = url_map[itag]; 477 qDebug() << "RetrieveYoutubeUrl::finish: p_url:" << p_url; 478 479 latest_preferred_url = p_url; 480 481 #if 0 && defined(YT_DASH_SUPPORT) 482 // Test findBestAudio 483 { 484 int itag = findBestAudio(url_map); 485 QString audio_url; 486 if (itag != -1) audio_url = url_map[itag]; 487 qDebug() << "RetrieveYoutubeUrl::finish: audio itag:" << itag; 488 qDebug() << "RetrieveYoutubeUrl::finish: audio url:" << audio_url; 489 } 490 #endif 491 492 if (!p_url.isNull()) { 493 emit gotUrls(url_map); 494 //emit gotPreferredUrl(p_url); 495 emit gotPreferredUrl(p_url, itag); 496 } else { 497 emit gotEmptyList(); 498 } 499 } 500 501 #ifdef YT_USE_SCRIPT 502 QString RetrieveYoutubeUrl::aclara(const QString & text, const QString & player) { 503 QString res; 504 505 #if defined(YT_USE_YTSIG) && !defined(YT_USE_SIG) 506 if (!player.isNull()) { 507 res = YTSig::aclara(text, player); 508 } else { 509 res = YTSig::aclara(text, "", "aclara_f"); 510 } 511 #endif 512 513 #ifdef YT_USE_SIG 514 if (!sig.decrypt_function.isEmpty()) { 515 res = sig.aclara(text); 516 } 517 #ifdef YT_USE_YTSIG 518 else { 519 if (!player.isNull()) { 520 res = YTSig::aclara(text, player); 521 } else { 522 res = YTSig::aclara(text, "", "aclara_f"); 523 } 524 } 525 #endif 526 #endif 527 528 return res; 529 } 530 #endif 531 532 UrlMap RetrieveYoutubeUrl::extractURLs(QString fmtArray, bool allow_https, bool use_player) { 533 UrlMap url_map; 534 535 failed_to_decrypt_signature = false; 188 536 189 537 #if QT_VERSION >= 0x050000 … … 191 539 #endif 192 540 541 //qDebug() << "RetrieveYoutubeUrl::extractURLs: fmtArray:" << fmtArray; 542 193 543 QList<QByteArray> codeList = fmtArray.toLatin1().split(','); 544 //qDebug() << "RetrieveYoutubeUrl::extractURLs: codeList.count:" << codeList.count(); 545 194 546 foreach(QByteArray code, codeList) { 195 547 code = QUrl::fromPercentEncoding(code).toLatin1(); 196 //qDebug( "code: %s", code.constData());548 //qDebug() << "RetrieveYoutubeUrl::extractURLs: code:" << code; 197 549 198 550 QUrl line; … … 212 564 #if QT_VERSION >= 0x050000 213 565 q->setQuery( q->query(QUrl::FullyDecoded) + "&" + url.query(QUrl::FullyDecoded) ); 214 /*215 QList < QPair < QString,QString > > l = q->queryItems();216 for (int n=0; n < l.count(); n++) {217 qDebug("n: %d, %s = %s", n, l[n].first.toLatin1().constData(), l[n].second.toLatin1().constData());218 }219 */220 566 #else 221 567 q->setEncodedQuery( q->encodedQuery() + "&" + url.encodedQuery() ); 222 /*223 QList < QPair < QString,QString > > l = q->queryItems();224 for (int n=0; n < l.count(); n++) {225 qDebug("n: %d, %s = %s", n, l[n].first.toLatin1().constData(), l[n].second.toLatin1().constData());226 }227 */228 568 #endif 229 569 … … 234 574 else 235 575 if (q->hasQueryItem("s")) { 236 #ifdef USE_PLAYER_NAME 237 QString signature = YTSig::aclara(q->queryItemValue("s"), player); 576 #ifdef YT_USE_SCRIPT 577 #ifdef YT_USE_SIG 578 QString player = sig.html5_player; 238 579 #else 239 QString signature = YTSig::aclara(q->queryItemValue("s"));580 QString player = html5_player; 240 581 #endif 582 QString signature = aclara(q->queryItemValue("s"), use_player ? player : QString::null); 241 583 if (!signature.isEmpty()) { 242 584 q->addQueryItem("signature", signature); 243 585 } else { 244 #ifndef YT_GET_VIDEOINFO245 586 failed_to_decrypt_signature = true; 587 } 588 #else // YT_USE_SCRIPT 589 failed_to_decrypt_signature = true; 246 590 #endif 247 }248 591 q->removeQueryItem("s"); 249 592 } … … 268 611 #endif 269 612 270 #ifdef YT_GET_VIDEOINFO 271 if (!line.toString().startsWith("https")) { 272 urlMap[itag.toInt()] = line.toString(); 613 if (!line.toString().startsWith("https") || allow_https) { 614 url_map[itag.toInt()] = line.toString(); 615 } else { 616 qDebug() << "RetrieveYoutubeUrl::extractURLs: discarted url with itag:" << itag.toInt(); 273 617 } 274 #else 275 urlMap[itag.toInt()] = line.toString(); 276 #endif 277 278 //qDebug("itag: %s line: %s", itag.toLatin1().constData(), line.toString().toLatin1().constData()); 618 619 //qDebug() << "RetrieveYoutubeUrl::extractURLs: itag:" << itag << "line:" << line.toString(); 279 620 } 280 621 } … … 285 626 #endif 286 627 287 qDebug("RetrieveYoutubeUrl::parse: url count: %d", urlMap.count()); 288 289 #ifndef YT_GET_VIDEOINFO 290 if ((urlMap.count() == 0) && (failed_to_decrypt_signature)) { 291 qDebug("RetrieveYoutubeUrl::parse: no url found with valid signature"); 292 emit signatureNotFound(url_title); 293 return; 294 } 295 #else 296 if (urlMap.count() == 0) { 297 qDebug("RetrieveYoutubeUrl::parse: no url found with valid signature"); 298 fetchVideoInfoPage(); 299 return; 300 } 301 #endif 302 303 QString p_url = findPreferredUrl(); 304 //qDebug("p_url: '%s'", p_url.toLatin1().constData()); 305 306 if (!p_url.isNull()) { 307 emit gotUrls(urlMap); 308 emit gotPreferredUrl(p_url); 309 #ifdef YT_GET_VIDEOINFO 310 emit gotVideoInfo(urlMap, url_title, video_id); 311 #endif 312 } else { 313 emit gotEmptyList(); 314 } 315 } 316 317 QString RetrieveYoutubeUrl::getVideoID(QString video_url) { 318 if (video_url.contains("youtu.be/")) { 319 video_url.replace("youtu.be/", "youtube.com/watch?v="); 320 } 321 else 322 if (video_url.contains("y2u.be/")) { 323 video_url.replace("y2u.be/", "youtube.com/watch?v="); 324 } 325 else 326 if (video_url.contains("m.youtube.com")) { 327 video_url.replace("m.youtube.com", "www.youtube.com"); 328 } 329 330 if ((video_url.startsWith("youtube.com")) || (video_url.startsWith("www.youtube.com"))) video_url = "http://" + video_url; 331 332 //qDebug("RetrieveYoutubeUrl::getVideoID: video_url: %s", video_url.toLatin1().constData()); 333 334 QUrl url(video_url); 335 336 QString ID; 337 338 #if QT_VERSION >= 0x050000 339 QUrlQuery * q = new QUrlQuery(url); 340 #else 341 const QUrl * q = &url; 342 #endif 343 344 if ((url.host().contains("youtube")) && (url.path().contains("watch_videos"))) { 345 if (q->hasQueryItem("video_ids")) { 346 int index = 0; 347 if (q->hasQueryItem("index")) index = q->queryItemValue("index").toInt(); 348 QStringList list = q->queryItemValue("video_ids").split(","); 349 if (index < list.count()) ID = list[index]; 350 } 351 } 352 else 353 if ((url.host().contains("youtube")) && (url.path().contains("watch"))) { 354 if (q->hasQueryItem("v")) { 355 ID = q->queryItemValue("v"); 356 } 357 } 358 359 #if QT_VERSION >= 0x050000 360 delete q; 361 #endif 362 363 //qDebug("RetrieveYoutubeUrl::getVideoID: ID: %s", ID.toLatin1().constData()); 364 365 return ID; 366 } 367 368 bool RetrieveYoutubeUrl::isUrlSupported(const QString & url) { 369 return (!getVideoID(url).isEmpty()); 370 } 371 372 QString RetrieveYoutubeUrl::fullUrl(const QString & url) { 373 QString r; 374 QString ID = getVideoID(url); 375 if (!ID.isEmpty()) { 376 QString scheme = use_https_main ? "https" : "http"; 377 r = scheme + "://www.youtube.com/watch?v=" + ID; 378 } 379 return r; 380 } 381 382 #ifdef YT_GET_VIDEOINFO 383 void RetrieveYoutubeUrl::parseVideoInfo(QByteArray text) { 384 urlMap.clear(); 385 386 #if QT_VERSION >= 0x050000 387 QUrlQuery all; 388 all.setQuery(text); 389 #else 390 QUrl all; 391 all.setEncodedQuery(text); 392 #endif 393 394 QByteArray fmtArray; 395 fmtArray = all.queryItemValue("url_encoded_fmt_stream_map").toLatin1(); 396 397 #ifdef YT_DASH_SUPPORT 398 if (!fmtArray.isEmpty()) fmtArray += ","; 399 fmtArray += all.queryItemValue("adaptive_fmts").toLatin1(); 400 #endif 401 402 /* 403 qDebug("fmtArray: %s", fmtArray.constData()); 404 return; 405 */ 406 407 bool failed_to_decrypt_signature = false; 408 409 #if QT_VERSION >= 0x050000 410 QUrlQuery * q = new QUrlQuery(); 411 #endif 412 413 QList<QByteArray> codeList = fmtArray.split(','); 414 foreach(QByteArray code, codeList) { 415 code = QUrl::fromPercentEncoding(code).toLatin1(); 416 //qDebug("code: %s", code.constData()); 417 418 QUrl line; 419 #if QT_VERSION >= 0x050000 420 q->setQuery(code); 421 #else 422 QUrl * q = &line; 423 q->setEncodedQuery(code); 424 #endif 425 426 if (q->hasQueryItem("url")) { 427 QUrl url( q->queryItemValue("url") ); 428 line.setScheme(url.scheme()); 429 line.setHost(url.host()); 430 line.setPath(url.path()); 431 q->removeQueryItem("url"); 432 #if QT_VERSION >= 0x050000 433 q->setQuery( q->query(QUrl::FullyDecoded) + "&" + url.query(QUrl::FullyDecoded) ); 434 /* 435 QList < QPair < QString,QString > > l = q->queryItems(); 436 for (int n=0; n < l.count(); n++) { 437 qDebug("n: %d, %s = %s", n, l[n].first.toLatin1().constData(), l[n].second.toLatin1().constData()); 438 } 439 */ 440 #else 441 q->setEncodedQuery( q->encodedQuery() + "&" + url.encodedQuery() ); 442 /* 443 QList < QPair < QString,QString > > l = q->queryItems(); 444 for (int n=0; n < l.count(); n++) { 445 qDebug("n: %d, %s = %s", n, l[n].first.toLatin1().constData(), l[n].second.toLatin1().constData()); 446 } 447 */ 448 #endif 449 450 if (q->hasQueryItem("sig")) { 451 q->addQueryItem("signature", q->queryItemValue("sig")); 452 q->removeQueryItem("sig"); 453 } 454 else 455 if (q->hasQueryItem("s")) { 456 QString signature = YTSig::aclara(q->queryItemValue("s"), "", "aclara_f"); 457 if (!signature.isEmpty()) { 458 q->addQueryItem("signature", signature); 459 } else { 460 failed_to_decrypt_signature = true; 461 } 462 q->removeQueryItem("s"); 463 } 464 q->removeAllQueryItems("fallback_host"); 465 q->removeAllQueryItems("type"); 466 467 if (!q->hasQueryItem("ratebypass")) q->addQueryItem("ratebypass", "yes"); 468 469 if ((q->hasQueryItem("itag")) && (q->hasQueryItem("signature"))) { 470 QString itag = q->queryItemValue("itag"); 471 472 // Remove duplicated queries 473 QPair <QString,QString> item; 474 QList<QPair<QString, QString> > items = q->queryItems(); 475 foreach(item, items) { 476 q->removeAllQueryItems(item.first); 477 q->addQueryItem(item.first, item.second); 478 } 479 480 #if QT_VERSION >= 0x050000 481 line.setQuery(q->query(QUrl::FullyDecoded)); 482 #endif 483 urlMap[itag.toInt()] = line.toString(); 484 //qDebug("itag: %s line: %s", itag.toLatin1().constData(), line.toString().toLatin1().constData()); 485 } 486 } 487 } 488 489 #if QT_VERSION >= 0x050000 490 delete q; 491 #endif 492 493 qDebug("RetrieveYoutubeUrl::parseVideoInfo: url count: %d", urlMap.count()); 494 495 if ((urlMap.count() == 0) && (failed_to_decrypt_signature)) { 496 qDebug("RetrieveYoutubeUrl::parseVideoInfo: no url found with valid signature"); 497 emit signatureNotFound(url_title); 498 return; 499 } 500 501 QString p_url = findPreferredUrl(); 502 //qDebug("p_url: '%s'", p_url.toLatin1().constData()); 503 504 if (!p_url.isNull()) { 505 emit gotUrls(urlMap); 506 emit gotPreferredUrl(p_url); 507 #ifdef YT_GET_VIDEOINFO 508 emit gotVideoInfo(urlMap, url_title, video_id); 509 #endif 510 } else { 511 emit gotEmptyList(); 512 } 513 } 514 #endif 515 516 QString RetrieveYoutubeUrl::findPreferredUrl() { 517 latest_preferred_url = findPreferredUrl(urlMap, preferred_quality); 518 return latest_preferred_url; 519 } 520 521 QString RetrieveYoutubeUrl::findPreferredUrl(const QMap<int, QString>& urlMap, Quality q) { 628 qDebug() << "RetrieveYoutubeUrl::extractURLs: url count:" << url_map.count(); 629 630 return url_map; 631 } 632 633 int RetrieveYoutubeUrl::findPreferredUrl(const UrlMap & url_map, Quality q) { 522 634 // Choose a url according to preferred quality 523 635 QString p_url; 524 636 //Quality q = preferred_quality; 525 637 638 int chosen_quality = -1; 639 640 #define SETPURL(QUALITY) { \ 641 p_url= url_map.value(QUALITY, QString()); \ 642 if (!p_url.isNull()) chosen_quality = QUALITY; \ 643 } 644 645 526 646 if (q==MP4_1080p) { 527 p_url = urlMap.value(MP4_1080p, QString());528 if (p_url.isNull()) p_url= urlMap.value(WEBM_1080p, QString());647 SETPURL(MP4_1080p) 648 if (p_url.isNull()) SETPURL(WEBM_1080p) 529 649 if (p_url.isNull()) q = MP4_720p; 530 650 } 531 651 532 652 if (q==WEBM_1080p) { 533 p_url = urlMap.value(WEBM_1080p, QString());534 if (p_url.isNull()) p_url= urlMap.value(MP4_1080p, QString());653 SETPURL(WEBM_1080p) 654 if (p_url.isNull()) SETPURL(MP4_1080p) 535 655 if (p_url.isNull()) q = WEBM_720p; 536 656 } 537 657 538 658 if (q==MP4_720p) { 539 p_url = urlMap.value(MP4_720p, QString());540 if (p_url.isNull()) p_url= urlMap.value(WEBM_720p, QString());541 if (p_url.isNull()) p_url = urlMap.value(WEBM_480p, QString());659 SETPURL(MP4_720p) 660 if (p_url.isNull()) SETPURL(WEBM_720p) 661 if (p_url.isNull()) SETPURL(WEBM_480p) 542 662 if (p_url.isNull()) q = MP4_360p; 543 663 } 544 664 545 665 if (q==WEBM_720p) { 546 p_url = urlMap.value(WEBM_720p, QString());547 if (p_url.isNull()) p_url= urlMap.value(MP4_720p, QString());666 SETPURL(WEBM_720p) 667 if (p_url.isNull()) SETPURL(MP4_720p) 548 668 if (p_url.isNull()) q = WEBM_480p; 549 669 } 550 670 551 671 if (q==WEBM_480p) { 552 p_url = urlMap.value(WEBM_480p, QString());672 SETPURL(WEBM_480p) 553 673 if (p_url.isNull()) q = WEBM_360p; 554 674 } 555 675 556 676 if (q==MP4_360p) { 557 p_url = urlMap.value(MP4_360p, QString());558 if (p_url.isNull()) p_url= urlMap.value(WEBM_360p, QString());677 SETPURL(MP4_360p) 678 if (p_url.isNull()) SETPURL(WEBM_360p) 559 679 if (p_url.isNull()) q = FLV_360p; 560 680 } 561 681 562 682 if (q==WEBM_360p) { 563 p_url = urlMap.value(WEBM_360p, QString());564 if (p_url.isNull()) p_url= urlMap.value(MP4_360p, QString());683 SETPURL(WEBM_360p) 684 if (p_url.isNull()) SETPURL(MP4_360p) 565 685 if (p_url.isNull()) q = FLV_360p; 566 686 } … … 568 688 // FLV, low priority 569 689 if (q==FLV_480p) { 570 p_url = urlMap.value(FLV_480p, QString());690 SETPURL(FLV_480p) 571 691 if (p_url.isNull()) q = FLV_360p; 572 692 } 573 693 574 694 if (q==FLV_360p) { 575 p_url = urlMap.value(FLV_360p, QString());695 SETPURL(FLV_360p) 576 696 if (p_url.isNull()) q = FLV_240p; 577 697 } 578 698 579 699 if (q==FLV_240p) { 580 p_url = urlMap.value(q, QString()); 581 } 582 583 return p_url; 584 } 585 586 #ifdef YT_DASH_SUPPORT 587 QString RetrieveYoutubeUrl::findBestAudio(const QMap<int, QString>& urlMap) { 588 QString url; 589 590 url = urlMap.value(DASH_AUDIO_MP4_256, QString()); 591 if (!url.isEmpty()) return url; 592 593 url = urlMap.value(DASH_AUDIO_WEBM_192, QString()); 594 if (!url.isEmpty()) return url; 595 596 url = urlMap.value(DASH_AUDIO_MP4_128, QString()); 597 if (!url.isEmpty()) return url; 598 599 url = urlMap.value(DASH_AUDIO_WEBM_128, QString()); 600 if (!url.isEmpty()) return url; 601 602 url = urlMap.value(DASH_AUDIO_MP4_48, QString()); 603 if (!url.isEmpty()) return url; 604 605 return url; 606 } 607 #endif 700 SETPURL(q) 701 } 702 703 // If everything fails, take the first url in the map 704 if (p_url.isEmpty()) { 705 QList<int> keys = url_map.keys(); 706 if (!keys.isEmpty()) SETPURL(keys[0]) 707 } 708 709 qDebug("RetrieveYoutubeUrl::findPreferredUrl: chosen_quality: %d", chosen_quality); 710 return chosen_quality; 711 } 608 712 609 713 QString RetrieveYoutubeUrl::sanitizeForUnicodePoint(QString string) { … … 615 719 } 616 720 617 void RetrieveYoutubeUrl::htmlDecode(QString& string) { 618 string.replace("%3A", ":", Qt::CaseInsensitive); 619 string.replace("%2F", "/", Qt::CaseInsensitive); 620 string.replace("%3F", "?", Qt::CaseInsensitive); 621 string.replace("%3D", "=", Qt::CaseInsensitive); 622 string.replace("%25", "%", Qt::CaseInsensitive); 623 string.replace("%26", "&", Qt::CaseInsensitive); 624 string.replace("%3D", "=", Qt::CaseInsensitive); 625 } 721 QString RetrieveYoutubeUrl::extensionForItag(int itag) { 722 QString ext = ".mp4"; 723 switch (itag) { 724 case RetrieveYoutubeUrl::FLV_240p: 725 case RetrieveYoutubeUrl::FLV_360p: 726 case RetrieveYoutubeUrl::FLV_480p: 727 ext = ".flv"; 728 break; 729 case RetrieveYoutubeUrl::WEBM_360p: 730 case RetrieveYoutubeUrl::WEBM_480p: 731 case RetrieveYoutubeUrl::WEBM_720p: 732 case RetrieveYoutubeUrl::WEBM_1080p: 733 ext = ".webm"; 734 break; 735 case RetrieveYoutubeUrl::DASH_AUDIO_MP4_48: 736 case RetrieveYoutubeUrl::DASH_AUDIO_MP4_128: 737 case RetrieveYoutubeUrl::DASH_AUDIO_MP4_256: 738 ext = ".m4a"; 739 break; 740 case RetrieveYoutubeUrl::DASH_AUDIO_WEBM_128: 741 case RetrieveYoutubeUrl::DASH_AUDIO_WEBM_192: 742 ext = ".webm"; 743 break; 744 } 745 746 return ext; 747 } 748 749 #ifdef YT_DASH_SUPPORT 750 int RetrieveYoutubeUrl::findBestAudio(const QMap<int, QString>& url_map) { 751 QString url; 752 753 #define CHECKAQ(QUALITY) { \ 754 url = url_map.value(QUALITY, QString()); \ 755 if (!url.isNull()) return QUALITY; \ 756 } 757 758 CHECKAQ(DASH_AUDIO_MP4_256); 759 CHECKAQ(DASH_AUDIO_WEBM_192); 760 CHECKAQ(DASH_AUDIO_MP4_128); 761 CHECKAQ(DASH_AUDIO_WEBM_128); 762 CHECKAQ(DASH_AUDIO_MP4_48); 763 764 return -1; 765 } 766 #endif 626 767 627 768 #include "moc_retrieveyoutubeurl.cpp" -
smplayer/trunk/src/youtube/retrieveyoutubeurl.h
r170 r176 1 1 /* smplayer, GUI front-end for mplayer. 2 Copyright (C) 2006-201 3Ricardo Villalba <rvm@users.sourceforge.net>2 Copyright (C) 2006-2016 Ricardo Villalba <rvm@users.sourceforge.net> 3 3 4 4 This program is free software; you can redistribute it and/or modify … … 17 17 */ 18 18 19 #ifndef _RETRIEVEYOUTUBEURL_20 #define _RETRIEVEYOUTUBEURL_19 #ifndef RETRIEVEYOUTUBEURL_H 20 #define RETRIEVEYOUTUBEURL_H 21 21 22 22 #include <QNetworkAccessManager> 23 #include <QNetworkReply>24 23 #include <QMap> 24 #include "loadpage.h" 25 26 #ifdef YT_USE_SIG 27 #include "sig.h" 28 #endif 29 30 class QSettings; 25 31 26 32 #define YT_GET_VIDEOINFO 27 33 //#define YT_DASH_SUPPORT 34 #define YT_LIVE_STREAM 35 36 #ifdef YT_GET_VIDEOINFO 37 #define YT_DISCARD_HTTPS 38 #endif 39 40 typedef QMap<int,QString> UrlMap; 28 41 29 42 class RetrieveYoutubeUrl : public QObject … … 44 57 ~RetrieveYoutubeUrl(); 45 58 46 void fetchPage(const QString & url);47 void close();48 49 static void setUserAgent(const QString & s) { user_agent = s; };50 static QString userAgent() { return user_agent; };51 52 59 void setPreferredQuality(Quality q) { preferred_quality = q; } 53 60 Quality preferredQuality() { return preferred_quality; } 54 61 55 static QString findPreferredUrl(const QMap<int, QString>& urlMap, Quality q); 56 QString findPreferredUrl(); 62 void setUserAgent(const QString & s) { LoadPage::setDefaultUserAgent(s); }; 63 QString userAgent() { return LoadPage::defaultUserAgent(); }; 64 65 void fetchPage(const QString & url); 66 67 #ifdef YT_USE_SIG 68 void setSettings(QSettings * settings); 69 #endif 57 70 58 71 #ifdef YT_DASH_SUPPORT 59 static QString findBestAudio(const QMap<int, QString>& urlMap);72 static int findBestAudio(const QMap<int, QString>& url_map); // Returns the itag 60 73 #endif 61 74 62 75 QString urlTitle() { return url_title; } 76 QString origUrl() { return yt_url; } 77 63 78 QString latestPreferredUrl() { return latest_preferred_url; } 64 QString origUrl() { return orig_url; }65 79 66 80 bool isUrlSupported(const QString & url); 67 81 QString fullUrl(const QString & url); 68 82 69 static void setUseHttpsMain(bool b) { use_https_main = b; }; 70 static void setUseHttpsVi(bool b) { use_https_vi = b; }; 71 static bool useHttpsMain() { return use_https_main; }; 72 static bool useHttpsVi() { return use_https_vi; }; 83 void setUseHttpsMain(bool b) { use_https_main = b; }; 84 void setUseHttpsVi(bool b) { use_https_vi = b; }; 85 bool useHttpsMain() { return use_https_main; }; 86 bool useHttpsVi() { return use_https_vi; }; 87 88 static int findPreferredUrl(const UrlMap & url_map, Quality q); // Returns the itag 89 static QString extensionForItag(int itag); 90 91 void close() { /* FIXME: do something */ }; 73 92 74 93 signals: 75 94 void gotUrls(const QMap<int, QString>&); 76 void gotPreferredUrl(const QString &); 95 //void gotPreferredUrl(const QString &); 96 void gotPreferredUrl(const QString & url, int itag); 77 97 void gotEmptyList(); 98 void connecting(QString host); 99 void errorOcurred(int error_number, QString error_str); 100 void signatureNotFound(const QString & title); 101 void noSslSupport(); 102 103 protected slots: 104 void videoPageLoaded(QByteArray page); 78 105 #ifdef YT_GET_VIDEOINFO 79 void gotVideoInfo(const QMap<int, QString>&, QString, QString); 106 void videoInfoPageLoaded(QByteArray page); 107 #endif 108 #ifdef YT_USE_SIG 109 void playerPageLoaded(QByteArray page); 110 #endif 111 #ifdef YT_LIVE_STREAM 112 void streamPageLoaded(QByteArray page); 80 113 #endif 81 114 82 void connecting(QString host); 83 void errorOcurred(int error_number, QString error_str); 115 void processVideoPage(); 84 116 85 void signatureNotFound(const QString & title); 86 87 protected slots: 88 void gotResponse(); 89 void parse(QByteArray text); 117 protected: 118 void fetchVideoPage(const QString & url); 90 119 #ifdef YT_GET_VIDEOINFO 91 void gotVideoInfoResponse(); 92 void parseVideoInfo(QByteArray text); 93 void fetchVideoInfoPage(QString url = QString::null); 120 void fetchVideoInfoPage(const QString & url); 121 #endif 122 #ifdef YT_USE_SIG 123 void fetchPlayerPage(const QString & player_name); 124 #endif 125 #ifdef YT_LIVE_STREAM 126 void fetchStreamPage(const QString & url); 94 127 #endif 95 128 96 protected: 129 QString getVideoID(QString video_url); 130 UrlMap extractURLs(QString fmtArray, bool allow_https, bool use_player); 131 132 void finish(const UrlMap & url_map); 133 134 #ifdef YT_USE_SCRIPT 135 QString aclara(const QString & text, const QString & player = ""); 136 #endif 137 97 138 static QString sanitizeForUnicodePoint(QString string); 98 static void htmlDecode(QString& string);99 QString getVideoID(QString video_url);100 101 QMap<int, QString> urlMap;102 QString url_title;103 QString orig_url;104 QString latest_preferred_url;105 106 Quality preferred_quality;107 static QString user_agent;108 static bool use_https_main;109 static bool use_https_vi;110 111 #ifdef YT_GET_VIDEOINFO112 QString video_id;113 #endif114 139 115 140 private: 116 141 QNetworkAccessManager* manager; 117 QNetworkReply* reply; 142 LoadPage * dl_video_page; 143 144 #ifdef YT_GET_VIDEOINFO 145 LoadPage * dl_video_info_page; 146 #endif 147 148 #ifdef YT_USE_SIG 149 LoadPage * dl_player_page; 150 Sig sig; 151 QSettings * set; 152 #else 153 QString html5_player; 154 #endif 155 156 #ifdef YT_LIVE_STREAM 157 LoadPage * dl_stream_page; 158 #endif 159 160 QString video_page; 161 QString url_title; 162 163 Quality preferred_quality; 164 bool use_https_main; 165 bool use_https_vi; 166 167 QString yt_url; 168 QString video_id; 169 170 QString latest_preferred_url; 171 172 bool failed_to_decrypt_signature; 118 173 }; 119 174 120 175 #endif 176 -
smplayer/trunk/src/youtube/ytsig.cpp
r170 r176 1 1 /* smplayer, GUI front-end for mplayer. 2 Copyright (C) 2006-201 4Ricardo Villalba <rvm@users.sourceforge.net>2 Copyright (C) 2006-2016 Ricardo Villalba <rvm@users.sourceforge.net> 3 3 4 4 This program is free software; you can redistribute it and/or modify … … 18 18 19 19 #include "ytsig.h" 20 #include <QtScript> 20 21 21 #ifdef YT_USE_SCRIPT 22 #include <QtScript> 22 QString YTSig::script_filename; 23 24 QString YTSig::script; 25 QString YTSig::default_script; 26 27 QString YTSig::parsed_ts; 28 23 29 24 30 QString YTSig::aclara(const QString & text, const QString & player, const QString & function_name) { … … 52 58 } 53 59 54 //qDebug( "YTSig::aclara: function_name: %s", function_name.toLatin1().constData());60 //qDebug() << "YTSig::aclara: function_name:" << function_name; 55 61 56 62 QScriptValue aclarar = engine.globalObject().property(fname); … … 60 66 61 67 if (res.isEmpty()) { 62 qDebug( "YTSig::aclara: signature length not supported: %d: %s", text.size(), text.toLatin1().constData());68 qDebug() << "YTSig::aclara: signature length not supported:" << text.size() << ":" << text; 63 69 } 64 70 … … 67 73 68 74 void YTSig::reloadScriptFile() { 69 qDebug( "YTSig::reloadScriptFile: %s", script_file.toUtf8().constData());75 qDebug() << "YTSig::reloadScriptFile:" << script_filename; 70 76 71 if (!QFile::exists(script_file )) {72 qDebug( "YTSig::reloadScriptFile: file doesn't exist.");77 if (!QFile::exists(script_filename)) { 78 qDebug() << "YTSig::reloadScriptFile: file doesn't exist."; 73 79 return; 74 80 } 75 81 76 QFile f(script_file );82 QFile f(script_filename); 77 83 f.open(QIODevice::ReadOnly); 78 84 QByteArray bytes = f.readAll(); … … 87 93 if (rx.indexIn(bytes)) { 88 94 QByteArray d = rx.cap(1).toLatin1(); 89 //qDebug("YTSig::reloadScriptFile: d: %s", d.constData());95 qDebug() << "YTSig::reloadScriptFile: d:" << d; 90 96 parsed_ts = QByteArray::fromBase64(d); 91 97 } … … 93 99 } 94 100 } 95 96 QString YTSig::script;97 QString YTSig::script_file;98 99 QString YTSig::default_script;100 101 #else // YT_USE_SCRIPT102 103 #ifdef YTSIG_STATIC104 #include "ytsig_priv.cpp"105 #else106 QString YTSig::aclara(const QString & text, const QString & player, const QString & function_name) {107 QString res;108 109 int dot = text.indexOf('.');110 qDebug("YTSig::aclara (2): length: %d (%d.%d)", text.size(), dot, text.size()-dot-1);111 112 /*113 qDebug("%d: orig: %s", text.size(), text.toLatin1().constData());114 qDebug("%d: conv: %s", text.size(), res.toLatin1().constData());115 */116 117 return res;118 }119 #endif120 121 #endif // YT_USE_SCRIPT122 101 123 102 void YTSig::check(QString & u) { … … 127 106 } 128 107 129 QString YTSig::parsed_ts; -
smplayer/trunk/src/youtube/ytsig.h
r165 r176 1 1 /* smplayer, GUI front-end for mplayer. 2 Copyright (C) 2006-201 4Ricardo Villalba <rvm@users.sourceforge.net>2 Copyright (C) 2006-2016 Ricardo Villalba <rvm@users.sourceforge.net> 3 3 4 4 This program is free software; you can redistribute it and/or modify … … 29 29 static void check(QString & u); 30 30 31 #ifdef YT_USE_SCRIPT 32 static void setScriptFile(const QString & f) { script_file = f; reloadScriptFile(); }; 31 static void setScriptFile(const QString & f) { script_filename = f; reloadScriptFile(); }; 33 32 34 33 private: 35 34 static QString script; 36 35 static QString default_script; 37 static QString script_file ;36 static QString script_filename; 38 37 static void reloadScriptFile(); 39 #endif40 38 41 39 private:
Note:
See TracChangeset
for help on using the changeset viewer.