File indexing completed on 2025-01-19 04:28:13

0001 /**
0002  * SPDX-FileCopyrightText: 2021 Bart De Vries <bart@mogwai.be>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005  */
0006 
0007 #include "episodeactionrequest.h"
0008 
0009 #include <QJsonArray>
0010 #include <QJsonDocument>
0011 #include <QJsonObject>
0012 #include <QNetworkReply>
0013 #include <QSqlQuery>
0014 #include <QString>
0015 #include <QVector>
0016 
0017 #include "database.h"
0018 #include "synclogging.h"
0019 
0020 EpisodeActionRequest::EpisodeActionRequest(SyncUtils::Provider provider, QNetworkReply *reply, QObject *parent)
0021     : GenericRequest(provider, reply, parent)
0022 {
0023 }
0024 
0025 QVector<SyncUtils::EpisodeAction> EpisodeActionRequest::episodeActions() const
0026 {
0027     return m_episodeActions;
0028 }
0029 
0030 qulonglong EpisodeActionRequest::timestamp() const
0031 {
0032     return m_timestamp;
0033 }
0034 
0035 void EpisodeActionRequest::processResults()
0036 {
0037     if (m_reply->error()) {
0038         m_error = m_reply->error();
0039         m_errorString = m_reply->errorString();
0040         qCDebug(kastsSync) << "m_reply error" << m_reply->errorString();
0041     } else {
0042         QJsonParseError *error = nullptr;
0043         QJsonDocument data = QJsonDocument::fromJson(m_reply->readAll(), error);
0044         if (error) {
0045             qCDebug(kastsSync) << "parse error" << error->errorString();
0046             m_error = 1;
0047             m_errorString = error->errorString();
0048         } else if (!m_abort) {
0049             for (const auto &jsonAction : data.object().value(QStringLiteral("actions")).toArray()) {
0050                 SyncUtils::EpisodeAction episodeAction;
0051                 episodeAction.id = jsonAction.toObject().value(QStringLiteral("guid")).toString();
0052                 episodeAction.url = jsonAction.toObject().value(QStringLiteral("episode")).toString();
0053                 episodeAction.podcast = cleanupUrl(jsonAction.toObject().value(QStringLiteral("podcast")).toString());
0054                 episodeAction.device = jsonAction.toObject().value(QStringLiteral("device")).toString();
0055                 episodeAction.action = jsonAction.toObject().value(QStringLiteral("action")).toString().toLower();
0056                 if (episodeAction.action == QStringLiteral("play")) {
0057                     episodeAction.started = jsonAction.toObject().value(QStringLiteral("started")).toInt();
0058                     episodeAction.position = jsonAction.toObject().value(QStringLiteral("position")).toInt();
0059                     episodeAction.total = jsonAction.toObject().value(QStringLiteral("total")).toInt();
0060                 } else {
0061                     episodeAction.started = 0;
0062                     episodeAction.position = 0;
0063                     episodeAction.total = 0;
0064                 }
0065                 QString actionTimestamp = jsonAction.toObject().value(QStringLiteral("timestamp")).toString();
0066                 episodeAction.timestamp = static_cast<qulonglong>(
0067                     QDateTime::fromString(actionTimestamp.section(QStringLiteral("."), 0, 0), QStringLiteral("yyyy-MM-dd'T'hh:mm:ss")).toMSecsSinceEpoch()
0068                     / 1000);
0069 
0070                 // Now we try to find the id for the entry based on either the GUID
0071                 // or the episode download URL.  We also try to match with a percent-
0072                 // decoded version of the URL.
0073                 // There can be several hits (e.g. different entries pointing to the
0074                 // same download URL; we add all of them to make sure everything's
0075                 // consistent.
0076                 // We also retrieve the feedUrl from the database to avoid problems with
0077                 // different URLs pointing to the same feed (e.g. http vs https)
0078                 QSqlQuery query;
0079                 query.prepare(QStringLiteral("SELECT id, feed, url FROM Enclosures WHERE url=:url OR url=:decodeurl OR id=:id;"));
0080                 query.bindValue(QStringLiteral(":url"), episodeAction.url);
0081                 query.bindValue(QStringLiteral(":decodeurl"), cleanupUrl(episodeAction.url));
0082                 query.bindValue(QStringLiteral(":id"), episodeAction.id);
0083                 Database::instance().execute(query);
0084                 if (!query.next()) {
0085                     qCDebug(kastsSync) << "cannot find episode with url:" << episodeAction.url;
0086                     continue;
0087                 }
0088                 do {
0089                     SyncUtils::EpisodeAction action = episodeAction;
0090                     action.id = query.value(QStringLiteral("id")).toString();
0091                     action.podcast = query.value(QStringLiteral("feed")).toString();
0092                     action.url = query.value(QStringLiteral("url")).toString();
0093                     m_episodeActions += action;
0094                 } while (query.next());
0095             }
0096             m_timestamp = data.object().value(QStringLiteral("timestamp")).toInt();
0097         }
0098     }
0099     Q_EMIT finished();
0100     m_reply->deleteLater();
0101     deleteLater();
0102 }