]> git.sur5r.net Git - minitube/blob - src/ytjs/ytjsvideo.cpp
New upstream version 3.6
[minitube] / src / ytjs / ytjsvideo.cpp
1 #include "ytjsvideo.h"
2
3 #include "videodefinition.h"
4 #include "yt3.h"
5 #include "ytjs.h"
6
7 YTJSVideo::YTJSVideo(const QString &videoId, QObject *parent)
8     : QObject(parent), videoId(videoId), definitionCode(0) {}
9
10 void YTJSVideo::loadStreamUrl() {
11     if (loadingStreamUrl) return;
12     loadingStreamUrl = true;
13
14     auto &ytjs = YTJS::instance();
15     if (!ytjs.isInitialized()) {
16         QTimer::singleShot(500, this, [this] { loadStreamUrl(); });
17         return;
18     }
19     auto &engine = ytjs.getEngine();
20
21     auto function = engine.evaluate("videoInfo");
22     if (!function.isCallable()) {
23         qWarning() << function.toString() << " is not callable";
24         loadingStreamUrl = false;
25         emit errorStreamUrl(function.toString());
26         return;
27     }
28
29     auto handler = new ResultHandler;
30     connect(handler, &ResultHandler::error, this, &YTJSVideo::errorStreamUrl);
31     connect(handler, &ResultHandler::data, this, [this](const QJsonDocument &doc) {
32         auto obj = doc.object();
33
34         QMap<int, QString> urlMap;
35         const auto formats = obj["formats"].toArray();
36         for (const auto &format : formats) {
37             bool isDashMpd = format["isDashMPD"].toBool();
38             if (isDashMpd) continue;
39             int itag = format["itag"].toInt();
40             QString url = format["url"].toString();
41             // qDebug() << itag << url;
42             urlMap.insert(itag, url);
43         }
44
45         qDebug() << "available formats" << urlMap.keys();
46         const VideoDefinition &definition = YT3::instance().maxVideoDefinition();
47         const QVector<VideoDefinition> &definitions = VideoDefinition::getDefinitions();
48         int previousIndex = std::max(definitions.indexOf(definition), 0);
49         for (; previousIndex >= 0; previousIndex--) {
50             const VideoDefinition &previousDefinition = definitions.at(previousIndex);
51             qDebug() << "Testing format" << previousDefinition.getCode();
52             if (urlMap.contains(previousDefinition.getCode())) {
53                 qDebug() << "Found format" << previousDefinition.getCode();
54
55                 QString url = urlMap.value(previousDefinition.getCode());
56                 definitionCode = previousDefinition.getCode();
57
58                 QString audioUrl;
59                 if (!previousDefinition.hasAudio()) {
60                     qDebug() << "Finding audio format";
61                     static const QVector<int> audioFormats({251, 171, 140});
62                     for (int audioFormat : audioFormats) {
63                         qDebug() << "Trying audio format" << audioFormat;
64                         auto i = urlMap.constFind(audioFormat);
65                         if (i != urlMap.constEnd()) {
66                             qDebug() << "Found audio format" << i.value();
67                             audioUrl = i.value();
68                             break;
69                         }
70                     }
71                 }
72
73                 loadingStreamUrl = false;
74                 emit gotStreamUrl(url, audioUrl);
75                 return;
76             }
77         }
78
79         loadingStreamUrl = false;
80         emit errorStreamUrl(tr("Cannot get video stream for %1").arg(videoId));
81     });
82     QJSValue h = engine.newQObject(handler);
83     auto value = function.call({h, videoId});
84     ytjs.checkError(value);
85 }