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 ®ion); 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 ¶meters) = 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 }