source: smplayer/trunk/src/youtube/retrieveyoutubeurl.cpp

Last change on this file was 188, checked in by Silvan Scherrer, 8 years ago

SMPlayer: update trunk to version 17.1.0

File size: 19.9 KB
Line 
1/* smplayer, GUI front-end for mplayer.
2 Copyright (C) 2006-2017 Ricardo Villalba <rvm@users.sourceforge.net>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17*/
18
19#include "retrieveyoutubeurl.h"
20#include "loadpage.h"
21
22#include <QUrl>
23#include <QDebug>
24#include <QRegExp>
25#include <QStringList>
26#include <QSslSocket>
27
28#ifdef YT_USE_YTSIG
29#include "ytsig.h"
30#endif
31
32#if QT_VERSION >= 0x050000
33#include <QUrlQuery>
34#endif
35
36
37RetrieveYoutubeUrl::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)
45{
46 manager = new QNetworkAccessManager(this);
47
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
69}
70
71RetrieveYoutubeUrl::~RetrieveYoutubeUrl() {
72}
73
74#ifdef YT_USE_SIG
75void RetrieveYoutubeUrl::setSettings(QSettings * settings) {
76 set = settings;
77 sig.load(set);
78}
79#endif
80
81bool RetrieveYoutubeUrl::isUrlSupported(const QString & url) {
82 return (!getVideoID(url).isEmpty());
83}
84
85QString 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
95QString 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
155void RetrieveYoutubeUrl::fetchPage(const QString & url) {
156 yt_url = url;
157 fetchVideoPage(url);
158 //fetchVideoInfoPage(url);
159}
160
161void 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);
171
172 emit connecting(QUrl(url).host());
173};
174
175#ifdef YT_GET_VIDEOINFO
176void RetrieveYoutubeUrl::fetchVideoInfoPage(const QString & url) {
177 video_id = getVideoID(url);
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();
187 return;
188 }
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 + "&amp;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
212void 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
232void RetrieveYoutubeUrl::fetchStreamPage(const QString & url) {
233 qDebug() << "RetrieveYoutubeUrl::fetchStreamPage:" << url;
234 dl_stream_page->fetchPage(url);
235}
236#endif
237
238void RetrieveYoutubeUrl::videoPageLoaded(QByteArray page) {
239 qDebug() << "RetrieveYoutubeUrl::videoPageLoaded";
240
241 QString replyString = QString::fromUtf8(page);
242
243 QRegExp rx_title(".*<title>(.*)</title>.*");
244 if (rx_title.indexIn(replyString) != -1) {
245 url_title = rx_title.cap(1).simplified();
246 url_title = QString(url_title).replace("&amp;","&").replace("&gt;", ">").replace("&lt;", "<").replace("&quot;","\"").replace("&#39;","'");
247 qDebug() << "RetrieveYoutubeUrl::videoPageLoaded: title:" << url_title;
248 } else {
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");
257 if (rxplayer.indexIn(replyString) != -1) {
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
277void 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
292
293 QString fmtArray;
294 QRegExp regex("\\\"url_encoded_fmt_stream_map\\\"\\s*:\\s*\\\"([^\\\"]*)");
295 if (regex.indexIn(replyString) != -1) {
296 fmtArray = regex.cap(1);
297 }
298
299 #ifdef YT_DASH_SUPPORT
300 QRegExp regex2("\\\"adaptive_fmts\\\"\\s*:\\s*\\\"([^\\\"]*)");
301 if (regex2.indexIn(replyString) != -1) {
302 if (!fmtArray.isEmpty()) fmtArray += ",";
303 fmtArray += regex2.cap(1);
304 }
305 #endif
306
307 fmtArray = sanitizeForUnicodePoint(fmtArray);
308 fmtArray.replace(QRegExp("\\\\(.)"), "\\1");
309
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
331void 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
373void 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
387void 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
470void 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
502QString 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
532UrlMap RetrieveYoutubeUrl::extractURLs(QString fmtArray, bool allow_https, bool use_player) {
533 UrlMap url_map;
534
535 failed_to_decrypt_signature = false;
536
537 #if QT_VERSION >= 0x050000
538 QUrlQuery * q = new QUrlQuery();
539 #endif
540
541 //qDebug() << "RetrieveYoutubeUrl::extractURLs: fmtArray:" << fmtArray;
542
543 QList<QByteArray> codeList = fmtArray.toLatin1().split(',');
544 //qDebug() << "RetrieveYoutubeUrl::extractURLs: codeList.count:" << codeList.count();
545
546 foreach(QByteArray code, codeList) {
547 code = QUrl::fromPercentEncoding(code).toLatin1();
548 //qDebug() << "RetrieveYoutubeUrl::extractURLs: code:" << code;
549
550 QUrl line;
551 #if QT_VERSION >= 0x050000
552 q->setQuery(code);
553 #else
554 QUrl * q = &line;
555 q->setEncodedQuery(code);
556 #endif
557
558 if (q->hasQueryItem("url")) {
559 QUrl url( q->queryItemValue("url") );
560 line.setScheme(url.scheme());
561 line.setHost(url.host());
562 line.setPath(url.path());
563 q->removeQueryItem("url");
564 #if QT_VERSION >= 0x050000
565 q->setQuery( q->query(QUrl::FullyDecoded) + "&" + url.query(QUrl::FullyDecoded) );
566 #else
567 q->setEncodedQuery( q->encodedQuery() + "&" + url.encodedQuery() );
568 #endif
569
570 if (q->hasQueryItem("sig")) {
571 q->addQueryItem("signature", q->queryItemValue("sig"));
572 q->removeQueryItem("sig");
573 }
574 else
575 if (q->hasQueryItem("s")) {
576 #ifdef YT_USE_SCRIPT
577 #ifdef YT_USE_SIG
578 QString player = sig.html5_player;
579 #else
580 QString player = html5_player;
581 #endif
582 QString signature = aclara(q->queryItemValue("s"), use_player ? player : QString::null);
583 if (!signature.isEmpty()) {
584 q->addQueryItem("signature", signature);
585 } else {
586 failed_to_decrypt_signature = true;
587 }
588 #else // YT_USE_SCRIPT
589 failed_to_decrypt_signature = true;
590 #endif
591 q->removeQueryItem("s");
592 }
593 q->removeAllQueryItems("fallback_host");
594 q->removeAllQueryItems("type");
595
596 if (!q->hasQueryItem("ratebypass")) q->addQueryItem("ratebypass", "yes");
597
598 if ((q->hasQueryItem("itag")) && (q->hasQueryItem("signature"))) {
599 QString itag = q->queryItemValue("itag");
600
601 // Remove duplicated queries
602 QPair <QString,QString> item;
603 QList<QPair<QString, QString> > items = q->queryItems();
604 foreach(item, items) {
605 q->removeAllQueryItems(item.first);
606 q->addQueryItem(item.first, item.second);
607 }
608
609 #if QT_VERSION >= 0x050000
610 line.setQuery(q->query(QUrl::FullyDecoded));
611 #endif
612
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();
617 }
618
619 //qDebug() << "RetrieveYoutubeUrl::extractURLs: itag:" << itag << "line:" << line.toString();
620 }
621 }
622 }
623
624 #if QT_VERSION >= 0x050000
625 delete q;
626 #endif
627
628 qDebug() << "RetrieveYoutubeUrl::extractURLs: url count:" << url_map.count();
629
630 return url_map;
631}
632
633int RetrieveYoutubeUrl::findPreferredUrl(const UrlMap & url_map, Quality q) {
634 // Choose a url according to preferred quality
635 QString p_url;
636 //Quality q = preferred_quality;
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
646 if (q==MP4_1080p) {
647 SETPURL(MP4_1080p)
648 if (p_url.isNull()) SETPURL(WEBM_1080p)
649 if (p_url.isNull()) q = MP4_720p;
650 }
651
652 if (q==WEBM_1080p) {
653 SETPURL(WEBM_1080p)
654 if (p_url.isNull()) SETPURL(MP4_1080p)
655 if (p_url.isNull()) q = WEBM_720p;
656 }
657
658 if (q==MP4_720p) {
659 SETPURL(MP4_720p)
660 if (p_url.isNull()) SETPURL(WEBM_720p)
661 if (p_url.isNull()) SETPURL(WEBM_480p)
662 if (p_url.isNull()) q = MP4_360p;
663 }
664
665 if (q==WEBM_720p) {
666 SETPURL(WEBM_720p)
667 if (p_url.isNull()) SETPURL(MP4_720p)
668 if (p_url.isNull()) q = WEBM_480p;
669 }
670
671 if (q==WEBM_480p) {
672 SETPURL(WEBM_480p)
673 if (p_url.isNull()) q = WEBM_360p;
674 }
675
676 if (q==MP4_360p) {
677 SETPURL(MP4_360p)
678 if (p_url.isNull()) SETPURL(WEBM_360p)
679 if (p_url.isNull()) q = FLV_360p;
680 }
681
682 if (q==WEBM_360p) {
683 SETPURL(WEBM_360p)
684 if (p_url.isNull()) SETPURL(MP4_360p)
685 if (p_url.isNull()) q = FLV_360p;
686 }
687
688 // FLV, low priority
689 if (q==FLV_480p) {
690 SETPURL(FLV_480p)
691 if (p_url.isNull()) q = FLV_360p;
692 }
693
694 if (q==FLV_360p) {
695 SETPURL(FLV_360p)
696 if (p_url.isNull()) q = FLV_240p;
697 }
698
699 if (q==FLV_240p) {
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}
712
713QString RetrieveYoutubeUrl::sanitizeForUnicodePoint(QString string) {
714 QRegExp rx("\\\\u(\\d{4})");
715 while (rx.indexIn(string) != -1) {
716 string.replace(rx.cap(0), QString(QChar(rx.cap(1).toInt(0,16))));
717 }
718 return string;
719}
720
721QString 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
750int 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
767
768#include "moc_retrieveyoutubeurl.cpp"
Note: See TracBrowser for help on using the repository browser.