Ignore:
Timestamp:
May 16, 2014, 9:51:55 AM (11 years ago)
Author:
Silvan Scherrer
Message:

SMPlayer: update trunk to latest 0.8.7

Location:
smplayer/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • smplayer/trunk

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

    r156 r165  
    11/*  smplayer, GUI front-end for mplayer.
    2     Copyright (C) 2006-2013 Ricardo Villalba <rvm@users.sourceforge.net>
     2    Copyright (C) 2006-2014 Ricardo Villalba <rvm@users.sourceforge.net>
    33    Copyright (C) 2010 Ori Rejwan
    44
     
    2525#include "ytsig.h"
    2626
     27#if QT_VERSION >= 0x050000
     28#include <QUrlQuery>
     29#endif
     30
     31#define USE_PLAYER_NAME
     32
     33QString RetrieveYoutubeUrl::user_agent;
     34
    2735RetrieveYoutubeUrl::RetrieveYoutubeUrl( QObject* parent ) : QObject(parent)
    2836{
    2937        reply = 0;
    3038        manager = new QNetworkAccessManager(this);
    31         connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(gotResponse(QNetworkReply*)));
    3239
    3340        preferred_quality = FLV_360p;
    34         user_agent = "Mozilla/5.0 (X11; Linux x86_64; rv:5.0.1) Gecko/20100101 Firefox/5.0.1";
    3541}
    3642
     
    3945
    4046void RetrieveYoutubeUrl::fetchPage(const QString & url) {
     47        QString agent = user_agent;
     48        if (agent.isEmpty()) agent = "Mozilla/5.0 (X11; Linux x86_64; rv:5.0.1) Gecko/20100101 Firefox/5.0.1";
     49        qDebug("RetrieveYoutubeUrl::fetchPage: user agent: %s", agent.toLatin1().constData());
     50
     51        QNetworkRequest req(url);
     52        req.setRawHeader("User-Agent", agent.toLatin1());
     53        reply = manager->get(req);
     54        connect(reply, SIGNAL(finished()), this, SLOT(gotResponse()));
     55        orig_url = url;
     56
     57        emit connecting(QUrl(url).host());
     58
     59#ifdef YT_GET_VIDEOINFO
     60        video_id = getVideoID(url);
     61#endif
     62}
     63
     64#ifdef YT_GET_VIDEOINFO
     65void RetrieveYoutubeUrl::fetchVideoInfoPage() {
     66        QString url = QString("http://www.youtube.com/get_video_info?el=detailpage&ps=default&eurl=&gl=US&hl=en&video_id=%1").arg(video_id);
     67        //qDebug("RetrieveYoutubeUrl::fetchVideoInfoPage: url: %s", url.toUtf8().constData());
     68
     69        YTSig::check(url);
    4170        QNetworkRequest req(url);
    4271        req.setRawHeader("User-Agent", user_agent.toLatin1());
    4372        reply = manager->get(req);
    44         orig_url = url;
    45 
    46         emit connecting(url);
    47 }
     73        connect(reply, SIGNAL(finished()), this, SLOT(gotVideoInfoResponse()));
     74
     75        emit connecting(QUrl(url).host());
     76}
     77#endif
    4878
    4979void RetrieveYoutubeUrl::close() {
     
    5181}
    5282
    53 void RetrieveYoutubeUrl::gotResponse(QNetworkReply* reply) {
     83void RetrieveYoutubeUrl::gotResponse() {
     84        QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
     85
    5486        if (reply->error() == QNetworkReply::NoError) {
    5587                int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
     
    71103}
    72104
     105#ifdef YT_GET_VIDEOINFO
     106void RetrieveYoutubeUrl::gotVideoInfoResponse() {
     107        qDebug("RetrieveYoutubeUrl::gotVideoInfoResponse");
     108
     109        QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
     110
     111        if (reply->error() != QNetworkReply::NoError) {
     112                emit errorOcurred((int)reply->error(), reply->errorString());
     113                return;
     114        }
     115        parseVideoInfo(reply->readAll());
     116}
     117#endif
     118
    73119void RetrieveYoutubeUrl::parse(QByteArray text) {
    74120        qDebug("RetrieveYoutubeUrl::parse");
     
    87133        }
    88134
     135        //qDebug("RetrieveYoutubeUrl::parse: replyString: %s",replyString.toLatin1().constData());
     136
     137        QString player;
     138        QRegExp rxplayer("html5player-([\\d,\\w,-]+)\\.js");
     139        if (rxplayer.indexIn(replyString) != -1) {
     140                player = rxplayer.cap(1);
     141                qDebug("RetrieveYoutubeUrl::parse: html5player: %s", player.toLatin1().constData());
     142        }
     143
    89144        QRegExp regex("\\\"url_encoded_fmt_stream_map\\\"\\s*:\\s*\\\"([^\\\"]*)");
    90145        regex.indexIn(replyString);
     
    93148        fmtArray.replace(QRegExp("\\\\(.)"), "\\1");
    94149
    95         bool signature_not_found = false;
     150#ifndef YT_GET_VIDEOINFO
     151        bool failed_to_decrypt_signature = false;
     152#endif
     153
     154        #if QT_VERSION >= 0x050000
     155        QUrlQuery * q = new QUrlQuery();
     156        #endif
    96157
    97158        QList<QByteArray> codeList = fmtArray.toLatin1().split(',');
     
    101162
    102163                QUrl line;
    103                 line.setEncodedQuery(code);
    104 
    105                 if (line.hasQueryItem("url")) {
    106                         QUrl url( line.queryItemValue("url") );
     164                #if QT_VERSION >= 0x050000
     165                q->setQuery(code);
     166                #else
     167                QUrl * q = &line;
     168                q->setEncodedQuery(code);
     169                #endif
     170
     171                if (q->hasQueryItem("url")) {
     172                        QUrl url( q->queryItemValue("url") );
    107173                        line.setScheme(url.scheme());
    108174                        line.setHost(url.host());
    109175                        line.setPath(url.path());
    110                         line.setEncodedQuery( line.encodedQuery() + "&" + url.encodedQuery() );
    111                         line.removeQueryItem("url");
    112 
    113                         if (line.hasQueryItem("sig")) {
    114                                 line.addQueryItem("signature", line.queryItemValue("sig"));
    115                                 line.removeQueryItem("sig");
     176                        q->removeQueryItem("url");
     177                        #if QT_VERSION >= 0x050000
     178                        q->setQuery( q->query(QUrl::FullyDecoded) + "&" + url.query(QUrl::FullyDecoded) );
     179                        /*
     180                        QList < QPair < QString,QString > > l = q->queryItems();
     181                        for (int n=0; n < l.count(); n++) {
     182                                qDebug("n: %d, %s = %s", n, l[n].first.toLatin1().constData(), l[n].second.toLatin1().constData());
     183                        }
     184                        */
     185                        #else
     186                        q->setEncodedQuery( q->encodedQuery() + "&" + url.encodedQuery() );
     187                        /*
     188                        QList < QPair < QString,QString > > l = q->queryItems();
     189                        for (int n=0; n < l.count(); n++) {
     190                                qDebug("n: %d, %s = %s", n, l[n].first.toLatin1().constData(), l[n].second.toLatin1().constData());
     191                        }
     192                        */
     193                        #endif
     194
     195                        if (q->hasQueryItem("sig")) {
     196                                q->addQueryItem("signature", q->queryItemValue("sig"));
     197                                q->removeQueryItem("sig");
    116198                        }
    117199                        else
    118                         if (line.hasQueryItem("s")) {
    119                                 QString signature = YTSig::aclara(line.queryItemValue("s"));
     200                        if (q->hasQueryItem("s")) {
     201                                #ifdef USE_PLAYER_NAME
     202                                QString signature = YTSig::aclara(q->queryItemValue("s"), player);
     203                                #else
     204                                QString signature = YTSig::aclara(q->queryItemValue("s"));
     205                                #endif
    120206                                if (!signature.isEmpty()) {
    121                                         line.addQueryItem("signature", signature);
     207                                        q->addQueryItem("signature", signature);
    122208                                } else {
    123                                         signature_not_found = true;
     209                                #ifndef YT_GET_VIDEOINFO
     210                                        failed_to_decrypt_signature = true;
     211                                #endif
    124212                                }
    125                                 line.removeQueryItem("s");
    126                         }
    127                         line.removeAllQueryItems("fallback_host");
    128                         line.removeAllQueryItems("type");
    129                         if ((line.hasQueryItem("itag")) && (line.hasQueryItem("signature"))) {
    130                                 QString itag = line.queryItemValue("itag");
    131                                 line.removeAllQueryItems("itag"); // Remove duplicated itag
    132                                 line.addQueryItem("itag", itag);
     213                                q->removeQueryItem("s");
     214                        }
     215                        q->removeAllQueryItems("fallback_host");
     216                        q->removeAllQueryItems("type");
     217
     218                        if ((q->hasQueryItem("itag")) && (q->hasQueryItem("signature"))) {
     219                                QString itag = q->queryItemValue("itag");
     220                                q->removeAllQueryItems("itag"); // Remove duplicated itag
     221                                q->addQueryItem("itag", itag);
     222                                #if QT_VERSION >= 0x050000
     223                                line.setQuery(q->query(QUrl::FullyDecoded));
     224                                #endif
    133225                                urlMap[itag.toInt()] = line.toString();
    134226                                //qDebug("line: %s", line.toString().toLatin1().constData());
     
    137229        }
    138230
     231        #if QT_VERSION >= 0x050000
     232        delete q;
     233        #endif
     234
    139235        qDebug("RetrieveYoutubeUrl::parse: url count: %d", urlMap.count());
    140236
    141         if ((urlMap.count() == 0) && (signature_not_found)) {
     237#ifndef YT_GET_VIDEOINFO
     238        if ((urlMap.count() == 0) && (failed_to_decrypt_signature)) {
    142239                qDebug("RetrieveYoutubeUrl::parse: no url found with valid signature");
    143240                emit signatureNotFound(url_title);
    144241                return;
    145242        }
     243#else
     244        if (urlMap.count() == 0) {
     245                qDebug("RetrieveYoutubeUrl::parse: no url found with valid signature");
     246                fetchVideoInfoPage();
     247                return;
     248        }
     249#endif
    146250
    147251        QString p_url = findPreferredUrl();
     
    155259        }
    156260}
     261
     262QString RetrieveYoutubeUrl::getVideoID(QString video_url) {
     263        if (video_url.contains("youtu.be/")) {
     264                video_url.replace("youtu.be/", "youtube.com/watch?v=");
     265        }
     266        else
     267        if (video_url.contains("y2u.be/")) {
     268                video_url.replace("y2u.be/", "youtube.com/watch?v=");
     269        }
     270        else
     271        if (video_url.contains("m.youtube.com")) {
     272                video_url.replace("m.youtube.com", "www.youtube.com");
     273        }
     274
     275        if ((video_url.startsWith("youtube.com")) || (video_url.startsWith("www.youtube.com"))) video_url = "http://" + video_url;
     276
     277        //qDebug("RetrieveYoutubeUrl::getVideoID: video_url: %s", video_url.toLatin1().constData());
     278
     279        QUrl url(video_url);
     280
     281        QString ID;
     282
     283#if QT_VERSION >= 0x050000
     284        QUrlQuery * q = new QUrlQuery(url);
     285#else
     286        const QUrl * q = &url;
     287#endif
     288
     289        if ((url.host().contains("youtube")) && (url.path().contains("watch_videos"))) {
     290                if (q->hasQueryItem("video_ids")) {
     291                        int index = 0;
     292                        if (q->hasQueryItem("index")) index = q->queryItemValue("index").toInt();
     293                        QStringList list = q->queryItemValue("video_ids").split(",");
     294                        if (index < list.count()) ID = list[index];
     295                }
     296        }
     297        else
     298        if ((url.host().contains("youtube")) && (url.path().contains("watch"))) {
     299                if (q->hasQueryItem("v")) {
     300                        ID = q->queryItemValue("v");
     301                }
     302        }
     303
     304#if QT_VERSION >= 0x050000
     305        delete q;
     306#endif
     307
     308        //qDebug("RetrieveYoutubeUrl::getVideoID: ID: %s", ID.toLatin1().constData());
     309
     310        return ID;
     311}
     312
     313bool RetrieveYoutubeUrl::isUrlSupported(const QString & url) {
     314        return (!getVideoID(url).isEmpty());
     315}
     316
     317QString RetrieveYoutubeUrl::fullUrl(const QString & url) {
     318        QString r;
     319        QString ID = getVideoID(url);
     320        if (!ID.isEmpty()) r = "http://www.youtube.com/watch?v=" + ID;
     321        return r;
     322}
     323
     324#ifdef YT_GET_VIDEOINFO
     325void RetrieveYoutubeUrl::parseVideoInfo(QByteArray text) {
     326        urlMap.clear();
     327
     328        #if QT_VERSION >= 0x050000
     329        QUrlQuery all;
     330        all.setQuery(text);
     331        QByteArray fmtArray = all.queryItemValue("url_encoded_fmt_stream_map").toLatin1();
     332        #else
     333        QUrl all;
     334        all.setEncodedQuery(text);
     335        QByteArray fmtArray = all.queryItemValue("url_encoded_fmt_stream_map").toLatin1();
     336        #endif
     337
     338        /*
     339        qDebug("fmtArray: %s", fmtArray.constData());
     340        return;
     341        */
     342
     343        bool failed_to_decrypt_signature = false;
     344
     345        #if QT_VERSION >= 0x050000
     346        QUrlQuery * q = new QUrlQuery();
     347        #endif
     348
     349        QList<QByteArray> codeList = fmtArray.split(',');
     350        foreach(QByteArray code, codeList) {
     351                code = QUrl::fromPercentEncoding(code).toLatin1();
     352                //qDebug("code: %s", code.constData());
     353
     354                QUrl line;
     355                #if QT_VERSION >= 0x050000
     356                q->setQuery(code);
     357                #else
     358                QUrl * q = &line;
     359                q->setEncodedQuery(code);
     360                #endif
     361
     362                if (q->hasQueryItem("url")) {
     363                        QUrl url( q->queryItemValue("url") );
     364                        line.setScheme(url.scheme());
     365                        line.setHost(url.host());
     366                        line.setPath(url.path());
     367                        q->removeQueryItem("url");
     368                        #if QT_VERSION >= 0x050000
     369                        q->setQuery( q->query(QUrl::FullyDecoded) + "&" + url.query(QUrl::FullyDecoded) );
     370                        /*
     371                        QList < QPair < QString,QString > > l = q->queryItems();
     372                        for (int n=0; n < l.count(); n++) {
     373                                qDebug("n: %d, %s = %s", n, l[n].first.toLatin1().constData(), l[n].second.toLatin1().constData());
     374                        }
     375                        */
     376                        #else
     377                        q->setEncodedQuery( q->encodedQuery() + "&" + url.encodedQuery() );
     378                        /*
     379                        QList < QPair < QString,QString > > l = q->queryItems();
     380                        for (int n=0; n < l.count(); n++) {
     381                                qDebug("n: %d, %s = %s", n, l[n].first.toLatin1().constData(), l[n].second.toLatin1().constData());
     382                        }
     383                        */
     384                        #endif
     385
     386                        if (q->hasQueryItem("sig")) {
     387                                q->addQueryItem("signature", q->queryItemValue("sig"));
     388                                q->removeQueryItem("sig");
     389                        }
     390                        else
     391                        if (q->hasQueryItem("s")) {
     392                                QString signature = YTSig::aclara(q->queryItemValue("s"), "", "aclara_f");
     393                                if (!signature.isEmpty()) {
     394                                        q->addQueryItem("signature", signature);
     395                                } else {
     396                                        failed_to_decrypt_signature = true;
     397                                }
     398                                q->removeQueryItem("s");
     399                        }
     400                        q->removeAllQueryItems("fallback_host");
     401                        q->removeAllQueryItems("type");
     402                        if ((q->hasQueryItem("itag")) && (q->hasQueryItem("signature"))) {
     403                                QString itag = q->queryItemValue("itag");
     404                                q->removeAllQueryItems("itag"); // Remove duplicated itag
     405                                q->addQueryItem("itag", itag);
     406                                #if QT_VERSION >= 0x050000
     407                                line.setQuery(q->query(QUrl::FullyDecoded));
     408                                #endif
     409                                urlMap[itag.toInt()] = line.toString();
     410                                //qDebug("line: %s", line.toString().toLatin1().constData());
     411                        }
     412                }
     413        }
     414
     415        #if QT_VERSION >= 0x050000
     416        delete q;
     417        #endif
     418
     419        qDebug("RetrieveYoutubeUrl::parseVideoInfo: url count: %d", urlMap.count());
     420
     421        if ((urlMap.count() == 0) && (failed_to_decrypt_signature)) {
     422                qDebug("RetrieveYoutubeUrl::parseVideoInfo: no url found with valid signature");
     423                emit signatureNotFound(url_title);
     424                return;
     425        }
     426
     427        QString p_url = findPreferredUrl();
     428        //qDebug("p_url: '%s'", p_url.toLatin1().constData());
     429
     430        if (!p_url.isNull()) {
     431                emit gotUrls(urlMap);
     432                emit gotPreferredUrl(p_url);
     433        } else {
     434                 emit gotEmptyList();
     435        }
     436}
     437#endif
    157438
    158439QString RetrieveYoutubeUrl::findPreferredUrl() {
Note: See TracChangeset for help on using the changeset viewer.