summaryrefslogtreecommitdiff
path: root/src/youtube
diff options
context:
space:
mode:
authorMateusz Łukasik <mati75@linuxmint.pl>2014-09-10 13:50:41 +0200
committerMateusz Łukasik <mati75@linuxmint.pl>2014-09-10 13:50:41 +0200
commit2d547200175bcaefcbca0862f8e0395e42c96224 (patch)
treed2d8508074c5035a8c5af248e147655cdeb0a1cb /src/youtube
parent02af8398ac9a1089a7fe9efda615a771e1c13637 (diff)
Imported Upstream version 14.9.0
Diffstat (limited to 'src/youtube')
-rw-r--r--src/youtube/retrieveyoutubeurl.cpp140
-rw-r--r--src/youtube/retrieveyoutubeurl.h28
-rw-r--r--src/youtube/ytsig.cpp2
3 files changed, 145 insertions, 25 deletions
diff --git a/src/youtube/retrieveyoutubeurl.cpp b/src/youtube/retrieveyoutubeurl.cpp
index 47a3650..e289996 100644
--- a/src/youtube/retrieveyoutubeurl.cpp
+++ b/src/youtube/retrieveyoutubeurl.cpp
@@ -31,6 +31,8 @@
#define USE_PLAYER_NAME
QString RetrieveYoutubeUrl::user_agent;
+bool RetrieveYoutubeUrl::use_https_main = false;
+bool RetrieveYoutubeUrl::use_https_vi = false;
RetrieveYoutubeUrl::RetrieveYoutubeUrl( QObject* parent ) : QObject(parent)
{
@@ -44,12 +46,12 @@ RetrieveYoutubeUrl::~RetrieveYoutubeUrl() {
}
void RetrieveYoutubeUrl::fetchPage(const QString & url) {
- QString agent = user_agent;
- if (agent.isEmpty()) agent = "Mozilla/5.0 (X11; Linux x86_64; rv:5.0.1) Gecko/20100101 Firefox/5.0.1";
- qDebug("RetrieveYoutubeUrl::fetchPage: user agent: %s", agent.toLatin1().constData());
+ qDebug("RetrieveYoutubeUrl::fetchPage: url: %s", url.toUtf8().constData());
+ qDebug("RetrieveYoutubeUrl::fetchPage: user agent: '%s'", user_agent.toLatin1().constData());
QNetworkRequest req(url);
- req.setRawHeader("User-Agent", agent.toLatin1());
+ req.setRawHeader("User-Agent", user_agent.toLatin1());
+ req.setRawHeader("Accept-Language", "en-us,en;q=0.5");
reply = manager->get(req);
connect(reply, SIGNAL(finished()), this, SLOT(gotResponse()));
orig_url = url;
@@ -62,13 +64,19 @@ void RetrieveYoutubeUrl::fetchPage(const QString & url) {
}
#ifdef YT_GET_VIDEOINFO
-void RetrieveYoutubeUrl::fetchVideoInfoPage() {
- 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);
- //qDebug("RetrieveYoutubeUrl::fetchVideoInfoPage: url: %s", url.toUtf8().constData());
+void RetrieveYoutubeUrl::fetchVideoInfoPage(QString url) {
+ if (url.isEmpty()) {
+ QString scheme = use_https_vi ? "https" : "http";
+ 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);
+ }
+ qDebug("RetrieveYoutubeUrl::fetchVideoInfoPage: url: %s...", url.left(20).toUtf8().constData());
+
+ qDebug("RetrieveYoutubeUrl::fetchPage: user agent: '%s'", user_agent.toLatin1().constData());
YTSig::check(url);
QNetworkRequest req(url);
req.setRawHeader("User-Agent", user_agent.toLatin1());
+ req.setRawHeader("Accept-Language", "en-us,en;q=0.5");
reply = manager->get(req);
connect(reply, SIGNAL(finished()), this, SLOT(gotVideoInfoResponse()));
@@ -81,6 +89,8 @@ void RetrieveYoutubeUrl::close() {
}
void RetrieveYoutubeUrl::gotResponse() {
+ qDebug("RetrieveYoutubeUrl::gotResponse");
+
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
if (reply->error() == QNetworkReply::NoError) {
@@ -96,6 +106,7 @@ void RetrieveYoutubeUrl::gotResponse() {
return;
}
} else {
+ qDebug("RetrieveYoutubeUrl::gotResponse: error %d: '%s'", (int)reply->error(), reply->errorString().toUtf8().constData());
emit errorOcurred((int)reply->error(), reply->errorString());
return;
}
@@ -108,7 +119,20 @@ void RetrieveYoutubeUrl::gotVideoInfoResponse() {
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
- if (reply->error() != QNetworkReply::NoError) {
+ if (reply->error() == QNetworkReply::NoError) {
+ int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+ qDebug("RetrieveYoutubeUrl::gotVideoInfoResponse: status: %d", status);
+ switch (status) {
+ case 301:
+ case 302:
+ case 307:
+ QString r_url = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl().toString();
+ //qDebug("RetrieveYoutubeUrl::gotVideoInfoResponse: redirected: %s", r_url.toLatin1().constData());
+ fetchVideoInfoPage(r_url);
+ return;
+ }
+ } else {
+ qDebug("RetrieveYoutubeUrl::gotVideoInfoResponse: error %d: '%s'", (int)reply->error(), reply->errorString().toUtf8().constData());
emit errorOcurred((int)reply->error(), reply->errorString());
return;
}
@@ -135,15 +159,26 @@ void RetrieveYoutubeUrl::parse(QByteArray text) {
//qDebug("RetrieveYoutubeUrl::parse: replyString: %s",replyString.toLatin1().constData());
QString player;
- QRegExp rxplayer("html5player-([\\d,\\w,-]+)\\.js");
+ QRegExp rxplayer("html5player-([\\d,\\w,-]+)\\\\");
if (rxplayer.indexIn(replyString) != -1) {
player = rxplayer.cap(1);
qDebug("RetrieveYoutubeUrl::parse: html5player: %s", player.toLatin1().constData());
}
+ QString fmtArray;
QRegExp regex("\\\"url_encoded_fmt_stream_map\\\"\\s*:\\s*\\\"([^\\\"]*)");
- regex.indexIn(replyString);
- QString fmtArray = regex.cap(1);
+ if (regex.indexIn(replyString) != -1) {
+ fmtArray = regex.cap(1);
+ }
+
+#ifdef YT_DASH_SUPPORT
+ QRegExp regex2("\\\"adaptive_fmts\\\"\\s*:\\s*\\\"([^\\\"]*)");
+ if (regex2.indexIn(replyString) != -1) {
+ if (!fmtArray.isEmpty()) fmtArray += ",";
+ fmtArray += regex2.cap(1);
+ }
+#endif
+
fmtArray = sanitizeForUnicodePoint(fmtArray);
fmtArray.replace(QRegExp("\\\\(.)"), "\\1");
@@ -215,15 +250,32 @@ void RetrieveYoutubeUrl::parse(QByteArray text) {
q->removeAllQueryItems("fallback_host");
q->removeAllQueryItems("type");
+ if (!q->hasQueryItem("ratebypass")) q->addQueryItem("ratebypass", "yes");
+
if ((q->hasQueryItem("itag")) && (q->hasQueryItem("signature"))) {
QString itag = q->queryItemValue("itag");
- q->removeAllQueryItems("itag"); // Remove duplicated itag
- q->addQueryItem("itag", itag);
+
+ // Remove duplicated queries
+ QPair <QString,QString> item;
+ QList<QPair<QString, QString> > items = q->queryItems();
+ foreach(item, items) {
+ q->removeAllQueryItems(item.first);
+ q->addQueryItem(item.first, item.second);
+ }
+
#if QT_VERSION >= 0x050000
line.setQuery(q->query(QUrl::FullyDecoded));
#endif
+
+ #ifdef YT_GET_VIDEOINFO
+ if (!line.toString().startsWith("https")) {
+ urlMap[itag.toInt()] = line.toString();
+ }
+ #else
urlMap[itag.toInt()] = line.toString();
- //qDebug("line: %s", line.toString().toLatin1().constData());
+ #endif
+
+ //qDebug("itag: %s line: %s", itag.toLatin1().constData(), line.toString().toLatin1().constData());
}
}
}
@@ -254,6 +306,9 @@ void RetrieveYoutubeUrl::parse(QByteArray text) {
if (!p_url.isNull()) {
emit gotUrls(urlMap);
emit gotPreferredUrl(p_url);
+ #ifdef YT_GET_VIDEOINFO
+ emit gotVideoInfo(urlMap, url_title, video_id);
+ #endif
} else {
emit gotEmptyList();
}
@@ -317,7 +372,10 @@ bool RetrieveYoutubeUrl::isUrlSupported(const QString & url) {
QString RetrieveYoutubeUrl::fullUrl(const QString & url) {
QString r;
QString ID = getVideoID(url);
- if (!ID.isEmpty()) r = "http://www.youtube.com/watch?v=" + ID;
+ if (!ID.isEmpty()) {
+ QString scheme = use_https_main ? "https" : "http";
+ r = scheme + "://www.youtube.com/watch?v=" + ID;
+ }
return r;
}
@@ -328,13 +386,19 @@ void RetrieveYoutubeUrl::parseVideoInfo(QByteArray text) {
#if QT_VERSION >= 0x050000
QUrlQuery all;
all.setQuery(text);
- QByteArray fmtArray = all.queryItemValue("url_encoded_fmt_stream_map").toLatin1();
#else
QUrl all;
all.setEncodedQuery(text);
- QByteArray fmtArray = all.queryItemValue("url_encoded_fmt_stream_map").toLatin1();
#endif
+ QByteArray fmtArray;
+ fmtArray = all.queryItemValue("url_encoded_fmt_stream_map").toLatin1();
+
+#ifdef YT_DASH_SUPPORT
+ if (!fmtArray.isEmpty()) fmtArray += ",";
+ fmtArray += all.queryItemValue("adaptive_fmts").toLatin1();
+#endif
+
/*
qDebug("fmtArray: %s", fmtArray.constData());
return;
@@ -399,15 +463,25 @@ void RetrieveYoutubeUrl::parseVideoInfo(QByteArray text) {
}
q->removeAllQueryItems("fallback_host");
q->removeAllQueryItems("type");
+
+ if (!q->hasQueryItem("ratebypass")) q->addQueryItem("ratebypass", "yes");
+
if ((q->hasQueryItem("itag")) && (q->hasQueryItem("signature"))) {
QString itag = q->queryItemValue("itag");
- q->removeAllQueryItems("itag"); // Remove duplicated itag
- q->addQueryItem("itag", itag);
+
+ // Remove duplicated queries
+ QPair <QString,QString> item;
+ QList<QPair<QString, QString> > items = q->queryItems();
+ foreach(item, items) {
+ q->removeAllQueryItems(item.first);
+ q->addQueryItem(item.first, item.second);
+ }
+
#if QT_VERSION >= 0x050000
line.setQuery(q->query(QUrl::FullyDecoded));
#endif
urlMap[itag.toInt()] = line.toString();
- //qDebug("line: %s", line.toString().toLatin1().constData());
+ //qDebug("itag: %s line: %s", itag.toLatin1().constData(), line.toString().toLatin1().constData());
}
}
}
@@ -430,6 +504,9 @@ void RetrieveYoutubeUrl::parseVideoInfo(QByteArray text) {
if (!p_url.isNull()) {
emit gotUrls(urlMap);
emit gotPreferredUrl(p_url);
+ #ifdef YT_GET_VIDEOINFO
+ emit gotVideoInfo(urlMap, url_title, video_id);
+ #endif
} else {
emit gotEmptyList();
}
@@ -506,6 +583,29 @@ QString RetrieveYoutubeUrl::findPreferredUrl(const QMap<int, QString>& urlMap, Q
return p_url;
}
+#ifdef YT_DASH_SUPPORT
+QString RetrieveYoutubeUrl::findBestAudio(const QMap<int, QString>& urlMap) {
+ QString url;
+
+ url = urlMap.value(DASH_AUDIO_MP4_256, QString());
+ if (!url.isEmpty()) return url;
+
+ url = urlMap.value(DASH_AUDIO_WEBM_192, QString());
+ if (!url.isEmpty()) return url;
+
+ url = urlMap.value(DASH_AUDIO_MP4_128, QString());
+ if (!url.isEmpty()) return url;
+
+ url = urlMap.value(DASH_AUDIO_WEBM_128, QString());
+ if (!url.isEmpty()) return url;
+
+ url = urlMap.value(DASH_AUDIO_MP4_48, QString());
+ if (!url.isEmpty()) return url;
+
+ return url;
+}
+#endif
+
QString RetrieveYoutubeUrl::sanitizeForUnicodePoint(QString string) {
QRegExp rx("\\\\u(\\d{4})");
while (rx.indexIn(string) != -1) {
diff --git a/src/youtube/retrieveyoutubeurl.h b/src/youtube/retrieveyoutubeurl.h
index d06e45b..c7dfe10 100644
--- a/src/youtube/retrieveyoutubeurl.h
+++ b/src/youtube/retrieveyoutubeurl.h
@@ -1,5 +1,5 @@
/* smplayer, GUI front-end for mplayer.
- Copyright (C) 2006-2014 Ricardo Villalba <rvm@users.sourceforge.net>
+ Copyright (C) 2006-2013 Ricardo Villalba <rvm@users.sourceforge.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -24,6 +24,7 @@
#include <QMap>
#define YT_GET_VIDEOINFO
+//#define YT_DASH_SUPPORT
class RetrieveYoutubeUrl : public QObject
{
@@ -31,8 +32,13 @@ class RetrieveYoutubeUrl : public QObject
public:
enum Quality { FLV_240p = 5, MP4_360p = 18, MP4_720p = 22, FLV_360p = 34,
- FLV_480p = 35, MP4_1080p = 37, WEBM_360p = 43,
- WEBM_480p = 44, WEBM_720p = 45, WEBM_1080p = 46 };
+ FLV_480p = 35, MP4_1080p = 37, WEBM_360p = 43,
+ WEBM_480p = 44, WEBM_720p = 45, WEBM_1080p = 46,
+ DASH_AUDIO_MP4_48 = 139, DASH_AUDIO_MP4_128 = 140, DASH_AUDIO_MP4_256 = 141,
+ DASH_AUDIO_WEBM_128 = 171, DASH_AUDIO_WEBM_192 = 172,
+ DASH_VIDEO_1080p = 137, DASH_VIDEO_720p = 136,
+ DASH_VIDEO_480p = 135, DASH_VIDEO_360p = 134,
+ DASH_VIDEO_240p = 133 };
RetrieveYoutubeUrl( QObject* parent = 0 );
~RetrieveYoutubeUrl();
@@ -49,6 +55,10 @@ public:
static QString findPreferredUrl(const QMap<int, QString>& urlMap, Quality q);
QString findPreferredUrl();
+#ifdef YT_DASH_SUPPORT
+ static QString findBestAudio(const QMap<int, QString>& urlMap);
+#endif
+
QString urlTitle() { return url_title; }
QString latestPreferredUrl() { return latest_preferred_url; }
QString origUrl() { return orig_url; }
@@ -56,10 +66,18 @@ public:
bool isUrlSupported(const QString & url);
QString fullUrl(const QString & url);
+ static void setUseHttpsMain(bool b) { use_https_main = b; };
+ static void setUseHttpsVi(bool b) { use_https_vi = b; };
+ static bool useHttpsMain() { return use_https_main; };
+ static bool useHttpsVi() { return use_https_vi; };
+
signals:
void gotUrls(const QMap<int, QString>&);
void gotPreferredUrl(const QString &);
void gotEmptyList();
+#ifdef YT_GET_VIDEOINFO
+ void gotVideoInfo(const QMap<int, QString>&, QString, QString);
+#endif
void connecting(QString host);
void errorOcurred(int error_number, QString error_str);
@@ -72,7 +90,7 @@ protected slots:
#ifdef YT_GET_VIDEOINFO
void gotVideoInfoResponse();
void parseVideoInfo(QByteArray text);
- void fetchVideoInfoPage();
+ void fetchVideoInfoPage(QString url = QString::null);
#endif
protected:
@@ -87,6 +105,8 @@ protected:
Quality preferred_quality;
static QString user_agent;
+ static bool use_https_main;
+ static bool use_https_vi;
#ifdef YT_GET_VIDEOINFO
QString video_id;
diff --git a/src/youtube/ytsig.cpp b/src/youtube/ytsig.cpp
index d85de43..f0cb3c0 100644
--- a/src/youtube/ytsig.cpp
+++ b/src/youtube/ytsig.cpp
@@ -86,7 +86,7 @@ void YTSig::reloadScriptFile() {
QRegExp rx("D: ([\\d,a-z,A-Z-]+)");
if (rx.indexIn(bytes)) {
QByteArray d = rx.cap(1).toLatin1();
- qDebug("YTSig::reloadScriptFile: d: %s", d.constData());
+ //qDebug("YTSig::reloadScriptFile: d: %s", d.constData());
parsed_ts = QByteArray::fromBase64(d);
}