3 #include "cachedhttp.h"
6 #include "jsfunctions.h"
7 #include "throttledhttp.h"
14 QStringList fallbackServers{"https://invidious.snopyta.org"};
15 QStringList preferredServers;
17 void shuffle(QStringList &sl) {
18 std::shuffle(sl.begin(), sl.end(), *QRandomGenerator::global());
23 Invidious &Invidious::instance() {
28 Http &Invidious::http() {
30 Http *http = new Http;
31 http->addRequestHeader("User-Agent", HttpUtils::stealthUserAgent());
32 http->setMaxRetries(0);
38 Http &Invidious::cachedHttp() {
40 ThrottledHttp *throttledHttp = new ThrottledHttp(http());
41 throttledHttp->setMilliseconds(500);
43 CachedHttp *cachedHttp = new CachedHttp(*throttledHttp, "iv");
44 cachedHttp->setMaxSeconds(86400);
45 cachedHttp->setIgnoreHostname(true);
47 cachedHttp->getValidators().insert("application/json", [](const auto &reply) -> bool {
48 const auto body = reply.body();
49 if (body.isEmpty() || body == "[]" || body == "{}") return false;
58 Invidious::Invidious(QObject *parent) : QObject(parent) {
60 preferredServers << Extra::extraFunctions()->stringArray("ivPreferred()");
61 shuffle(preferredServers);
63 fallbackServers = JsFunctions::instance()->stringArray("ivFallback()");
64 shuffle(fallbackServers);
67 void Invidious::initServers() {
68 if (!servers.isEmpty()) shuffleServers();
70 QString instanceApi = JsFunctions::instance()->string("ivInstances()");
71 if (instanceApi.isEmpty()) return;
73 auto reply = http().get(instanceApi);
74 connect(reply, &HttpReply::finished, this, [this](auto &reply) {
75 if (reply.isSuccessful()) {
79 QStringList keywords = settings.value("recentKeywords").toStringList();
80 QString testKeyword = keywords.isEmpty() ? "test" : keywords.first();
82 QJsonDocument doc = QJsonDocument::fromJson(reply.body());
83 for (const auto &v : doc.array()) {
84 if (servers.size() > 3) break;
86 auto serverArray = v.toArray();
87 QString host = serverArray.first().toString();
88 QJsonObject serverObj = serverArray.at(1).toObject();
89 if (serverObj["type"] == "https") {
90 QString url = "https://" + host;
92 QUrl testUrl(url + "/api/v1/search?q=" + testKeyword);
93 auto reply = http().get(testUrl);
94 connect(reply, &HttpReply::finished, this, [this, url](auto &reply) {
95 if (reply.isSuccessful()) {
96 QJsonDocument doc = QJsonDocument::fromJson(reply.body());
97 if (!doc.array().isEmpty()) {
98 if (servers.size() < 3) {
100 if (servers.size() == 3) {
102 for (const auto &s : qAsConst(preferredServers))
105 emit serversInitialized();
117 void Invidious::shuffleServers() {
121 QString Invidious::baseUrl() {
123 if (servers.isEmpty()) {
124 if (preferredServers.isEmpty())
125 host = fallbackServers.first();
127 host = preferredServers.first();
129 host = servers.first();
131 QString url = host + QLatin1String("/api/v1/");
135 QUrl Invidious::method(const QString &name) {
136 QUrl url(baseUrl() + name);