File indexing completed on 2025-02-23 04:35:13

0001 // SPDX-FileCopyrightText: 2021 Linus Jahn <lnj@kaidan.im>
0002 // SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
0003 // SPDX-License-Identifier: GPL-3.0-or-later
0004 
0005 #pragma once
0006 
0007 #include "channel.h"
0008 #include "comment.h"
0009 #include "credentials.h"
0010 #include "playlist.h"
0011 #include "preferences.h"
0012 #include "searchparameters.h"
0013 #include "searchresult.h"
0014 #include "video.h"
0015 
0016 #include <QFuture>
0017 #include <QHash>
0018 #include <QNetworkCookie>
0019 #include <QNetworkReply>
0020 #include <QObject>
0021 
0022 #include <variant>
0023 
0024 class QNetworkAccessManager;
0025 
0026 namespace QInvidious
0027 {
0028 
0029 struct Comments {
0030     QList<Comment> comments;
0031     QString continuation;
0032 };
0033 
0034 using Error = std::pair<QNetworkReply::NetworkError, QString>;
0035 using Success = std::monostate;
0036 using LogInResult = std::variant<Credentials, Error>;
0037 using VideoResult = std::variant<Video, Error>;
0038 using VideoListResult = std::variant<QList<VideoBasicInfo>, Error>;
0039 using SubscriptionsResult = std::variant<QList<QString>, Error>;
0040 using Result = std::variant<Success, Error>;
0041 using HistoryResult = std::variant<QList<QString>, Error>;
0042 using CommentsResult = std::variant<Comments, Error>;
0043 using PlaylistsResult = std::variant<QList<Playlist>, Error>;
0044 using PreferencesResult = std::variant<Preferences, Error>;
0045 using ChannelResult = std::variant<QInvidious::Channel, Error>;
0046 using SearchListResult = std::variant<QList<SearchResult>, Error>;
0047 
0048 enum TrendingTopic : quint8 { Main, Music, Gaming, Movies, News };
0049 
0050 class AbstractApi : public QObject
0051 {
0052     Q_OBJECT
0053 
0054 public:
0055     explicit AbstractApi(QNetworkAccessManager *netManager, QObject *parent = nullptr);
0056 
0057     enum SupportedFeature { PopularPage, TrendingCategories };
0058     Q_ENUM(SupportedFeature);
0059 
0060     virtual bool supportsFeature(SupportedFeature feature) = 0;
0061 
0062     QString region() const;
0063     void setRegion(const QString &region);
0064 
0065     QString language() const;
0066     void setLanguage(const QString &language);
0067 
0068     Credentials credentials() const;
0069     void setCredentials(const Credentials &credentials);
0070 
0071     QNetworkAccessManager *net() const;
0072 
0073     void setApiHost(const QString &host);
0074     QString apiHost() const;
0075 
0076     virtual QFuture<LogInResult> logIn(QStringView username, QStringView password) = 0;
0077     virtual QFuture<VideoResult> requestVideo(QStringView videoId) = 0;
0078     virtual QString resolveVideoUrl(QStringView videoId) = 0;
0079     virtual QFuture<SearchListResult> requestSearchResults(const SearchParameters &parameters) = 0;
0080     virtual QFuture<VideoListResult> requestFeed(qint32 page = 1) = 0;
0081     virtual QFuture<VideoListResult> requestTop() = 0;
0082     virtual QFuture<VideoListResult> requestTrending(TrendingTopic = Main) = 0;
0083     virtual QFuture<VideoListResult> requestChannel(QStringView query, qint32 page = 1) = 0;
0084     virtual QFuture<SubscriptionsResult> requestSubscriptions() = 0;
0085     virtual QFuture<Result> subscribeToChannel(QStringView channel) = 0;
0086     virtual QFuture<Result> unsubscribeFromChannel(QStringView channel) = 0;
0087     virtual QFuture<HistoryResult> requestHistory(qint32 page = 1) = 0;
0088     virtual QFuture<Result> markWatched(const QString &videoId) = 0;
0089     virtual QFuture<Result> markUnwatched(const QString &videoId) = 0;
0090     virtual QFuture<CommentsResult> requestComments(const QString &videoId, const QString &continuation = {}) = 0;
0091     virtual QFuture<PlaylistsResult> requestPlaylists() = 0;
0092     virtual QFuture<PreferencesResult> requestPreferences() = 0;
0093     virtual QFuture<Result> setPreferences(const QInvidious::Preferences &preferences) = 0;
0094     virtual QFuture<VideoListResult> requestPlaylist(const QString &plid) = 0;
0095     virtual QFuture<ChannelResult> requestChannelInfo(QStringView queryd) = 0;
0096     virtual QFuture<Result> addVideoToPlaylist(const QString &plid, const QString &videoId) = 0;
0097     virtual QFuture<Result> removeVideoFromPlaylist(const QString &plid, const QString &indexId) = 0;
0098 
0099 Q_SIGNALS:
0100     void credentialsChanged();
0101 
0102 protected:
0103     QUrl apiUrl(const QString &path) const;
0104 
0105     template<typename T>
0106     QFuture<T> reportResults(QNetworkReply *reply, std::function<T(QNetworkReply *)> processs)
0107     {
0108         auto interface = std::make_shared<QFutureInterface<T>>(QFutureInterfaceBase::Started);
0109 
0110         connect(reply, &QNetworkReply::finished, this, [=]() {
0111             interface->reportResult(processs(reply));
0112             interface->reportFinished();
0113             reply->deleteLater();
0114         });
0115         connect(reply, &QNetworkReply::errorOccurred, this, [=](QNetworkReply::NetworkError error) {
0116             qWarning() << "Error for" << error << reply->url() << reply->errorString();
0117             interface->reportResult(std::pair(error, reply->errorString()));
0118             interface->reportFinished();
0119             reply->deleteLater();
0120         });
0121 
0122         return interface->future();
0123     }
0124 
0125     template<typename T>
0126     QFuture<T> get(QNetworkRequest &&request, std::function<T(QNetworkReply *)> processs)
0127     {
0128         return reportResults<T>(m_netManager->get(request), std::move(processs));
0129     }
0130 
0131     template<typename T>
0132     QFuture<T> post(QNetworkRequest &&request, const QByteArray &data, std::function<T(QNetworkReply *)> processs)
0133     {
0134         return reportResults<T>(m_netManager->post(request, data), std::move(processs));
0135     }
0136 
0137     template<typename T>
0138     QFuture<T> deleteResource(QNetworkRequest &&request, std::function<T(QNetworkReply *)> processs)
0139     {
0140         return reportResults<T>(m_netManager->deleteResource(request), std::move(processs));
0141     }
0142 
0143     QNetworkAccessManager *m_netManager;
0144     QString m_region;
0145     QString m_language;
0146     QString m_apiHost;
0147     Credentials m_credentials;
0148 };
0149 
0150 }