1 /*
2 * Copyright © 2015-2016 Antti Lamminsalo
3 *
4 * This file is part of Orion.
5 *
6 * Orion is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * You should have received a copy of the GNU General Public License
12 * along with Orion. If not, see <http://www.gnu.org/licenses/>.
13 */
14
15 #include "networkmanager.h"
16 #include "../util/fileutils.h"
17 #include "../util/jsonparser.h"
18 #include "../util/m3u8parser.h"
19 #include <QNetworkConfiguration>
20 #include <QEventLoop>
21 #include <QSet>
22 #include <QUrlQuery>
23 #include "../model/settingsmanager.h"
24
25 NetworkManager *NetworkManager::singleton = 0;
26
NetworkManager(QNetworkAccessManager * man)27 NetworkManager::NetworkManager(QNetworkAccessManager *man) : QObject(man)
28 {
29 operation = man;
30
31 initReplayChat();
32
33 //Select interface
34 connectionOK = false;
35 testNetworkInterface();
36
37 //SSL errors handle (down the drain)
38 connect(operation, &QNetworkAccessManager::sslErrors, this, &NetworkManager::handleSslErrors);
39
40 //Handshake
41 operation->connectToHost(TWITCH_API);
42
43 //Set up offline poller
44 offlinePoller.setInterval(2000);
45 connect(&offlinePoller, &QTimer::timeout, this, &NetworkManager::testNetworkInterface);
46
47 //Set up listening to access token changes
48 connect(SettingsManager::getInstance(), &SettingsManager::accessTokenChanged, this, &NetworkManager::setAccessToken);
49 setAccessToken(SettingsManager::getInstance()->accessToken());
50
51 lastVodChatRequest = nullptr;
52 }
53
setAccessToken(const QString & accessToken)54 void NetworkManager::setAccessToken(const QString &accessToken)
55 {
56 access_token = accessToken;
57 }
58
~NetworkManager()59 NetworkManager::~NetworkManager()
60 {
61 offlinePoller.stop();
62 qDebug() << "Destroyer: NetworkManager";
63 //operation->deleteLater();
64 teardownReplayChat();
65 }
66
initialize(QNetworkAccessManager * mgr)67 void NetworkManager::initialize(QNetworkAccessManager *mgr)
68 {
69 singleton = new NetworkManager(mgr);
70 }
71
testNetworkInterface()72 void NetworkManager::testNetworkInterface()
73 {
74 //Chooses a working network interface from interfaces list, if default configuration doesn't work
75
76 QNetworkConfigurationManager conf;
77 QString identifier;
78
79 QEventLoop loop;
80 connect(this, &NetworkManager::finishedConnectionTest, &loop, &QEventLoop::quit);
81
82 //Test default configuration
83 operation->setConfiguration(conf.defaultConfiguration());
84
85 testConnection();
86 loop.exec();
87
88 if (connectionOK == true) {
89 qDebug() << "Selected default network configuration";
90 return;
91 }
92
93 else {
94 qDebug() << "Failure on default configuration, attempt to choose another interaface..";
95
96 foreach (const QNetworkInterface & interface, QNetworkInterface::allInterfaces())
97 {
98 if (!interface.isValid())
99 continue;
100
101 // qDebug() << "Identifier: " << interface.name();
102 // qDebug() << "HW addr: " << interface.hardwareAddress();
103
104 bool isUp = interface.flags().testFlag(QNetworkInterface::IsUp);
105 bool isLoopback = interface.flags().testFlag(QNetworkInterface::IsLoopBack);
106 bool isActive = interface.flags().testFlag(QNetworkInterface::IsRunning);
107 // bool isPtP = interface.flags().testFlag(QNetworkInterface::IsPointToPoint);
108
109 // qDebug() << "Properties: ";
110 // qDebug() << (isUp ? "Is up" : "Is down");
111
112 // if (isLoopback)
113 // qDebug() << "Loopback";
114
115 // qDebug() << (isActive ? "Active" : "Inactive");
116
117 // if (isPtP)
118 // qDebug() << "Is Point-to-Point";
119
120 // qDebug() << "";
121
122 if (isUp && isActive && !isLoopback) {
123 identifier = interface.name();
124 qDebug() << "Testing connection for interface " << identifier;
125 operation->setConfiguration(conf.configurationFromIdentifier(identifier));
126
127 testConnection();
128 loop.exec();
129
130 if (connectionOK == true) {
131 qDebug() << "Success!";
132 return;
133 }
134
135 else
136 qDebug() << "Failure, trying another interface...";
137 }
138
139 }
140 }
141
142 if (!connectionOK) {
143 operation->setConfiguration(conf.defaultConfiguration());
144 offlinePoller.start();
145 }
146 }
147
networkAccess()148 bool NetworkManager::networkAccess() {
149 return connectionOK;
150 }
151
testConnection()152 void NetworkManager::testConnection()
153 {
154 QNetworkRequest request;
155 //request.setRawHeader("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html");
156 request.setRawHeader("Accept", "application/vnd.twitchtv.v5+json");
157 request.setRawHeader("Client-ID", getClientId().toUtf8());
158 request.setUrl(QUrl(KRAKEN_API));
159
160 QNetworkReply *reply = operation->get(request);
161
162 connect(reply, &QNetworkReply::finished, this, &NetworkManager::testConnectionReply);
163 }
164
testConnectionReply()165 void NetworkManager::testConnectionReply()
166 {
167 QNetworkReply* reply = qobject_cast<QNetworkReply *>(sender());
168
169 // if (reply->error() == QNetworkReply::NoError)
170 // qDebug() << "Got response: " << reply->readAll();
171
172 handleNetworkError(reply);
173
174 emit finishedConnectionTest();
175 }
176
checkVersion()177 void NetworkManager::checkVersion()
178 {
179 }
180
181 /**
182 * @brief NetworkManager::getStream
183 * Gets single stream status. Usable for polling a channel's stream
184 */
getStream(const quint64 channelId)185 void NetworkManager::getStream(const quint64 channelId)
186 {
187 QString url = KRAKEN_API + QString("/streams/%1").arg(channelId);
188 QNetworkRequest request;
189 //request.setRawHeader("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html");
190 request.setRawHeader("Accept", "application/vnd.twitchtv.v5+json");
191 request.setRawHeader("Client-ID", getClientId().toUtf8());
192 request.setUrl(QUrl(url));
193
194 QNetworkReply *reply = operation->get(request);
195
196 connect(reply, &QNetworkReply::finished, this, &NetworkManager::streamReply);
197 }
198
getStreams(const QString & url)199 void NetworkManager::getStreams(const QString &url)
200 {
201 //qDebug() << "GET: " << url;
202 QNetworkRequest request;
203 //request.setRawHeader("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html");
204 request.setRawHeader("Accept", "application/vnd.twitchtv.v5+json");
205 request.setRawHeader("Client-ID", getClientId().toUtf8());
206 request.setUrl(QUrl(url));
207
208 QNetworkReply *reply = operation->get(request);
209
210 connect(reply, &QNetworkReply::finished, this, &NetworkManager::allStreamsReply);
211 }
212
getGames(const quint32 & offset,const quint32 & limit)213 void NetworkManager::getGames(const quint32 &offset, const quint32 &limit)
214 {
215 QNetworkRequest request;
216 //request.setRawHeader("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html");
217 request.setRawHeader("Accept", "application/vnd.twitchtv.v5+json");
218 request.setRawHeader("Client-ID", getClientId().toUtf8());
219 QString url = KRAKEN_API;
220 url += QString("/games/top?limit=%1").arg(limit)
221 + QString("&offset=%1").arg(offset);
222 request.setUrl(QUrl(url));
223
224 QNetworkReply *reply = operation->get(request);
225
226 connect(reply, &QNetworkReply::finished, this, &NetworkManager::gamesReply);
227 }
228
searchChannels(const QString & query,const quint32 & offset,const quint32 & limit)229 void NetworkManager::searchChannels(const QString &query, const quint32 &offset, const quint32 &limit)
230 {
231 QNetworkRequest request;
232 //request.setRawHeader("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html");
233 request.setRawHeader("Accept", "application/vnd.twitchtv.v5+json");
234 request.setRawHeader("Client-ID", getClientId().toUtf8());
235 QString url = QString(KRAKEN_API)
236 + QString("/search/channels?query=") + QUrl::toPercentEncoding(query)
237 + QString("&offset=%1").arg(offset)
238 + QString("&limit=%1").arg(limit);
239
240 qDebug() << "requesting" << url;
241 request.setUrl(QUrl(url));
242
243 QNetworkReply *reply = operation->get(request);
244
245 connect(reply, &QNetworkReply::finished, this, &NetworkManager::searchChannelsReply);
246 }
247
searchGames(const QString & query)248 void NetworkManager::searchGames(const QString &query)
249 {
250 QNetworkRequest request;
251 //request.setRawHeader("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html");
252 request.setRawHeader("Accept", "application/vnd.twitchtv.v5+json");
253 request.setRawHeader("Client-ID", getClientId().toUtf8());
254 QString url = QString(KRAKEN_API)
255 + QString("/search/games?query=") + QUrl::toPercentEncoding(query);
256
257 request.setUrl(QUrl(url));
258
259 QNetworkReply *reply = operation->get(request);
260
261 connect(reply, &QNetworkReply::finished, this, &NetworkManager::searchGamesReply);
262 }
263
getFeaturedStreams()264 void NetworkManager::getFeaturedStreams()
265 {
266 QNetworkRequest request;
267 //request.setRawHeader("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html");
268 request.setRawHeader("Accept", "application/vnd.twitchtv.v5+json");
269 request.setRawHeader("Client-ID", getClientId().toUtf8());
270 QString url = QString(KRAKEN_API)
271 + "/streams/featured?limit=25&offset=0";
272 request.setUrl(QUrl(url));
273
274 //qDebug() << url;
275
276 QNetworkReply *reply = operation->get(request);
277
278 connect(reply, &QNetworkReply::finished, this, &NetworkManager::featuredStreamsReply);
279 }
280
getStreamsForGame(const QString & game,const quint32 & offset,const quint32 & limit)281 void NetworkManager::getStreamsForGame(const QString &game, const quint32 &offset, const quint32 &limit)
282 {
283 QNetworkRequest request;
284 //request.setRawHeader("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html");
285 request.setRawHeader("Client-ID", getClientId().toUtf8());
286 request.setRawHeader("Accept", "application/vnd.twitchtv.v5+json");
287 QString url = QString(KRAKEN_API)
288 + QString("/streams?game=") + QUrl::toPercentEncoding(game)
289 + QString("&offset=%1").arg(offset)
290 + QString("&limit=%1").arg(limit);
291 request.setUrl(QUrl(url));
292
293 QNetworkReply *reply = operation->get(request);
294
295 connect(reply, &QNetworkReply::finished, this, &NetworkManager::gameStreamsReply);
296 }
297
getChannelPlaybackStream(const QString & channelName)298 void NetworkManager::getChannelPlaybackStream(const QString &channelName)
299 {
300 QString url = QString(TWITCH_API)
301 + QString("/channels/%1").arg(channelName)
302 + QString("/access_token");
303 QNetworkRequest request;
304 //request.setRawHeader("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html");
305 request.setRawHeader("Client-ID", getPrivateClientId().toUtf8());
306 request.setUrl(QUrl(url));
307
308 request.setAttribute(QNetworkRequest::User, LIVE);
309
310 QNetworkReply *reply = operation->get(request);
311
312 connect(reply, &QNetworkReply::finished, this, &NetworkManager::streamExtractReply);
313 }
314
getBroadcasts(const quint64 channelId,quint32 offset,quint32 limit)315 void NetworkManager::getBroadcasts(const quint64 channelId, quint32 offset, quint32 limit)
316 {
317 QString url = QString(KRAKEN_API)
318 + QString("/channels/%1/videos").arg(channelId)
319 + QString("?offset=%1").arg(offset)
320 + QString("&limit=%1").arg(limit);
321
322 if (ONLY_BROADCASTS)
323 url += "&broadcast_type=archive";
324
325 //if (USE_HLS)
326 //url += "&hls=true";
327
328 QNetworkRequest request;
329 //request.setRawHeader("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html");
330 request.setRawHeader("Accept", "application/vnd.twitchtv.v5+json");
331 request.setRawHeader("Client-ID", getClientId().toUtf8());
332 request.setUrl(QUrl(url));
333
334 QNetworkReply *reply = operation->get(request);
335
336 connect(reply, &QNetworkReply::finished, this, &NetworkManager::broadcastsReply);
337 }
338
getBroadcastPlaybackStream(const QString & vod)339 void NetworkManager::getBroadcastPlaybackStream(const QString &vod)
340 {
341 QString url = QString(TWITCH_API)
342 + QString("/vods/%1").arg(vod)
343 + QString("/access_token");
344 QNetworkRequest request;
345 //request.setRawHeader("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html");
346 request.setRawHeader("Client-ID", getPrivateClientId().toUtf8());
347 request.setUrl(QUrl(url));
348
349 request.setAttribute(QNetworkRequest::User, VOD);
350
351 QNetworkReply *reply = operation->get(request);
352
353 connect(reply, &QNetworkReply::finished, this, &NetworkManager::streamExtractReply);
354 }
355
getUser()356 void NetworkManager::getUser()
357 {
358 QString url = QString(KRAKEN_API) + "/user";
359 QString auth = "OAuth " + access_token;
360
361 QNetworkRequest request;
362 //request.setRawHeader("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html");
363 request.setRawHeader("Accept", "application/vnd.twitchtv.v5+json");
364 request.setRawHeader("Client-ID", getClientId().toUtf8());
365 request.setUrl(QUrl(url));
366 request.setRawHeader(QString("Authorization").toUtf8(), auth.toUtf8());
367
368 QNetworkReply *reply = operation->get(request);
369
370 connect(reply, &QNetworkReply::finished, this, &NetworkManager::userReply);
371 }
372
getUserFavourites(const quint64 userId,quint32 offset,quint32 limit)373 void NetworkManager::getUserFavourites(const quint64 userId, quint32 offset, quint32 limit)
374 {
375 if (!userId)
376 return;
377
378 QString url = QString(KRAKEN_API) + "/users/" + QString::number(userId) + "/follows/channels"
379 + QString("?offset=%1").arg(offset)
380 + QString("&limit=%1").arg(limit);
381 QNetworkRequest request;
382 //request.setRawHeader("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html");
383 request.setRawHeader("Accept", "application/vnd.twitchtv.v5+json");
384 request.setRawHeader("Client-ID", getClientId().toUtf8());
385 request.setUrl(QUrl(url));
386 request.setAttribute(QNetworkRequest::User, (int) (offset + limit));
387
388 QNetworkReply *reply = operation->get(request);
389
390 connect(reply, &QNetworkReply::finished, this, &NetworkManager::favouritesReply);
391 }
392
getEmoteSets(const QList<int> & emoteSetIDs)393 void NetworkManager::getEmoteSets(const QList<int> &emoteSetIDs) {
394 QList<QString> emoteSetsIDsStr;
395 for (auto id : emoteSetIDs) {
396 emoteSetsIDsStr.append(QString::number(id));
397 }
398
399 QString url = QString(KRAKEN_API) + "/chat/emoticon_images"
400 + QString("?emotesets=") + emoteSetsIDsStr.join(',');
401 QString auth = "OAuth " + access_token;
402
403 qDebug() << "Requesting" << url;
404
405 QNetworkRequest request;
406 //request.setRawHeader("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html");
407 request.setRawHeader("Accept", "application/vnd.twitchtv.v5+json");
408 request.setRawHeader("Client-ID", getClientId().toUtf8());
409 request.setUrl(QUrl(url));
410 request.setRawHeader(QString("Authorization").toUtf8(), auth.toUtf8());
411
412 QNetworkReply *reply = operation->get(request);
413
414 connect(reply, &QNetworkReply::finished, this, &NetworkManager::emoteSetsReply);
415 }
416
loadChatterList(const QString channel)417 void NetworkManager::loadChatterList(const QString channel) {
418 qDebug() << "Loading viewer list for" << channel;
419 const QString url = QString(TWITCH_TMI_USER_API) + channel + QString("/chatters");
420
421 qDebug() << "Request" << url;
422
423 QNetworkRequest request;
424 //request.setRawHeader("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html");
425 request.setUrl(url);
426
427 QNetworkReply *reply = operation->get(request);
428
429 connect(reply, &QNetworkReply::finished, this, &NetworkManager::chatterListReply);
430 }
431
getBlockedUserList(const quint64 userId,const quint32 offset,const quint32 limit)432 void NetworkManager::getBlockedUserList(const quint64 userId, const quint32 offset, const quint32 limit) {
433 qDebug() << "Loading blocked user list for user" << userId;
434 const QString url = QString(KRAKEN_API) + QString("/users/") + QString::number(userId) + QString("/blocks?offset=" + QString::number(offset) + "&limit=" + QString::number(limit) );
435 qDebug() << "Request" << url;
436
437 QNetworkRequest request;
438 //request.setRawHeader("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html");
439 request.setRawHeader("Accept", "application/vnd.twitchtv.v5+json");
440 request.setRawHeader("Client-ID", getClientId().toUtf8());
441 request.setUrl(url);
442
443 int nextOffset = offset + limit;
444 request.setAttribute(QNetworkRequest::User, nextOffset);
445
446 QString auth = "OAuth " + access_token;
447 request.setRawHeader(QString("Authorization").toUtf8(), auth.toUtf8());
448
449 QNetworkReply *reply = operation->get(request);
450
451 connect(reply, &QNetworkReply::finished, this, &NetworkManager::blockedUserListReply);
452 }
453
editUserBlock(const quint64 myUserId,const QString & blockUsername,const bool isBlock)454 void NetworkManager::editUserBlock(const quint64 myUserId, const QString & blockUsername, const bool isBlock) {
455 const QString url = QString(KRAKEN_API) + QString("/users?login=") + QUrl::toPercentEncoding(blockUsername);
456
457 QNetworkRequest request;
458 //request.setRawHeader("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html");
459 request.setRawHeader("Accept", "application/vnd.twitchtv.v5+json");
460 request.setRawHeader("Client-ID", getClientId().toUtf8());
461 request.setUrl(url);
462
463 request.setAttribute(QNetworkRequest::User, myUserId);
464 request.setAttribute(static_cast<QNetworkRequest::Attribute>(QNetworkRequest::User + 1), blockUsername);
465 request.setAttribute(static_cast<QNetworkRequest::Attribute>(QNetworkRequest::User + 2), isBlock);
466 request.setAttribute(static_cast<QNetworkRequest::Attribute>(QNetworkRequest::User + 3), access_token);
467
468 QNetworkReply *reply = operation->get(request);
469
470 connect(reply, &QNetworkReply::finished, this, &NetworkManager::blockUserLookupReply);
471 }
472
blockUserLookupReply()473 void NetworkManager::blockUserLookupReply() {
474 QNetworkReply* reply = qobject_cast<QNetworkReply *>(sender());
475
476 if (!handleNetworkError(reply)) {
477 return;
478 }
479
480 quint64 myUserId = reply->request().attribute(QNetworkRequest::User).toULongLong();
481 QString blockUsername = reply->request().attribute(static_cast<QNetworkRequest::Attribute>(QNetworkRequest::User + 1)).toString();
482 bool isBlock = reply->request().attribute(static_cast<QNetworkRequest::Attribute>(QNetworkRequest::User + 2)).toBool();
483 //QString access_token = reply->request().attribute(static_cast<QNetworkRequest::Attribute>(QNetworkRequest::User + 3)).toString();
484
485 QByteArray data = reply->readAll();
486 const auto & userIds = JsonParser::parseUsers(data);
487
488 if (userIds.length() == 0 || userIds[0] == 0) {
489 qDebug() << "userId lookup failed for" << blockUsername;
490 }
491
492 quint64 blockUserId = userIds[0];
493
494 editUserBlockWithId(myUserId, blockUsername, blockUserId, isBlock);
495 }
496
editUserBlockWithId(const quint64 myUserId,const QString & blockUsername,const quint64 blockUserId,const bool isBlock)497 void NetworkManager::editUserBlockWithId(const quint64 myUserId, const QString & blockUsername, const quint64 blockUserId, const bool isBlock) {
498 qDebug() << "Setting block for user" << blockUserId << "to" << isBlock << "for user" << myUserId;
499 const QString url = QString(KRAKEN_API) + QString("/users/") + QString::number(myUserId) + QString("/blocks/") + QString::number(blockUserId);
500 qDebug() << "Request" << url;
501
502 QNetworkRequest request;
503 //request.setRawHeader("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html");
504 request.setRawHeader("Accept", "application/vnd.twitchtv.v5+json");
505 request.setRawHeader("Client-ID", getClientId().toUtf8());
506 request.setUrl(url);
507
508 request.setAttribute(QNetworkRequest::User, myUserId);
509 request.setAttribute(static_cast<QNetworkRequest::Attribute>(QNetworkRequest::User + 1), blockUsername);
510 request.setAttribute(static_cast<QNetworkRequest::Attribute>(QNetworkRequest::User + 2), isBlock);
511
512 QString auth = "OAuth " + access_token;
513 request.setRawHeader(QString("Authorization").toUtf8(), auth.toUtf8());
514
515 QNetworkReply *reply;
516 if (isBlock) {
517 reply = operation->put(request, "");
518 }
519 else {
520 reply = operation->deleteResource(request);
521 }
522
523 connect(reply, &QNetworkReply::finished, this, &NetworkManager::blockUserReply);
524 }
525
blockUserReply()526 void NetworkManager::blockUserReply() {
527 QNetworkReply* reply = qobject_cast<QNetworkReply *>(sender());
528
529 if (!handleNetworkError(reply)) {
530 int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
531 if (statusCode == 401) {
532 qWarning() << "Warning: Not authorized to edit blocked users list; logout and log in again to update OAuth scopes";
533 }
534 return;
535 }
536
537 quint64 myUserId = reply->request().attribute(QNetworkRequest::User).toULongLong();
538 QString blockUsername = reply->request().attribute(static_cast<QNetworkRequest::Attribute>(QNetworkRequest::User + 1)).toString();
539 bool isBlock = reply->request().attribute(static_cast<QNetworkRequest::Attribute>(QNetworkRequest::User + 2)).toBool();
540
541 if (isBlock) {
542 emit userBlocked(myUserId, blockUsername);
543 }
544 else {
545 emit userUnblocked(myUserId, blockUsername);
546 }
547 }
548
chatterListReply()549 void NetworkManager::chatterListReply() {
550 QNetworkReply* reply = qobject_cast<QNetworkReply *>(sender());
551
552 if (!handleNetworkError(reply)) {
553 return;
554 }
555
556 QByteArray data = reply->readAll();
557
558 //qDebug() << data;
559
560 QMap<QString, QList<QString>> ret = JsonParser::parseChatterList(data);
561
562 emit chatterListLoadOperationFinished(ret);
563
564 reply->deleteLater();
565 }
566
blockedUserListReply()567 void NetworkManager::blockedUserListReply() {
568 QNetworkReply* reply = qobject_cast<QNetworkReply *>(sender());
569
570 if (!handleNetworkError(reply)) {
571 int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
572 if (statusCode == 401) {
573 qWarning() << "Warning: Not authorized to read blocked users list; logout and log in again to update OAuth scopes";
574 }
575 return;
576 }
577
578 QByteArray data = reply->readAll();
579
580 auto result = JsonParser::parseBlockList(data);
581
582 int nextOffset = reply->request().attribute(QNetworkRequest::User).toInt();
583
584 emit blockedUserListLoadOperationFinished(result.items, nextOffset, result.total);
585
586 reply->deleteLater();
587 }
588
getVodChatPiece(quint64 vodId,quint64 offset)589 void NetworkManager::getVodChatPiece(quint64 vodId, quint64 offset) {
590 QString url = QString(TWITCH_API_V5) + QString("/videos/%2/comments?content_offset_seconds=%1").arg(offset).arg(vodId);
591
592 qDebug() << "Requesting" << url;
593
594 QNetworkRequest request;
595 //request.setRawHeader("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html");
596 request.setRawHeader("Accept", "application/vnd.twitchtv.v5+json");
597 request.setRawHeader("Client-ID", getClientId().toUtf8());
598 request.setUrl(url);
599
600 QNetworkReply *reply = operation->get(request);
601
602 lastVodChatRequest = reply;
603
604 connect(reply, &QNetworkReply::finished, this, &NetworkManager::vodChatPieceReply);
605 }
606
getNextVodChatPiece(quint64 vodId,QString cursor)607 void NetworkManager::getNextVodChatPiece(quint64 vodId, QString cursor) {
608 QString url = QString(TWITCH_API_V5) + QString("/videos/%2/comments?cursor=%1").arg(cursor).arg(vodId);
609
610 qDebug() << "Requesting" << url;
611
612 QNetworkRequest request;
613 //request.setRawHeader("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html");
614 request.setRawHeader("Accept", "application/vnd.twitchtv.v5+json");
615 request.setRawHeader("Client-ID", getClientId().toUtf8());
616 request.setUrl(url);
617
618 QNetworkReply *reply = operation->get(request);
619
620 lastVodChatRequest = reply;
621
622 connect(reply, &QNetworkReply::finished, this, &NetworkManager::vodChatPieceReply);
623 }
624
cancelLastVodChatRequest()625 void NetworkManager::cancelLastVodChatRequest() {
626 if (lastVodChatRequest != nullptr) {
627 lastVodChatRequest->abort();
628 lastVodChatRequest = nullptr;
629 }
630 }
631
resetVodChat()632 void NetworkManager::resetVodChat() {
633 replayChatPartNum = 0;
634 curChatReplayDedupeBatch->clear();
635 prevChatReplayDedupeBatch->clear();
636 }
637
initReplayChat()638 void NetworkManager::initReplayChat() {
639 curChatReplayDedupeBatch = new QSet<QString>();
640 prevChatReplayDedupeBatch = new QSet<QString>();
641 }
642
teardownReplayChat()643 void NetworkManager::teardownReplayChat() {
644 delete curChatReplayDedupeBatch;
645 delete prevChatReplayDedupeBatch;
646 }
647
filterReplayChat(QList<ReplayChatMessage> & replayChat)648 void NetworkManager::filterReplayChat(QList<ReplayChatMessage> & replayChat) {
649 if (replayChatPartNum % REPLAY_CHAT_DEDUPE_SWAP_ITERATIONS == 0) {
650 auto oldPrev = prevChatReplayDedupeBatch;
651 prevChatReplayDedupeBatch = curChatReplayDedupeBatch;
652 oldPrev->clear();
653 curChatReplayDedupeBatch = oldPrev;
654 }
655
656 for (auto entry = replayChat.begin(); entry != replayChat.end(); ) {
657 if (entry->deleted || curChatReplayDedupeBatch->contains(entry->id) || prevChatReplayDedupeBatch->contains(entry->id)) {
658 qDebug() << "DUPE" << entry->from << ":" << entry->id << entry->message;
659 entry = replayChat.erase(entry);
660 }
661 else {
662 //qDebug() << "GOOD" << entry->from << ":" << entry->id << entry->message;
663 curChatReplayDedupeBatch->insert(entry->id);
664 entry++;
665 }
666 }
667
668 replayChatPartNum++;
669 }
670
vodChatPieceReply()671 void NetworkManager::vodChatPieceReply() {
672 QNetworkReply* reply = qobject_cast<QNetworkReply *>(sender());
673
674 if (lastVodChatRequest == reply) {
675 lastVodChatRequest = nullptr;
676 }
677
678 if (!handleNetworkError(reply)) {
679 return;
680 }
681
682 QByteArray data = reply->readAll();
683
684 //qDebug() << data;
685
686 ReplayChatPiece ret = JsonParser::parseVodChatPiece(data);
687
688 filterReplayChat(ret.comments);
689
690 emit vodChatPieceGetOperationFinished(ret);
691
692 reply->deleteLater();
693 }
694
695 const QString NetworkManager::CHANNEL_BADGES_URL_PREFIX = QString(KRAKEN_API) + "/chat/";
696 const QString NetworkManager::CHANNEL_BADGES_URL_SUFFIX = "/badges";
697
getChannelBadgeUrls(const quint64 channelId)698 void NetworkManager::getChannelBadgeUrls(const quint64 channelId) {
699 QString url = CHANNEL_BADGES_URL_PREFIX + QString::number(channelId) + CHANNEL_BADGES_URL_SUFFIX;
700 QString auth = "OAuth " + access_token;
701
702 qDebug() << "Requesting" << url;
703
704 QNetworkRequest request;
705 //request.setRawHeader("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html");
706 request.setRawHeader("Accept", "application/vnd.twitchtv.v5+json");
707 request.setRawHeader("Client-ID", getClientId().toUtf8());
708 request.setUrl(QUrl(url));
709 request.setRawHeader(QString("Authorization").toUtf8(), auth.toUtf8());
710
711 QNetworkReply *reply = operation->get(request);
712
713 connect(reply, &QNetworkReply::finished, this, &NetworkManager::channelBadgeUrlsReply);
714 }
715
716 const QString NetworkManager::CHANNEL_BADGES_BETA_URL_PREFIX = "https://badges.twitch.tv/v1/badges/channels/";
717 const QString NetworkManager::CHANNEL_BADGES_BETA_URL_SUFFIX = "/display?language=en";
718 const QString NetworkManager::GLOBAL_BADGES_BETA_URL = "https://badges.twitch.tv/v1/badges/global/display?language=en";
719
getChannelBadgeUrlsBeta(const int channelID)720 void NetworkManager::getChannelBadgeUrlsBeta(const int channelID) {
721 QString url = CHANNEL_BADGES_BETA_URL_PREFIX + QString::number(channelID) + CHANNEL_BADGES_BETA_URL_SUFFIX;
722
723 qDebug() << "Requesting" << url;
724
725 QNetworkRequest request;
726 //request.setRawHeader("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html");
727 request.setRawHeader("Accept", "application/vnd.twitchtv.v5+json");
728 request.setRawHeader("Client-ID", getClientId().toUtf8());
729 request.setUrl(QUrl(url));
730
731 QNetworkReply *reply = operation->get(request);
732
733 connect(reply, &QNetworkReply::finished, this, &NetworkManager::channelBadgeUrlsBetaReply);
734 }
735
getGlobalBadgesUrlsBeta()736 void NetworkManager::getGlobalBadgesUrlsBeta() {
737 QString url = GLOBAL_BADGES_BETA_URL;
738
739 qDebug() << "Requesting" << url;
740
741 QNetworkRequest request;
742 //request.setRawHeader("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html");
743 request.setRawHeader("Accept", "application/vnd.twitchtv.v5+json");
744 request.setRawHeader("Client-ID", getClientId().toUtf8());
745 request.setUrl(QUrl(url));
746
747 QNetworkReply *reply = operation->get(request);
748
749 connect(reply, &QNetworkReply::finished, this, &NetworkManager::globalBadgeUrlsBetaReply);
750 }
751
getChannelBitsUrls(const int channelID)752 void NetworkManager::getChannelBitsUrls(const int channelID) {
753 QString url = QString(KRAKEN_API) + QString("/bits/actions?channel_id=") + QString::number(channelID);
754
755 qDebug() << "Requesting" << url;
756
757 QNetworkRequest request;
758 //request.setRawHeader("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html");
759 request.setRawHeader("Client-ID", getClientId().toUtf8());
760 request.setRawHeader("Accept", QString("application/vnd.twitchtv.v5+json").toUtf8());
761 request.setUrl(QUrl(url));
762
763 QNetworkReply *reply = operation->get(request);
764
765 connect(reply, &QNetworkReply::finished, this, &NetworkManager::channelBitsUrlsReply);
766 }
767
channelBitsUrlsReply()768 void NetworkManager::channelBitsUrlsReply() {
769 QNetworkReply* reply = qobject_cast<QNetworkReply *>(sender());
770
771 if (!handleNetworkError(reply)) {
772 return;
773 }
774 QByteArray data = reply->readAll();
775
776 QString urlString = reply->url().toString();
777
778 qDebug() << "url was" << urlString;
779
780 int eqPos = urlString.lastIndexOf('=');
781
782 if (eqPos != -1) {
783 QString channelIDStr = urlString.mid(eqPos + 1);
784 int channelID = channelIDStr.toInt();
785 qDebug() << "bits urls for channel" << channelID << "loaded";
786 BitsQStringsMap urls;
787 BitsQStringsMap colors;
788 JsonParser::parseBitsData(data, urls, colors);
789
790 emit getChannelBitsUrlsOperationFinished(channelID, urls, colors);
791 }
792 else {
793 qDebug() << "can't determine channel from request url";
794 }
795
796 reply->deleteLater();
797 }
798
getGlobalBitsUrls()799 void NetworkManager::getGlobalBitsUrls() {
800 QString url = QString(KRAKEN_API) + QString("/bits/actions");
801
802 qDebug() << "Requesting" << url;
803
804 QNetworkRequest request;
805 //request.setRawHeader("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html");
806 request.setRawHeader("Accept", QString("application/vnd.twitchtv.v5+json").toUtf8());
807 request.setRawHeader("Client-ID", getClientId().toUtf8());
808 request.setUrl(QUrl(url));
809
810 QNetworkReply *reply = operation->get(request);
811
812 connect(reply, &QNetworkReply::finished, this, &NetworkManager::globalBitsUrlsReply);
813 }
814
globalBitsUrlsReply()815 void NetworkManager::globalBitsUrlsReply() {
816 QNetworkReply* reply = qobject_cast<QNetworkReply *>(sender());
817
818 if (!handleNetworkError(reply)) {
819 return;
820 }
821 QByteArray data = reply->readAll();
822
823 QString urlString = reply->url().toString();
824
825
826 BitsQStringsMap urls;
827 BitsQStringsMap colors;
828 JsonParser::parseBitsData(data, urls, colors);
829
830 emit getGlobalBitsUrlsOperationFinished(urls, colors);
831
832 reply->deleteLater();
833 }
834
getChannelBttvEmotes(const QString channel)835 void NetworkManager::getChannelBttvEmotes(const QString channel) {
836 QString url = QString(BTTV_API) + QString("/users/twitch/") + QUrl::toPercentEncoding(channel);
837
838 qDebug() << "Requesting" << url;
839
840 QNetworkRequest request;
841 request.setUrl(QUrl(url));
842
843 QNetworkReply *reply = operation->get(request);
844
845 connect(reply, &QNetworkReply::finished, this, &NetworkManager::channelBttvEmotesReply);
846 }
847
channelBttvEmotesReply()848 void NetworkManager::channelBttvEmotesReply() {
849 QNetworkReply* reply = qobject_cast<QNetworkReply *>(sender());
850
851 if (!handleNetworkError(reply)) {
852 return;
853 }
854 QByteArray data = reply->readAll();
855
856 auto url = reply->url();
857 QString urlString = url.toString();
858 QString channel = urlString.mid(urlString.lastIndexOf("/") + 1);
859
860 auto emotes = JsonParser::parseBttvEmotesData(data);
861
862 emit getChannelBttvEmotesOperationFinished(channel, emotes);
863
864 reply->deleteLater();
865 }
866
getGlobalBttvEmotes()867 void NetworkManager::getGlobalBttvEmotes() {
868 QString url = QString(BTTV_API) + QString("/emotes/global");
869
870 qDebug() << "Requesting" << url;
871
872 QNetworkRequest request;
873 request.setUrl(QUrl(url));
874
875 QNetworkReply *reply = operation->get(request);
876
877 connect(reply, &QNetworkReply::finished, this, &NetworkManager::globalBttvEmotesReply);
878 }
879
globalBttvEmotesReply()880 void NetworkManager::globalBttvEmotesReply() {
881 QNetworkReply* reply = qobject_cast<QNetworkReply *>(sender());
882
883 if (!handleNetworkError(reply)) {
884 return;
885 }
886 QByteArray data = reply->readAll();
887
888 auto emotes = JsonParser::parseBttvEmotesData(data);
889
890 emit getGlobalBttvEmotesOperationFinished(emotes);
891
892 reply->deleteLater();
893 }
894
editUserFavourite(const quint64 userId,const quint64 channelId,bool add)895 void NetworkManager::editUserFavourite(const quint64 userId, const quint64 channelId, bool add)
896 {
897 QString url = QString(KRAKEN_API) + "/users/" + QString::number(userId)
898 + "/follows/channels/" + QString::number(channelId);
899
900 QString auth = "OAuth " + access_token;
901
902 QNetworkRequest request;
903 //request.setRawHeader("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html");
904 request.setRawHeader("Accept", QString("application/vnd.twitchtv.v5+json").toUtf8());
905 request.setRawHeader("Client-ID", getClientId().toUtf8());
906 request.setUrl(QUrl(url));
907 request.setRawHeader(QString("Authorization").toUtf8(), auth.toUtf8());
908
909 QNetworkReply *reply = 0;
910
911 if (add)
912 reply = operation->put(request, QByteArray());
913 else
914 reply = operation->deleteResource(request);
915
916 connect(reply, &QNetworkReply::finished, this, &NetworkManager::editUserFavouritesReply);
917 }
918
getManager() const919 QNetworkAccessManager *NetworkManager::getManager() const
920 {
921 return operation;
922 }
923
getM3U8Data(const QString & url,M3U8TYPE type)924 void NetworkManager::getM3U8Data(const QString &url, M3U8TYPE type)
925 {
926 QNetworkRequest request;
927 //request.setRawHeader("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html");
928 request.setRawHeader("Client-ID", getClientId().toUtf8());
929 request.setUrl(QUrl(url));
930
931 request.setAttribute(QNetworkRequest::User, type);
932
933 QNetworkReply *reply = operation->get(request);
934
935 connect(reply, &QNetworkReply::finished, this, &NetworkManager::m3u8Reply);
936 }
937
handleNetworkError(QNetworkReply * reply)938 bool NetworkManager::handleNetworkError(QNetworkReply *reply)
939 {
940 if (reply->error() != QNetworkReply::NoError){
941
942 if (reply->error() >= 1 && reply->error() <= 199) {
943
944 if (connectionOK == true) {
945 connectionOK = false;
946 emit networkAccessChanged(false);
947 }
948
949 if (!offlinePoller.isActive())
950 offlinePoller.start();
951 }
952
953 qDebug() << reply->errorString();
954
955 return false;
956 }
957
958 if (!connectionOK) {
959 connectionOK = true;
960 emit networkAccessChanged(true);
961 }
962
963 if (offlinePoller.isActive())
964 offlinePoller.stop();
965
966 return true;
967 }
968
handleSslErrors(QNetworkReply *,QList<QSslError> errors)969 void NetworkManager::handleSslErrors(QNetworkReply * /*reply*/, QList<QSslError> errors)
970 {
971 foreach (const QSslError & e, errors) {
972 qDebug() << "Ssl error: " << e.errorString();
973 }
974
975 //reply->ignoreSslErrors(errors);
976 }
977
streamReply()978 void NetworkManager::streamReply()
979 {
980 QNetworkReply* reply = qobject_cast<QNetworkReply *>(sender());
981
982 if (!handleNetworkError(reply)) {
983 return;
984 }
985
986 QByteArray data = reply->readAll();
987
988 //qDebug() << data;
989
990 Channel *channel = JsonParser::parseStream(data);
991
992 QString channelIdStr = reply->url().toString();
993 channelIdStr.remove(0, channelIdStr.lastIndexOf('/') + 1);
994 const quint64 channelId = channelIdStr.toULongLong();
995
996 emit streamGetOperationFinished(channelId, channel->isOnline());
997
998 channel->deleteLater();
999
1000 reply->deleteLater();
1001 }
1002
addOfflineChannels(QList<Channel * > & channels,const QList<quint64> & expectedChannelIds)1003 void addOfflineChannels(QList<Channel *> & channels, const QList<quint64> & expectedChannelIds) {
1004 if (channels.count() < expectedChannelIds.count()) {
1005 QSet<quint64> unseenChannelIds = expectedChannelIds.toSet();
1006
1007 foreach(const Channel* channel, channels) {
1008 unseenChannelIds.remove(channel->getId());
1009 }
1010 foreach(const quint64 id, unseenChannelIds) {
1011 channels.append(new Channel(id));
1012 }
1013 }
1014 }
1015
1016 template <class U>
addULongLongStringList(U & modify,const QStringList & newItems)1017 void addULongLongStringList(U & modify, const QStringList & newItems) {
1018 modify.reserve(modify.length() + newItems.length());
1019 for (const QString & s : newItems) {
1020 modify.append(s.toULongLong());
1021 }
1022 }
1023
allStreamsReply()1024 void NetworkManager::allStreamsReply()
1025 {
1026 QNetworkReply* reply = qobject_cast<QNetworkReply *>(sender());
1027
1028 if (!handleNetworkError(reply)) {
1029 return;
1030 }
1031 QByteArray data = reply->readAll();
1032
1033 QList<quint64> queriedChannelIds;
1034
1035 const QUrlQuery query(reply->url().query());
1036 if (query.hasQueryItem("channel")) {
1037 addULongLongStringList(queriedChannelIds, query.queryItemValue("channel").split(","));
1038 }
1039
1040 PagedResult<Channel *> out = JsonParser::parseStreams(data);
1041
1042 addOfflineChannels(out.items, queriedChannelIds);
1043
1044 emit allStreamsOperationFinished(out.items);
1045
1046 reply->deleteLater();
1047 }
1048
searchGamesReply()1049 void NetworkManager::searchGamesReply()
1050 {
1051
1052 QNetworkReply* reply = qobject_cast<QNetworkReply *>(sender());
1053
1054 if (!handleNetworkError(reply)) {
1055 return;
1056 }
1057 QByteArray data = reply->readAll();
1058
1059 emit searchGamesOperationFinished(JsonParser::parseGames(data));
1060
1061 reply->deleteLater();
1062 }
1063
gamesReply()1064 void NetworkManager::gamesReply()
1065 {
1066 QNetworkReply* reply = qobject_cast<QNetworkReply *>(sender());
1067
1068 if (!handleNetworkError(reply)) {
1069 return;
1070 }
1071 QByteArray data = reply->readAll();
1072
1073 emit gamesOperationFinished(JsonParser::parseGames(data));
1074
1075 reply->deleteLater();
1076 }
1077
gameStreamsReply()1078 void NetworkManager::gameStreamsReply()
1079 {
1080 QNetworkReply* reply = qobject_cast<QNetworkReply *>(sender());
1081
1082 if (!handleNetworkError(reply)) {
1083 return;
1084 }
1085 QByteArray data = reply->readAll();
1086
1087 //qDebug() << data;
1088
1089 QList<quint64> queriedChannelIds;
1090
1091 const QUrlQuery query(reply->url().query());
1092 if (query.hasQueryItem("channel")) {
1093 addULongLongStringList(queriedChannelIds, query.queryItemValue("channel").split(","));
1094 }
1095
1096 PagedResult<Channel *> out = JsonParser::parseStreams(data);
1097
1098 addOfflineChannels(out.items, queriedChannelIds);
1099
1100 emit gameStreamsOperationFinished(out.items, out.total);
1101
1102 reply->deleteLater();
1103 }
1104
featuredStreamsReply()1105 void NetworkManager::featuredStreamsReply()
1106 {
1107 QNetworkReply* reply = qobject_cast<QNetworkReply *>(sender());
1108
1109 if (!handleNetworkError(reply)) {
1110 return;
1111 }
1112 QByteArray data = reply->readAll();
1113
1114 //qDebug() << data;
1115
1116 QList<Channel *> channels = JsonParser::parseFeatured(data);
1117 emit featuredStreamsOperationFinished(channels, channels.count());
1118
1119 reply->deleteLater();
1120 }
1121
searchChannelsReply()1122 void NetworkManager::searchChannelsReply()
1123 {
1124 QNetworkReply* reply = qobject_cast<QNetworkReply *>(sender());
1125
1126 if (!handleNetworkError(reply)) {
1127 return;
1128 }
1129 QByteArray data = reply->readAll();
1130
1131 //qDebug() << data;
1132
1133 auto result = JsonParser::parseChannels(data);
1134 emit searchChannelsOperationFinished(result.items, result.total);
1135
1136 reply->deleteLater();
1137 }
1138
streamExtractReply()1139 void NetworkManager::streamExtractReply()
1140 {
1141 QNetworkReply* reply = qobject_cast<QNetworkReply *>(sender());
1142
1143 if (!handleNetworkError(reply)) {
1144 emit error("token_error");
1145 return;
1146 }
1147
1148 QByteArray data = reply->readAll();
1149 //qDebug() << data;
1150
1151 M3U8TYPE type = (M3U8TYPE) reply->request().attribute(QNetworkRequest::User).toInt();
1152
1153 QString url;
1154
1155 switch (type) {
1156 case LIVE:
1157 url = JsonParser::parseChannelStreamExtractionInfo(data);
1158 break;
1159
1160 case VOD:
1161 url = JsonParser::parseVodExtractionInfo(data);
1162 break;
1163 }
1164
1165 getM3U8Data(url, type);
1166
1167 reply->deleteLater();
1168 }
1169
m3u8Reply()1170 void NetworkManager::m3u8Reply()
1171 {
1172 QNetworkReply* reply = qobject_cast<QNetworkReply *>(sender());
1173
1174 if (!handleNetworkError(reply)) {
1175
1176 emit error("playlist_error");
1177
1178 return;
1179 }
1180
1181 QByteArray data = reply->readAll();
1182
1183 switch ((M3U8TYPE) reply->request().attribute(QNetworkRequest::User).toInt()) {
1184 case LIVE:
1185 emit m3u8OperationFinished(m3u8::getUrls(data));
1186 break;
1187
1188 case VOD:
1189 emit m3u8OperationBFinished(m3u8::getUrls(data));
1190 break;
1191 }
1192 //qDebug() << data;
1193
1194 reply->deleteLater();
1195 }
1196
broadcastsReply()1197 void NetworkManager::broadcastsReply()
1198 {
1199 QNetworkReply* reply = qobject_cast<QNetworkReply *>(sender());
1200
1201 if (!handleNetworkError(reply)) {
1202 return;
1203 }
1204
1205 QByteArray data = reply->readAll();
1206
1207 emit broadcastsOperationFinished(JsonParser::parseVods(data));
1208
1209 reply->deleteLater();
1210 }
1211
favouritesReply()1212 void NetworkManager::favouritesReply()
1213 {
1214 QNetworkReply* reply = qobject_cast<QNetworkReply *>(sender());
1215
1216 if (!handleNetworkError(reply)) {
1217 return;
1218 }
1219
1220 QByteArray data = reply->readAll();
1221
1222 int offset = reply->request().attribute(QNetworkRequest::User).toInt();
1223
1224 auto result = JsonParser::parseFavourites(data);
1225 emit favouritesReplyFinished(result.items, offset, result.total);
1226
1227 reply->deleteLater();
1228 }
1229
editUserFavouritesReply()1230 void NetworkManager::editUserFavouritesReply()
1231 {
1232 QNetworkReply* reply = qobject_cast<QNetworkReply *>(sender());
1233
1234 if (!handleNetworkError(reply)) {
1235 return;
1236 }
1237
1238 //Nothing to do
1239 emit userEditFollowsOperationFinished();
1240
1241 reply->deleteLater();
1242 }
1243
userReply()1244 void NetworkManager::userReply()
1245 {
1246 QNetworkReply* reply = qobject_cast<QNetworkReply *>(sender());
1247
1248 if (!handleNetworkError(reply)) {
1249 return;
1250 }
1251 QByteArray data = reply->readAll();
1252
1253 auto pair = JsonParser::parseUser(data);
1254 emit userOperationFinished(pair.first, pair.second);
1255
1256 reply->deleteLater();
1257 }
1258
emoteSetsReply()1259 void NetworkManager::emoteSetsReply()
1260 {
1261 QNetworkReply* reply = qobject_cast<QNetworkReply *>(sender());
1262
1263 if (!handleNetworkError(reply)) {
1264 return;
1265 }
1266 QByteArray data = reply->readAll();
1267
1268 emit getEmoteSetsOperationFinished(JsonParser::parseEmoteSets(data));
1269
1270 reply->deleteLater();
1271 }
1272
channelBadgeUrlsReply()1273 void NetworkManager::channelBadgeUrlsReply()
1274 {
1275 QNetworkReply* reply = qobject_cast<QNetworkReply *>(sender());
1276
1277 if (!handleNetworkError(reply)) {
1278 return;
1279 }
1280 QByteArray data = reply->readAll();
1281
1282 QString urlString = reply->url().toString();
1283
1284 qDebug() << "url was" << urlString;
1285
1286 if (urlString.startsWith(CHANNEL_BADGES_URL_PREFIX) && urlString.endsWith(CHANNEL_BADGES_URL_SUFFIX)) {
1287 quint64 channelId = urlString.mid(CHANNEL_BADGES_URL_PREFIX.length(), urlString.length() - CHANNEL_BADGES_URL_PREFIX.length() - CHANNEL_BADGES_URL_SUFFIX.length()).toULongLong();
1288 qDebug() << "badges for channel" << channelId << "loaded";
1289 auto badges = JsonParser::parseChannelBadgeUrls(data);
1290
1291 emit getChannelBadgeUrlsOperationFinished(channelId, badges);
1292 }
1293 else {
1294 qDebug() << "can't determine channel from badges request url";
1295 }
1296
1297
1298 reply->deleteLater();
1299 }
1300
channelBadgeUrlsBetaReply()1301 void NetworkManager::channelBadgeUrlsBetaReply()
1302 {
1303 QNetworkReply* reply = qobject_cast<QNetworkReply *>(sender());
1304
1305 if (!handleNetworkError(reply)) {
1306 return;
1307 }
1308 QByteArray data = reply->readAll();
1309
1310 QString urlString = reply->url().toString();
1311
1312 qDebug() << "url was" << urlString;
1313
1314 if (urlString.startsWith(CHANNEL_BADGES_BETA_URL_PREFIX) && urlString.endsWith(CHANNEL_BADGES_BETA_URL_SUFFIX)) {
1315 QString channelIDStr = urlString.mid(CHANNEL_BADGES_BETA_URL_PREFIX.length(), urlString.length() - CHANNEL_BADGES_BETA_URL_PREFIX.length() - CHANNEL_BADGES_BETA_URL_SUFFIX.length());
1316 int channelID = channelIDStr.toInt();
1317 qDebug() << "beta badges for channel" << channelID << "loaded";
1318 auto badges = JsonParser::parseBadgeUrlsBetaFormat(data);
1319
1320 emit getChannelBadgeBetaUrlsOperationFinished(channelID, badges);
1321 }
1322 else {
1323 qDebug() << "can't determine channel from badges request url";
1324 }
1325
1326 reply->deleteLater();
1327 }
1328
globalBadgeUrlsBetaReply()1329 void NetworkManager::globalBadgeUrlsBetaReply()
1330 {
1331 QNetworkReply* reply = qobject_cast<QNetworkReply *>(sender());
1332
1333 if (!handleNetworkError(reply)) {
1334 return;
1335 }
1336 QByteArray data = reply->readAll();
1337
1338 QString urlString = reply->url().toString();
1339
1340 qDebug() << "url was" << urlString;
1341
1342 qDebug() << "global beta badges loaded";
1343 auto badges = JsonParser::parseBadgeUrlsBetaFormat(data);
1344
1345 emit getGlobalBadgeBetaUrlsOperationFinished(badges);
1346
1347 reply->deleteLater();
1348 }
1349