Changeset 165 for smplayer/trunk/src/youtube
- Timestamp:
- May 16, 2014, 9:51:55 AM (11 years ago)
- Location:
- smplayer/trunk
- Files:
-
- 7 edited
-
. (modified) (1 prop)
-
src/youtube/codedownloader.cpp (modified) (1 diff)
-
src/youtube/codedownloader.h (modified) (1 diff)
-
src/youtube/retrieveyoutubeurl.cpp (modified) (10 diffs)
-
src/youtube/retrieveyoutubeurl.h (modified) (6 diffs)
-
src/youtube/ytsig.cpp (modified) (6 diffs)
-
src/youtube/ytsig.h (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
smplayer/trunk
- Property svn:mergeinfo changed
/smplayer/vendor/current merged: 163
- Property svn:mergeinfo changed
-
smplayer/trunk/src/youtube/codedownloader.cpp
r156 r165 1 1 /* smplayer, GUI front-end for mplayer. 2 Copyright (C) 2006-201 3Ricardo Villalba <rvm@users.sourceforge.net>2 Copyright (C) 2006-2014 Ricardo Villalba <rvm@users.sourceforge.net> 3 3 4 4 This program is free software; you can redistribute it and/or modify -
smplayer/trunk/src/youtube/codedownloader.h
r156 r165 1 1 /* smplayer, GUI front-end for mplayer. 2 Copyright (C) 2006-201 3Ricardo Villalba <rvm@users.sourceforge.net>2 Copyright (C) 2006-2014 Ricardo Villalba <rvm@users.sourceforge.net> 3 3 4 4 This program is free software; you can redistribute it and/or modify -
smplayer/trunk/src/youtube/retrieveyoutubeurl.cpp
r156 r165 1 1 /* smplayer, GUI front-end for mplayer. 2 Copyright (C) 2006-201 3Ricardo Villalba <rvm@users.sourceforge.net>2 Copyright (C) 2006-2014 Ricardo Villalba <rvm@users.sourceforge.net> 3 3 Copyright (C) 2010 Ori Rejwan 4 4 … … 25 25 #include "ytsig.h" 26 26 27 #if QT_VERSION >= 0x050000 28 #include <QUrlQuery> 29 #endif 30 31 #define USE_PLAYER_NAME 32 33 QString RetrieveYoutubeUrl::user_agent; 34 27 35 RetrieveYoutubeUrl::RetrieveYoutubeUrl( QObject* parent ) : QObject(parent) 28 36 { 29 37 reply = 0; 30 38 manager = new QNetworkAccessManager(this); 31 connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(gotResponse(QNetworkReply*)));32 39 33 40 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 41 } 36 42 … … 39 45 40 46 void 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 65 void 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); 41 70 QNetworkRequest req(url); 42 71 req.setRawHeader("User-Agent", user_agent.toLatin1()); 43 72 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 48 78 49 79 void RetrieveYoutubeUrl::close() { … … 51 81 } 52 82 53 void RetrieveYoutubeUrl::gotResponse(QNetworkReply* reply) { 83 void RetrieveYoutubeUrl::gotResponse() { 84 QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender()); 85 54 86 if (reply->error() == QNetworkReply::NoError) { 55 87 int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); … … 71 103 } 72 104 105 #ifdef YT_GET_VIDEOINFO 106 void 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 73 119 void RetrieveYoutubeUrl::parse(QByteArray text) { 74 120 qDebug("RetrieveYoutubeUrl::parse"); … … 87 133 } 88 134 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 89 144 QRegExp regex("\\\"url_encoded_fmt_stream_map\\\"\\s*:\\s*\\\"([^\\\"]*)"); 90 145 regex.indexIn(replyString); … … 93 148 fmtArray.replace(QRegExp("\\\\(.)"), "\\1"); 94 149 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 96 157 97 158 QList<QByteArray> codeList = fmtArray.toLatin1().split(','); … … 101 162 102 163 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") ); 107 173 line.setScheme(url.scheme()); 108 174 line.setHost(url.host()); 109 175 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"); 116 198 } 117 199 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 120 206 if (!signature.isEmpty()) { 121 line.addQueryItem("signature", signature);207 q->addQueryItem("signature", signature); 122 208 } else { 123 signature_not_found = true; 209 #ifndef YT_GET_VIDEOINFO 210 failed_to_decrypt_signature = true; 211 #endif 124 212 } 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 133 225 urlMap[itag.toInt()] = line.toString(); 134 226 //qDebug("line: %s", line.toString().toLatin1().constData()); … … 137 229 } 138 230 231 #if QT_VERSION >= 0x050000 232 delete q; 233 #endif 234 139 235 qDebug("RetrieveYoutubeUrl::parse: url count: %d", urlMap.count()); 140 236 141 if ((urlMap.count() == 0) && (signature_not_found)) { 237 #ifndef YT_GET_VIDEOINFO 238 if ((urlMap.count() == 0) && (failed_to_decrypt_signature)) { 142 239 qDebug("RetrieveYoutubeUrl::parse: no url found with valid signature"); 143 240 emit signatureNotFound(url_title); 144 241 return; 145 242 } 243 #else 244 if (urlMap.count() == 0) { 245 qDebug("RetrieveYoutubeUrl::parse: no url found with valid signature"); 246 fetchVideoInfoPage(); 247 return; 248 } 249 #endif 146 250 147 251 QString p_url = findPreferredUrl(); … … 155 259 } 156 260 } 261 262 QString 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 313 bool RetrieveYoutubeUrl::isUrlSupported(const QString & url) { 314 return (!getVideoID(url).isEmpty()); 315 } 316 317 QString 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 325 void 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 157 438 158 439 QString RetrieveYoutubeUrl::findPreferredUrl() { -
smplayer/trunk/src/youtube/retrieveyoutubeurl.h
r156 r165 1 1 /* smplayer, GUI front-end for mplayer. 2 Copyright (C) 2006-201 3Ricardo Villalba <rvm@users.sourceforge.net>2 Copyright (C) 2006-2014 Ricardo Villalba <rvm@users.sourceforge.net> 3 3 4 4 This program is free software; you can redistribute it and/or modify … … 24 24 #include <QMap> 25 25 26 #define YT_GET_VIDEOINFO 27 26 28 class RetrieveYoutubeUrl : public QObject 27 29 { … … 39 41 void close(); 40 42 41 void setUserAgent(const QString & s) { user_agent = s; };42 QString userAgent() { return user_agent; };43 static void setUserAgent(const QString & s) { user_agent = s; }; 44 static QString userAgent() { return user_agent; }; 43 45 44 46 void setPreferredQuality(Quality q) { preferred_quality = q; } … … 51 53 QString latestPreferredUrl() { return latest_preferred_url; } 52 54 QString origUrl() { return orig_url; } 55 56 bool isUrlSupported(const QString & url); 57 QString fullUrl(const QString & url); 53 58 54 59 signals: … … 63 68 64 69 protected slots: 65 void gotResponse( QNetworkReply* reply);70 void gotResponse(); 66 71 void parse(QByteArray text); 72 #ifdef YT_GET_VIDEOINFO 73 void gotVideoInfoResponse(); 74 void parseVideoInfo(QByteArray text); 75 void fetchVideoInfoPage(); 76 #endif 67 77 68 78 protected: 69 79 static QString sanitizeForUnicodePoint(QString string); 70 80 static void htmlDecode(QString& string); 81 QString getVideoID(QString video_url); 71 82 72 83 QMap<int, QString> urlMap; … … 76 87 77 88 Quality preferred_quality; 78 QString user_agent; 89 static QString user_agent; 90 91 #ifdef YT_GET_VIDEOINFO 92 QString video_id; 93 #endif 79 94 80 95 private: -
smplayer/trunk/src/youtube/ytsig.cpp
r156 r165 1 1 /* smplayer, GUI front-end for mplayer. 2 Copyright (C) 2006-201 3Ricardo Villalba <rvm@users.sourceforge.net>2 Copyright (C) 2006-2014 Ricardo Villalba <rvm@users.sourceforge.net> 3 3 4 4 This program is free software; you can redistribute it and/or modify … … 21 21 #ifdef YT_USE_SCRIPT 22 22 #include <QtScript> 23 #endif24 23 25 #ifdef YT_USE_SCRIPT 26 QString YTSig::aclara(const QString & text) { 24 QString YTSig::aclara(const QString & text, const QString & player, const QString & function_name) { 27 25 int dot = text.indexOf('.'); 28 qDebug("YTSig::aclara: length: %d (%d.%d) ", text.size(), dot, text.size()-dot-1);26 qDebug("YTSig::aclara: length: %d (%d.%d) p: %d", text.size(), dot, text.size()-dot-1, !player.isEmpty()); 29 27 30 28 if (script.isEmpty()) script = default_script; … … 36 34 37 35 engine.evaluate(script); 38 QScriptValue aclarar = engine.globalObject().property("aclara"); 39 QString res = aclarar.call(QScriptValue(), QScriptValueList() << text).toString(); 36 37 QScriptValueList args; 38 QString fname; 39 40 if (!function_name.isEmpty()) { 41 fname = function_name; 42 args << text; 43 } 44 else 45 if (player.isEmpty()) { 46 fname = "aclara"; 47 args << text; 48 } 49 else { 50 fname = "aclara_p"; 51 args << text << player; 52 } 53 54 //qDebug("YTSig::aclara: function_name: %s", function_name.toLatin1().constData()); 55 56 QScriptValue aclarar = engine.globalObject().property(fname); 57 QString res = aclarar.call(QScriptValue(), args).toString(); 40 58 41 59 //qDebug() << res; … … 61 79 f.close(); 62 80 81 parsed_ts = ""; 82 63 83 if (!bytes.isEmpty()) { 64 84 script = bytes; 85 86 QRegExp rx("D: ([\\d,a-z,A-Z-]+)"); 87 if (rx.indexIn(bytes)) { 88 QByteArray d = rx.cap(1).toLatin1(); 89 qDebug("YTSig::reloadScriptFile: d: %s", d.constData()); 90 parsed_ts = QByteArray::fromBase64(d); 91 } 92 65 93 } 66 94 } … … 69 97 QString YTSig::script_file; 70 98 71 // Algorithms from youtube-dl (http://rg3.github.io/youtube-dl/)72 73 99 QString YTSig::default_script; 74 100 101 #else // YT_USE_SCRIPT 102 103 #ifdef YTSIG_STATIC 104 #include "ytsig_priv.cpp" 75 105 #else 76 77 QString YTSig::rev(const QString & orig) { 78 QString r; 79 for (int n = orig.size()-1; n >= 0; n--) { 80 r.append(orig.at(n)); 81 } 82 return r; 83 } 84 85 QString YTSig::aclara(const QString & text) { 106 QString YTSig::aclara(const QString & text, const QString & player, const QString & function_name) { 86 107 QString res; 87 108 88 109 int dot = text.indexOf('.'); 89 110 qDebug("YTSig::aclara (2): length: %d (%d.%d)", text.size(), dot, text.size()-dot-1); 90 91 #if 092 if (text.size() == xx) {93 res = <your code>;94 }95 else {96 qDebug("YTSig::aclara: signature length not supported: %d: %s", text.size(), text.toLatin1().constData());97 return res;98 }99 #endif100 111 101 112 /* … … 106 117 return res; 107 118 } 119 #endif 108 120 109 #endif 121 #endif // YT_USE_SCRIPT 122 123 void YTSig::check(QString & u) { 124 if (!parsed_ts.isEmpty()) { 125 u.append(QString("&%1").arg(parsed_ts)); 126 } 127 } 128 129 QString YTSig::parsed_ts; -
smplayer/trunk/src/youtube/ytsig.h
r156 r165 1 1 /* smplayer, GUI front-end for mplayer. 2 Copyright (C) 2006-201 3Ricardo Villalba <rvm@users.sourceforge.net>2 Copyright (C) 2006-2014 Ricardo Villalba <rvm@users.sourceforge.net> 3 3 4 4 This program is free software; you can redistribute it and/or modify … … 25 25 { 26 26 public: 27 static QString aclara(const QString &); 27 static QString aclara(const QString & text, const QString & player = "", const QString & function_name = QString::null); 28 29 static void check(QString & u); 28 30 29 31 #ifdef YT_USE_SCRIPT 30 32 static void setScriptFile(const QString & f) { script_file = f; reloadScriptFile(); }; 31 33 32 pr otected:34 private: 33 35 static QString script; 34 36 static QString default_script; 35 37 static QString script_file; 36 38 static void reloadScriptFile(); 37 #else38 protected:39 static QString rev(const QString & orig);40 39 #endif 40 41 private: 42 static QString parsed_ts; 41 43 }; 42 44
Note:
See TracChangeset
for help on using the changeset viewer.
