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

Last change on this file since 156 was 156, checked in by Silvan Scherrer, 11 years ago

SMPlayer: update trunk to 0.8.6

File size: 7.4 KB
Line 
1/* smplayer, GUI front-end for mplayer.
2 Copyright (C) 2006-2013 Ricardo Villalba <rvm@users.sourceforge.net>
3 Copyright (C) 2010 Ori Rejwan
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18*/
19
20#include "retrieveyoutubeurl.h"
21#include <QUrl>
22#include <QRegExp>
23#include <QStringList>
24#include <QFile>
25#include "ytsig.h"
26
27RetrieveYoutubeUrl::RetrieveYoutubeUrl( QObject* parent ) : QObject(parent)
28{
29 reply = 0;
30 manager = new QNetworkAccessManager(this);
31 connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(gotResponse(QNetworkReply*)));
32
33 preferred_quality = FLV_360p;
34 user_agent = "Mozilla/5.0 (X11; Linux x86_64; rv:5.0.1) Gecko/20100101 Firefox/5.0.1";
35}
36
37RetrieveYoutubeUrl::~RetrieveYoutubeUrl() {
38}
39
40void RetrieveYoutubeUrl::fetchPage(const QString & url) {
41 QNetworkRequest req(url);
42 req.setRawHeader("User-Agent", user_agent.toLatin1());
43 reply = manager->get(req);
44 orig_url = url;
45
46 emit connecting(url);
47}
48
49void RetrieveYoutubeUrl::close() {
50 if (reply) reply->abort();
51}
52
53void RetrieveYoutubeUrl::gotResponse(QNetworkReply* reply) {
54 if (reply->error() == QNetworkReply::NoError) {
55 int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
56 qDebug("RetrieveYoutubeUrl::gotResponse: status: %d", status);
57 switch (status) {
58 case 301:
59 case 302:
60 case 307:
61 QString r_url = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl().toString();
62 qDebug("RetrieveYoutubeUrl::gotResponse: redirected: %s", r_url.toLatin1().constData());
63 fetchPage(r_url);
64 return;
65 }
66 } else {
67 emit errorOcurred((int)reply->error(), reply->errorString());
68 return;
69 }
70 parse(reply->readAll());
71}
72
73void RetrieveYoutubeUrl::parse(QByteArray text) {
74 qDebug("RetrieveYoutubeUrl::parse");
75
76 urlMap.clear();
77
78 QString replyString = QString::fromUtf8(text);
79
80 QRegExp rx_title(".*<title>(.*)</title>.*");
81 if (rx_title.indexIn(replyString) != -1) {
82 url_title = rx_title.cap(1).simplified();
83 url_title = QString(url_title).replace("&amp;","&").replace("&gt;", ">").replace("&lt;", "<").replace("&quot;","\"").replace("&#39;","'")/*.replace(" - YouTube", "")*/;
84 qDebug("RetrieveYoutubeUrl::parse: title '%s'", url_title.toUtf8().constData());
85 } else {
86 url_title = "Youtube video";
87 }
88
89 QRegExp regex("\\\"url_encoded_fmt_stream_map\\\"\\s*:\\s*\\\"([^\\\"]*)");
90 regex.indexIn(replyString);
91 QString fmtArray = regex.cap(1);
92 fmtArray = sanitizeForUnicodePoint(fmtArray);
93 fmtArray.replace(QRegExp("\\\\(.)"), "\\1");
94
95 bool signature_not_found = false;
96
97 QList<QByteArray> codeList = fmtArray.toLatin1().split(',');
98 foreach(QByteArray code, codeList) {
99 code = QUrl::fromPercentEncoding(code).toLatin1();
100 //qDebug("code: %s", code.constData());
101
102 QUrl line;
103 line.setEncodedQuery(code);
104
105 if (line.hasQueryItem("url")) {
106 QUrl url( line.queryItemValue("url") );
107 line.setScheme(url.scheme());
108 line.setHost(url.host());
109 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");
116 }
117 else
118 if (line.hasQueryItem("s")) {
119 QString signature = YTSig::aclara(line.queryItemValue("s"));
120 if (!signature.isEmpty()) {
121 line.addQueryItem("signature", signature);
122 } else {
123 signature_not_found = true;
124 }
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);
133 urlMap[itag.toInt()] = line.toString();
134 //qDebug("line: %s", line.toString().toLatin1().constData());
135 }
136 }
137 }
138
139 qDebug("RetrieveYoutubeUrl::parse: url count: %d", urlMap.count());
140
141 if ((urlMap.count() == 0) && (signature_not_found)) {
142 qDebug("RetrieveYoutubeUrl::parse: no url found with valid signature");
143 emit signatureNotFound(url_title);
144 return;
145 }
146
147 QString p_url = findPreferredUrl();
148 //qDebug("p_url: '%s'", p_url.toLatin1().constData());
149
150 if (!p_url.isNull()) {
151 emit gotUrls(urlMap);
152 emit gotPreferredUrl(p_url);
153 } else {
154 emit gotEmptyList();
155 }
156}
157
158QString RetrieveYoutubeUrl::findPreferredUrl() {
159 latest_preferred_url = findPreferredUrl(urlMap, preferred_quality);
160 return latest_preferred_url;
161}
162
163QString RetrieveYoutubeUrl::findPreferredUrl(const QMap<int, QString>& urlMap, Quality q) {
164 // Choose a url according to preferred quality
165 QString p_url;
166 //Quality q = preferred_quality;
167
168 if (q==MP4_1080p) {
169 p_url = urlMap.value(MP4_1080p, QString());
170 if (p_url.isNull()) p_url= urlMap.value(WEBM_1080p, QString());
171 if (p_url.isNull()) q = MP4_720p;
172 }
173
174 if (q==WEBM_1080p) {
175 p_url = urlMap.value(WEBM_1080p, QString());
176 if (p_url.isNull()) p_url= urlMap.value(MP4_1080p, QString());
177 if (p_url.isNull()) q = WEBM_720p;
178 }
179
180 if (q==MP4_720p) {
181 p_url = urlMap.value(MP4_720p, QString());
182 if (p_url.isNull()) p_url= urlMap.value(WEBM_720p, QString());
183 if (p_url.isNull()) p_url = urlMap.value(WEBM_480p, QString());
184 if (p_url.isNull()) q = MP4_360p;
185 }
186
187 if (q==WEBM_720p) {
188 p_url = urlMap.value(WEBM_720p, QString());
189 if (p_url.isNull()) p_url= urlMap.value(MP4_720p, QString());
190 if (p_url.isNull()) q = WEBM_480p;
191 }
192
193 if (q==WEBM_480p) {
194 p_url = urlMap.value(WEBM_480p, QString());
195 if (p_url.isNull()) q = WEBM_360p;
196 }
197
198 if (q==MP4_360p) {
199 p_url = urlMap.value(MP4_360p, QString());
200 if (p_url.isNull()) p_url= urlMap.value(WEBM_360p, QString());
201 if (p_url.isNull()) q = FLV_360p;
202 }
203
204 if (q==WEBM_360p) {
205 p_url = urlMap.value(WEBM_360p, QString());
206 if (p_url.isNull()) p_url= urlMap.value(MP4_360p, QString());
207 if (p_url.isNull()) q = FLV_360p;
208 }
209
210 // FLV, low priority
211 if (q==FLV_480p) {
212 p_url = urlMap.value(FLV_480p, QString());
213 if (p_url.isNull()) q = FLV_360p;
214 }
215
216 if (q==FLV_360p) {
217 p_url = urlMap.value(FLV_360p, QString());
218 if (p_url.isNull()) q = FLV_240p;
219 }
220
221 if (q==FLV_240p) {
222 p_url = urlMap.value(q, QString());
223 }
224
225 return p_url;
226}
227
228QString RetrieveYoutubeUrl::sanitizeForUnicodePoint(QString string) {
229 QRegExp rx("\\\\u(\\d{4})");
230 while (rx.indexIn(string) != -1) {
231 string.replace(rx.cap(0), QString(QChar(rx.cap(1).toInt(0,16))));
232 }
233 return string;
234}
235
236void RetrieveYoutubeUrl::htmlDecode(QString& string) {
237 string.replace("%3A", ":", Qt::CaseInsensitive);
238 string.replace("%2F", "/", Qt::CaseInsensitive);
239 string.replace("%3F", "?", Qt::CaseInsensitive);
240 string.replace("%3D", "=", Qt::CaseInsensitive);
241 string.replace("%25", "%", Qt::CaseInsensitive);
242 string.replace("%26", "&", Qt::CaseInsensitive);
243 string.replace("%3D", "=", Qt::CaseInsensitive);
244}
245
246#include "moc_retrieveyoutubeurl.cpp"
Note: See TracBrowser for help on using the repository browser.