Ignore:
Timestamp:
May 3, 2016, 5:25:45 PM (9 years ago)
Author:
Silvan Scherrer
Message:

smplayer: update trunk to version 16.4

Location:
smplayer/trunk
Files:
7 edited
4 copied

Legend:

Unmodified
Added
Removed
  • smplayer/trunk

  • smplayer/trunk/src/youtube/codedownloader.cpp

    r165 r176  
    11/*  smplayer, GUI front-end for mplayer.
    2     Copyright (C) 2006-2014 Ricardo Villalba <rvm@users.sourceforge.net>
     2    Copyright (C) 2006-2013 Ricardo Villalba <rvm@users.sourceforge.net>
    33
    44    This program is free software; you can redistribute it and/or modify
     
    113113
    114114void CodeDownloader::updateDataReadProgress(qint64 bytes_read, qint64 total_bytes) {
     115#ifndef QT_NO_DEBUG_OUTPUT
    115116        qDebug() << "CodeDownloader::updateDataReadProgress: " << bytes_read << " " << total_bytes;
     117#endif
    116118        if (total_bytes > -1) {
    117119                setMaximum(total_bytes);
  • smplayer/trunk/src/youtube/codedownloader.h

    r165 r176  
    11/*  smplayer, GUI front-end for mplayer.
    2     Copyright (C) 2006-2014 Ricardo Villalba <rvm@users.sourceforge.net>
     2    Copyright (C) 2006-2016 Ricardo Villalba <rvm@users.sourceforge.net>
    33
    44    This program is free software; you can redistribute it and/or modify
  • smplayer/trunk/src/youtube/retrieveyoutubeurl.cpp

    r170 r176  
    11/*  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>
    43
    54    This program is free software; you can redistribute it and/or modify
     
    1918
    2019#include "retrieveyoutubeurl.h"
     20#include "loadpage.h"
     21
    2122#include <QUrl>
     23#include <QDebug>
    2224#include <QRegExp>
    2325#include <QStringList>
    24 #include <QFile>
     26#include <QSslSocket>
     27
     28#ifdef YT_USE_YTSIG
    2529#include "ytsig.h"
     30#endif
    2631
    2732#if QT_VERSION >= 0x050000
     
    2934#endif
    3035
    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
     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)
    3845{
    39         reply = 0;
    4046        manager = new QNetworkAccessManager(this);
    4147
    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
    4369}
    4470
     
    4672}
    4773
     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
    48155void 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
     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);
    58171
    59172        emit connecting(QUrl(url).host());
     173};
    60174
    61175#ifdef YT_GET_VIDEOINFO
     176void RetrieveYoutubeUrl::fetchVideoInfoPage(const QString & url) {
    62177        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();
    111187                return;
    112188        }
    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 + "&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);
    149242
    150243        QRegExp rx_title(".*<title>(.*)</title>.*");
    151244        if (rx_title.indexIn(replyString) != -1) {
    152245                url_title = rx_title.cap(1).simplified();
    153                 url_title = QString(url_title).replace("&amp;","&").replace("&gt;", ">").replace("&lt;", "<").replace("&quot;","\"").replace("&#39;","'")/*.replace(" - YouTube", "")*/;
    154                 qDebug("RetrieveYoutubeUrl::parse: title '%s'", url_title.toUtf8().constData());
     246                url_title = QString(url_title).replace("&amp;","&").replace("&gt;", ">").replace("&lt;", "<").replace("&quot;","\"").replace("&#39;","'");
     247                qDebug() << "RetrieveYoutubeUrl::videoPageLoaded: title:" << url_title;
    155248        } 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");
    163257        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
     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
    167292
    168293        QString fmtArray;
     
    172297        }
    173298
    174 #ifdef YT_DASH_SUPPORT
     299        #ifdef YT_DASH_SUPPORT
    175300        QRegExp regex2("\\\"adaptive_fmts\\\"\\s*:\\s*\\\"([^\\\"]*)");
    176301        if (regex2.indexIn(replyString) != -1) {
     
    178303                fmtArray += regex2.cap(1);
    179304        }
    180 #endif
     305        #endif
    181306
    182307        fmtArray = sanitizeForUnicodePoint(fmtArray);
    183308        fmtArray.replace(QRegExp("\\\\(.)"), "\\1");
    184309
    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
     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;
    188536
    189537        #if QT_VERSION >= 0x050000
     
    191539        #endif
    192540
     541        //qDebug() << "RetrieveYoutubeUrl::extractURLs: fmtArray:" << fmtArray;
     542
    193543        QList<QByteArray> codeList = fmtArray.toLatin1().split(',');
     544        //qDebug() << "RetrieveYoutubeUrl::extractURLs: codeList.count:" << codeList.count();
     545
    194546        foreach(QByteArray code, codeList) {
    195547                code = QUrl::fromPercentEncoding(code).toLatin1();
    196                 //qDebug("code: %s", code.constData());
     548                //qDebug() << "RetrieveYoutubeUrl::extractURLs: code:" << code;
    197549
    198550                QUrl line;
     
    212564                        #if QT_VERSION >= 0x050000
    213565                        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                         */
    220566                        #else
    221567                        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                         */
    228568                        #endif
    229569
     
    234574                        else
    235575                        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;
    238579                                #else
    239                                 QString signature = YTSig::aclara(q->queryItemValue("s"));
     580                                QString player = html5_player;
    240581                                #endif
     582                                QString signature = aclara(q->queryItemValue("s"), use_player ? player : QString::null);
    241583                                if (!signature.isEmpty()) {
    242584                                        q->addQueryItem("signature", signature);
    243585                                } else {
    244                                 #ifndef YT_GET_VIDEOINFO
    245586                                        failed_to_decrypt_signature = true;
     587                                }
     588                                #else // YT_USE_SCRIPT
     589                                failed_to_decrypt_signature = true;
    246590                                #endif
    247                                 }
    248591                                q->removeQueryItem("s");
    249592                        }
     
    268611                                #endif
    269612
    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();
    273617                                }
    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();
    279620                        }
    280621                }
     
    285626        #endif
    286627
    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
     633int RetrieveYoutubeUrl::findPreferredUrl(const UrlMap & url_map, Quality q) {
    522634        // Choose a url according to preferred quality
    523635        QString p_url;
    524636        //Quality q = preferred_quality;
    525637
     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
    526646        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)
    529649                if (p_url.isNull()) q = MP4_720p;
    530650        }
    531651
    532652        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)
    535655                if (p_url.isNull()) q = WEBM_720p;
    536656        }
    537657
    538658        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)
    542662                if (p_url.isNull()) q = MP4_360p;
    543663        }
    544664
    545665        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)
    548668                if (p_url.isNull()) q = WEBM_480p;
    549669        }
    550670
    551671        if (q==WEBM_480p) {
    552                 p_url = urlMap.value(WEBM_480p, QString());
     672                SETPURL(WEBM_480p)
    553673                if (p_url.isNull()) q = WEBM_360p;
    554674        }
    555675
    556676        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)
    559679                if (p_url.isNull()) q = FLV_360p;
    560680        }
    561681
    562682        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)
    565685                if (p_url.isNull()) q = FLV_360p;
    566686        }
     
    568688        // FLV, low priority
    569689        if (q==FLV_480p) {
    570                 p_url = urlMap.value(FLV_480p, QString());
     690                SETPURL(FLV_480p)
    571691                if (p_url.isNull()) q = FLV_360p;
    572692        }
    573693
    574694        if (q==FLV_360p) {
    575                 p_url = urlMap.value(FLV_360p, QString());
     695                SETPURL(FLV_360p)
    576696                if (p_url.isNull()) q = FLV_240p;
    577697        }
    578698
    579699        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}
    608712
    609713QString RetrieveYoutubeUrl::sanitizeForUnicodePoint(QString string) {
     
    615719}
    616720
    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 }
     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
    626767
    627768#include "moc_retrieveyoutubeurl.cpp"
  • smplayer/trunk/src/youtube/retrieveyoutubeurl.h

    r170 r176  
    11/*  smplayer, GUI front-end for mplayer.
    2     Copyright (C) 2006-2013 Ricardo Villalba <rvm@users.sourceforge.net>
     2    Copyright (C) 2006-2016 Ricardo Villalba <rvm@users.sourceforge.net>
    33
    44    This program is free software; you can redistribute it and/or modify
     
    1717*/
    1818
    19 #ifndef _RETRIEVEYOUTUBEURL_
    20 #define _RETRIEVEYOUTUBEURL_
     19#ifndef RETRIEVEYOUTUBEURL_H
     20#define RETRIEVEYOUTUBEURL_H
    2121
    2222#include <QNetworkAccessManager>
    23 #include <QNetworkReply>
    2423#include <QMap>
     24#include "loadpage.h"
     25
     26#ifdef YT_USE_SIG
     27#include "sig.h"
     28#endif
     29
     30class QSettings;
    2531
    2632#define YT_GET_VIDEOINFO
    2733//#define YT_DASH_SUPPORT
     34#define YT_LIVE_STREAM
     35
     36#ifdef YT_GET_VIDEOINFO
     37#define YT_DISCARD_HTTPS
     38#endif
     39
     40typedef QMap<int,QString> UrlMap;
    2841
    2942class RetrieveYoutubeUrl : public QObject
     
    4457        ~RetrieveYoutubeUrl();
    4558
    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 
    5259        void setPreferredQuality(Quality q) { preferred_quality = q; }
    5360        Quality preferredQuality() { return preferred_quality; }
    5461
    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
    5770
    5871#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
    6073#endif
    6174
    6275        QString urlTitle() { return url_title; }
     76        QString origUrl() { return yt_url; }
     77
    6378        QString latestPreferredUrl() { return latest_preferred_url; }
    64         QString origUrl() { return orig_url; }
    6579
    6680        bool isUrlSupported(const QString & url);
    6781        QString fullUrl(const QString & url);
    6882
    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 */ };
    7392
    7493signals:
    7594        void gotUrls(const QMap<int, QString>&);
    76         void gotPreferredUrl(const QString &);
     95        //void gotPreferredUrl(const QString &);
     96        void gotPreferredUrl(const QString & url, int itag);
    7797        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
     103protected slots:
     104        void videoPageLoaded(QByteArray page);
    78105#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);
    80113#endif
    81114
    82         void connecting(QString host);
    83         void errorOcurred(int error_number, QString error_str);
     115        void processVideoPage();
    84116
    85         void signatureNotFound(const QString & title);
    86 
    87 protected slots:
    88         void gotResponse();
    89         void parse(QByteArray text);
     117protected:
     118        void fetchVideoPage(const QString & url);
    90119#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);
    94127#endif
    95128
    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
    97138        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_VIDEOINFO
    112         QString video_id;
    113 #endif
    114139
    115140private:
    116141        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;
    118173};
    119174
    120175#endif
     176
  • smplayer/trunk/src/youtube/ytsig.cpp

    r170 r176  
    11/*  smplayer, GUI front-end for mplayer.
    2     Copyright (C) 2006-2014 Ricardo Villalba <rvm@users.sourceforge.net>
     2    Copyright (C) 2006-2016 Ricardo Villalba <rvm@users.sourceforge.net>
    33
    44    This program is free software; you can redistribute it and/or modify
     
    1818
    1919#include "ytsig.h"
     20#include <QtScript>
    2021
    21 #ifdef YT_USE_SCRIPT
    22 #include <QtScript>
     22QString YTSig::script_filename;
     23
     24QString YTSig::script;
     25QString YTSig::default_script;
     26
     27QString YTSig::parsed_ts;
     28
    2329
    2430QString YTSig::aclara(const QString & text, const QString & player, const QString & function_name) {
     
    5258        }
    5359
    54         //qDebug("YTSig::aclara: function_name: %s", function_name.toLatin1().constData());
     60        //qDebug() << "YTSig::aclara: function_name:" << function_name;
    5561
    5662        QScriptValue aclarar = engine.globalObject().property(fname);
     
    6066
    6167        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;
    6369        }
    6470
     
    6773
    6874void YTSig::reloadScriptFile() {
    69         qDebug("YTSig::reloadScriptFile: %s", script_file.toUtf8().constData());
     75        qDebug() << "YTSig::reloadScriptFile:" << script_filename;
    7076
    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.";
    7379                return;
    7480        }
    7581
    76         QFile f(script_file);
     82        QFile f(script_filename);
    7783        f.open(QIODevice::ReadOnly);
    7884        QByteArray bytes = f.readAll();
     
    8793                if (rx.indexIn(bytes)) {
    8894                        QByteArray d = rx.cap(1).toLatin1();
    89                         //qDebug("YTSig::reloadScriptFile: d: %s", d.constData());
     95                        qDebug() << "YTSig::reloadScriptFile: d:" << d;
    9096                        parsed_ts = QByteArray::fromBase64(d);
    9197                }
     
    9399        }
    94100}
    95 
    96 QString YTSig::script;
    97 QString YTSig::script_file;
    98 
    99 QString YTSig::default_script;
    100 
    101 #else // YT_USE_SCRIPT
    102 
    103 #ifdef YTSIG_STATIC
    104 #include "ytsig_priv.cpp"
    105 #else
    106 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 #endif
    120 
    121 #endif // YT_USE_SCRIPT
    122101
    123102void YTSig::check(QString & u) {
     
    127106}
    128107
    129 QString YTSig::parsed_ts;
  • smplayer/trunk/src/youtube/ytsig.h

    r165 r176  
    11/*  smplayer, GUI front-end for mplayer.
    2     Copyright (C) 2006-2014 Ricardo Villalba <rvm@users.sourceforge.net>
     2    Copyright (C) 2006-2016 Ricardo Villalba <rvm@users.sourceforge.net>
    33
    44    This program is free software; you can redistribute it and/or modify
     
    2929        static void check(QString & u);
    3030
    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(); };
    3332
    3433private:
    3534        static QString script;
    3635        static QString default_script;
    37         static QString script_file;
     36        static QString script_filename;
    3837        static void reloadScriptFile();
    39 #endif
    4038
    4139private:
Note: See TracChangeset for help on using the changeset viewer.