From b257fe60aae0c60a97003daa830d8220e8ab038a Mon Sep 17 00:00:00 2001 From: Henk Kalkwater Date: Wed, 28 Dec 2022 21:20:04 +0100 Subject: [PATCH 01/10] Discover remote sessions Adds a way of discovering remote sessions and in Jellyfin the UI. --- core/CMakeLists.txt | 76 ++++---- core/include/JellyfinQt/apiclient.h | 4 + .../JellyfinQt/model/controllablesession.h | 171 ++++++++++++++++++ .../JellyfinQt/model/playbackmanager.h | 23 +++ .../JellyfinQt/model/remotejellyfinplayback.h | 74 ++++++++ .../JellyfinQt/viewmodel/playbackmanager.h | 44 +++-- .../JellyfinQt/viewmodel/remotedevice.h | 118 ++++++++++++ core/include/JellyfinQt/viewmodel/usermodel.h | 10 +- core/src/apiclient.cpp | 19 +- core/src/jellyfin.cpp | 4 + core/src/model/controllablesession.cpp | 132 ++++++++++++++ core/src/model/player.cpp | 2 +- core/src/model/remotejellyfinplayback.cpp | 132 ++++++++++++++ core/src/viewmodel/playbackmanager.cpp | 75 ++++++-- core/src/viewmodel/remotedevice.cpp | 152 ++++++++++++++++ sailfish/CMakeLists.txt | 15 +- sailfish/qml/components/PlaybackBar.qml | 11 +- sailfish/qml/harbour-sailfin.qml | 1 + .../qml/pages/ControllableDevicesPage.qml | 63 +++++++ sailfish/qml/pages/MainPage.qml | 5 + 20 files changed, 1051 insertions(+), 80 deletions(-) create mode 100644 core/include/JellyfinQt/model/controllablesession.h create mode 100644 core/include/JellyfinQt/model/remotejellyfinplayback.h create mode 100644 core/include/JellyfinQt/viewmodel/remotedevice.h create mode 100644 core/src/model/controllablesession.cpp create mode 100644 core/src/model/remotejellyfinplayback.cpp create mode 100644 core/src/viewmodel/remotedevice.cpp create mode 100644 sailfish/qml/pages/ControllableDevicesPage.qml diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 3b444bc..e01a21d 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -13,12 +13,14 @@ include(GNUInstallDirs) include(GeneratedSources.cmake) set(JellyfinQt_SOURCES + src/model/controllablesession.cpp src/model/deviceprofile.cpp src/model/item.cpp src/model/player.cpp src/model/playbackmanager.cpp src/model/playbackreporter.cpp src/model/playlist.cpp + src/model/remotejellyfinplayback.cpp src/model/shuffle.cpp src/model/user.cpp @@ -32,6 +34,7 @@ set(JellyfinQt_SOURCES src/viewmodel/modelstatus.cpp src/viewmodel/playbackmanager.cpp src/viewmodel/playlist.cpp + src/viewmodel/remotedevice.cpp src/viewmodel/settings.cpp src/viewmodel/userdata.cpp src/viewmodel/usermodel.cpp @@ -49,41 +52,44 @@ set(JellyfinQt_SOURCES list(APPEND JellyfinQt_SOURCES ${openapi_SOURCES}) set(JellyfinQt_HEADERS - include/JellyfinQt/model/deviceprofile.h - include/JellyfinQt/model/item.h - include/JellyfinQt/model/player.h - include/JellyfinQt/model/playbackmanager.h - include/JellyfinQt/model/playbackreporter.h - include/JellyfinQt/model/playlist.h - include/JellyfinQt/model/shuffle.h - include/JellyfinQt/model/user.h - include/JellyfinQt/support/jsonconv.h - include/JellyfinQt/support/jsonconvimpl.h - include/JellyfinQt/support/loader.h - include/JellyfinQt/support/parseexception.h - include/JellyfinQt/viewmodel/item.h - include/JellyfinQt/viewmodel/itemmodel.h - include/JellyfinQt/viewmodel/loader.h - include/JellyfinQt/viewmodel/mediastream.h - include/JellyfinQt/viewmodel/modelstatus.h - include/JellyfinQt/viewmodel/propertyhelper.h - include/JellyfinQt/viewmodel/playbackmanager.h - include/JellyfinQt/viewmodel/platformmediacontrol.h - include/JellyfinQt/viewmodel/playlist.h - include/JellyfinQt/viewmodel/settings.h - include/JellyfinQt/viewmodel/userdata.h - include/JellyfinQt/viewmodel/usermodel.h - include/JellyfinQt/viewmodel/user.h - include/JellyfinQt/viewmodel/utils.h - include/JellyfinQt/apiclient.h - include/JellyfinQt/apimodel.h - include/JellyfinQt/credentialmanager.h - include/JellyfinQt/eventbus.h - include/JellyfinQt/jellyfin.h - include/JellyfinQt/jsonhelper.h - include/JellyfinQt/qobjectsettingswrapper.h - include/JellyfinQt/serverdiscoverymodel.h - include/JellyfinQt/websocket.h) + include/JellyfinQt/model/controllablesession.h + include/JellyfinQt/model/deviceprofile.h + include/JellyfinQt/model/item.h + include/JellyfinQt/model/player.h + include/JellyfinQt/model/playbackmanager.h + include/JellyfinQt/model/playbackreporter.h + include/JellyfinQt/model/playlist.h + include/JellyfinQt/model/remotejellyfinplayback.h + include/JellyfinQt/model/shuffle.h + include/JellyfinQt/model/user.h + include/JellyfinQt/support/jsonconv.h + include/JellyfinQt/support/jsonconvimpl.h + include/JellyfinQt/support/loader.h + include/JellyfinQt/support/parseexception.h + include/JellyfinQt/viewmodel/item.h + include/JellyfinQt/viewmodel/itemmodel.h + include/JellyfinQt/viewmodel/loader.h + include/JellyfinQt/viewmodel/mediastream.h + include/JellyfinQt/viewmodel/modelstatus.h + include/JellyfinQt/viewmodel/propertyhelper.h + include/JellyfinQt/viewmodel/playbackmanager.h + include/JellyfinQt/viewmodel/platformmediacontrol.h + include/JellyfinQt/viewmodel/playlist.h + include/JellyfinQt/viewmodel/remotedevice.h + include/JellyfinQt/viewmodel/settings.h + include/JellyfinQt/viewmodel/userdata.h + include/JellyfinQt/viewmodel/usermodel.h + include/JellyfinQt/viewmodel/user.h + include/JellyfinQt/viewmodel/utils.h + include/JellyfinQt/apiclient.h + include/JellyfinQt/apimodel.h + include/JellyfinQt/credentialmanager.h + include/JellyfinQt/eventbus.h + include/JellyfinQt/jellyfin.h + include/JellyfinQt/jsonhelper.h + include/JellyfinQt/qobjectsettingswrapper.h + include/JellyfinQt/serverdiscoverymodel.h + include/JellyfinQt/websocket.h) if (FREEDESKTOP_INTEGRATION) list(APPEND JellyfinQt_SOURCES diff --git a/core/include/JellyfinQt/apiclient.h b/core/include/JellyfinQt/apiclient.h index a96a5ed..d5cbbe6 100644 --- a/core/include/JellyfinQt/apiclient.h +++ b/core/include/JellyfinQt/apiclient.h @@ -96,6 +96,7 @@ public: explicit ApiClient(QObject *parent = nullptr); virtual ~ApiClient(); Q_PROPERTY(QString baseUrl READ baseUrl WRITE setBaseUrl NOTIFY baseUrlChanged) + Q_PROPERTY(QString appName READ appName WRITE setAppName NOTIFY appNameChanged) Q_PROPERTY(bool authenticated READ authenticated WRITE setAuthenticated NOTIFY authenticatedChanged) Q_PROPERTY(QString userId READ userId NOTIFY userIdChanged) Q_PROPERTY(QJsonObject deviceProfile READ deviceProfileJson NOTIFY deviceProfileChanged) @@ -114,6 +115,7 @@ public: bool authenticated() const; void setBaseUrl(const QString &url); + void setAppName(const QString &appName); QNetworkReply *get(const QString &path, const QUrlQuery ¶ms = QUrlQuery()); QNetworkReply *post(const QString &path, const QJsonDocument &data, const QUrlQuery ¶ms = QUrlQuery()); QNetworkReply *post(const QString &path, const QByteArray &data = QByteArray(), const QUrlQuery ¶ms = QUrlQuery()); @@ -127,6 +129,7 @@ public: Q_ENUM(ApiError) const QString &baseUrl() const; + const QString &appName() const; const QString &userId() const; const QString &deviceId() const; /** @@ -185,6 +188,7 @@ signals: void authenticatedChanged(bool authenticated); void baseUrlChanged(const QString &baseUrl); + void appNameChanged(const QString &newAppName); void settingsChanged(); /** diff --git a/core/include/JellyfinQt/model/controllablesession.h b/core/include/JellyfinQt/model/controllablesession.h new file mode 100644 index 0000000..3860b48 --- /dev/null +++ b/core/include/JellyfinQt/model/controllablesession.h @@ -0,0 +1,171 @@ +#ifndef JELLYFIN_MODEL_CONTROLLABLESESSION_H +#define JELLYFIN_MODEL_CONTROLLABLESESSION_H + +#include +#include +#include + +#include "JellyfinQt/dto/sessioninfo.h" + +namespace Jellyfin { + +class ApiClient; + +namespace DTO { +class ClientCapabilities; +} // NS DTO + +namespace Model { + +class PlaybackManager; + +class DeviceTypeClass { Q_GADGET +public: + enum Value { + Unknown, + Tv, + Computer, + Phone + }; + Q_ENUM(Value) +}; + +class MediaTypeClass { + Q_GADGET +public: + enum Value { + None = 0x0, + Audio = 0x1, + Video = 0x2, + Photo = 0x4 + }; + Q_DECLARE_FLAGS(MediaTypes, Value) +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(MediaTypeClass::MediaTypes) + +using DeviceType = DeviceTypeClass::Value; +using MediaTypes = MediaTypeClass::MediaTypes; + +/** + * @brief Abstract class for describing a playback session that can be controlled. + * + * Main purpose for this class is to hold information for displaying it in a UI for an user to select + * and to create an implementation of a PlaybackManager instance to control this session. + */ +class ControllableSession : public QObject { + Q_OBJECT +public: + explicit ControllableSession(QObject *parent = nullptr); + /** + * @brief An unique id for this session. + */ + virtual QString id() const = 0; + /** + * @brief An human-readable name for this session + */ + virtual QString name() const = 0; + /** + * @brief The app for this session + */ + virtual QString appName() const = 0; + virtual DeviceType deviceType() const = 0; + + /** + * @brief user The username of who started this session + */ + virtual QString userName() const = 0; + /** + * @brief Creates a playbackManager for this device. This PlaybackManager has no + * QObject parent and must be cleaned up by the caller. + */ + virtual PlaybackManager *createPlaybackManager() const = 0; +}; + +/** + * @brief Dummy session representing this device. + */ +class LocalSession : public ControllableSession { + Q_OBJECT +public: + LocalSession(ApiClient &apiClient, QObject *parent = nullptr); + QString id() const override; + QString name() const override; + QString appName() const override; + DeviceType deviceType() const override; + QString userName() const override; + PlaybackManager *createPlaybackManager() const override; +private: + ApiClient &m_apiClient; +}; + +/** + * @brief A session on the Jellyfin server that can be controlled. + */ +class ControllableJellyfinSession : public ControllableSession { + Q_OBJECT +public: + ControllableJellyfinSession(QSharedPointer info, QObject *parent = nullptr); + QString id() const override; + QString name() const override; + QString appName() const override; + DeviceType deviceType() const override; + QString userName() const override; + PlaybackManager *createPlaybackManager() const override; +private: + QSharedPointer m_data; +}; + +/** + * Abstract class for finding remotely controllable sessions + */ +class RemoteSessionScanner : public QObject { + Q_OBJECT +public: + explicit RemoteSessionScanner(QObject *parent = nullptr); + /** + * The session scanner should start discovering sessions + */ + virtual void startScanning() = 0; + /** + * The session scanner should stop discovering sessions + */ + virtual void stopScanning() = 0; +signals: + /** + * This signal should be emitted when an session has been discovered. + * The session should be reparented to whoever is listening for this signal. + */ + void sessionFound(Jellyfin::Model::ControllableSession *session); + /** + * Should be emitted when an session is gone. + */ + void sessionLost(const QString &sessionId); + /** + * Should be emitted when the listener should delete all sessions by this discoverer. + */ + void resetSessions(); +}; + + +class RemoteJellyfinSessionScannerPrivate; +/** + * @brief Lists controllable Jellyfin sessions from the Jellyfin server + */ +class RemoteJellyfinSessionScanner : public RemoteSessionScanner { + Q_OBJECT + Q_DECLARE_PRIVATE(RemoteJellyfinSessionScanner); +public: + explicit RemoteJellyfinSessionScanner(ApiClient *client, QObject *parent); + virtual ~RemoteJellyfinSessionScanner(); + + void startScanning() override; + void stopScanning() override; +private: + QScopedPointer d_ptr; +}; + +} // NS Model +} // NS Jellyfin + +#endif // JELLYFIN_MODEL_CONTROLLABLESESSION_H diff --git a/core/include/JellyfinQt/model/playbackmanager.h b/core/include/JellyfinQt/model/playbackmanager.h index 7918554..1b49bbc 100644 --- a/core/include/JellyfinQt/model/playbackmanager.h +++ b/core/include/JellyfinQt/model/playbackmanager.h @@ -62,10 +62,25 @@ class PlaybackManager : public QObject { Q_PROPERTY(bool resumePlayback READ resumePlayback WRITE setResumePlayback NOTIFY resumePlaybackChanged) Q_PROPERTY(int audioIndex READ audioIndex WRITE setAudioIndex NOTIFY audioIndexChanged) Q_PROPERTY(int subtitleIndex READ subtitleIndex WRITE setSubtitleIndex NOTIFY subtitleIndexChanged) + /** + * @brief The position in ticks in the currently playing item + */ Q_PROPERTY(qint64 position READ position NOTIFY positionChanged) + /** + * @brief The duration in ticks of the currently playing item + */ Q_PROPERTY(qint64 duration READ duration NOTIFY durationChanged) + /** + * @brief Whether the playbackmanager is currently able to seek + */ Q_PROPERTY(bool seekable READ seekable NOTIFY seekableChanged) + /** + * @brief Whether the currently playing item has audio + */ Q_PROPERTY(bool hasAudio READ hasAudio NOTIFY hasAudioChanged) + /** + * @brief Whether the currently playing item has video + */ Q_PROPERTY(bool hasVideo READ hasVideo NOTIFY hasVideoChanged) Q_PROPERTY(Jellyfin::Model::PlayerStateClass::Value playbackState READ playbackState NOTIFY playbackStateChanged) Q_PROPERTY(Jellyfin::Model::MediaStatusClass::Value mediaStatus READ mediaStatus NOTIFY mediaStatusChanged) @@ -104,7 +119,15 @@ public: virtual bool hasAudio() const = 0; virtual bool hasVideo() const = 0; + /** + * @brief Start playing the given item + */ virtual void playItem(QSharedPointer item) = 0; + /** + * @brief Set the playlist to the given playlist and start playing the item at the given index + * @param items The list of items to play + * @param index Index of the item to play + */ virtual void playItemInList(const QList> &items, int index) = 0; signals: diff --git a/core/include/JellyfinQt/model/remotejellyfinplayback.h b/core/include/JellyfinQt/model/remotejellyfinplayback.h new file mode 100644 index 0000000..2d123c3 --- /dev/null +++ b/core/include/JellyfinQt/model/remotejellyfinplayback.h @@ -0,0 +1,74 @@ +/* + * Sailfin: a Jellyfin client written using Qt + * Copyright (C) 2023 Chris Josten and the Sailfin Contributors. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef JELLYFIN_MODEL_REMOTEJELLYFINPLAYBACK_H +#define JELLYFIN_MODEL_REMOTEJELLYFINPLAYBACK_H + +#include +#include + +#include +#include + +namespace Jellyfin { + +class ApiClient; + +namespace Model { + +class RemoteJellyfinPlayback : public PlaybackManager { +public: + RemoteJellyfinPlayback(ApiClient &apiClient, QObject *parent = nullptr); + + + // PlaybackManager + void swap(PlaybackManager &other) override; + PlayerState playbackState() const override; + MediaStatus mediaStatus() const override; + bool hasNext() const override; + bool hasPrevious() const override; + PlaybackManagerError error() const override; + const QString &errorString() const override; + qint64 position() const override; + qint64 duration() const override; + bool seekable() const override; + bool hasAudio() const override; + bool hasVideo() const override; + void playItem(QSharedPointer item) override; + void playItemInList(const QList > &items, int index) override; + +public slots: + void pause() override; + void play() override; + void playItemId(const QString &id) override; + void previous() override; + void next() override; + void goTo(int index) override; + void stop() override; + void seek(qint64 pos) override; +private: + void sendGeneralCommand(DTO::GeneralCommandType command, QJsonObject arguments = QJsonObject()); + ApiClient &m_apiClient; +}; + + +} // NS Model +} // NS Jellyfin + + +#endif // JELLYFIN_MODEL_REMOTEJELLYFINPLAYBACK_H diff --git a/core/include/JellyfinQt/viewmodel/playbackmanager.h b/core/include/JellyfinQt/viewmodel/playbackmanager.h index 3d36907..c956ef9 100644 --- a/core/include/JellyfinQt/viewmodel/playbackmanager.h +++ b/core/include/JellyfinQt/viewmodel/playbackmanager.h @@ -20,11 +20,12 @@ #define JELLYFIN_VIEWMODEL_PLAYBACKMANAGER_H #include +#include #include #include #include -#include #include +#include #include #include #include @@ -34,17 +35,18 @@ #include -#include "../dto/baseitemdto.h" -#include "../dto/playbackinfodto.h" -#include "../dto/playbackinforesponse.h" -#include "../dto/playmethod.h" -#include "../loader/requesttypes.h" -#include "../model/player.h" -#include "../model/playlist.h" -#include "../support/jsonconv.h" -#include "../viewmodel/item.h" -#include "../viewmodel/playlist.h" -#include "../apiclient.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "itemmodel.h" @@ -81,6 +83,13 @@ public: virtual ~PlaybackManager(); Q_PROPERTY(ApiClient *apiClient READ apiClient WRITE setApiClient) + Q_PROPERTY(QString controllingSessionId READ controllingSessionId NOTIFY controllingSessionIdChanged) + Q_PROPERTY(QString controllingSessionName READ controllingSessionName NOTIFY controllingSessionNameChanged) + /** + * Whether the playback is done by this client + */ + Q_PROPERTY(bool controllingSessionLocal READ controllingSessionLocal NOTIFY controllingSessionLocalChanged) + Q_PROPERTY(int audioIndex READ audioIndex WRITE setAudioIndex NOTIFY audioIndexChanged) Q_PROPERTY(int subtitleIndex READ subtitleIndex WRITE setSubtitleIndex NOTIFY subtitleIndexChanged) Q_PROPERTY(QString streamUrl READ streamUrl NOTIFY streamUrlChanged) @@ -91,7 +100,7 @@ public: Q_PROPERTY(bool resumePlayback READ resumePlayback WRITE setResumePlayback NOTIFY resumePlaybackChanged) Q_PROPERTY(Jellyfin::DTO::PlayMethodClass::Value playMethod READ playMethod NOTIFY playMethodChanged) - // Current Item and queue informatoion + // Current Item and queue information Q_PROPERTY(QObject *item READ item NOTIFY itemChanged) Q_PROPERTY(int queueIndex READ queueIndex NOTIFY queueIndexChanged) Q_PROPERTY(Jellyfin::ViewModel::Playlist *queue READ queue NOTIFY queueChanged) @@ -124,6 +133,11 @@ public: ViewModel::Item *item() const; QSharedPointer dataItem() const; + QSharedPointer controllingSession() const; + void setControllingSession(QSharedPointer session); + QString controllingSessionId() const; + QString controllingSessionName() const; + bool controllingSessionLocal() const; QString streamUrl() const; PlayMethod playMethod() const; qint64 position() const; @@ -146,6 +160,10 @@ public: void setHandlePlaystateCommands(bool newHandlePlaystateCommands); signals: void itemChanged(); + void controllingSessionChanged(); + void controllingSessionIdChanged(); + void controllingSessionNameChanged(); + void controllingSessionLocalChanged(); void streamUrlChanged(const QString &newStreamUrl); void autoOpenChanged(bool autoOpen); void audioIndexChanged(int audioIndex); diff --git a/core/include/JellyfinQt/viewmodel/remotedevice.h b/core/include/JellyfinQt/viewmodel/remotedevice.h new file mode 100644 index 0000000..c5183da --- /dev/null +++ b/core/include/JellyfinQt/viewmodel/remotedevice.h @@ -0,0 +1,118 @@ +/* + * Sailfin: a Jellyfin client written using Qt + * Copyright (C) 2022 Chris Josten and the Sailfin Contributors. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef JELLYFIN_VIEWMODEL_REMOTEDEVICE_H +#define JELLYFIN_VIEWMODEL_REMOTEDEVICE_H + +#include + +#include +#include +#include +#include +#include + +#include + +namespace Jellyfin { + +class ApiClient; + +namespace ViewModel { + +class PlaybackManager; + +/** + * @brief AbstractListModel of remotely controllable devices by JellyfinQt. + * + * This class controls a set of \link ViewModel::RemoteSessionScanner RemoteSessionScanners\endlink and + * puts their found devices in this list. + */ +class RemoteDeviceList : public QAbstractListModel, public QQmlParserStatus { + Q_OBJECT + Q_INTERFACES(QQmlParserStatus) + + /** + * The ApiClient for interacting with the Jellyfin API. + */ + Q_PROPERTY(Jellyfin::ApiClient* apiClient READ apiClient WRITE setApiClient NOTIFY apiClientChanged) + /** + * Gets/sets whether the model is scanning for other devices. + */ + Q_PROPERTY(bool scanning READ scanning WRITE setScanning NOTIFY scanningChanged); +public: + enum RoleNames { + jellyfinId = Qt::UserRole + 1, + name, + deviceName, + deviceType, + userName, + session + }; + + explicit RemoteDeviceList(QObject *parent = nullptr); + + ApiClient *apiClient() const { return m_apiClient; } + void setApiClient(ApiClient *apiClient); + + bool scanning() const { return m_scanning; } + void setScanning(bool scanning); + + // QAbstractListModel + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role) const override; + QHash roleNames() const override { + return { + { RoleNames::jellyfinId, "jellyfinId"}, + { RoleNames::name, "name" }, + { RoleNames::deviceName, "deviceName" }, + { RoleNames::deviceType, "deviceType" }, + { RoleNames::userName, "userName" }, + { RoleNames::session, "session" } + }; + } + + /** + * @brief Sets the PlaybackManager to control the session at the given index in this model + * @param manager The PlaybackManager + * @param index The index of the session that should be controlled + */ + Q_INVOKABLE void activateSession(Jellyfin::ViewModel::PlaybackManager *manager, int index); + + // QQmlParserStatus + void classBegin() override; + void componentComplete() override; +signals: + void apiClientChanged(); + void scanningChanged(); +private slots: + void onSessionFound(Jellyfin::Model::ControllableSession * session); + void onSessionLost(QString sessionId); + void onSessionsReset(); +private: + ApiClient *m_apiClient = nullptr; + bool m_scanning = false; + bool m_componentComplete = false; + QList>> m_sessions; + QList m_scanners; +}; + +} // NS ViewModel +} // NS Jellyfin + +#endif // JELLYFIN_VIEWMODEL_REMOTEDEVICE_H diff --git a/core/include/JellyfinQt/viewmodel/usermodel.h b/core/include/JellyfinQt/viewmodel/usermodel.h index b49625a..1ea026a 100644 --- a/core/include/JellyfinQt/viewmodel/usermodel.h +++ b/core/include/JellyfinQt/viewmodel/usermodel.h @@ -43,17 +43,17 @@ public: userId = Qt::UserRole + 1, name, hasPassword, - primaryImageTag, + primaryImageTag }; explicit UserModel (QObject *parent = nullptr); virtual QHash roleNames() const override { return { - { RoleNames::userId, "userId" }, - { RoleNames::name, "name" }, - { RoleNames::hasPassword, "hasPassword" }, - { RoleNames::primaryImageTag, "primaryImageTag" }, + { RoleNames::userId, "userId" }, + { RoleNames::name, "name" }, + { RoleNames::hasPassword, "hasPassword" }, + { RoleNames::primaryImageTag, "primaryImageTag" } }; } QVariant data(const QModelIndex &index, int role) const override; diff --git a/core/src/apiclient.cpp b/core/src/apiclient.cpp index db6a33e..b607a0a 100644 --- a/core/src/apiclient.cpp +++ b/core/src/apiclient.cpp @@ -44,6 +44,7 @@ public: // Authentication-related variables QString token; QString baseUrl; + QString appName; QString deviceName; QString deviceId; QString userId; @@ -103,6 +104,21 @@ void ApiClient::setBaseUrl(const QString &url) { emit this->baseUrlChanged(d->baseUrl); } +const QString &ApiClient::appName() const { + const Q_D(ApiClient); + return d->appName; +} + +void ApiClient::setAppName(const QString &name) { + Q_D(ApiClient); + d->appName = name; + emit appNameChanged(name); + + if (!d->componentBeingParsed) { + generateDeviceProfile(); + } +} + const QString &ApiClient::userId() const { Q_D(const ApiClient); return d->userId; @@ -220,7 +236,7 @@ void ApiClient::addBaseRequestHeaders(QNetworkRequest &request, const QString &p void ApiClient::addTokenHeader(QNetworkRequest &request) const { Q_D(const ApiClient); QString authentication = "MediaBrowser "; - authentication += "Client=\"Sailfin\""; + authentication += "Client=\"" +d->appName +"\""; authentication += ", Device=\"" + d->deviceName + "\""; authentication += ", DeviceId=\"" + d->deviceId + "\""; authentication += ", Version=\"" + version() + "\""; @@ -425,7 +441,6 @@ QString ApiClient::downloadUrl(const QString &itemId) const { void ApiClient::generateDeviceProfile() { Q_D(ApiClient); QSharedPointer deviceProfile = QSharedPointer::create(Model::DeviceProfile::generateProfile()); - deviceProfile->setName(d->deviceName); deviceProfile->setJellyfinId(d->deviceId); deviceProfile->setFriendlyName(QSysInfo::prettyProductName()); deviceProfile->setMaxStreamingBitrate(d->settings->maxStreamingBitRate()); diff --git a/core/src/jellyfin.cpp b/core/src/jellyfin.cpp index 843a62c..f637bce 100644 --- a/core/src/jellyfin.cpp +++ b/core/src/jellyfin.cpp @@ -30,6 +30,7 @@ #include "JellyfinQt/eventbus.h" #include "JellyfinQt/serverdiscoverymodel.h" #include "JellyfinQt/websocket.h" +#include "JellyfinQt/model/controllablesession.h" #include "JellyfinQt/model/player.h" #include "JellyfinQt/viewmodel/item.h" #include "JellyfinQt/viewmodel/itemmodel.h" @@ -39,6 +40,7 @@ #include "JellyfinQt/viewmodel/platformmediacontrol.h" #include "JellyfinQt/viewmodel/playbackmanager.h" #include "JellyfinQt/viewmodel/playlist.h" +#include "JellyfinQt/viewmodel/remotedevice.h" #include "JellyfinQt/viewmodel/settings.h" #include "JellyfinQt/viewmodel/userdata.h" #include "JellyfinQt/viewmodel/usermodel.h" @@ -66,6 +68,7 @@ void JellyfinPlugin::registerTypes(const char *uri) { qmlRegisterType(uri, 1, 0, "ItemModel"); qmlRegisterType(uri, 1, 0, "UserModel"); qmlRegisterUncreatableType(uri, 1, 0, "Playlist", "Available via PlaybackManager"); + qmlRegisterType(uri, 1, 0, "RemoteDeviceList"); // Loaders qmlRegisterUncreatableType(uri, 1, 0, "LoaderBase", "Use one of its subclasses"); @@ -90,6 +93,7 @@ void JellyfinPlugin::registerTypes(const char *uri) { qmlRegisterUncreatableType(uri, 1, 0, "NowPlayingSection", "Is an enum"); qmlRegisterUncreatableType(uri, 1, 0, "PlayerState", "Is an enum"); qmlRegisterUncreatableType(uri, 1, 0, "MediaStatus", "Is an enum"); + qmlRegisterUncreatableType(uri, 1, 0, "DeviceType", "Is an enum"); qRegisterMetaType(); } diff --git a/core/src/model/controllablesession.cpp b/core/src/model/controllablesession.cpp new file mode 100644 index 0000000..1bec6a0 --- /dev/null +++ b/core/src/model/controllablesession.cpp @@ -0,0 +1,132 @@ +#include "JellyfinQt/model/controllablesession.h" + +#include + +#include "JellyfinQt/loader/http/session.h" +#include "JellyfinQt/loader/requesttypes.h" +#include + + +namespace Jellyfin { +namespace Model { + +ControllableSession::ControllableSession(QObject *parent) + : QObject(parent) {} + +// LocalSession +LocalSession::LocalSession(ApiClient &apiClient, QObject *parent) + : ControllableSession(parent), m_apiClient(apiClient) {} + +QString LocalSession::id() const { + return m_apiClient.deviceId(); +} + +QString LocalSession::appName() const { + return m_apiClient.appName(); +} + +QString LocalSession::name() const { + //: Shown in a list of devices to indicate that media should be played on this device + return tr("This device"); +} + +DeviceType LocalSession::deviceType() const { + return DeviceType::Unknown; +} + +QString LocalSession::userName() const { + return m_apiClient.userId(); +} + +PlaybackManager *LocalSession::createPlaybackManager() const { + return new LocalPlaybackManager(); +} + +// ControllableJellyfinSession +ControllableJellyfinSession::ControllableJellyfinSession(const QSharedPointer info, QObject *parent) + : ControllableSession(parent), + m_data(info) {} + +QString ControllableJellyfinSession::id() const { + return m_data->jellyfinId(); +} + +QString ControllableJellyfinSession::appName() const { + return m_data->client(); +} + +QString ControllableJellyfinSession::name() const { + return m_data->deviceName(); +} + +DeviceType ControllableJellyfinSession::deviceType() const { + return DeviceType::Unknown; +} + +QString ControllableJellyfinSession::userName() const { + return m_data->userName(); +} + +PlaybackManager * ControllableJellyfinSession::createPlaybackManager() const { + // TODO: implement + return nullptr; +} + +RemoteSessionScanner::RemoteSessionScanner(QObject *parent) + : QObject(parent) {} + +using GetSessionsLoader = Loader::HTTP::GetSessionsLoader; +class RemoteJellyfinSessionScannerPrivate { +public: + RemoteJellyfinSessionScannerPrivate(ApiClient *apiClient) + : apiClient(apiClient) { + }; + + ApiClient *apiClient; + GetSessionsLoader *loader = nullptr; +}; + + +RemoteJellyfinSessionScanner::RemoteJellyfinSessionScanner(ApiClient *apiClient, QObject *parent) + : RemoteSessionScanner(parent), + d_ptr(new RemoteJellyfinSessionScannerPrivate(apiClient)) { +} + +RemoteJellyfinSessionScanner::~RemoteJellyfinSessionScanner() {} + +void RemoteJellyfinSessionScanner::startScanning() { + Q_D(RemoteJellyfinSessionScanner); + if (d->loader != nullptr) return; + + emit resetSessions(); + emit sessionFound(new LocalSession(*d->apiClient)); + + Loader::GetSessionsParams params; + params.setControllableByUserId(d->apiClient->userId()); + d->loader = new GetSessionsLoader(d->apiClient); + d->loader->setParameters(params); + connect(d->loader, &Loader::HTTP::GetSessionsLoader::ready, this, [this, d]() { + if (d->loader == nullptr) return; + QList sessions = d->loader->result(); + + for(auto it = sessions.begin(); it != sessions.end(); it++) { + + // Skip this device + if (it->jellyfinId() == d->apiClient->deviceId()) continue; + + emit sessionFound(new ControllableJellyfinSession(QSharedPointer::create(*it))); + } + }); + d->loader->load(); +} + +void RemoteJellyfinSessionScanner::stopScanning() { + Q_D(RemoteJellyfinSessionScanner); + if (d->loader != nullptr) { + d->loader->deleteLater(); + d->loader = nullptr; + } +} + +} // NS Model +} // NS Jellyfin diff --git a/core/src/model/player.cpp b/core/src/model/player.cpp index e1213d7..62e3a4a 100644 --- a/core/src/model/player.cpp +++ b/core/src/model/player.cpp @@ -89,7 +89,7 @@ QtMultimediaPlayerPrivate::QtMultimediaPlayerPrivate(QtMultimediaPlayer *q) q->connect(m_mediaPlayer, &QMediaPlayer::seekableChanged, q, &QtMultimediaPlayer::seekableChanged); q->connect(m_mediaPlayer, &QMediaPlayer::audioAvailableChanged, q, &QtMultimediaPlayer::hasAudioChanged); q->connect(m_mediaPlayer, &QMediaPlayer::videoAvailableChanged, q, &QtMultimediaPlayer::hasVideoChanged); - q->connect(m_mediaPlayer, SIGNAL(error(QMediaPlayer::Error)), q, SLOT(errorStringChanged)); + //q->connect(m_mediaPlayer, SIGNAL(error(QMediaPlayer::Error)), q, SLOT(errorStringChanged(QString))); if (m_mediaStreamsControl != nullptr) { q->connect(m_mediaStreamsControl, &QMediaStreamsControl::streamsChanged, q, [this](){ qCDebug(player) << m_mediaStreamsControl->streamCount() << " streams in the medi source"; diff --git a/core/src/model/remotejellyfinplayback.cpp b/core/src/model/remotejellyfinplayback.cpp new file mode 100644 index 0000000..68bc84b --- /dev/null +++ b/core/src/model/remotejellyfinplayback.cpp @@ -0,0 +1,132 @@ +/* + * Sailfin: a Jellyfin client written using Qt + * Copyright (C) 2023 Chris Josten and the Sailfin Contributors. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include +#include +#include + +namespace Jellyfin { +namespace Model { + +RemoteJellyfinPlayback::RemoteJellyfinPlayback(ApiClient &apiClient, QObject *parent) + : PlaybackManager(parent), m_apiClient(apiClient) { + +} + +void RemoteJellyfinPlayback::swap(PlaybackManager &other) { + +} + +PlayerState RemoteJellyfinPlayback::playbackState() const { + +} + +MediaStatus RemoteJellyfinPlayback::mediaStatus() const { + +} + +bool RemoteJellyfinPlayback::hasNext() const { + +} + +bool RemoteJellyfinPlayback::hasPrevious() const { + +} + +PlaybackManagerError RemoteJellyfinPlayback::error() const { + +} + +const QString &RemoteJellyfinPlayback::errorString() const { + +} + +qint64 RemoteJellyfinPlayback::position() const { + +} + +qint64 RemoteJellyfinPlayback::duration() const { + +} + +bool RemoteJellyfinPlayback::seekable() const { + +} + +bool RemoteJellyfinPlayback::hasAudio() const { + +} + +bool RemoteJellyfinPlayback::hasVideo() const { + +} + +void RemoteJellyfinPlayback::playItem(QSharedPointer item) { + +} + +void RemoteJellyfinPlayback::playItemInList(const QList > &items, int index) { + +} + +void RemoteJellyfinPlayback::pause() { +} + +void RemoteJellyfinPlayback::play() { + +} + +void RemoteJellyfinPlayback::playItemId(const QString &id) { + +} + +void RemoteJellyfinPlayback::previous() { + +} + +void RemoteJellyfinPlayback::next() { + +} + +void RemoteJellyfinPlayback::goTo(int index) { + +} + +void RemoteJellyfinPlayback::stop() { + +} + +void RemoteJellyfinPlayback::seek(qint64 pos) { + +} + +void RemoteJellyfinPlayback::sendGeneralCommand(DTO::GeneralCommandType command, QJsonObject arguments) { + Loader::SendFullGeneralCommandParams params; + QSharedPointer fullCommand = QSharedPointer::create(command, m_apiClient.userId()); + fullCommand->setArguments(arguments); + // FIXME: send command +} + + + +} // NS Model +} // NS Jellyfin + diff --git a/core/src/viewmodel/playbackmanager.cpp b/core/src/viewmodel/playbackmanager.cpp index c296534..8ca1496 100644 --- a/core/src/viewmodel/playbackmanager.cpp +++ b/core/src/viewmodel/playbackmanager.cpp @@ -23,10 +23,13 @@ #include #include -// #include "JellyfinQt/DTO/dto.h" #include +#include #include #include + +#include + #include namespace Jellyfin { @@ -47,7 +50,8 @@ public: PlaybackManager *q_ptr = nullptr; ApiClient *m_apiClient = nullptr; - Model::PlaybackManager *m_impl = nullptr; + QSharedPointer m_session; + QScopedPointer m_impl; /// The currently played item that will be shown in the GUI ViewModel::Item *m_displayItem = nullptr; @@ -59,6 +63,7 @@ public: PlaybackManagerPrivate::PlaybackManagerPrivate(PlaybackManager *q) : q_ptr(q), + m_session(nullptr), m_impl(new Model::LocalPlaybackManager(q)), m_displayItem(new ViewModel::Item(q)), m_displayQueue(new ViewModel::Playlist(m_impl->queue())) { @@ -73,21 +78,22 @@ PlaybackManager::PlaybackManager(QObject *parent) Q_D(PlaybackManager); // Set up connections. - connect(d->m_impl, &Model::PlaybackManager::positionChanged, this, &PlaybackManager::positionChanged); - connect(d->m_impl, &Model::PlaybackManager::durationChanged, this, &PlaybackManager::durationChanged); - connect(d->m_impl, &Model::PlaybackManager::hasNextChanged, this, &PlaybackManager::hasNextChanged); - connect(d->m_impl, &Model::PlaybackManager::hasPreviousChanged, this, &PlaybackManager::hasPreviousChanged); - connect(d->m_impl, &Model::PlaybackManager::seekableChanged, this, &PlaybackManager::seekableChanged); - connect(d->m_impl, &Model::PlaybackManager::queueIndexChanged, this, &PlaybackManager::queueIndexChanged); - connect(d->m_impl, &Model::PlaybackManager::itemChanged, this, &PlaybackManager::mediaPlayerItemChanged); - connect(d->m_impl, &Model::PlaybackManager::playbackStateChanged, this, &PlaybackManager::playbackStateChanged); - if (auto localImp = qobject_cast(d->m_impl)) { + connect(d->m_impl.data(), &Model::PlaybackManager::positionChanged, this, &PlaybackManager::positionChanged); + connect(d->m_impl.data(), &Model::PlaybackManager::durationChanged, this, &PlaybackManager::durationChanged); + connect(d->m_impl.data(), &Model::PlaybackManager::hasNextChanged, this, &PlaybackManager::hasNextChanged); + connect(d->m_impl.data(), &Model::PlaybackManager::hasPreviousChanged, this, &PlaybackManager::hasPreviousChanged); + connect(d->m_impl.data(), &Model::PlaybackManager::seekableChanged, this, &PlaybackManager::seekableChanged); + connect(d->m_impl.data(), &Model::PlaybackManager::queueIndexChanged, this, &PlaybackManager::queueIndexChanged); + connect(d->m_impl.data(), &Model::PlaybackManager::itemChanged, this, &PlaybackManager::mediaPlayerItemChanged); + connect(d->m_impl.data(), &Model::PlaybackManager::playbackStateChanged, this, &PlaybackManager::playbackStateChanged); + + if (auto localImp = qobject_cast(d->m_impl.data())) { connect(localImp, &Model::LocalPlaybackManager::streamUrlChanged, this, [this](const QUrl& newUrl){ - this->streamUrlChanged(newUrl.toString()); + emit this->streamUrlChanged(newUrl.toString()); }); connect(localImp, &Model::LocalPlaybackManager::playMethodChanged, this, &PlaybackManager::playMethodChanged); } - connect(d->m_impl, &Model::PlaybackManager::mediaStatusChanged, this, &PlaybackManager::mediaStatusChanged); + connect(d->m_impl.data(), &Model::PlaybackManager::mediaStatusChanged, this, &PlaybackManager::mediaStatusChanged); } PlaybackManager::~PlaybackManager() { @@ -107,6 +113,10 @@ void PlaybackManager::setApiClient(ApiClient *apiClient) { d->m_impl->setApiClient(apiClient); if (d->m_apiClient != nullptr) { + // Set the session to a new LocalSession in case it hasn't been set yet. + if (d->m_session.isNull()) { + setControllingSession(QSharedPointer::create(*apiClient, this)); + } connect(d->m_apiClient->eventbus(), &EventBus::playstateCommandReceived, this, &PlaybackManager::handlePlaystateRequest); } } @@ -155,9 +165,42 @@ ApiClient * PlaybackManager::apiClient() const { return d->m_apiClient; } +QSharedPointer PlaybackManager::controllingSession() const { + const Q_D(PlaybackManager); + return d->m_session; +} + +void PlaybackManager::setControllingSession(QSharedPointer session) { + Q_D(PlaybackManager); + + qCDebug(playbackManager()) << "Now controlling session " << session->name(); + session->setParent(this); + d->m_session.swap(session); + // TODO: swap out playback manager + emit controllingSessionChanged(); + emit controllingSessionIdChanged(); + emit controllingSessionNameChanged(); + emit controllingSessionLocalChanged(); +} + +QString PlaybackManager::controllingSessionId() const { + const Q_D(PlaybackManager); + return d->m_session->id(); +} + +QString PlaybackManager::controllingSessionName() const { + const Q_D(PlaybackManager); + return d->m_session->name(); +} + +bool PlaybackManager::controllingSessionLocal() const { + const Q_D(PlaybackManager); + return qobject_cast(d->m_impl.data()) != nullptr; +} + QString PlaybackManager::streamUrl() const { const Q_D(PlaybackManager); - if (Model::LocalPlaybackManager *lpm = qobject_cast(d->m_impl)) { + if (Model::LocalPlaybackManager *lpm = qobject_cast(d->m_impl.data())) { return lpm->streamUrl().toString(); } else { return QStringLiteral(""); @@ -166,7 +209,7 @@ QString PlaybackManager::streamUrl() const { PlayMethod PlaybackManager::playMethod() const { const Q_D(PlaybackManager); - if (Model::LocalPlaybackManager *lpm = qobject_cast(d->m_impl)) { + if (Model::LocalPlaybackManager *lpm = qobject_cast(d->m_impl.data())) { return lpm->playMethod(); } else { return PlayMethod::EnumNotSet; @@ -210,7 +253,7 @@ bool PlaybackManager::hasPrevious() const { QObject* PlaybackManager::mediaObject() const { const Q_D(PlaybackManager); - if (auto localPb = qobject_cast(d->m_impl)) { + if (auto localPb = qobject_cast(d->m_impl.data())) { return localPb->player()->videoOutputSource(); } else { return nullptr; diff --git a/core/src/viewmodel/remotedevice.cpp b/core/src/viewmodel/remotedevice.cpp new file mode 100644 index 0000000..25236f9 --- /dev/null +++ b/core/src/viewmodel/remotedevice.cpp @@ -0,0 +1,152 @@ +/* + * Sailfin: a Jellyfin client written using Qt + * Copyright (C) 2022 Chris Josten and the Sailfin Contributors. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include +#include + +namespace Jellyfin { +namespace ViewModel { + +RemoteDeviceList::RemoteDeviceList(QObject *parent) + : QAbstractListModel(parent) {} + +void RemoteDeviceList::classBegin() {} +void RemoteDeviceList::componentComplete() { + m_componentComplete = true; + if (m_apiClient != nullptr) { + setApiClient(m_apiClient); + } +} + +void RemoteDeviceList::setApiClient(ApiClient *apiClient) { + if (m_apiClient != nullptr) { + for (auto it = m_scanners.begin(); it != m_scanners.end(); it++) { + disconnect(*it, &Model::RemoteSessionScanner::sessionFound, this, &RemoteDeviceList::onSessionFound); + disconnect(*it, &Model::RemoteSessionScanner::sessionLost, this, &RemoteDeviceList::onSessionLost); + disconnect(*it, &Model::RemoteSessionScanner::resetSessions, this, &RemoteDeviceList::onSessionsReset); + } + for (auto it = m_sessions.begin(); it != m_sessions.end(); it++) { + it->first->stopScanning(); + it->first->deleteLater(); + it->second->deleteLater(); + } + m_scanners.clear(); + m_sessions.clear(); + } + m_apiClient = apiClient; + emit apiClientChanged(); + if (!m_componentComplete) return; + + m_scanners.append(new Model::RemoteJellyfinSessionScanner(m_apiClient, this)); + for (auto it = m_scanners.begin(); it != m_scanners.end(); it++) { + connect(*it, &Model::RemoteSessionScanner::sessionFound, this, &RemoteDeviceList::onSessionFound); + connect(*it, &Model::RemoteSessionScanner::sessionLost, this, &RemoteDeviceList::onSessionLost); + connect(*it, &Model::RemoteSessionScanner::resetSessions, this, &RemoteDeviceList::onSessionsReset); + } +} + +int RemoteDeviceList::rowCount(const QModelIndex &parent) const { + return m_sessions.size(); +} + +QVariant RemoteDeviceList::data(const QModelIndex &index, int role) const { + int row = index.row(); + if (!index.isValid() || row < 0 || row > rowCount()) return QVariant(); + const QSharedPointer session = m_sessions.at(row).second; + if (session.isNull()) return QVariant(); + + switch (role) { + case RoleNames::jellyfinId: + return session->id(); + case RoleNames::name: + return session->name(); + case RoleNames::deviceName: + return session->appName(); + case RoleNames::deviceType: + return QVariant::fromValue(session->deviceType()); + case RoleNames::userName: + return session->userName(); + default: + return QVariant(); + } +} + +void RemoteDeviceList::activateSession(PlaybackManager *manager, int index) { + manager->setControllingSession(m_sessions.at(index).second); +} + +void RemoteDeviceList::setScanning(bool scanning) { + if (scanning == m_scanning) return; + m_scanning = scanning; + emit scanningChanged(); + + if (scanning) { + for (auto it = m_scanners.begin(); it != m_scanners.end(); it++) { + (*it)->startScanning(); + } + } else { + for (auto it = m_scanners.begin(); it != m_scanners.end(); it++) { + (*it)->stopScanning(); + } + } +} + +void RemoteDeviceList::onSessionFound(Model::ControllableSession *session) { + beginInsertRows(QModelIndex(), rowCount(), rowCount()); + m_sessions.append(std::make_pair(qobject_cast(sender()), QSharedPointer(session))); + endInsertRows(); +} + +void RemoteDeviceList::onSessionLost(QString sessionId) { + Model::RemoteSessionScanner *scanner = qobject_cast(sender()); + for (int i = 0; i < m_sessions.size(); i++) { + auto row = m_sessions.at(i); + if (row.first == scanner && row.second->name() == sessionId) { + beginRemoveRows(QModelIndex(), i, i); + m_sessions.removeAt(i); + if (row.second->parent() == this) { + row.second->deleteLater(); + } + endRemoveRows(); + i--; + } + } +} + +void RemoteDeviceList::onSessionsReset() { + Model::RemoteSessionScanner *scanner = qobject_cast(sender()); + for (int i = 0; i < m_sessions.size(); i++) { + auto row = m_sessions.at(i); + if (row.first == scanner) { + beginRemoveRows(QModelIndex(), i, i); + m_sessions.removeAt(i); + if (row.second->parent() == this) { + row.second->deleteLater(); + } + endRemoveRows(); + i--; + } + } +} + + +} // NS Model +} // NS Jellyfin diff --git a/sailfish/CMakeLists.txt b/sailfish/CMakeLists.txt index 5018548..8cf33fd 100644 --- a/sailfish/CMakeLists.txt +++ b/sailfish/CMakeLists.txt @@ -26,7 +26,7 @@ set(sailfin_QML_SOURCES qml/components/videoplayer/VideoError.qml qml/components/videoplayer/VideoHud.qml qml/components/IconListItem.qml - qml/components/ItemChildrenShowcase.qml + qml/components/ItemChildrenShowcase.qml qml/components/JItem.qml qml/components/LibraryItemDelegate.qml qml/components/MoreSection.qml @@ -39,14 +39,15 @@ set(sailfin_QML_SOURCES qml/components/UserGridDelegate.qml qml/components/VideoPlayer.qml qml/components/VideoTrackSelector.qml - qml/cover/CollectionPage.qml + qml/cover/CollectionPage.qml qml/cover/PosterCover.qml - qml/cover/NowPlayingCover.qml + qml/cover/NowPlayingCover.qml qml/pages/LegalPage.qml qml/pages/MainPage.qml qml/pages/AboutPage.qml - qml/harbour-sailfin.qml - qml/pages/ConnectingPage.qml + qml/harbour-sailfin.qml + qml/pages/ConnectingPage.qml + qml/pages/ControllableDevicesPage.qml qml/pages/SettingsPage.qml qml/pages/VideoPage.qml qml/pages/itemdetails/BaseDetailPage.qml @@ -54,8 +55,8 @@ set(sailfin_QML_SOURCES qml/pages/itemdetails/EpisodePage.qml qml/pages/itemdetails/FilmPage.qml qml/pages/itemdetails/MusicAlbumPage.qml - qml/pages/itemdetails/MusicArtistPage.qml - qml/pages/itemdetails/MusicLibraryPage.qml + qml/pages/itemdetails/MusicArtistPage.qml + qml/pages/itemdetails/MusicLibraryPage.qml qml/pages/itemdetails/PhotoPage.qml qml/pages/itemdetails/SeasonPage.qml qml/pages/itemdetails/SeriesPage.qml diff --git a/sailfish/qml/components/PlaybackBar.qml b/sailfish/qml/components/PlaybackBar.qml index 86bcaec..5614521 100644 --- a/sailfish/qml/components/PlaybackBar.qml +++ b/sailfish/qml/components/PlaybackBar.qml @@ -267,7 +267,16 @@ PanelBackground { states: [ State { name: "" - when: manager.playbackState !== J.PlayerState.Stopped && !isFullPage && !("__hidePlaybackBar" in pageStack.currentPage) + // Show the bar whenever: + // 1. Either one of the following is true: + // a. The playbackmanager is playing media + // b. The playbackmanager is controlling a remote session + // AND + // 2. The playback bar isn't in the full page state + // AND + // 3. The topmost page on the pagestack hasn't requested to hide the page + when: (manager.playbackState !== J.PlayerState.Stopped || !manager.controllingSessionLocal) + && !isFullPage && !("__hidePlaybackBar" in pageStack.currentPage) }, State { name: "large" diff --git a/sailfish/qml/harbour-sailfin.qml b/sailfish/qml/harbour-sailfin.qml index deeebd7..f968b5b 100644 --- a/sailfish/qml/harbour-sailfin.qml +++ b/sailfish/qml/harbour-sailfin.qml @@ -50,6 +50,7 @@ ApplicationWindow { ApiClient { id: _apiClient objectName: "Test" + appName: "Sailfin" supportedCommands: [GeneralCommandType.Play, GeneralCommandType.DisplayMessage] } diff --git a/sailfish/qml/pages/ControllableDevicesPage.qml b/sailfish/qml/pages/ControllableDevicesPage.qml new file mode 100644 index 0000000..2a40841 --- /dev/null +++ b/sailfish/qml/pages/ControllableDevicesPage.qml @@ -0,0 +1,63 @@ +import QtQuick 2.6 +import Sailfish.Silica 1.0 + +import nl.netsoj.chris.Jellyfin 1.0 as J +import ".." + +Page { + id: pageRoot + SilicaListView { + id: listView + anchors.fill: parent + contentHeight: Theme.itemSizeLarge + + header: PageHeader { + //: Page title: page for remote controlling other Jellyfin apps + title: qsTr("Remote control") + } + model: J.RemoteDeviceList { + id: deviceList + apiClient: appWindow.apiClient + scanning: pageRoot.status == PageStatus.Active + } + + delegate: ListItem { + property bool isConnected: model.jellyfinId === appWindow.playbackManager.controllingSessionId + onClicked: deviceList.activateSession(appWindow.playbackManager, model.index) + contentHeight: Theme.itemSizeMedium + HighlightImage { + id: deviceIcon + anchors { + left: parent.left + leftMargin: Theme.horizontalPageMargin + verticalCenter: parent.verticalCenter + } + height: parent.contentHeight - 2 * Theme.paddingMedium + width: height + source: "image://theme/icon-m-computer" + highlighted: parent.down || isConnected + } + Column { + anchors { + left: deviceIcon.right + right: parent.right + verticalCenter: parent.verticalCenter + leftMargin: Theme.paddingLarge + rightMargin: Theme.horizontalPageMargin + } + Label { + id: deviceName + //: List of devices item title in the form of + text: qsTr("%1 — %2").arg(model.name).arg(model.deviceName) + color: isConnected || highlighted ? Theme.highlightColor : Theme.primaryColor + } + Label { + id: deviceUser + text: model.userName + color: isConnected || highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor + } + } + } + } + +} diff --git a/sailfish/qml/pages/MainPage.qml b/sailfish/qml/pages/MainPage.qml index e894d75..d8019e0 100644 --- a/sailfish/qml/pages/MainPage.qml +++ b/sailfish/qml/pages/MainPage.qml @@ -45,6 +45,11 @@ Page { text: qsTr("Settings") onClicked: pageStack.push(Qt.resolvedUrl("SettingsPage.qml")) } + MenuItem { + //: Pulley menu item: shows controllable device page + text: qsTr("Remote control") + onClicked: pageStack.push(Qt.resolvedUrl("ControllableDevicesPage.qml")) + } MenuItem { //: Pulley menu item: reload items on page text: qsTr("Reload") From 77cb5d5957f65e87df7a69f7903dd51a33ed9fb4 Mon Sep 17 00:00:00 2001 From: Chris Josten Date: Mon, 2 Jan 2023 20:24:40 +0100 Subject: [PATCH 02/10] openapigen: support for 204 No Content endpoints --- core/include/JellyfinQt/loader/http/apikey.h | 28 + .../include/JellyfinQt/loader/http/branding.h | 4 +- .../JellyfinQt/loader/http/collection.h | 28 + .../JellyfinQt/loader/http/configuration.h | 42 ++ core/include/JellyfinQt/loader/http/devices.h | 28 + .../loader/http/displaypreferences.h | 14 + core/include/JellyfinQt/loader/http/dlna.h | 42 ++ .../JellyfinQt/loader/http/environment.h | 14 + .../JellyfinQt/loader/http/hlssegment.h | 14 + core/include/JellyfinQt/loader/http/image.h | 126 ++++ .../JellyfinQt/loader/http/itemlookup.h | 14 + .../JellyfinQt/loader/http/itemrefresh.h | 14 + .../JellyfinQt/loader/http/itemupdate.h | 28 + core/include/JellyfinQt/loader/http/library.h | 112 ++++ .../JellyfinQt/loader/http/librarystructure.h | 98 +++ core/include/JellyfinQt/loader/http/livetv.h | 140 +++++ .../JellyfinQt/loader/http/mediainfo.h | 14 + .../JellyfinQt/loader/http/notifications.h | 42 ++ core/include/JellyfinQt/loader/http/package.h | 42 ++ .../JellyfinQt/loader/http/playlists.h | 42 ++ .../JellyfinQt/loader/http/playstate.h | 98 +++ core/include/JellyfinQt/loader/http/plugins.h | 98 +++ .../JellyfinQt/loader/http/quickconnect.h | 28 + .../JellyfinQt/loader/http/remoteimage.h | 14 + .../JellyfinQt/loader/http/scheduledtasks.h | 42 ++ core/include/JellyfinQt/loader/http/session.h | 182 ++++++ core/include/JellyfinQt/loader/http/startup.h | 56 ++ .../include/JellyfinQt/loader/http/subtitle.h | 42 ++ .../include/JellyfinQt/loader/http/syncplay.h | 280 +++++++++ core/include/JellyfinQt/loader/http/system.h | 28 + core/include/JellyfinQt/loader/http/user.h | 84 +++ core/include/JellyfinQt/loader/http/videos.h | 28 + core/include/JellyfinQt/support/loader.h | 251 +++++--- core/openapigenerator.d | 6 +- core/src/loader/http/apikey.cpp | 59 ++ core/src/loader/http/branding.cpp | 4 +- core/src/loader/http/collection.cpp | 60 ++ core/src/loader/http/configuration.cpp | 87 +++ core/src/loader/http/devices.cpp | 60 ++ core/src/loader/http/displaypreferences.cpp | 31 + core/src/loader/http/dlna.cpp | 87 +++ core/src/loader/http/environment.cpp | 29 + core/src/loader/http/hlssegment.cpp | 35 ++ core/src/loader/http/image.cpp | 273 +++++++++ core/src/loader/http/itemlookup.cpp | 32 + core/src/loader/http/itemrefresh.cpp | 41 ++ core/src/loader/http/itemupdate.cpp | 61 ++ core/src/loader/http/library.cpp | 253 ++++++++ core/src/loader/http/librarystructure.cpp | 245 ++++++++ core/src/loader/http/livetv.cpp | 296 +++++++++ core/src/loader/http/mediainfo.cpp | 30 + core/src/loader/http/notifications.cpp | 99 +++ core/src/loader/http/package.cpp | 96 +++ core/src/loader/http/playlists.cpp | 96 +++ core/src/loader/http/playstate.cpp | 275 +++++++++ core/src/loader/http/plugins.cpp | 203 ++++++ core/src/loader/http/quickconnect.cpp | 61 ++ core/src/loader/http/remoteimage.cpp | 33 + core/src/loader/http/scheduledtasks.cpp | 87 +++ core/src/loader/http/session.cpp | 423 +++++++++++++ core/src/loader/http/startup.cpp | 116 ++++ core/src/loader/http/subtitle.cpp | 87 +++ core/src/loader/http/syncplay.cpp | 580 ++++++++++++++++++ core/src/loader/http/system.cpp | 58 ++ core/src/loader/http/user.cpp | 174 ++++++ core/src/loader/http/videos.cpp | 59 ++ 66 files changed, 6169 insertions(+), 84 deletions(-) diff --git a/core/include/JellyfinQt/loader/http/apikey.h b/core/include/JellyfinQt/loader/http/apikey.h index ee5c7c7..af7fa9f 100644 --- a/core/include/JellyfinQt/loader/http/apikey.h +++ b/core/include/JellyfinQt/loader/http/apikey.h @@ -61,6 +61,34 @@ protected: QByteArray body(const GetKeysParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Create a new api key. + */ + +class CreateKeyLoader : public Jellyfin::Support::HttpLoader { +public: + explicit CreateKeyLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const CreateKeyParams& parameters) const override; + QUrlQuery query(const CreateKeyParams& parameters) const override; + QByteArray body(const CreateKeyParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Remove an api key. + */ + +class RevokeKeyLoader : public Jellyfin::Support::HttpLoader { +public: + explicit RevokeKeyLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const RevokeKeyParams& parameters) const override; + QUrlQuery query(const RevokeKeyParams& parameters) const override; + QByteArray body(const RevokeKeyParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; } // NS HTTP } // NS Loader diff --git a/core/include/JellyfinQt/loader/http/branding.h b/core/include/JellyfinQt/loader/http/branding.h index fdfa68c..e584088 100644 --- a/core/include/JellyfinQt/loader/http/branding.h +++ b/core/include/JellyfinQt/loader/http/branding.h @@ -65,7 +65,7 @@ protected: * @brief Gets branding css. */ -class GetBrandingCssLoader : public Jellyfin::Support::HttpLoader { +class GetBrandingCssLoader : public Jellyfin::Support::HttpLoader { public: explicit GetBrandingCssLoader(ApiClient *apiClient = nullptr); @@ -79,7 +79,7 @@ protected: * @brief Gets branding css. */ -class GetBrandingCss_2Loader : public Jellyfin::Support::HttpLoader { +class GetBrandingCss_2Loader : public Jellyfin::Support::HttpLoader { public: explicit GetBrandingCss_2Loader(ApiClient *apiClient = nullptr); diff --git a/core/include/JellyfinQt/loader/http/collection.h b/core/include/JellyfinQt/loader/http/collection.h index fc2c7af..545ac3e 100644 --- a/core/include/JellyfinQt/loader/http/collection.h +++ b/core/include/JellyfinQt/loader/http/collection.h @@ -61,6 +61,34 @@ protected: QByteArray body(const CreateCollectionParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Adds items to a collection. + */ + +class AddToCollectionLoader : public Jellyfin::Support::HttpLoader { +public: + explicit AddToCollectionLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const AddToCollectionParams& parameters) const override; + QUrlQuery query(const AddToCollectionParams& parameters) const override; + QByteArray body(const AddToCollectionParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Removes items from a collection. + */ + +class RemoveFromCollectionLoader : public Jellyfin::Support::HttpLoader { +public: + explicit RemoveFromCollectionLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const RemoveFromCollectionParams& parameters) const override; + QUrlQuery query(const RemoveFromCollectionParams& parameters) const override; + QByteArray body(const RemoveFromCollectionParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; } // NS HTTP } // NS Loader diff --git a/core/include/JellyfinQt/loader/http/configuration.h b/core/include/JellyfinQt/loader/http/configuration.h index d66d18a..f2636e7 100644 --- a/core/include/JellyfinQt/loader/http/configuration.h +++ b/core/include/JellyfinQt/loader/http/configuration.h @@ -62,6 +62,20 @@ protected: QByteArray body(const GetConfigurationParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Updates application configuration. + */ + +class UpdateConfigurationLoader : public Jellyfin::Support::HttpLoader { +public: + explicit UpdateConfigurationLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const UpdateConfigurationParams& parameters) const override; + QUrlQuery query(const UpdateConfigurationParams& parameters) const override; + QByteArray body(const UpdateConfigurationParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Gets a named configuration. */ @@ -76,6 +90,20 @@ protected: QByteArray body(const GetNamedConfigurationParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Updates named configuration. + */ + +class UpdateNamedConfigurationLoader : public Jellyfin::Support::HttpLoader { +public: + explicit UpdateNamedConfigurationLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const UpdateNamedConfigurationParams& parameters) const override; + QUrlQuery query(const UpdateNamedConfigurationParams& parameters) const override; + QByteArray body(const UpdateNamedConfigurationParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Gets a default MetadataOptions object. */ @@ -90,6 +118,20 @@ protected: QByteArray body(const GetDefaultMetadataOptionsParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Updates the path to the media encoder. + */ + +class UpdateMediaEncoderPathLoader : public Jellyfin::Support::HttpLoader { +public: + explicit UpdateMediaEncoderPathLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const UpdateMediaEncoderPathParams& parameters) const override; + QUrlQuery query(const UpdateMediaEncoderPathParams& parameters) const override; + QByteArray body(const UpdateMediaEncoderPathParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; } // NS HTTP } // NS Loader diff --git a/core/include/JellyfinQt/loader/http/devices.h b/core/include/JellyfinQt/loader/http/devices.h index 0b8dfe5..54c6bdc 100644 --- a/core/include/JellyfinQt/loader/http/devices.h +++ b/core/include/JellyfinQt/loader/http/devices.h @@ -63,6 +63,20 @@ protected: QByteArray body(const GetDevicesParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Deletes a device. + */ + +class DeleteDeviceLoader : public Jellyfin::Support::HttpLoader { +public: + explicit DeleteDeviceLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const DeleteDeviceParams& parameters) const override; + QUrlQuery query(const DeleteDeviceParams& parameters) const override; + QByteArray body(const DeleteDeviceParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Get info for a device. */ @@ -91,6 +105,20 @@ protected: QByteArray body(const GetDeviceOptionsParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Update device options. + */ + +class UpdateDeviceOptionsLoader : public Jellyfin::Support::HttpLoader { +public: + explicit UpdateDeviceOptionsLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const UpdateDeviceOptionsParams& parameters) const override; + QUrlQuery query(const UpdateDeviceOptionsParams& parameters) const override; + QByteArray body(const UpdateDeviceOptionsParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; } // NS HTTP } // NS Loader diff --git a/core/include/JellyfinQt/loader/http/displaypreferences.h b/core/include/JellyfinQt/loader/http/displaypreferences.h index 8493181..f1eb715 100644 --- a/core/include/JellyfinQt/loader/http/displaypreferences.h +++ b/core/include/JellyfinQt/loader/http/displaypreferences.h @@ -61,6 +61,20 @@ protected: QByteArray body(const GetDisplayPreferencesParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Update Display Preferences. + */ + +class UpdateDisplayPreferencesLoader : public Jellyfin::Support::HttpLoader { +public: + explicit UpdateDisplayPreferencesLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const UpdateDisplayPreferencesParams& parameters) const override; + QUrlQuery query(const UpdateDisplayPreferencesParams& parameters) const override; + QByteArray body(const UpdateDisplayPreferencesParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; } // NS HTTP } // NS Loader diff --git a/core/include/JellyfinQt/loader/http/dlna.h b/core/include/JellyfinQt/loader/http/dlna.h index 38a3c2c..67f1b80 100644 --- a/core/include/JellyfinQt/loader/http/dlna.h +++ b/core/include/JellyfinQt/loader/http/dlna.h @@ -63,6 +63,20 @@ protected: QByteArray body(const GetProfileInfosParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Creates a profile. + */ + +class CreateProfileLoader : public Jellyfin::Support::HttpLoader { +public: + explicit CreateProfileLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const CreateProfileParams& parameters) const override; + QUrlQuery query(const CreateProfileParams& parameters) const override; + QByteArray body(const CreateProfileParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Gets a single profile. */ @@ -77,6 +91,34 @@ protected: QByteArray body(const GetProfileParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Deletes a profile. + */ + +class DeleteProfileLoader : public Jellyfin::Support::HttpLoader { +public: + explicit DeleteProfileLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const DeleteProfileParams& parameters) const override; + QUrlQuery query(const DeleteProfileParams& parameters) const override; + QByteArray body(const DeleteProfileParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Updates a profile. + */ + +class UpdateProfileLoader : public Jellyfin::Support::HttpLoader { +public: + explicit UpdateProfileLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const UpdateProfileParams& parameters) const override; + QUrlQuery query(const UpdateProfileParams& parameters) const override; + QByteArray body(const UpdateProfileParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Gets the default profile. */ diff --git a/core/include/JellyfinQt/loader/http/environment.h b/core/include/JellyfinQt/loader/http/environment.h index 74e38d1..02ed78e 100644 --- a/core/include/JellyfinQt/loader/http/environment.h +++ b/core/include/JellyfinQt/loader/http/environment.h @@ -120,6 +120,20 @@ protected: QByteArray body(const GetParentPathParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Validates path. + */ + +class ValidatePathLoader : public Jellyfin::Support::HttpLoader { +public: + explicit ValidatePathLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const ValidatePathParams& parameters) const override; + QUrlQuery query(const ValidatePathParams& parameters) const override; + QByteArray body(const ValidatePathParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; } // NS HTTP } // NS Loader diff --git a/core/include/JellyfinQt/loader/http/hlssegment.h b/core/include/JellyfinQt/loader/http/hlssegment.h index cff457c..14dfcf8 100644 --- a/core/include/JellyfinQt/loader/http/hlssegment.h +++ b/core/include/JellyfinQt/loader/http/hlssegment.h @@ -46,6 +46,20 @@ namespace HTTP { using namespace Jellyfin::DTO; +/** + * @brief Stops an active encoding. + */ + +class StopEncodingProcessLoader : public Jellyfin::Support::HttpLoader { +public: + explicit StopEncodingProcessLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const StopEncodingProcessParams& parameters) const override; + QUrlQuery query(const StopEncodingProcessParams& parameters) const override; + QByteArray body(const StopEncodingProcessParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; } // NS HTTP } // NS Loader diff --git a/core/include/JellyfinQt/loader/http/image.h b/core/include/JellyfinQt/loader/http/image.h index eeb808b..0bb28f6 100644 --- a/core/include/JellyfinQt/loader/http/image.h +++ b/core/include/JellyfinQt/loader/http/image.h @@ -61,6 +61,132 @@ protected: QByteArray body(const GetItemImageInfosParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Delete an item's image. + */ + +class DeleteItemImageLoader : public Jellyfin::Support::HttpLoader { +public: + explicit DeleteItemImageLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const DeleteItemImageParams& parameters) const override; + QUrlQuery query(const DeleteItemImageParams& parameters) const override; + QByteArray body(const DeleteItemImageParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Set item image. + */ + +class SetItemImageLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SetItemImageLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SetItemImageParams& parameters) const override; + QUrlQuery query(const SetItemImageParams& parameters) const override; + QByteArray body(const SetItemImageParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Delete an item's image. + */ + +class DeleteItemImageByIndexLoader : public Jellyfin::Support::HttpLoader { +public: + explicit DeleteItemImageByIndexLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const DeleteItemImageByIndexParams& parameters) const override; + QUrlQuery query(const DeleteItemImageByIndexParams& parameters) const override; + QByteArray body(const DeleteItemImageByIndexParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Set item image. + */ + +class SetItemImageByIndexLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SetItemImageByIndexLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SetItemImageByIndexParams& parameters) const override; + QUrlQuery query(const SetItemImageByIndexParams& parameters) const override; + QByteArray body(const SetItemImageByIndexParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Updates the index for an item image. + */ + +class UpdateItemImageIndexLoader : public Jellyfin::Support::HttpLoader { +public: + explicit UpdateItemImageIndexLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const UpdateItemImageIndexParams& parameters) const override; + QUrlQuery query(const UpdateItemImageIndexParams& parameters) const override; + QByteArray body(const UpdateItemImageIndexParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Sets the user image. + */ + +class PostUserImageLoader : public Jellyfin::Support::HttpLoader { +public: + explicit PostUserImageLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const PostUserImageParams& parameters) const override; + QUrlQuery query(const PostUserImageParams& parameters) const override; + QByteArray body(const PostUserImageParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Delete the user's image. + */ + +class DeleteUserImageLoader : public Jellyfin::Support::HttpLoader { +public: + explicit DeleteUserImageLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const DeleteUserImageParams& parameters) const override; + QUrlQuery query(const DeleteUserImageParams& parameters) const override; + QByteArray body(const DeleteUserImageParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Sets the user image. + */ + +class PostUserImageByIndexLoader : public Jellyfin::Support::HttpLoader { +public: + explicit PostUserImageByIndexLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const PostUserImageByIndexParams& parameters) const override; + QUrlQuery query(const PostUserImageByIndexParams& parameters) const override; + QByteArray body(const PostUserImageByIndexParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Delete the user's image. + */ + +class DeleteUserImageByIndexLoader : public Jellyfin::Support::HttpLoader { +public: + explicit DeleteUserImageByIndexLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const DeleteUserImageByIndexParams& parameters) const override; + QUrlQuery query(const DeleteUserImageByIndexParams& parameters) const override; + QByteArray body(const DeleteUserImageByIndexParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; } // NS HTTP } // NS Loader diff --git a/core/include/JellyfinQt/loader/http/itemlookup.h b/core/include/JellyfinQt/loader/http/itemlookup.h index 63c4d89..442ea79 100644 --- a/core/include/JellyfinQt/loader/http/itemlookup.h +++ b/core/include/JellyfinQt/loader/http/itemlookup.h @@ -70,6 +70,20 @@ protected: QByteArray body(const GetExternalIdInfosParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Applies search criteria to an item and refreshes metadata. + */ + +class ApplySearchCriteriaLoader : public Jellyfin::Support::HttpLoader { +public: + explicit ApplySearchCriteriaLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const ApplySearchCriteriaParams& parameters) const override; + QUrlQuery query(const ApplySearchCriteriaParams& parameters) const override; + QByteArray body(const ApplySearchCriteriaParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Get book remote search. */ diff --git a/core/include/JellyfinQt/loader/http/itemrefresh.h b/core/include/JellyfinQt/loader/http/itemrefresh.h index 3489f50..61ec6be 100644 --- a/core/include/JellyfinQt/loader/http/itemrefresh.h +++ b/core/include/JellyfinQt/loader/http/itemrefresh.h @@ -46,6 +46,20 @@ namespace HTTP { using namespace Jellyfin::DTO; +/** + * @brief Refreshes metadata for an item. + */ + +class PostLoader : public Jellyfin::Support::HttpLoader { +public: + explicit PostLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const PostParams& parameters) const override; + QUrlQuery query(const PostParams& parameters) const override; + QByteArray body(const PostParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; } // NS HTTP } // NS Loader diff --git a/core/include/JellyfinQt/loader/http/itemupdate.h b/core/include/JellyfinQt/loader/http/itemupdate.h index b594f18..19a59d0 100644 --- a/core/include/JellyfinQt/loader/http/itemupdate.h +++ b/core/include/JellyfinQt/loader/http/itemupdate.h @@ -47,6 +47,34 @@ namespace HTTP { using namespace Jellyfin::DTO; +/** + * @brief Updates an item. + */ + +class UpdateItemLoader : public Jellyfin::Support::HttpLoader { +public: + explicit UpdateItemLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const UpdateItemParams& parameters) const override; + QUrlQuery query(const UpdateItemParams& parameters) const override; + QByteArray body(const UpdateItemParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Updates an item's content type. + */ + +class UpdateItemContentTypeLoader : public Jellyfin::Support::HttpLoader { +public: + explicit UpdateItemContentTypeLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const UpdateItemContentTypeParams& parameters) const override; + QUrlQuery query(const UpdateItemContentTypeParams& parameters) const override; + QByteArray body(const UpdateItemContentTypeParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Gets metadata editor info for an item. */ diff --git a/core/include/JellyfinQt/loader/http/library.h b/core/include/JellyfinQt/loader/http/library.h index a56c1b7..b2df897 100644 --- a/core/include/JellyfinQt/loader/http/library.h +++ b/core/include/JellyfinQt/loader/http/library.h @@ -61,6 +61,34 @@ namespace HTTP { using namespace Jellyfin::DTO; +/** + * @brief Deletes items from the library and filesystem. + */ + +class DeleteItemsLoader : public Jellyfin::Support::HttpLoader { +public: + explicit DeleteItemsLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const DeleteItemsParams& parameters) const override; + QUrlQuery query(const DeleteItemsParams& parameters) const override; + QByteArray body(const DeleteItemsParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Deletes an item from the library and filesystem. + */ + +class DeleteItemLoader : public Jellyfin::Support::HttpLoader { +public: + explicit DeleteItemLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const DeleteItemParams& parameters) const override; + QUrlQuery query(const DeleteItemParams& parameters) const override; + QByteArray body(const DeleteItemParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Gets similar items. */ @@ -201,6 +229,20 @@ protected: QByteArray body(const GetLibraryOptionsInfoParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Reports that new movies have been added by an external source. + */ + +class PostUpdatedMediaLoader : public Jellyfin::Support::HttpLoader { +public: + explicit PostUpdatedMediaLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const PostUpdatedMediaParams& parameters) const override; + QUrlQuery query(const PostUpdatedMediaParams& parameters) const override; + QByteArray body(const PostUpdatedMediaParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Gets all user media folders. */ @@ -215,6 +257,34 @@ protected: QByteArray body(const GetMediaFoldersParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Reports that new movies have been added by an external source. + */ + +class PostAddedMoviesLoader : public Jellyfin::Support::HttpLoader { +public: + explicit PostAddedMoviesLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const PostAddedMoviesParams& parameters) const override; + QUrlQuery query(const PostAddedMoviesParams& parameters) const override; + QByteArray body(const PostAddedMoviesParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Reports that new movies have been added by an external source. + */ + +class PostUpdatedMoviesLoader : public Jellyfin::Support::HttpLoader { +public: + explicit PostUpdatedMoviesLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const PostUpdatedMoviesParams& parameters) const override; + QUrlQuery query(const PostUpdatedMoviesParams& parameters) const override; + QByteArray body(const PostUpdatedMoviesParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Gets a list of physical paths from virtual folders. */ @@ -229,6 +299,48 @@ protected: QByteArray body(const GetPhysicalPathsParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Starts a library scan. + */ + +class RefreshLibraryLoader : public Jellyfin::Support::HttpLoader { +public: + explicit RefreshLibraryLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const RefreshLibraryParams& parameters) const override; + QUrlQuery query(const RefreshLibraryParams& parameters) const override; + QByteArray body(const RefreshLibraryParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Reports that new episodes of a series have been added by an external source. + */ + +class PostAddedSeriesLoader : public Jellyfin::Support::HttpLoader { +public: + explicit PostAddedSeriesLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const PostAddedSeriesParams& parameters) const override; + QUrlQuery query(const PostAddedSeriesParams& parameters) const override; + QByteArray body(const PostAddedSeriesParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Reports that new episodes of a series have been added by an external source. + */ + +class PostUpdatedSeriesLoader : public Jellyfin::Support::HttpLoader { +public: + explicit PostUpdatedSeriesLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const PostUpdatedSeriesParams& parameters) const override; + QUrlQuery query(const PostUpdatedSeriesParams& parameters) const override; + QByteArray body(const PostUpdatedSeriesParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Gets similar items. */ diff --git a/core/include/JellyfinQt/loader/http/librarystructure.h b/core/include/JellyfinQt/loader/http/librarystructure.h index 201356e..5a2f50b 100644 --- a/core/include/JellyfinQt/loader/http/librarystructure.h +++ b/core/include/JellyfinQt/loader/http/librarystructure.h @@ -61,6 +61,104 @@ protected: QByteArray body(const GetVirtualFoldersParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Adds a virtual folder. + */ + +class AddVirtualFolderLoader : public Jellyfin::Support::HttpLoader { +public: + explicit AddVirtualFolderLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const AddVirtualFolderParams& parameters) const override; + QUrlQuery query(const AddVirtualFolderParams& parameters) const override; + QByteArray body(const AddVirtualFolderParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Removes a virtual folder. + */ + +class RemoveVirtualFolderLoader : public Jellyfin::Support::HttpLoader { +public: + explicit RemoveVirtualFolderLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const RemoveVirtualFolderParams& parameters) const override; + QUrlQuery query(const RemoveVirtualFolderParams& parameters) const override; + QByteArray body(const RemoveVirtualFolderParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Update library options. + */ + +class UpdateLibraryOptionsLoader : public Jellyfin::Support::HttpLoader { +public: + explicit UpdateLibraryOptionsLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const UpdateLibraryOptionsParams& parameters) const override; + QUrlQuery query(const UpdateLibraryOptionsParams& parameters) const override; + QByteArray body(const UpdateLibraryOptionsParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Renames a virtual folder. + */ + +class RenameVirtualFolderLoader : public Jellyfin::Support::HttpLoader { +public: + explicit RenameVirtualFolderLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const RenameVirtualFolderParams& parameters) const override; + QUrlQuery query(const RenameVirtualFolderParams& parameters) const override; + QByteArray body(const RenameVirtualFolderParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Add a media path to a library. + */ + +class AddMediaPathLoader : public Jellyfin::Support::HttpLoader { +public: + explicit AddMediaPathLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const AddMediaPathParams& parameters) const override; + QUrlQuery query(const AddMediaPathParams& parameters) const override; + QByteArray body(const AddMediaPathParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Remove a media path. + */ + +class RemoveMediaPathLoader : public Jellyfin::Support::HttpLoader { +public: + explicit RemoveMediaPathLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const RemoveMediaPathParams& parameters) const override; + QUrlQuery query(const RemoveMediaPathParams& parameters) const override; + QByteArray body(const RemoveMediaPathParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Updates a media path. + */ + +class UpdateMediaPathLoader : public Jellyfin::Support::HttpLoader { +public: + explicit UpdateMediaPathLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const UpdateMediaPathParams& parameters) const override; + QUrlQuery query(const UpdateMediaPathParams& parameters) const override; + QByteArray body(const UpdateMediaPathParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; } // NS HTTP } // NS Loader diff --git a/core/include/JellyfinQt/loader/http/livetv.h b/core/include/JellyfinQt/loader/http/livetv.h index d154807..7f172de 100644 --- a/core/include/JellyfinQt/loader/http/livetv.h +++ b/core/include/JellyfinQt/loader/http/livetv.h @@ -171,6 +171,20 @@ protected: QByteArray body(const AddListingProviderParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Delete listing provider. + */ + +class DeleteListingProviderLoader : public Jellyfin::Support::HttpLoader { +public: + explicit DeleteListingProviderLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const DeleteListingProviderParams& parameters) const override; + QUrlQuery query(const DeleteListingProviderParams& parameters) const override; + QByteArray body(const DeleteListingProviderParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Gets default listings provider info. */ @@ -297,6 +311,20 @@ protected: QByteArray body(const GetRecordingParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Deletes a live tv recording. + */ + +class DeleteRecordingLoader : public Jellyfin::Support::HttpLoader { +public: + explicit DeleteRecordingLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const DeleteRecordingParams& parameters) const override; + QUrlQuery query(const DeleteRecordingParams& parameters) const override; + QByteArray body(const DeleteRecordingParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Gets recording folders. */ @@ -353,6 +381,20 @@ protected: QByteArray body(const GetSeriesTimersParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Creates a live tv series timer. + */ + +class CreateSeriesTimerLoader : public Jellyfin::Support::HttpLoader { +public: + explicit CreateSeriesTimerLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const CreateSeriesTimerParams& parameters) const override; + QUrlQuery query(const CreateSeriesTimerParams& parameters) const override; + QByteArray body(const CreateSeriesTimerParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Gets a live tv series timer. */ @@ -367,6 +409,34 @@ protected: QByteArray body(const GetSeriesTimerParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Cancels a live tv series timer. + */ + +class CancelSeriesTimerLoader : public Jellyfin::Support::HttpLoader { +public: + explicit CancelSeriesTimerLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const CancelSeriesTimerParams& parameters) const override; + QUrlQuery query(const CancelSeriesTimerParams& parameters) const override; + QByteArray body(const CancelSeriesTimerParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Updates a live tv series timer. + */ + +class UpdateSeriesTimerLoader : public Jellyfin::Support::HttpLoader { +public: + explicit UpdateSeriesTimerLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const UpdateSeriesTimerParams& parameters) const override; + QUrlQuery query(const UpdateSeriesTimerParams& parameters) const override; + QByteArray body(const UpdateSeriesTimerParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Gets the live tv timers. */ @@ -381,6 +451,20 @@ protected: QByteArray body(const GetTimersParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Creates a live tv timer. + */ + +class CreateTimerLoader : public Jellyfin::Support::HttpLoader { +public: + explicit CreateTimerLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const CreateTimerParams& parameters) const override; + QUrlQuery query(const CreateTimerParams& parameters) const override; + QByteArray body(const CreateTimerParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Gets a timer. */ @@ -395,6 +479,34 @@ protected: QByteArray body(const GetTimerParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Cancels a live tv timer. + */ + +class CancelTimerLoader : public Jellyfin::Support::HttpLoader { +public: + explicit CancelTimerLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const CancelTimerParams& parameters) const override; + QUrlQuery query(const CancelTimerParams& parameters) const override; + QByteArray body(const CancelTimerParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Updates a live tv timer. + */ + +class UpdateTimerLoader : public Jellyfin::Support::HttpLoader { +public: + explicit UpdateTimerLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const UpdateTimerParams& parameters) const override; + QUrlQuery query(const UpdateTimerParams& parameters) const override; + QByteArray body(const UpdateTimerParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Gets the default values for a new timer. */ @@ -423,6 +535,20 @@ protected: QByteArray body(const AddTunerHostParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Deletes a tuner host. + */ + +class DeleteTunerHostLoader : public Jellyfin::Support::HttpLoader { +public: + explicit DeleteTunerHostLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const DeleteTunerHostParams& parameters) const override; + QUrlQuery query(const DeleteTunerHostParams& parameters) const override; + QByteArray body(const DeleteTunerHostParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Get tuner host types. */ @@ -437,6 +563,20 @@ protected: QByteArray body(const GetTunerHostTypesParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Resets a tv tuner. + */ + +class ResetTunerLoader : public Jellyfin::Support::HttpLoader { +public: + explicit ResetTunerLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const ResetTunerParams& parameters) const override; + QUrlQuery query(const ResetTunerParams& parameters) const override; + QByteArray body(const ResetTunerParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Discover tuners. */ diff --git a/core/include/JellyfinQt/loader/http/mediainfo.h b/core/include/JellyfinQt/loader/http/mediainfo.h index 6249094..9270b45 100644 --- a/core/include/JellyfinQt/loader/http/mediainfo.h +++ b/core/include/JellyfinQt/loader/http/mediainfo.h @@ -77,6 +77,20 @@ protected: QByteArray body(const GetPostedPlaybackInfoParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Closes a media source. + */ + +class CloseLiveStreamLoader : public Jellyfin::Support::HttpLoader { +public: + explicit CloseLiveStreamLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const CloseLiveStreamParams& parameters) const override; + QUrlQuery query(const CloseLiveStreamParams& parameters) const override; + QByteArray body(const CloseLiveStreamParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Opens a media source. */ diff --git a/core/include/JellyfinQt/loader/http/notifications.h b/core/include/JellyfinQt/loader/http/notifications.h index c17d92e..6ce32df 100644 --- a/core/include/JellyfinQt/loader/http/notifications.h +++ b/core/include/JellyfinQt/loader/http/notifications.h @@ -64,6 +64,20 @@ protected: QByteArray body(const GetNotificationsParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Sets notifications as read. + */ + +class SetReadLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SetReadLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SetReadParams& parameters) const override; + QUrlQuery query(const SetReadParams& parameters) const override; + QByteArray body(const SetReadParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Gets a user's notification summary. */ @@ -78,6 +92,34 @@ protected: QByteArray body(const GetNotificationsSummaryParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Sets notifications as unread. + */ + +class SetUnreadLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SetUnreadLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SetUnreadParams& parameters) const override; + QUrlQuery query(const SetUnreadParams& parameters) const override; + QByteArray body(const SetUnreadParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Sends a notification to all admins. + */ + +class CreateAdminNotificationLoader : public Jellyfin::Support::HttpLoader { +public: + explicit CreateAdminNotificationLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const CreateAdminNotificationParams& parameters) const override; + QUrlQuery query(const CreateAdminNotificationParams& parameters) const override; + QByteArray body(const CreateAdminNotificationParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Gets notification services. */ diff --git a/core/include/JellyfinQt/loader/http/package.h b/core/include/JellyfinQt/loader/http/package.h index b715612..cd1d42a 100644 --- a/core/include/JellyfinQt/loader/http/package.h +++ b/core/include/JellyfinQt/loader/http/package.h @@ -77,6 +77,34 @@ protected: QByteArray body(const GetPackageInfoParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Installs a package. + */ + +class InstallPackageLoader : public Jellyfin::Support::HttpLoader { +public: + explicit InstallPackageLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const InstallPackageParams& parameters) const override; + QUrlQuery query(const InstallPackageParams& parameters) const override; + QByteArray body(const InstallPackageParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Cancels a package installation. + */ + +class CancelPackageInstallationLoader : public Jellyfin::Support::HttpLoader { +public: + explicit CancelPackageInstallationLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const CancelPackageInstallationParams& parameters) const override; + QUrlQuery query(const CancelPackageInstallationParams& parameters) const override; + QByteArray body(const CancelPackageInstallationParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Gets all package repositories. */ @@ -91,6 +119,20 @@ protected: QByteArray body(const GetRepositoriesParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Sets the enabled and existing package repositories. + */ + +class SetRepositoriesLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SetRepositoriesLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SetRepositoriesParams& parameters) const override; + QUrlQuery query(const SetRepositoriesParams& parameters) const override; + QByteArray body(const SetRepositoriesParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; } // NS HTTP } // NS Loader diff --git a/core/include/JellyfinQt/loader/http/playlists.h b/core/include/JellyfinQt/loader/http/playlists.h index bd58284..8df3078 100644 --- a/core/include/JellyfinQt/loader/http/playlists.h +++ b/core/include/JellyfinQt/loader/http/playlists.h @@ -62,6 +62,34 @@ protected: QByteArray body(const CreatePlaylistParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Adds items to a playlist. + */ + +class AddToPlaylistLoader : public Jellyfin::Support::HttpLoader { +public: + explicit AddToPlaylistLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const AddToPlaylistParams& parameters) const override; + QUrlQuery query(const AddToPlaylistParams& parameters) const override; + QByteArray body(const AddToPlaylistParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Removes items from a playlist. + */ + +class RemoveFromPlaylistLoader : public Jellyfin::Support::HttpLoader { +public: + explicit RemoveFromPlaylistLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const RemoveFromPlaylistParams& parameters) const override; + QUrlQuery query(const RemoveFromPlaylistParams& parameters) const override; + QByteArray body(const RemoveFromPlaylistParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Gets the original items of a playlist. */ @@ -76,6 +104,20 @@ protected: QByteArray body(const GetPlaylistItemsParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Moves a playlist item. + */ + +class MoveItemLoader : public Jellyfin::Support::HttpLoader { +public: + explicit MoveItemLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const MoveItemParams& parameters) const override; + QUrlQuery query(const MoveItemParams& parameters) const override; + QByteArray body(const MoveItemParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; } // NS HTTP } // NS Loader diff --git a/core/include/JellyfinQt/loader/http/playstate.h b/core/include/JellyfinQt/loader/http/playstate.h index 6dc6e39..1c981fa 100644 --- a/core/include/JellyfinQt/loader/http/playstate.h +++ b/core/include/JellyfinQt/loader/http/playstate.h @@ -48,6 +48,62 @@ namespace HTTP { using namespace Jellyfin::DTO; +/** + * @brief Reports playback has started within a session. + */ + +class ReportPlaybackStartLoader : public Jellyfin::Support::HttpLoader { +public: + explicit ReportPlaybackStartLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const ReportPlaybackStartParams& parameters) const override; + QUrlQuery query(const ReportPlaybackStartParams& parameters) const override; + QByteArray body(const ReportPlaybackStartParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Pings a playback session. + */ + +class PingPlaybackSessionLoader : public Jellyfin::Support::HttpLoader { +public: + explicit PingPlaybackSessionLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const PingPlaybackSessionParams& parameters) const override; + QUrlQuery query(const PingPlaybackSessionParams& parameters) const override; + QByteArray body(const PingPlaybackSessionParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Reports playback progress within a session. + */ + +class ReportPlaybackProgressLoader : public Jellyfin::Support::HttpLoader { +public: + explicit ReportPlaybackProgressLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const ReportPlaybackProgressParams& parameters) const override; + QUrlQuery query(const ReportPlaybackProgressParams& parameters) const override; + QByteArray body(const ReportPlaybackProgressParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Reports playback has stopped within a session. + */ + +class ReportPlaybackStoppedLoader : public Jellyfin::Support::HttpLoader { +public: + explicit ReportPlaybackStoppedLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const ReportPlaybackStoppedParams& parameters) const override; + QUrlQuery query(const ReportPlaybackStoppedParams& parameters) const override; + QByteArray body(const ReportPlaybackStoppedParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Marks an item as played for user. */ @@ -76,6 +132,48 @@ protected: QByteArray body(const MarkUnplayedItemParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Reports that a user has begun playing an item. + */ + +class OnPlaybackStartLoader : public Jellyfin::Support::HttpLoader { +public: + explicit OnPlaybackStartLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const OnPlaybackStartParams& parameters) const override; + QUrlQuery query(const OnPlaybackStartParams& parameters) const override; + QByteArray body(const OnPlaybackStartParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Reports that a user has stopped playing an item. + */ + +class OnPlaybackStoppedLoader : public Jellyfin::Support::HttpLoader { +public: + explicit OnPlaybackStoppedLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const OnPlaybackStoppedParams& parameters) const override; + QUrlQuery query(const OnPlaybackStoppedParams& parameters) const override; + QByteArray body(const OnPlaybackStoppedParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Reports a user's playback progress. + */ + +class OnPlaybackProgressLoader : public Jellyfin::Support::HttpLoader { +public: + explicit OnPlaybackProgressLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const OnPlaybackProgressParams& parameters) const override; + QUrlQuery query(const OnPlaybackProgressParams& parameters) const override; + QByteArray body(const OnPlaybackProgressParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; } // NS HTTP } // NS Loader diff --git a/core/include/JellyfinQt/loader/http/plugins.h b/core/include/JellyfinQt/loader/http/plugins.h index 8a1cdb1..9931970 100644 --- a/core/include/JellyfinQt/loader/http/plugins.h +++ b/core/include/JellyfinQt/loader/http/plugins.h @@ -62,6 +62,62 @@ protected: QByteArray body(const GetPluginsParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Uninstalls a plugin. + */ + +class UninstallPluginLoader : public Jellyfin::Support::HttpLoader { +public: + explicit UninstallPluginLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const UninstallPluginParams& parameters) const override; + QUrlQuery query(const UninstallPluginParams& parameters) const override; + QByteArray body(const UninstallPluginParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Uninstalls a plugin by version. + */ + +class UninstallPluginByVersionLoader : public Jellyfin::Support::HttpLoader { +public: + explicit UninstallPluginByVersionLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const UninstallPluginByVersionParams& parameters) const override; + QUrlQuery query(const UninstallPluginByVersionParams& parameters) const override; + QByteArray body(const UninstallPluginByVersionParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Disable a plugin. + */ + +class DisablePluginLoader : public Jellyfin::Support::HttpLoader { +public: + explicit DisablePluginLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const DisablePluginParams& parameters) const override; + QUrlQuery query(const DisablePluginParams& parameters) const override; + QByteArray body(const DisablePluginParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Enables a disabled plugin. + */ + +class EnablePluginLoader : public Jellyfin::Support::HttpLoader { +public: + explicit EnablePluginLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const EnablePluginParams& parameters) const override; + QUrlQuery query(const EnablePluginParams& parameters) const override; + QByteArray body(const EnablePluginParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Gets plugin configuration. */ @@ -76,6 +132,48 @@ protected: QByteArray body(const GetPluginConfigurationParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Updates plugin configuration. + */ + +class UpdatePluginConfigurationLoader : public Jellyfin::Support::HttpLoader { +public: + explicit UpdatePluginConfigurationLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const UpdatePluginConfigurationParams& parameters) const override; + QUrlQuery query(const UpdatePluginConfigurationParams& parameters) const override; + QByteArray body(const UpdatePluginConfigurationParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Gets a plugin's manifest. + */ + +class GetPluginManifestLoader : public Jellyfin::Support::HttpLoader { +public: + explicit GetPluginManifestLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const GetPluginManifestParams& parameters) const override; + QUrlQuery query(const GetPluginManifestParams& parameters) const override; + QByteArray body(const GetPluginManifestParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Updates plugin security info. + */ + +class UpdatePluginSecurityInfoLoader : public Jellyfin::Support::HttpLoader { +public: + explicit UpdatePluginSecurityInfoLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const UpdatePluginSecurityInfoParams& parameters) const override; + QUrlQuery query(const UpdatePluginSecurityInfoParams& parameters) const override; + QByteArray body(const UpdatePluginSecurityInfoParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; } // NS HTTP } // NS Loader diff --git a/core/include/JellyfinQt/loader/http/quickconnect.h b/core/include/JellyfinQt/loader/http/quickconnect.h index 7397fd8..1478958 100644 --- a/core/include/JellyfinQt/loader/http/quickconnect.h +++ b/core/include/JellyfinQt/loader/http/quickconnect.h @@ -49,6 +49,20 @@ namespace HTTP { using namespace Jellyfin::DTO; +/** + * @brief Temporarily activates quick connect for five minutes. + */ + +class ActivateLoader : public Jellyfin::Support::HttpLoader { +public: + explicit ActivateLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const ActivateParams& parameters) const override; + QUrlQuery query(const ActivateParams& parameters) const override; + QByteArray body(const ActivateParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Authorizes a pending quick connect request. */ @@ -63,6 +77,20 @@ protected: QByteArray body(const AuthorizeParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Enables or disables quick connect. + */ + +class AvailableLoader : public Jellyfin::Support::HttpLoader { +public: + explicit AvailableLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const AvailableParams& parameters) const override; + QUrlQuery query(const AvailableParams& parameters) const override; + QByteArray body(const AvailableParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Attempts to retrieve authentication information. */ diff --git a/core/include/JellyfinQt/loader/http/remoteimage.h b/core/include/JellyfinQt/loader/http/remoteimage.h index 61ab76b..a0e8546 100644 --- a/core/include/JellyfinQt/loader/http/remoteimage.h +++ b/core/include/JellyfinQt/loader/http/remoteimage.h @@ -62,6 +62,20 @@ protected: QByteArray body(const GetRemoteImagesParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Downloads a remote image for an item. + */ + +class DownloadRemoteImageLoader : public Jellyfin::Support::HttpLoader { +public: + explicit DownloadRemoteImageLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const DownloadRemoteImageParams& parameters) const override; + QUrlQuery query(const DownloadRemoteImageParams& parameters) const override; + QByteArray body(const DownloadRemoteImageParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Gets available remote image providers for an item. */ diff --git a/core/include/JellyfinQt/loader/http/scheduledtasks.h b/core/include/JellyfinQt/loader/http/scheduledtasks.h index e5523d2..42761db 100644 --- a/core/include/JellyfinQt/loader/http/scheduledtasks.h +++ b/core/include/JellyfinQt/loader/http/scheduledtasks.h @@ -76,6 +76,48 @@ protected: QByteArray body(const GetTaskParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Update specified task triggers. + */ + +class UpdateTaskLoader : public Jellyfin::Support::HttpLoader { +public: + explicit UpdateTaskLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const UpdateTaskParams& parameters) const override; + QUrlQuery query(const UpdateTaskParams& parameters) const override; + QByteArray body(const UpdateTaskParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Start specified task. + */ + +class StartTaskLoader : public Jellyfin::Support::HttpLoader { +public: + explicit StartTaskLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const StartTaskParams& parameters) const override; + QUrlQuery query(const StartTaskParams& parameters) const override; + QByteArray body(const StartTaskParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Stop specified task. + */ + +class StopTaskLoader : public Jellyfin::Support::HttpLoader { +public: + explicit StopTaskLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const StopTaskParams& parameters) const override; + QUrlQuery query(const StopTaskParams& parameters) const override; + QByteArray body(const StopTaskParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; } // NS HTTP } // NS Loader diff --git a/core/include/JellyfinQt/loader/http/session.h b/core/include/JellyfinQt/loader/http/session.h index 35fd2cc..ffd5a6b 100644 --- a/core/include/JellyfinQt/loader/http/session.h +++ b/core/include/JellyfinQt/loader/http/session.h @@ -91,6 +91,188 @@ protected: QByteArray body(const GetSessionsParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Issues a full general command to a client. + */ + +class SendFullGeneralCommandLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SendFullGeneralCommandLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SendFullGeneralCommandParams& parameters) const override; + QUrlQuery query(const SendFullGeneralCommandParams& parameters) const override; + QByteArray body(const SendFullGeneralCommandParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Issues a general command to a client. + */ + +class SendGeneralCommandLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SendGeneralCommandLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SendGeneralCommandParams& parameters) const override; + QUrlQuery query(const SendGeneralCommandParams& parameters) const override; + QByteArray body(const SendGeneralCommandParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Issues a command to a client to display a message to the user. + */ + +class SendMessageCommandLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SendMessageCommandLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SendMessageCommandParams& parameters) const override; + QUrlQuery query(const SendMessageCommandParams& parameters) const override; + QByteArray body(const SendMessageCommandParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Instructs a session to play an item. + */ + +class PlayLoader : public Jellyfin::Support::HttpLoader { +public: + explicit PlayLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const PlayParams& parameters) const override; + QUrlQuery query(const PlayParams& parameters) const override; + QByteArray body(const PlayParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Issues a playstate command to a client. + */ + +class SendPlaystateCommandLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SendPlaystateCommandLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SendPlaystateCommandParams& parameters) const override; + QUrlQuery query(const SendPlaystateCommandParams& parameters) const override; + QByteArray body(const SendPlaystateCommandParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Issues a system command to a client. + */ + +class SendSystemCommandLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SendSystemCommandLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SendSystemCommandParams& parameters) const override; + QUrlQuery query(const SendSystemCommandParams& parameters) const override; + QByteArray body(const SendSystemCommandParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Adds an additional user to a session. + */ + +class AddUserToSessionLoader : public Jellyfin::Support::HttpLoader { +public: + explicit AddUserToSessionLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const AddUserToSessionParams& parameters) const override; + QUrlQuery query(const AddUserToSessionParams& parameters) const override; + QByteArray body(const AddUserToSessionParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Removes an additional user from a session. + */ + +class RemoveUserFromSessionLoader : public Jellyfin::Support::HttpLoader { +public: + explicit RemoveUserFromSessionLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const RemoveUserFromSessionParams& parameters) const override; + QUrlQuery query(const RemoveUserFromSessionParams& parameters) const override; + QByteArray body(const RemoveUserFromSessionParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Instructs a session to browse to an item or view. + */ + +class DisplayContentLoader : public Jellyfin::Support::HttpLoader { +public: + explicit DisplayContentLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const DisplayContentParams& parameters) const override; + QUrlQuery query(const DisplayContentParams& parameters) const override; + QByteArray body(const DisplayContentParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Updates capabilities for a device. + */ + +class PostCapabilitiesLoader : public Jellyfin::Support::HttpLoader { +public: + explicit PostCapabilitiesLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const PostCapabilitiesParams& parameters) const override; + QUrlQuery query(const PostCapabilitiesParams& parameters) const override; + QByteArray body(const PostCapabilitiesParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Updates capabilities for a device. + */ + +class PostFullCapabilitiesLoader : public Jellyfin::Support::HttpLoader { +public: + explicit PostFullCapabilitiesLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const PostFullCapabilitiesParams& parameters) const override; + QUrlQuery query(const PostFullCapabilitiesParams& parameters) const override; + QByteArray body(const PostFullCapabilitiesParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Reports that a session has ended. + */ + +class ReportSessionEndedLoader : public Jellyfin::Support::HttpLoader { +public: + explicit ReportSessionEndedLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const ReportSessionEndedParams& parameters) const override; + QUrlQuery query(const ReportSessionEndedParams& parameters) const override; + QByteArray body(const ReportSessionEndedParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Reports that a session is viewing an item. + */ + +class ReportViewingLoader : public Jellyfin::Support::HttpLoader { +public: + explicit ReportViewingLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const ReportViewingParams& parameters) const override; + QUrlQuery query(const ReportViewingParams& parameters) const override; + QByteArray body(const ReportViewingParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; } // NS HTTP } // NS Loader diff --git a/core/include/JellyfinQt/loader/http/startup.h b/core/include/JellyfinQt/loader/http/startup.h index b9d3bf8..e074a5e 100644 --- a/core/include/JellyfinQt/loader/http/startup.h +++ b/core/include/JellyfinQt/loader/http/startup.h @@ -49,6 +49,20 @@ namespace HTTP { using namespace Jellyfin::DTO; +/** + * @brief Completes the startup wizard. + */ + +class CompleteWizardLoader : public Jellyfin::Support::HttpLoader { +public: + explicit CompleteWizardLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const CompleteWizardParams& parameters) const override; + QUrlQuery query(const CompleteWizardParams& parameters) const override; + QByteArray body(const CompleteWizardParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Gets the initial startup wizard configuration. */ @@ -63,6 +77,20 @@ protected: QByteArray body(const GetStartupConfigurationParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Sets the initial startup wizard configuration. + */ + +class UpdateInitialConfigurationLoader : public Jellyfin::Support::HttpLoader { +public: + explicit UpdateInitialConfigurationLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const UpdateInitialConfigurationParams& parameters) const override; + QUrlQuery query(const UpdateInitialConfigurationParams& parameters) const override; + QByteArray body(const UpdateInitialConfigurationParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Gets the first user. */ @@ -77,6 +105,20 @@ protected: QByteArray body(const GetFirstUser_2Params& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Sets remote access and UPnP. + */ + +class SetRemoteAccessLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SetRemoteAccessLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SetRemoteAccessParams& parameters) const override; + QUrlQuery query(const SetRemoteAccessParams& parameters) const override; + QByteArray body(const SetRemoteAccessParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Gets the first user. */ @@ -91,6 +133,20 @@ protected: QByteArray body(const GetFirstUserParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Sets the user name and password. + */ + +class UpdateStartupUserLoader : public Jellyfin::Support::HttpLoader { +public: + explicit UpdateStartupUserLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const UpdateStartupUserParams& parameters) const override; + QUrlQuery query(const UpdateStartupUserParams& parameters) const override; + QByteArray body(const UpdateStartupUserParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; } // NS HTTP } // NS Loader diff --git a/core/include/JellyfinQt/loader/http/subtitle.h b/core/include/JellyfinQt/loader/http/subtitle.h index 069724f..88ecf79 100644 --- a/core/include/JellyfinQt/loader/http/subtitle.h +++ b/core/include/JellyfinQt/loader/http/subtitle.h @@ -76,6 +76,48 @@ protected: QByteArray body(const SearchRemoteSubtitlesParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Downloads a remote subtitle. + */ + +class DownloadRemoteSubtitlesLoader : public Jellyfin::Support::HttpLoader { +public: + explicit DownloadRemoteSubtitlesLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const DownloadRemoteSubtitlesParams& parameters) const override; + QUrlQuery query(const DownloadRemoteSubtitlesParams& parameters) const override; + QByteArray body(const DownloadRemoteSubtitlesParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Upload an external subtitle file. + */ + +class UploadSubtitleLoader : public Jellyfin::Support::HttpLoader { +public: + explicit UploadSubtitleLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const UploadSubtitleParams& parameters) const override; + QUrlQuery query(const UploadSubtitleParams& parameters) const override; + QByteArray body(const UploadSubtitleParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Deletes an external subtitle file. + */ + +class DeleteSubtitleLoader : public Jellyfin::Support::HttpLoader { +public: + explicit DeleteSubtitleLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const DeleteSubtitleParams& parameters) const override; + QUrlQuery query(const DeleteSubtitleParams& parameters) const override; + QByteArray body(const DeleteSubtitleParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; } // NS HTTP } // NS Loader diff --git a/core/include/JellyfinQt/loader/http/syncplay.h b/core/include/JellyfinQt/loader/http/syncplay.h index a121798..d4cc834 100644 --- a/core/include/JellyfinQt/loader/http/syncplay.h +++ b/core/include/JellyfinQt/loader/http/syncplay.h @@ -47,6 +47,48 @@ namespace HTTP { using namespace Jellyfin::DTO; +/** + * @brief Notify SyncPlay group that member is buffering. + */ + +class SyncPlayBufferingLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SyncPlayBufferingLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SyncPlayBufferingParams& parameters) const override; + QUrlQuery query(const SyncPlayBufferingParams& parameters) const override; + QByteArray body(const SyncPlayBufferingParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Join an existing SyncPlay group. + */ + +class SyncPlayJoinGroupLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SyncPlayJoinGroupLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SyncPlayJoinGroupParams& parameters) const override; + QUrlQuery query(const SyncPlayJoinGroupParams& parameters) const override; + QByteArray body(const SyncPlayJoinGroupParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Leave the joined SyncPlay group. + */ + +class SyncPlayLeaveGroupLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SyncPlayLeaveGroupLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SyncPlayLeaveGroupParams& parameters) const override; + QUrlQuery query(const SyncPlayLeaveGroupParams& parameters) const override; + QByteArray body(const SyncPlayLeaveGroupParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Gets all SyncPlay groups. */ @@ -61,6 +103,244 @@ protected: QByteArray body(const SyncPlayGetGroupsParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Request to move an item in the playlist in SyncPlay group. + */ + +class SyncPlayMovePlaylistItemLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SyncPlayMovePlaylistItemLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SyncPlayMovePlaylistItemParams& parameters) const override; + QUrlQuery query(const SyncPlayMovePlaylistItemParams& parameters) const override; + QByteArray body(const SyncPlayMovePlaylistItemParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Create a new SyncPlay group. + */ + +class SyncPlayCreateGroupLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SyncPlayCreateGroupLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SyncPlayCreateGroupParams& parameters) const override; + QUrlQuery query(const SyncPlayCreateGroupParams& parameters) const override; + QByteArray body(const SyncPlayCreateGroupParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Request next item in SyncPlay group. + */ + +class SyncPlayNextItemLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SyncPlayNextItemLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SyncPlayNextItemParams& parameters) const override; + QUrlQuery query(const SyncPlayNextItemParams& parameters) const override; + QByteArray body(const SyncPlayNextItemParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Request pause in SyncPlay group. + */ + +class SyncPlayPauseLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SyncPlayPauseLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SyncPlayPauseParams& parameters) const override; + QUrlQuery query(const SyncPlayPauseParams& parameters) const override; + QByteArray body(const SyncPlayPauseParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Update session ping. + */ + +class SyncPlayPingLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SyncPlayPingLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SyncPlayPingParams& parameters) const override; + QUrlQuery query(const SyncPlayPingParams& parameters) const override; + QByteArray body(const SyncPlayPingParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Request previous item in SyncPlay group. + */ + +class SyncPlayPreviousItemLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SyncPlayPreviousItemLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SyncPlayPreviousItemParams& parameters) const override; + QUrlQuery query(const SyncPlayPreviousItemParams& parameters) const override; + QByteArray body(const SyncPlayPreviousItemParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Request to queue items to the playlist of a SyncPlay group. + */ + +class SyncPlayQueueLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SyncPlayQueueLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SyncPlayQueueParams& parameters) const override; + QUrlQuery query(const SyncPlayQueueParams& parameters) const override; + QByteArray body(const SyncPlayQueueParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Notify SyncPlay group that member is ready for playback. + */ + +class SyncPlayReadyLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SyncPlayReadyLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SyncPlayReadyParams& parameters) const override; + QUrlQuery query(const SyncPlayReadyParams& parameters) const override; + QByteArray body(const SyncPlayReadyParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Request to remove items from the playlist in SyncPlay group. + */ + +class SyncPlayRemoveFromPlaylistLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SyncPlayRemoveFromPlaylistLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SyncPlayRemoveFromPlaylistParams& parameters) const override; + QUrlQuery query(const SyncPlayRemoveFromPlaylistParams& parameters) const override; + QByteArray body(const SyncPlayRemoveFromPlaylistParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Request seek in SyncPlay group. + */ + +class SyncPlaySeekLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SyncPlaySeekLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SyncPlaySeekParams& parameters) const override; + QUrlQuery query(const SyncPlaySeekParams& parameters) const override; + QByteArray body(const SyncPlaySeekParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Request SyncPlay group to ignore member during group-wait. + */ + +class SyncPlaySetIgnoreWaitLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SyncPlaySetIgnoreWaitLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SyncPlaySetIgnoreWaitParams& parameters) const override; + QUrlQuery query(const SyncPlaySetIgnoreWaitParams& parameters) const override; + QByteArray body(const SyncPlaySetIgnoreWaitParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Request to set new playlist in SyncPlay group. + */ + +class SyncPlaySetNewQueueLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SyncPlaySetNewQueueLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SyncPlaySetNewQueueParams& parameters) const override; + QUrlQuery query(const SyncPlaySetNewQueueParams& parameters) const override; + QByteArray body(const SyncPlaySetNewQueueParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Request to change playlist item in SyncPlay group. + */ + +class SyncPlaySetPlaylistItemLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SyncPlaySetPlaylistItemLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SyncPlaySetPlaylistItemParams& parameters) const override; + QUrlQuery query(const SyncPlaySetPlaylistItemParams& parameters) const override; + QByteArray body(const SyncPlaySetPlaylistItemParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Request to set repeat mode in SyncPlay group. + */ + +class SyncPlaySetRepeatModeLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SyncPlaySetRepeatModeLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SyncPlaySetRepeatModeParams& parameters) const override; + QUrlQuery query(const SyncPlaySetRepeatModeParams& parameters) const override; + QByteArray body(const SyncPlaySetRepeatModeParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Request to set shuffle mode in SyncPlay group. + */ + +class SyncPlaySetShuffleModeLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SyncPlaySetShuffleModeLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SyncPlaySetShuffleModeParams& parameters) const override; + QUrlQuery query(const SyncPlaySetShuffleModeParams& parameters) const override; + QByteArray body(const SyncPlaySetShuffleModeParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Request stop in SyncPlay group. + */ + +class SyncPlayStopLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SyncPlayStopLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SyncPlayStopParams& parameters) const override; + QUrlQuery query(const SyncPlayStopParams& parameters) const override; + QByteArray body(const SyncPlayStopParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Request unpause in SyncPlay group. + */ + +class SyncPlayUnpauseLoader : public Jellyfin::Support::HttpLoader { +public: + explicit SyncPlayUnpauseLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const SyncPlayUnpauseParams& parameters) const override; + QUrlQuery query(const SyncPlayUnpauseParams& parameters) const override; + QByteArray body(const SyncPlayUnpauseParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; } // NS HTTP } // NS Loader diff --git a/core/include/JellyfinQt/loader/http/system.h b/core/include/JellyfinQt/loader/http/system.h index dc5ce1c..a709c3e 100644 --- a/core/include/JellyfinQt/loader/http/system.h +++ b/core/include/JellyfinQt/loader/http/system.h @@ -135,6 +135,34 @@ protected: QByteArray body(const PostPingSystemParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Restarts the application. + */ + +class RestartApplicationLoader : public Jellyfin::Support::HttpLoader { +public: + explicit RestartApplicationLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const RestartApplicationParams& parameters) const override; + QUrlQuery query(const RestartApplicationParams& parameters) const override; + QByteArray body(const RestartApplicationParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Shuts down the application. + */ + +class ShutdownApplicationLoader : public Jellyfin::Support::HttpLoader { +public: + explicit ShutdownApplicationLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const ShutdownApplicationParams& parameters) const override; + QUrlQuery query(const ShutdownApplicationParams& parameters) const override; + QByteArray body(const ShutdownApplicationParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Gets wake on lan information. */ diff --git a/core/include/JellyfinQt/loader/http/user.h b/core/include/JellyfinQt/loader/http/user.h index b927587..bd3f319 100644 --- a/core/include/JellyfinQt/loader/http/user.h +++ b/core/include/JellyfinQt/loader/http/user.h @@ -84,6 +84,34 @@ protected: QByteArray body(const GetUserByIdParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Deletes a user. + */ + +class DeleteUserLoader : public Jellyfin::Support::HttpLoader { +public: + explicit DeleteUserLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const DeleteUserParams& parameters) const override; + QUrlQuery query(const DeleteUserParams& parameters) const override; + QByteArray body(const DeleteUserParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Updates a user. + */ + +class UpdateUserLoader : public Jellyfin::Support::HttpLoader { +public: + explicit UpdateUserLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const UpdateUserParams& parameters) const override; + QUrlQuery query(const UpdateUserParams& parameters) const override; + QByteArray body(const UpdateUserParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Authenticates a user. */ @@ -98,6 +126,62 @@ protected: QByteArray body(const AuthenticateUserParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Updates a user configuration. + */ + +class UpdateUserConfigurationLoader : public Jellyfin::Support::HttpLoader { +public: + explicit UpdateUserConfigurationLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const UpdateUserConfigurationParams& parameters) const override; + QUrlQuery query(const UpdateUserConfigurationParams& parameters) const override; + QByteArray body(const UpdateUserConfigurationParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Updates a user's easy password. + */ + +class UpdateUserEasyPasswordLoader : public Jellyfin::Support::HttpLoader { +public: + explicit UpdateUserEasyPasswordLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const UpdateUserEasyPasswordParams& parameters) const override; + QUrlQuery query(const UpdateUserEasyPasswordParams& parameters) const override; + QByteArray body(const UpdateUserEasyPasswordParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Updates a user's password. + */ + +class UpdateUserPasswordLoader : public Jellyfin::Support::HttpLoader { +public: + explicit UpdateUserPasswordLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const UpdateUserPasswordParams& parameters) const override; + QUrlQuery query(const UpdateUserPasswordParams& parameters) const override; + QByteArray body(const UpdateUserPasswordParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Updates a user policy. + */ + +class UpdateUserPolicyLoader : public Jellyfin::Support::HttpLoader { +public: + explicit UpdateUserPolicyLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const UpdateUserPolicyParams& parameters) const override; + QUrlQuery query(const UpdateUserPolicyParams& parameters) const override; + QByteArray body(const UpdateUserPolicyParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; /** * @brief Authenticates a user by name. */ diff --git a/core/include/JellyfinQt/loader/http/videos.h b/core/include/JellyfinQt/loader/http/videos.h index 8cbc415..6ac74e3 100644 --- a/core/include/JellyfinQt/loader/http/videos.h +++ b/core/include/JellyfinQt/loader/http/videos.h @@ -61,6 +61,34 @@ protected: QByteArray body(const GetAdditionalPartParams& parameters) const override; QNetworkAccessManager::Operation operation() const override; }; +/** + * @brief Removes alternate video sources. + */ + +class DeleteAlternateSourcesLoader : public Jellyfin::Support::HttpLoader { +public: + explicit DeleteAlternateSourcesLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const DeleteAlternateSourcesParams& parameters) const override; + QUrlQuery query(const DeleteAlternateSourcesParams& parameters) const override; + QByteArray body(const DeleteAlternateSourcesParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; +/** + * @brief Merges videos into a single record. + */ + +class MergeVersionsLoader : public Jellyfin::Support::HttpLoader { +public: + explicit MergeVersionsLoader(ApiClient *apiClient = nullptr); + +protected: + QString path(const MergeVersionsParams& parameters) const override; + QUrlQuery query(const MergeVersionsParams& parameters) const override; + QByteArray body(const MergeVersionsParams& parameters) const override; + QNetworkAccessManager::Operation operation() const override; +}; } // NS HTTP } // NS Loader diff --git a/core/include/JellyfinQt/support/loader.h b/core/include/JellyfinQt/support/loader.h index 0487d10..df09ccf 100644 --- a/core/include/JellyfinQt/support/loader.h +++ b/core/include/JellyfinQt/support/loader.h @@ -62,40 +62,11 @@ static const int HTTP_TIMEOUT = 30000; // 30 seconds; */ class LoaderBase : public QObject { Q_OBJECT -signals: - /** - * @brief Emitted when an error has occurred during loading and no result - * is available. - */ - void error(QString message = QString()); - /** - * @brief Emitted when data was successfully loaded. - */ - void ready(); -}; - -/** - * Interface describing a way to load items. Used to abstract away - * the difference between loading from a cache or loading over the network. - * - * To implement this class, implement prepareLoad() and load(). These are always called - * in the same order, but prepareLoad() must always be called on the same thread as the - * m_apiClient, while load() may be called on another thread. - * - * @note: Loaders should NEVER call load() again while load() is running on another - * thread or change the apiClient while running. This will result in undefined behaviour. - * Please use a Mutex to enforce this. - * - * @tparam R the type of data that should be fetched, R for result. - * @tparam P the type of paramaters given, to determine which resource should - * be loaded. - */ -template -class Loader : public LoaderBase { -public: - explicit Loader(ApiClient *apiClient) +protected: + explicit LoaderBase(ApiClient *apiClient) : m_apiClient(apiClient) {} +public: /** * @brief load Loads the given resource asynchronously. */ @@ -103,19 +74,6 @@ public: throw LoadException(QStringLiteral("Loader not set")); } - /** - * @brief Retrieves the loaded resource. Only valid after the ready signal has been emitted. - * - * @return The loaded resource. - */ - R result() const { - return m_result.value(); - } - - bool hasResult() const { - return m_result; - } - /** * @returns whether this loader is already fetching a resource */ @@ -136,6 +94,61 @@ public: void setApiClient(ApiClient *newApiClient) { m_apiClient = newApiClient; } ApiClient *apiClient() const { return m_apiClient; } +signals: + /** + * @brief Emitted when an error has occurred during loading and no result + * is available. + */ + void error(QString message = QString()); + /** + * @brief Emitted when data was successfully loaded. + */ + void ready(); +protected: + Jellyfin::ApiClient *m_apiClient; + bool m_isRunning = false; + + void stopWithError(QString message = QString()) { + m_isRunning = false; + emit this->error(message); + } +}; + +/** + * Interface describing a way to load items. Used to abstract away + * the difference between loading from a cache or loading over the network. + * + * To implement this class, implement prepareLoad() and load(). These are always called + * in the same order, but prepareLoad() must always be called on the same thread as the + * m_apiClient, while load() may be called on another thread. + * + * @note: Loaders should NEVER call load() again while load() is running on another + * thread or change the apiClient while running. This will result in undefined behaviour. + * Please use a Mutex to enforce this. + * + * @tparam R the type of data that should be fetched, R for result. + * @tparam P the type of paramaters given, to determine which resource should + * be loaded. + */ +template +class Loader : public LoaderBase { +public: + using ResultType = std::optional; + explicit Loader(ApiClient *apiClient) + : LoaderBase(apiClient) {} + + /** + * @brief Retrieves the loaded resource. Only valid after the ready signal has been emitted. + * + * @return The loaded resource. + */ + R result() const { + return m_result.value(); + } + + bool hasResult() const { + return m_result; + } /** * @brief Sets the parameters for this loader. * @param parameters The parameters to set @@ -146,26 +159,112 @@ public: void setParameters(const P ¶meters) { m_parameters = parameters; } -protected: - Jellyfin::ApiClient *m_apiClient; - std::optional

m_parameters; - std::optional m_result; - bool m_isRunning = false; - void stopWithError(QString message = QString()) { - m_isRunning = false; - emit this->error(message); +protected: + std::optional

m_parameters; + ResultType m_result; + + ResultType createFailureResult() { + return std::nullopt; + } + + ResultType createSuccessResult(R &&result) { + return std::make_optional(result); + } + + static R createDummyResponse() { + return fromJsonValue(QJsonValue()); + } + +}; + +template +class Loader : public LoaderBase { +public: + using ResultType = bool; + explicit Loader(ApiClient *apiClient) + : LoaderBase(apiClient) {} + + void result() const { } + + bool hasResult() const { + return m_result; + } + /** + * @brief Sets the parameters for this loader. + * @param parameters The parameters to set + * + * This method will copy the parameters. The parameters must have a + * copy constructor. + */ + void setParameters(const P ¶meters) { + m_parameters = parameters; + } + +protected: + std::optional

m_parameters; + ResultType m_result; + + ResultType createFailureResult() { + return false; + } + + ResultType createSuccessResult(void) { + return true; + } + + static void createDummyResponse() { } +}; + +template +class HttpLoaderBase : public Loader { +public: + explicit HttpLoaderBase(Jellyfin::ApiClient *apiClient) + : Loader (apiClient) {} + + typename Loader::ResultType parseResponse(int /*statusCode*/, QByteArray response) { + QJsonParseError error; + QJsonDocument document = QJsonDocument::fromJson(response, &error); + if (error.error != QJsonParseError::NoError) { + qWarning() << response; + this->stopWithError(error.errorString().toLocal8Bit().constData()); + } + if (document.isNull() || document.isEmpty()) { + this->stopWithError(QStringLiteral("Unexpected empty JSON response")); + return this->createFailureResult(); + } else if (document.isArray()) { + return this->createSuccessResult(fromJsonValue(document.array())); + } else if (document.isObject()){ + return this->createSuccessResult(fromJsonValue(document.object())); + } else { + this->stopWithError(QStringLiteral("Unexpected JSON response")); + return this->createFailureResult(); + } + } + +}; + +// Specialisation for void result +template +class HttpLoaderBase : public Loader { +public: + explicit HttpLoaderBase(Jellyfin::ApiClient *apiClient) + : Loader (apiClient) {} + + typename Loader::ResultType parseResponse(int statusCode, QByteArray response) { + return statusCode == 204; } }; + /** * Implementation of Loader that loads Items over HTTP */ template -class HttpLoader : public Loader { +class HttpLoader : public HttpLoaderBase { public: explicit HttpLoader(Jellyfin::ApiClient *apiClient) - : Loader (apiClient) { + : HttpLoaderBase (apiClient) { this->connect(&m_parsedWatcher, &QFutureWatcher>::finished, this, &HttpLoader::onResponseParsed); } @@ -221,7 +320,7 @@ protected: virtual QNetworkAccessManager::Operation operation() const = 0; private: QNetworkReply *m_reply = nullptr; - QFutureWatcher> m_parsedWatcher; + QFutureWatcher::ResultType> m_parsedWatcher; void onRequestFinished() { if (m_reply->error() != QNetworkReply::NoError) { @@ -229,38 +328,32 @@ private: m_parsedWatcher.cancel(); //: An HTTP has occurred. First argument is replaced by QNetworkReply->errorString() this->stopWithError(QStringLiteral("HTTP error: %1").arg(m_reply->errorString())); + return; } QByteArray array = m_reply->readAll(); + int statusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); m_reply->deleteLater(); m_reply = nullptr; - m_parsedWatcher.setFuture(QtConcurrent::run(this, &HttpLoader::parseResponse, array)); - } - - std::optional parseResponse(QByteArray response) { - QJsonParseError error; - QJsonDocument document = QJsonDocument::fromJson(response, &error); - if (error.error != QJsonParseError::NoError) { - qWarning() << response; - this->stopWithError(error.errorString().toLocal8Bit().constData()); - } - if (document.isNull() || document.isEmpty()) { - this->stopWithError(QStringLiteral("Unexpected empty JSON response")); - return std::nullopt; - } else if (document.isArray()) { - return std::make_optional(fromJsonValue(document.array())); - } else if (document.isObject()){ - return std::make_optional(fromJsonValue(document.object())); - } else { - this->stopWithError(QStringLiteral("Unexpected JSON response")); - return std::nullopt; - } + /*m_parsedWatcher.setFuture(QtConcurrent::run([this, statusCode, array]() { + return this->parseResponse(statusCode, array); + }));*/ + m_parsedWatcher.setFuture( + QtConcurrent::run::ResultType, // Result + HttpLoader, // class + int, int, // Argument 1 + QByteArray, QByteArray> // Argument 2 + (this, &HttpLoader::parseResponse, statusCode, array) + ); } void onResponseParsed() { Q_ASSERT(m_parsedWatcher.isFinished()); try { - if (m_parsedWatcher.result().has_value()) { - this->m_result = m_parsedWatcher.result().value(); + /* In case the result is an optional, it invokes the bool cast of std::optional, checking + if it has a value. + In case the result is a boolean, it just checks the boolean */ + if (m_parsedWatcher.result()) { + this->m_result = m_parsedWatcher.result(); this->m_isRunning = false; emit this->ready(); } else { diff --git a/core/openapigenerator.d b/core/openapigenerator.d index 34861c5..87cb560 100755 --- a/core/openapigenerator.d +++ b/core/openapigenerator.d @@ -457,7 +457,11 @@ void generateFileForEndpoints(ref const Node[] endpointNodes, } } } - } + } + if (codeNo == 204 /* No content */) { + endpoint.resultType = "void"; + endpoint.hasSuccessResponse = true; + } } if ("requestBody" in endpointNode) { diff --git a/core/src/loader/http/apikey.cpp b/core/src/loader/http/apikey.cpp index e5a3f06..3fa5e65 100644 --- a/core/src/loader/http/apikey.cpp +++ b/core/src/loader/http/apikey.cpp @@ -64,6 +64,65 @@ QNetworkAccessManager::Operation GetKeysLoader::operation() const { } +CreateKeyLoader::CreateKeyLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString CreateKeyLoader::path(const CreateKeyParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Auth/Keys"); +} + +QUrlQuery CreateKeyLoader::query(const CreateKeyParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + result.addQueryItem("app", Support::toString(params.app())); + + // Optional parameters + + return result; +} + +QByteArray CreateKeyLoader::body(const CreateKeyParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation CreateKeyLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +RevokeKeyLoader::RevokeKeyLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString RevokeKeyLoader::path(const RevokeKeyParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Auth/Keys/") + Support::toString< QString>(params.key()) ; +} + +QUrlQuery RevokeKeyLoader::query(const RevokeKeyParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray RevokeKeyLoader::body(const RevokeKeyParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation RevokeKeyLoader::operation() const { + // HTTP method Delete + return QNetworkAccessManager::DeleteOperation; + +} + } // NS HTTP } // NS Loader diff --git a/core/src/loader/http/branding.cpp b/core/src/loader/http/branding.cpp index cea8aeb..cde1e76 100644 --- a/core/src/loader/http/branding.cpp +++ b/core/src/loader/http/branding.cpp @@ -65,7 +65,7 @@ QNetworkAccessManager::Operation GetBrandingOptionsLoader::operation() const { } GetBrandingCssLoader::GetBrandingCssLoader(ApiClient *apiClient) - : Jellyfin::Support::HttpLoader(apiClient) {} + : Jellyfin::Support::HttpLoader(apiClient) {} QString GetBrandingCssLoader::path(const GetBrandingCssParams ¶ms) const { Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings @@ -94,7 +94,7 @@ QNetworkAccessManager::Operation GetBrandingCssLoader::operation() const { } GetBrandingCss_2Loader::GetBrandingCss_2Loader(ApiClient *apiClient) - : Jellyfin::Support::HttpLoader(apiClient) {} + : Jellyfin::Support::HttpLoader(apiClient) {} QString GetBrandingCss_2Loader::path(const GetBrandingCss_2Params ¶ms) const { Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings diff --git a/core/src/loader/http/collection.cpp b/core/src/loader/http/collection.cpp index 72bdc86..e21af1c 100644 --- a/core/src/loader/http/collection.cpp +++ b/core/src/loader/http/collection.cpp @@ -76,6 +76,66 @@ QNetworkAccessManager::Operation CreateCollectionLoader::operation() const { } +AddToCollectionLoader::AddToCollectionLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString AddToCollectionLoader::path(const AddToCollectionParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Collections/") + Support::toString< QString>(params.collectionId()) + QStringLiteral("/Items"); +} + +QUrlQuery AddToCollectionLoader::query(const AddToCollectionParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + result.addQueryItem("ids", Support::toString(params.ids())); + + // Optional parameters + + return result; +} + +QByteArray AddToCollectionLoader::body(const AddToCollectionParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation AddToCollectionLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +RemoveFromCollectionLoader::RemoveFromCollectionLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString RemoveFromCollectionLoader::path(const RemoveFromCollectionParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Collections/") + Support::toString< QString>(params.collectionId()) + QStringLiteral("/Items"); +} + +QUrlQuery RemoveFromCollectionLoader::query(const RemoveFromCollectionParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + result.addQueryItem("ids", Support::toString(params.ids())); + + // Optional parameters + + return result; +} + +QByteArray RemoveFromCollectionLoader::body(const RemoveFromCollectionParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation RemoveFromCollectionLoader::operation() const { + // HTTP method Delete + return QNetworkAccessManager::DeleteOperation; + +} + } // NS HTTP } // NS Loader diff --git a/core/src/loader/http/configuration.cpp b/core/src/loader/http/configuration.cpp index f61fbb1..77dadc3 100644 --- a/core/src/loader/http/configuration.cpp +++ b/core/src/loader/http/configuration.cpp @@ -64,6 +64,35 @@ QNetworkAccessManager::Operation GetConfigurationLoader::operation() const { } +UpdateConfigurationLoader::UpdateConfigurationLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString UpdateConfigurationLoader::path(const UpdateConfigurationParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/System/Configuration"); +} + +QUrlQuery UpdateConfigurationLoader::query(const UpdateConfigurationParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray UpdateConfigurationLoader::body(const UpdateConfigurationParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation UpdateConfigurationLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + GetNamedConfigurationLoader::GetNamedConfigurationLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader(apiClient) {} @@ -93,6 +122,35 @@ QNetworkAccessManager::Operation GetNamedConfigurationLoader::operation() const } +UpdateNamedConfigurationLoader::UpdateNamedConfigurationLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString UpdateNamedConfigurationLoader::path(const UpdateNamedConfigurationParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/System/Configuration/") + Support::toString< QString>(params.key()) ; +} + +QUrlQuery UpdateNamedConfigurationLoader::query(const UpdateNamedConfigurationParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray UpdateNamedConfigurationLoader::body(const UpdateNamedConfigurationParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation UpdateNamedConfigurationLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + GetDefaultMetadataOptionsLoader::GetDefaultMetadataOptionsLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader(apiClient) {} @@ -122,6 +180,35 @@ QNetworkAccessManager::Operation GetDefaultMetadataOptionsLoader::operation() co } +UpdateMediaEncoderPathLoader::UpdateMediaEncoderPathLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString UpdateMediaEncoderPathLoader::path(const UpdateMediaEncoderPathParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/System/MediaEncoder/Path"); +} + +QUrlQuery UpdateMediaEncoderPathLoader::query(const UpdateMediaEncoderPathParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray UpdateMediaEncoderPathLoader::body(const UpdateMediaEncoderPathParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation UpdateMediaEncoderPathLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + } // NS HTTP } // NS Loader diff --git a/core/src/loader/http/devices.cpp b/core/src/loader/http/devices.cpp index 4a46437..9941836 100644 --- a/core/src/loader/http/devices.cpp +++ b/core/src/loader/http/devices.cpp @@ -70,6 +70,36 @@ QNetworkAccessManager::Operation GetDevicesLoader::operation() const { } +DeleteDeviceLoader::DeleteDeviceLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString DeleteDeviceLoader::path(const DeleteDeviceParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Devices"); +} + +QUrlQuery DeleteDeviceLoader::query(const DeleteDeviceParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + result.addQueryItem("id", Support::toString(params.jellyfinId())); + + // Optional parameters + + return result; +} + +QByteArray DeleteDeviceLoader::body(const DeleteDeviceParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation DeleteDeviceLoader::operation() const { + // HTTP method Delete + return QNetworkAccessManager::DeleteOperation; + +} + GetDeviceInfoLoader::GetDeviceInfoLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader(apiClient) {} @@ -130,6 +160,36 @@ QNetworkAccessManager::Operation GetDeviceOptionsLoader::operation() const { } +UpdateDeviceOptionsLoader::UpdateDeviceOptionsLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString UpdateDeviceOptionsLoader::path(const UpdateDeviceOptionsParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Devices/Options"); +} + +QUrlQuery UpdateDeviceOptionsLoader::query(const UpdateDeviceOptionsParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + result.addQueryItem("id", Support::toString(params.jellyfinId())); + + // Optional parameters + + return result; +} + +QByteArray UpdateDeviceOptionsLoader::body(const UpdateDeviceOptionsParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation UpdateDeviceOptionsLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + } // NS HTTP } // NS Loader diff --git a/core/src/loader/http/displaypreferences.cpp b/core/src/loader/http/displaypreferences.cpp index 5032340..73bb14f 100644 --- a/core/src/loader/http/displaypreferences.cpp +++ b/core/src/loader/http/displaypreferences.cpp @@ -66,6 +66,37 @@ QNetworkAccessManager::Operation GetDisplayPreferencesLoader::operation() const } +UpdateDisplayPreferencesLoader::UpdateDisplayPreferencesLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString UpdateDisplayPreferencesLoader::path(const UpdateDisplayPreferencesParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/DisplayPreferences/") + Support::toString< QString>(params.displayPreferencesId()) ; +} + +QUrlQuery UpdateDisplayPreferencesLoader::query(const UpdateDisplayPreferencesParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + result.addQueryItem("userId", Support::toString(params.userId())); + result.addQueryItem("client", Support::toString(params.client())); + + // Optional parameters + + return result; +} + +QByteArray UpdateDisplayPreferencesLoader::body(const UpdateDisplayPreferencesParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation UpdateDisplayPreferencesLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + } // NS HTTP } // NS Loader diff --git a/core/src/loader/http/dlna.cpp b/core/src/loader/http/dlna.cpp index 76ff119..76add46 100644 --- a/core/src/loader/http/dlna.cpp +++ b/core/src/loader/http/dlna.cpp @@ -64,6 +64,35 @@ QNetworkAccessManager::Operation GetProfileInfosLoader::operation() const { } +CreateProfileLoader::CreateProfileLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString CreateProfileLoader::path(const CreateProfileParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Dlna/Profiles"); +} + +QUrlQuery CreateProfileLoader::query(const CreateProfileParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray CreateProfileLoader::body(const CreateProfileParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation CreateProfileLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + GetProfileLoader::GetProfileLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader(apiClient) {} @@ -93,6 +122,64 @@ QNetworkAccessManager::Operation GetProfileLoader::operation() const { } +DeleteProfileLoader::DeleteProfileLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString DeleteProfileLoader::path(const DeleteProfileParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Dlna/Profiles/") + Support::toString< QString>(params.profileId()) ; +} + +QUrlQuery DeleteProfileLoader::query(const DeleteProfileParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray DeleteProfileLoader::body(const DeleteProfileParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation DeleteProfileLoader::operation() const { + // HTTP method Delete + return QNetworkAccessManager::DeleteOperation; + +} + +UpdateProfileLoader::UpdateProfileLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString UpdateProfileLoader::path(const UpdateProfileParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Dlna/Profiles/") + Support::toString< QString>(params.profileId()) ; +} + +QUrlQuery UpdateProfileLoader::query(const UpdateProfileParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray UpdateProfileLoader::body(const UpdateProfileParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation UpdateProfileLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + GetDefaultProfileLoader::GetDefaultProfileLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader(apiClient) {} diff --git a/core/src/loader/http/environment.cpp b/core/src/loader/http/environment.cpp index 148be92..a2c8e52 100644 --- a/core/src/loader/http/environment.cpp +++ b/core/src/loader/http/environment.cpp @@ -188,6 +188,35 @@ QNetworkAccessManager::Operation GetParentPathLoader::operation() const { } +ValidatePathLoader::ValidatePathLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString ValidatePathLoader::path(const ValidatePathParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Environment/ValidatePath"); +} + +QUrlQuery ValidatePathLoader::query(const ValidatePathParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray ValidatePathLoader::body(const ValidatePathParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation ValidatePathLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + } // NS HTTP } // NS Loader diff --git a/core/src/loader/http/hlssegment.cpp b/core/src/loader/http/hlssegment.cpp index e3a9db8..cb0354f 100644 --- a/core/src/loader/http/hlssegment.cpp +++ b/core/src/loader/http/hlssegment.cpp @@ -35,6 +35,41 @@ namespace HTTP { using namespace Jellyfin::DTO; +StopEncodingProcessLoader::StopEncodingProcessLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString StopEncodingProcessLoader::path(const StopEncodingProcessParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Videos/ActiveEncodings"); +} + +QUrlQuery StopEncodingProcessLoader::query(const StopEncodingProcessParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.deviceIdNull()) { + result.addQueryItem("deviceId", Support::toString(params.deviceId())); + } + if (!params.playSessionIdNull()) { + result.addQueryItem("playSessionId", Support::toString(params.playSessionId())); + } + + return result; +} + +QByteArray StopEncodingProcessLoader::body(const StopEncodingProcessParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation StopEncodingProcessLoader::operation() const { + // HTTP method Delete + return QNetworkAccessManager::DeleteOperation; + +} + } // NS HTTP } // NS Loader diff --git a/core/src/loader/http/image.cpp b/core/src/loader/http/image.cpp index 8cc075f..e17ac3d 100644 --- a/core/src/loader/http/image.cpp +++ b/core/src/loader/http/image.cpp @@ -64,6 +64,279 @@ QNetworkAccessManager::Operation GetItemImageInfosLoader::operation() const { } +DeleteItemImageLoader::DeleteItemImageLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString DeleteItemImageLoader::path(const DeleteItemImageParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Items/") + Support::toString< QString>(params.itemId()) + QStringLiteral("/Images/") + Support::toString< ImageType>(params.imageType()) ; +} + +QUrlQuery DeleteItemImageLoader::query(const DeleteItemImageParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.imageIndexNull()) { + result.addQueryItem("imageIndex", Support::toString>(params.imageIndex())); + } + + return result; +} + +QByteArray DeleteItemImageLoader::body(const DeleteItemImageParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation DeleteItemImageLoader::operation() const { + // HTTP method Delete + return QNetworkAccessManager::DeleteOperation; + +} + +SetItemImageLoader::SetItemImageLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SetItemImageLoader::path(const SetItemImageParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Items/") + Support::toString< QString>(params.itemId()) + QStringLiteral("/Images/") + Support::toString< ImageType>(params.imageType()) ; +} + +QUrlQuery SetItemImageLoader::query(const SetItemImageParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray SetItemImageLoader::body(const SetItemImageParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation SetItemImageLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +DeleteItemImageByIndexLoader::DeleteItemImageByIndexLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString DeleteItemImageByIndexLoader::path(const DeleteItemImageByIndexParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Items/") + Support::toString< QString>(params.itemId()) + QStringLiteral("/Images/") + Support::toString< ImageType>(params.imageType()) + QStringLiteral("/") + Support::toString< qint32>(params.imageIndex()) ; +} + +QUrlQuery DeleteItemImageByIndexLoader::query(const DeleteItemImageByIndexParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray DeleteItemImageByIndexLoader::body(const DeleteItemImageByIndexParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation DeleteItemImageByIndexLoader::operation() const { + // HTTP method Delete + return QNetworkAccessManager::DeleteOperation; + +} + +SetItemImageByIndexLoader::SetItemImageByIndexLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SetItemImageByIndexLoader::path(const SetItemImageByIndexParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Items/") + Support::toString< QString>(params.itemId()) + QStringLiteral("/Images/") + Support::toString< ImageType>(params.imageType()) + QStringLiteral("/") + Support::toString< qint32>(params.imageIndex()) ; +} + +QUrlQuery SetItemImageByIndexLoader::query(const SetItemImageByIndexParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray SetItemImageByIndexLoader::body(const SetItemImageByIndexParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation SetItemImageByIndexLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +UpdateItemImageIndexLoader::UpdateItemImageIndexLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString UpdateItemImageIndexLoader::path(const UpdateItemImageIndexParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Items/") + Support::toString< QString>(params.itemId()) + QStringLiteral("/Images/") + Support::toString< ImageType>(params.imageType()) + QStringLiteral("/") + Support::toString< qint32>(params.imageIndex()) + QStringLiteral("/Index"); +} + +QUrlQuery UpdateItemImageIndexLoader::query(const UpdateItemImageIndexParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.newIndexNull()) { + result.addQueryItem("newIndex", Support::toString>(params.newIndex())); + } + + return result; +} + +QByteArray UpdateItemImageIndexLoader::body(const UpdateItemImageIndexParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation UpdateItemImageIndexLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +PostUserImageLoader::PostUserImageLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString PostUserImageLoader::path(const PostUserImageParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Users/") + Support::toString< QString>(params.userId()) + QStringLiteral("/Images/") + Support::toString< ImageType>(params.imageType()) ; +} + +QUrlQuery PostUserImageLoader::query(const PostUserImageParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.indexNull()) { + result.addQueryItem("index", Support::toString>(params.index())); + } + + return result; +} + +QByteArray PostUserImageLoader::body(const PostUserImageParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation PostUserImageLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +DeleteUserImageLoader::DeleteUserImageLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString DeleteUserImageLoader::path(const DeleteUserImageParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Users/") + Support::toString< QString>(params.userId()) + QStringLiteral("/Images/") + Support::toString< ImageType>(params.imageType()) ; +} + +QUrlQuery DeleteUserImageLoader::query(const DeleteUserImageParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.indexNull()) { + result.addQueryItem("index", Support::toString>(params.index())); + } + + return result; +} + +QByteArray DeleteUserImageLoader::body(const DeleteUserImageParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation DeleteUserImageLoader::operation() const { + // HTTP method Delete + return QNetworkAccessManager::DeleteOperation; + +} + +PostUserImageByIndexLoader::PostUserImageByIndexLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString PostUserImageByIndexLoader::path(const PostUserImageByIndexParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Users/") + Support::toString< QString>(params.userId()) + QStringLiteral("/Images/") + Support::toString< ImageType>(params.imageType()) + QStringLiteral("/") + Support::toString< qint32>(params.index()) ; +} + +QUrlQuery PostUserImageByIndexLoader::query(const PostUserImageByIndexParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray PostUserImageByIndexLoader::body(const PostUserImageByIndexParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation PostUserImageByIndexLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +DeleteUserImageByIndexLoader::DeleteUserImageByIndexLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString DeleteUserImageByIndexLoader::path(const DeleteUserImageByIndexParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Users/") + Support::toString< QString>(params.userId()) + QStringLiteral("/Images/") + Support::toString< ImageType>(params.imageType()) + QStringLiteral("/") + Support::toString< qint32>(params.index()) ; +} + +QUrlQuery DeleteUserImageByIndexLoader::query(const DeleteUserImageByIndexParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray DeleteUserImageByIndexLoader::body(const DeleteUserImageByIndexParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation DeleteUserImageByIndexLoader::operation() const { + // HTTP method Delete + return QNetworkAccessManager::DeleteOperation; + +} + } // NS HTTP } // NS Loader diff --git a/core/src/loader/http/itemlookup.cpp b/core/src/loader/http/itemlookup.cpp index 983d177..0e26dec 100644 --- a/core/src/loader/http/itemlookup.cpp +++ b/core/src/loader/http/itemlookup.cpp @@ -64,6 +64,38 @@ QNetworkAccessManager::Operation GetExternalIdInfosLoader::operation() const { } +ApplySearchCriteriaLoader::ApplySearchCriteriaLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString ApplySearchCriteriaLoader::path(const ApplySearchCriteriaParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Items/RemoteSearch/Apply/") + Support::toString< QString>(params.itemId()) ; +} + +QUrlQuery ApplySearchCriteriaLoader::query(const ApplySearchCriteriaParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.replaceAllImagesNull()) { + result.addQueryItem("replaceAllImages", Support::toString>(params.replaceAllImages())); + } + + return result; +} + +QByteArray ApplySearchCriteriaLoader::body(const ApplySearchCriteriaParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation ApplySearchCriteriaLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + GetBookRemoteSearchResultsLoader::GetBookRemoteSearchResultsLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader, GetBookRemoteSearchResultsParams>(apiClient) {} diff --git a/core/src/loader/http/itemrefresh.cpp b/core/src/loader/http/itemrefresh.cpp index 8131f15..5be3700 100644 --- a/core/src/loader/http/itemrefresh.cpp +++ b/core/src/loader/http/itemrefresh.cpp @@ -35,6 +35,47 @@ namespace HTTP { using namespace Jellyfin::DTO; +PostLoader::PostLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString PostLoader::path(const PostParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Items/") + Support::toString< QString>(params.itemId()) + QStringLiteral("/Refresh"); +} + +QUrlQuery PostLoader::query(const PostParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.metadataRefreshModeNull()) { + result.addQueryItem("metadataRefreshMode", Support::toString(params.metadataRefreshMode())); + } + if (!params.imageRefreshModeNull()) { + result.addQueryItem("imageRefreshMode", Support::toString(params.imageRefreshMode())); + } + if (!params.replaceAllMetadataNull()) { + result.addQueryItem("replaceAllMetadata", Support::toString>(params.replaceAllMetadata())); + } + if (!params.replaceAllImagesNull()) { + result.addQueryItem("replaceAllImages", Support::toString>(params.replaceAllImages())); + } + + return result; +} + +QByteArray PostLoader::body(const PostParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation PostLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + } // NS HTTP } // NS Loader diff --git a/core/src/loader/http/itemupdate.cpp b/core/src/loader/http/itemupdate.cpp index d186ff3..17644ff 100644 --- a/core/src/loader/http/itemupdate.cpp +++ b/core/src/loader/http/itemupdate.cpp @@ -35,6 +35,67 @@ namespace HTTP { using namespace Jellyfin::DTO; +UpdateItemLoader::UpdateItemLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString UpdateItemLoader::path(const UpdateItemParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Items/") + Support::toString< QString>(params.itemId()) ; +} + +QUrlQuery UpdateItemLoader::query(const UpdateItemParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray UpdateItemLoader::body(const UpdateItemParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation UpdateItemLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +UpdateItemContentTypeLoader::UpdateItemContentTypeLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString UpdateItemContentTypeLoader::path(const UpdateItemContentTypeParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Items/") + Support::toString< QString>(params.itemId()) + QStringLiteral("/ContentType"); +} + +QUrlQuery UpdateItemContentTypeLoader::query(const UpdateItemContentTypeParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.contentTypeNull()) { + result.addQueryItem("contentType", Support::toString(params.contentType())); + } + + return result; +} + +QByteArray UpdateItemContentTypeLoader::body(const UpdateItemContentTypeParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation UpdateItemContentTypeLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + GetMetadataEditorInfoLoader::GetMetadataEditorInfoLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader(apiClient) {} diff --git a/core/src/loader/http/library.cpp b/core/src/loader/http/library.cpp index 70fec6f..c53dbe8 100644 --- a/core/src/loader/http/library.cpp +++ b/core/src/loader/http/library.cpp @@ -35,6 +35,67 @@ namespace HTTP { using namespace Jellyfin::DTO; +DeleteItemsLoader::DeleteItemsLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString DeleteItemsLoader::path(const DeleteItemsParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Items"); +} + +QUrlQuery DeleteItemsLoader::query(const DeleteItemsParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.idsNull()) { + result.addQueryItem("ids", Support::toString(params.ids())); + } + + return result; +} + +QByteArray DeleteItemsLoader::body(const DeleteItemsParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation DeleteItemsLoader::operation() const { + // HTTP method Delete + return QNetworkAccessManager::DeleteOperation; + +} + +DeleteItemLoader::DeleteItemLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString DeleteItemLoader::path(const DeleteItemParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Items/") + Support::toString< QString>(params.itemId()) ; +} + +QUrlQuery DeleteItemLoader::query(const DeleteItemParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray DeleteItemLoader::body(const DeleteItemParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation DeleteItemLoader::operation() const { + // HTTP method Delete + return QNetworkAccessManager::DeleteOperation; + +} + GetSimilarAlbumsLoader::GetSimilarAlbumsLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader(apiClient) {} @@ -394,6 +455,35 @@ QNetworkAccessManager::Operation GetLibraryOptionsInfoLoader::operation() const } +PostUpdatedMediaLoader::PostUpdatedMediaLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString PostUpdatedMediaLoader::path(const PostUpdatedMediaParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Library/Media/Updated"); +} + +QUrlQuery PostUpdatedMediaLoader::query(const PostUpdatedMediaParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray PostUpdatedMediaLoader::body(const PostUpdatedMediaParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation PostUpdatedMediaLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + GetMediaFoldersLoader::GetMediaFoldersLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader(apiClient) {} @@ -426,6 +516,76 @@ QNetworkAccessManager::Operation GetMediaFoldersLoader::operation() const { } +PostAddedMoviesLoader::PostAddedMoviesLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString PostAddedMoviesLoader::path(const PostAddedMoviesParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Library/Movies/Added"); +} + +QUrlQuery PostAddedMoviesLoader::query(const PostAddedMoviesParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.tmdbIdNull()) { + result.addQueryItem("tmdbId", Support::toString(params.tmdbId())); + } + if (!params.imdbIdNull()) { + result.addQueryItem("imdbId", Support::toString(params.imdbId())); + } + + return result; +} + +QByteArray PostAddedMoviesLoader::body(const PostAddedMoviesParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation PostAddedMoviesLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +PostUpdatedMoviesLoader::PostUpdatedMoviesLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString PostUpdatedMoviesLoader::path(const PostUpdatedMoviesParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Library/Movies/Updated"); +} + +QUrlQuery PostUpdatedMoviesLoader::query(const PostUpdatedMoviesParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.tmdbIdNull()) { + result.addQueryItem("tmdbId", Support::toString(params.tmdbId())); + } + if (!params.imdbIdNull()) { + result.addQueryItem("imdbId", Support::toString(params.imdbId())); + } + + return result; +} + +QByteArray PostUpdatedMoviesLoader::body(const PostUpdatedMoviesParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation PostUpdatedMoviesLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + GetPhysicalPathsLoader::GetPhysicalPathsLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader(apiClient) {} @@ -455,6 +615,99 @@ QNetworkAccessManager::Operation GetPhysicalPathsLoader::operation() const { } +RefreshLibraryLoader::RefreshLibraryLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString RefreshLibraryLoader::path(const RefreshLibraryParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Library/Refresh"); +} + +QUrlQuery RefreshLibraryLoader::query(const RefreshLibraryParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray RefreshLibraryLoader::body(const RefreshLibraryParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation RefreshLibraryLoader::operation() const { + // HTTP method Get + return QNetworkAccessManager::GetOperation; + +} + +PostAddedSeriesLoader::PostAddedSeriesLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString PostAddedSeriesLoader::path(const PostAddedSeriesParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Library/Series/Added"); +} + +QUrlQuery PostAddedSeriesLoader::query(const PostAddedSeriesParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.tvdbIdNull()) { + result.addQueryItem("tvdbId", Support::toString(params.tvdbId())); + } + + return result; +} + +QByteArray PostAddedSeriesLoader::body(const PostAddedSeriesParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation PostAddedSeriesLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +PostUpdatedSeriesLoader::PostUpdatedSeriesLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString PostUpdatedSeriesLoader::path(const PostUpdatedSeriesParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Library/Series/Updated"); +} + +QUrlQuery PostUpdatedSeriesLoader::query(const PostUpdatedSeriesParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.tvdbIdNull()) { + result.addQueryItem("tvdbId", Support::toString(params.tvdbId())); + } + + return result; +} + +QByteArray PostUpdatedSeriesLoader::body(const PostUpdatedSeriesParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation PostUpdatedSeriesLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + GetSimilarMoviesLoader::GetSimilarMoviesLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader(apiClient) {} diff --git a/core/src/loader/http/librarystructure.cpp b/core/src/loader/http/librarystructure.cpp index 9549d97..17898b7 100644 --- a/core/src/loader/http/librarystructure.cpp +++ b/core/src/loader/http/librarystructure.cpp @@ -64,6 +64,251 @@ QNetworkAccessManager::Operation GetVirtualFoldersLoader::operation() const { } +AddVirtualFolderLoader::AddVirtualFolderLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString AddVirtualFolderLoader::path(const AddVirtualFolderParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Library/VirtualFolders"); +} + +QUrlQuery AddVirtualFolderLoader::query(const AddVirtualFolderParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.nameNull()) { + result.addQueryItem("name", Support::toString(params.name())); + } + if (!params.collectionTypeNull()) { + result.addQueryItem("collectionType", Support::toString(params.collectionType())); + } + if (!params.pathsNull()) { + result.addQueryItem("paths", Support::toString(params.paths())); + } + if (!params.refreshLibraryNull()) { + result.addQueryItem("refreshLibrary", Support::toString>(params.refreshLibrary())); + } + + return result; +} + +QByteArray AddVirtualFolderLoader::body(const AddVirtualFolderParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation AddVirtualFolderLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +RemoveVirtualFolderLoader::RemoveVirtualFolderLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString RemoveVirtualFolderLoader::path(const RemoveVirtualFolderParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Library/VirtualFolders"); +} + +QUrlQuery RemoveVirtualFolderLoader::query(const RemoveVirtualFolderParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.nameNull()) { + result.addQueryItem("name", Support::toString(params.name())); + } + if (!params.refreshLibraryNull()) { + result.addQueryItem("refreshLibrary", Support::toString>(params.refreshLibrary())); + } + + return result; +} + +QByteArray RemoveVirtualFolderLoader::body(const RemoveVirtualFolderParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation RemoveVirtualFolderLoader::operation() const { + // HTTP method Delete + return QNetworkAccessManager::DeleteOperation; + +} + +UpdateLibraryOptionsLoader::UpdateLibraryOptionsLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString UpdateLibraryOptionsLoader::path(const UpdateLibraryOptionsParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Library/VirtualFolders/LibraryOptions"); +} + +QUrlQuery UpdateLibraryOptionsLoader::query(const UpdateLibraryOptionsParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray UpdateLibraryOptionsLoader::body(const UpdateLibraryOptionsParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation UpdateLibraryOptionsLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +RenameVirtualFolderLoader::RenameVirtualFolderLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString RenameVirtualFolderLoader::path(const RenameVirtualFolderParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Library/VirtualFolders/Name"); +} + +QUrlQuery RenameVirtualFolderLoader::query(const RenameVirtualFolderParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.nameNull()) { + result.addQueryItem("name", Support::toString(params.name())); + } + if (!params.newNameNull()) { + result.addQueryItem("newName", Support::toString(params.newName())); + } + if (!params.refreshLibraryNull()) { + result.addQueryItem("refreshLibrary", Support::toString>(params.refreshLibrary())); + } + + return result; +} + +QByteArray RenameVirtualFolderLoader::body(const RenameVirtualFolderParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation RenameVirtualFolderLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +AddMediaPathLoader::AddMediaPathLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString AddMediaPathLoader::path(const AddMediaPathParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Library/VirtualFolders/Paths"); +} + +QUrlQuery AddMediaPathLoader::query(const AddMediaPathParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.refreshLibraryNull()) { + result.addQueryItem("refreshLibrary", Support::toString>(params.refreshLibrary())); + } + + return result; +} + +QByteArray AddMediaPathLoader::body(const AddMediaPathParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation AddMediaPathLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +RemoveMediaPathLoader::RemoveMediaPathLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString RemoveMediaPathLoader::path(const RemoveMediaPathParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Library/VirtualFolders/Paths"); +} + +QUrlQuery RemoveMediaPathLoader::query(const RemoveMediaPathParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.nameNull()) { + result.addQueryItem("name", Support::toString(params.name())); + } + if (!params.pathNull()) { + result.addQueryItem("path", Support::toString(params.path())); + } + if (!params.refreshLibraryNull()) { + result.addQueryItem("refreshLibrary", Support::toString>(params.refreshLibrary())); + } + + return result; +} + +QByteArray RemoveMediaPathLoader::body(const RemoveMediaPathParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation RemoveMediaPathLoader::operation() const { + // HTTP method Delete + return QNetworkAccessManager::DeleteOperation; + +} + +UpdateMediaPathLoader::UpdateMediaPathLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString UpdateMediaPathLoader::path(const UpdateMediaPathParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Library/VirtualFolders/Paths/Update"); +} + +QUrlQuery UpdateMediaPathLoader::query(const UpdateMediaPathParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.nameNull()) { + result.addQueryItem("name", Support::toString(params.name())); + } + + return result; +} + +QByteArray UpdateMediaPathLoader::body(const UpdateMediaPathParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation UpdateMediaPathLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + } // NS HTTP } // NS Loader diff --git a/core/src/loader/http/livetv.cpp b/core/src/loader/http/livetv.cpp index 3963c07..dfce054 100644 --- a/core/src/loader/http/livetv.cpp +++ b/core/src/loader/http/livetv.cpp @@ -316,6 +316,38 @@ QNetworkAccessManager::Operation AddListingProviderLoader::operation() const { } +DeleteListingProviderLoader::DeleteListingProviderLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString DeleteListingProviderLoader::path(const DeleteListingProviderParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/LiveTv/ListingProviders"); +} + +QUrlQuery DeleteListingProviderLoader::query(const DeleteListingProviderParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.jellyfinIdNull()) { + result.addQueryItem("id", Support::toString(params.jellyfinId())); + } + + return result; +} + +QByteArray DeleteListingProviderLoader::body(const DeleteListingProviderParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation DeleteListingProviderLoader::operation() const { + // HTTP method Delete + return QNetworkAccessManager::DeleteOperation; + +} + GetDefaultListingProviderLoader::GetDefaultListingProviderLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader(apiClient) {} @@ -781,6 +813,35 @@ QNetworkAccessManager::Operation GetRecordingLoader::operation() const { } +DeleteRecordingLoader::DeleteRecordingLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString DeleteRecordingLoader::path(const DeleteRecordingParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/LiveTv/Recordings/") + Support::toString< QString>(params.recordingId()) ; +} + +QUrlQuery DeleteRecordingLoader::query(const DeleteRecordingParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray DeleteRecordingLoader::body(const DeleteRecordingParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation DeleteRecordingLoader::operation() const { + // HTTP method Delete + return QNetworkAccessManager::DeleteOperation; + +} + GetRecordingFoldersLoader::GetRecordingFoldersLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader(apiClient) {} @@ -951,6 +1012,35 @@ QNetworkAccessManager::Operation GetSeriesTimersLoader::operation() const { } +CreateSeriesTimerLoader::CreateSeriesTimerLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString CreateSeriesTimerLoader::path(const CreateSeriesTimerParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/LiveTv/SeriesTimers"); +} + +QUrlQuery CreateSeriesTimerLoader::query(const CreateSeriesTimerParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray CreateSeriesTimerLoader::body(const CreateSeriesTimerParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation CreateSeriesTimerLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + GetSeriesTimerLoader::GetSeriesTimerLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader(apiClient) {} @@ -980,6 +1070,64 @@ QNetworkAccessManager::Operation GetSeriesTimerLoader::operation() const { } +CancelSeriesTimerLoader::CancelSeriesTimerLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString CancelSeriesTimerLoader::path(const CancelSeriesTimerParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/LiveTv/SeriesTimers/") + Support::toString< QString>(params.timerId()) ; +} + +QUrlQuery CancelSeriesTimerLoader::query(const CancelSeriesTimerParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray CancelSeriesTimerLoader::body(const CancelSeriesTimerParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation CancelSeriesTimerLoader::operation() const { + // HTTP method Delete + return QNetworkAccessManager::DeleteOperation; + +} + +UpdateSeriesTimerLoader::UpdateSeriesTimerLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString UpdateSeriesTimerLoader::path(const UpdateSeriesTimerParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/LiveTv/SeriesTimers/") + Support::toString< QString>(params.timerId()) ; +} + +QUrlQuery UpdateSeriesTimerLoader::query(const UpdateSeriesTimerParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray UpdateSeriesTimerLoader::body(const UpdateSeriesTimerParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation UpdateSeriesTimerLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + GetTimersLoader::GetTimersLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader(apiClient) {} @@ -1021,6 +1169,35 @@ QNetworkAccessManager::Operation GetTimersLoader::operation() const { } +CreateTimerLoader::CreateTimerLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString CreateTimerLoader::path(const CreateTimerParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/LiveTv/Timers"); +} + +QUrlQuery CreateTimerLoader::query(const CreateTimerParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray CreateTimerLoader::body(const CreateTimerParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation CreateTimerLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + GetTimerLoader::GetTimerLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader(apiClient) {} @@ -1050,6 +1227,64 @@ QNetworkAccessManager::Operation GetTimerLoader::operation() const { } +CancelTimerLoader::CancelTimerLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString CancelTimerLoader::path(const CancelTimerParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/LiveTv/Timers/") + Support::toString< QString>(params.timerId()) ; +} + +QUrlQuery CancelTimerLoader::query(const CancelTimerParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray CancelTimerLoader::body(const CancelTimerParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation CancelTimerLoader::operation() const { + // HTTP method Delete + return QNetworkAccessManager::DeleteOperation; + +} + +UpdateTimerLoader::UpdateTimerLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString UpdateTimerLoader::path(const UpdateTimerParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/LiveTv/Timers/") + Support::toString< QString>(params.timerId()) ; +} + +QUrlQuery UpdateTimerLoader::query(const UpdateTimerParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray UpdateTimerLoader::body(const UpdateTimerParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation UpdateTimerLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + GetDefaultTimerLoader::GetDefaultTimerLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader(apiClient) {} @@ -1111,6 +1346,38 @@ QNetworkAccessManager::Operation AddTunerHostLoader::operation() const { } +DeleteTunerHostLoader::DeleteTunerHostLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString DeleteTunerHostLoader::path(const DeleteTunerHostParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/LiveTv/TunerHosts"); +} + +QUrlQuery DeleteTunerHostLoader::query(const DeleteTunerHostParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.jellyfinIdNull()) { + result.addQueryItem("id", Support::toString(params.jellyfinId())); + } + + return result; +} + +QByteArray DeleteTunerHostLoader::body(const DeleteTunerHostParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation DeleteTunerHostLoader::operation() const { + // HTTP method Delete + return QNetworkAccessManager::DeleteOperation; + +} + GetTunerHostTypesLoader::GetTunerHostTypesLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader, GetTunerHostTypesParams>(apiClient) {} @@ -1140,6 +1407,35 @@ QNetworkAccessManager::Operation GetTunerHostTypesLoader::operation() const { } +ResetTunerLoader::ResetTunerLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString ResetTunerLoader::path(const ResetTunerParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/LiveTv/Tuners/") + Support::toString< QString>(params.tunerId()) + QStringLiteral("/Reset"); +} + +QUrlQuery ResetTunerLoader::query(const ResetTunerParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray ResetTunerLoader::body(const ResetTunerParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation ResetTunerLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + DiscoverTunersLoader::DiscoverTunersLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader, DiscoverTunersParams>(apiClient) {} diff --git a/core/src/loader/http/mediainfo.cpp b/core/src/loader/http/mediainfo.cpp index 69c944e..c2aaf46 100644 --- a/core/src/loader/http/mediainfo.cpp +++ b/core/src/loader/http/mediainfo.cpp @@ -136,6 +136,36 @@ QNetworkAccessManager::Operation GetPostedPlaybackInfoLoader::operation() const } +CloseLiveStreamLoader::CloseLiveStreamLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString CloseLiveStreamLoader::path(const CloseLiveStreamParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/LiveStreams/Close"); +} + +QUrlQuery CloseLiveStreamLoader::query(const CloseLiveStreamParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + result.addQueryItem("liveStreamId", Support::toString(params.liveStreamId())); + + // Optional parameters + + return result; +} + +QByteArray CloseLiveStreamLoader::body(const CloseLiveStreamParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation CloseLiveStreamLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + OpenLiveStreamLoader::OpenLiveStreamLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader(apiClient) {} diff --git a/core/src/loader/http/notifications.cpp b/core/src/loader/http/notifications.cpp index c1c2ca1..5041bce 100644 --- a/core/src/loader/http/notifications.cpp +++ b/core/src/loader/http/notifications.cpp @@ -64,6 +64,35 @@ QNetworkAccessManager::Operation GetNotificationsLoader::operation() const { } +SetReadLoader::SetReadLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SetReadLoader::path(const SetReadParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Notifications/") + Support::toString< QString>(params.userId()) + QStringLiteral("/Read"); +} + +QUrlQuery SetReadLoader::query(const SetReadParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray SetReadLoader::body(const SetReadParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation SetReadLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + GetNotificationsSummaryLoader::GetNotificationsSummaryLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader(apiClient) {} @@ -93,6 +122,76 @@ QNetworkAccessManager::Operation GetNotificationsSummaryLoader::operation() cons } +SetUnreadLoader::SetUnreadLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SetUnreadLoader::path(const SetUnreadParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Notifications/") + Support::toString< QString>(params.userId()) + QStringLiteral("/Unread"); +} + +QUrlQuery SetUnreadLoader::query(const SetUnreadParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray SetUnreadLoader::body(const SetUnreadParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation SetUnreadLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +CreateAdminNotificationLoader::CreateAdminNotificationLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString CreateAdminNotificationLoader::path(const CreateAdminNotificationParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Notifications/Admin"); +} + +QUrlQuery CreateAdminNotificationLoader::query(const CreateAdminNotificationParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.urlNull()) { + result.addQueryItem("url", Support::toString(params.url())); + } + if (!params.levelNull()) { + result.addQueryItem("level", Support::toString(params.level())); + } + if (!params.nameNull()) { + result.addQueryItem("name", Support::toString(params.name())); + } + if (!params.descriptionNull()) { + result.addQueryItem("description", Support::toString(params.description())); + } + + return result; +} + +QByteArray CreateAdminNotificationLoader::body(const CreateAdminNotificationParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation CreateAdminNotificationLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + GetNotificationServicesLoader::GetNotificationServicesLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader, GetNotificationServicesParams>(apiClient) {} diff --git a/core/src/loader/http/package.cpp b/core/src/loader/http/package.cpp index b8da359..285ab24 100644 --- a/core/src/loader/http/package.cpp +++ b/core/src/loader/http/package.cpp @@ -96,6 +96,73 @@ QNetworkAccessManager::Operation GetPackageInfoLoader::operation() const { } +InstallPackageLoader::InstallPackageLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString InstallPackageLoader::path(const InstallPackageParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Packages/Installed/") + Support::toString< QString>(params.name()) ; +} + +QUrlQuery InstallPackageLoader::query(const InstallPackageParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.assemblyGuidNull()) { + result.addQueryItem("assemblyGuid", Support::toString(params.assemblyGuid())); + } + if (!params.versionNull()) { + result.addQueryItem("version", Support::toString(params.version())); + } + if (!params.repositoryUrlNull()) { + result.addQueryItem("repositoryUrl", Support::toString(params.repositoryUrl())); + } + + return result; +} + +QByteArray InstallPackageLoader::body(const InstallPackageParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation InstallPackageLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +CancelPackageInstallationLoader::CancelPackageInstallationLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString CancelPackageInstallationLoader::path(const CancelPackageInstallationParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Packages/Installing/") + Support::toString< QString>(params.packageId()) ; +} + +QUrlQuery CancelPackageInstallationLoader::query(const CancelPackageInstallationParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray CancelPackageInstallationLoader::body(const CancelPackageInstallationParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation CancelPackageInstallationLoader::operation() const { + // HTTP method Delete + return QNetworkAccessManager::DeleteOperation; + +} + GetRepositoriesLoader::GetRepositoriesLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader, GetRepositoriesParams>(apiClient) {} @@ -125,6 +192,35 @@ QNetworkAccessManager::Operation GetRepositoriesLoader::operation() const { } +SetRepositoriesLoader::SetRepositoriesLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SetRepositoriesLoader::path(const SetRepositoriesParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Repositories"); +} + +QUrlQuery SetRepositoriesLoader::query(const SetRepositoriesParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray SetRepositoriesLoader::body(const SetRepositoriesParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation SetRepositoriesLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + } // NS HTTP } // NS Loader diff --git a/core/src/loader/http/playlists.cpp b/core/src/loader/http/playlists.cpp index 9465683..dc7f2db 100644 --- a/core/src/loader/http/playlists.cpp +++ b/core/src/loader/http/playlists.cpp @@ -76,6 +76,73 @@ QNetworkAccessManager::Operation CreatePlaylistLoader::operation() const { } +AddToPlaylistLoader::AddToPlaylistLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString AddToPlaylistLoader::path(const AddToPlaylistParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Playlists/") + Support::toString< QString>(params.playlistId()) + QStringLiteral("/Items"); +} + +QUrlQuery AddToPlaylistLoader::query(const AddToPlaylistParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.idsNull()) { + result.addQueryItem("ids", Support::toString(params.ids())); + } + if (!params.userIdNull()) { + result.addQueryItem("userId", Support::toString(params.userId())); + } + + return result; +} + +QByteArray AddToPlaylistLoader::body(const AddToPlaylistParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation AddToPlaylistLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +RemoveFromPlaylistLoader::RemoveFromPlaylistLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString RemoveFromPlaylistLoader::path(const RemoveFromPlaylistParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Playlists/") + Support::toString< QString>(params.playlistId()) + QStringLiteral("/Items"); +} + +QUrlQuery RemoveFromPlaylistLoader::query(const RemoveFromPlaylistParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.entryIdsNull()) { + result.addQueryItem("entryIds", Support::toString(params.entryIds())); + } + + return result; +} + +QByteArray RemoveFromPlaylistLoader::body(const RemoveFromPlaylistParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation RemoveFromPlaylistLoader::operation() const { + // HTTP method Delete + return QNetworkAccessManager::DeleteOperation; + +} + GetPlaylistItemsLoader::GetPlaylistItemsLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader(apiClient) {} @@ -127,6 +194,35 @@ QNetworkAccessManager::Operation GetPlaylistItemsLoader::operation() const { } +MoveItemLoader::MoveItemLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString MoveItemLoader::path(const MoveItemParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Playlists/") + Support::toString< QString>(params.playlistId()) + QStringLiteral("/Items/") + Support::toString< QString>(params.itemId()) + QStringLiteral("/Move/") + Support::toString< qint32>(params.newIndex()) ; +} + +QUrlQuery MoveItemLoader::query(const MoveItemParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray MoveItemLoader::body(const MoveItemParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation MoveItemLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + } // NS HTTP } // NS Loader diff --git a/core/src/loader/http/playstate.cpp b/core/src/loader/http/playstate.cpp index e0bf7b7..abd37d1 100644 --- a/core/src/loader/http/playstate.cpp +++ b/core/src/loader/http/playstate.cpp @@ -35,6 +35,125 @@ namespace HTTP { using namespace Jellyfin::DTO; +ReportPlaybackStartLoader::ReportPlaybackStartLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString ReportPlaybackStartLoader::path(const ReportPlaybackStartParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Sessions/Playing"); +} + +QUrlQuery ReportPlaybackStartLoader::query(const ReportPlaybackStartParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray ReportPlaybackStartLoader::body(const ReportPlaybackStartParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation ReportPlaybackStartLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +PingPlaybackSessionLoader::PingPlaybackSessionLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString PingPlaybackSessionLoader::path(const PingPlaybackSessionParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Sessions/Playing/Ping"); +} + +QUrlQuery PingPlaybackSessionLoader::query(const PingPlaybackSessionParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.playSessionIdNull()) { + result.addQueryItem("playSessionId", Support::toString(params.playSessionId())); + } + + return result; +} + +QByteArray PingPlaybackSessionLoader::body(const PingPlaybackSessionParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation PingPlaybackSessionLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +ReportPlaybackProgressLoader::ReportPlaybackProgressLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString ReportPlaybackProgressLoader::path(const ReportPlaybackProgressParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Sessions/Playing/Progress"); +} + +QUrlQuery ReportPlaybackProgressLoader::query(const ReportPlaybackProgressParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray ReportPlaybackProgressLoader::body(const ReportPlaybackProgressParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation ReportPlaybackProgressLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +ReportPlaybackStoppedLoader::ReportPlaybackStoppedLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString ReportPlaybackStoppedLoader::path(const ReportPlaybackStoppedParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Sessions/Playing/Stopped"); +} + +QUrlQuery ReportPlaybackStoppedLoader::query(const ReportPlaybackStoppedParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray ReportPlaybackStoppedLoader::body(const ReportPlaybackStoppedParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation ReportPlaybackStoppedLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + MarkPlayedItemLoader::MarkPlayedItemLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader(apiClient) {} @@ -96,6 +215,162 @@ QNetworkAccessManager::Operation MarkUnplayedItemLoader::operation() const { } +OnPlaybackStartLoader::OnPlaybackStartLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString OnPlaybackStartLoader::path(const OnPlaybackStartParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Users/") + Support::toString< QString>(params.userId()) + QStringLiteral("/PlayingItems/") + Support::toString< QString>(params.itemId()) ; +} + +QUrlQuery OnPlaybackStartLoader::query(const OnPlaybackStartParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.mediaSourceIdNull()) { + result.addQueryItem("mediaSourceId", Support::toString(params.mediaSourceId())); + } + if (!params.audioStreamIndexNull()) { + result.addQueryItem("audioStreamIndex", Support::toString>(params.audioStreamIndex())); + } + if (!params.subtitleStreamIndexNull()) { + result.addQueryItem("subtitleStreamIndex", Support::toString>(params.subtitleStreamIndex())); + } + if (!params.playMethodNull()) { + result.addQueryItem("playMethod", Support::toString(params.playMethod())); + } + if (!params.liveStreamIdNull()) { + result.addQueryItem("liveStreamId", Support::toString(params.liveStreamId())); + } + if (!params.playSessionIdNull()) { + result.addQueryItem("playSessionId", Support::toString(params.playSessionId())); + } + if (!params.canSeekNull()) { + result.addQueryItem("canSeek", Support::toString>(params.canSeek())); + } + + return result; +} + +QByteArray OnPlaybackStartLoader::body(const OnPlaybackStartParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation OnPlaybackStartLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +OnPlaybackStoppedLoader::OnPlaybackStoppedLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString OnPlaybackStoppedLoader::path(const OnPlaybackStoppedParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Users/") + Support::toString< QString>(params.userId()) + QStringLiteral("/PlayingItems/") + Support::toString< QString>(params.itemId()) ; +} + +QUrlQuery OnPlaybackStoppedLoader::query(const OnPlaybackStoppedParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.mediaSourceIdNull()) { + result.addQueryItem("mediaSourceId", Support::toString(params.mediaSourceId())); + } + if (!params.nextMediaTypeNull()) { + result.addQueryItem("nextMediaType", Support::toString(params.nextMediaType())); + } + if (!params.positionTicksNull()) { + result.addQueryItem("positionTicks", Support::toString>(params.positionTicks())); + } + if (!params.liveStreamIdNull()) { + result.addQueryItem("liveStreamId", Support::toString(params.liveStreamId())); + } + if (!params.playSessionIdNull()) { + result.addQueryItem("playSessionId", Support::toString(params.playSessionId())); + } + + return result; +} + +QByteArray OnPlaybackStoppedLoader::body(const OnPlaybackStoppedParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation OnPlaybackStoppedLoader::operation() const { + // HTTP method Delete + return QNetworkAccessManager::DeleteOperation; + +} + +OnPlaybackProgressLoader::OnPlaybackProgressLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString OnPlaybackProgressLoader::path(const OnPlaybackProgressParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Users/") + Support::toString< QString>(params.userId()) + QStringLiteral("/PlayingItems/") + Support::toString< QString>(params.itemId()) + QStringLiteral("/Progress"); +} + +QUrlQuery OnPlaybackProgressLoader::query(const OnPlaybackProgressParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.mediaSourceIdNull()) { + result.addQueryItem("mediaSourceId", Support::toString(params.mediaSourceId())); + } + if (!params.positionTicksNull()) { + result.addQueryItem("positionTicks", Support::toString>(params.positionTicks())); + } + if (!params.audioStreamIndexNull()) { + result.addQueryItem("audioStreamIndex", Support::toString>(params.audioStreamIndex())); + } + if (!params.subtitleStreamIndexNull()) { + result.addQueryItem("subtitleStreamIndex", Support::toString>(params.subtitleStreamIndex())); + } + if (!params.volumeLevelNull()) { + result.addQueryItem("volumeLevel", Support::toString>(params.volumeLevel())); + } + if (!params.playMethodNull()) { + result.addQueryItem("playMethod", Support::toString(params.playMethod())); + } + if (!params.liveStreamIdNull()) { + result.addQueryItem("liveStreamId", Support::toString(params.liveStreamId())); + } + if (!params.playSessionIdNull()) { + result.addQueryItem("playSessionId", Support::toString(params.playSessionId())); + } + if (!params.repeatModeNull()) { + result.addQueryItem("repeatMode", Support::toString(params.repeatMode())); + } + if (!params.isPausedNull()) { + result.addQueryItem("isPaused", Support::toString>(params.isPaused())); + } + if (!params.isMutedNull()) { + result.addQueryItem("isMuted", Support::toString>(params.isMuted())); + } + + return result; +} + +QByteArray OnPlaybackProgressLoader::body(const OnPlaybackProgressParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation OnPlaybackProgressLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + } // NS HTTP } // NS Loader diff --git a/core/src/loader/http/plugins.cpp b/core/src/loader/http/plugins.cpp index 6928943..6a813b7 100644 --- a/core/src/loader/http/plugins.cpp +++ b/core/src/loader/http/plugins.cpp @@ -64,6 +64,122 @@ QNetworkAccessManager::Operation GetPluginsLoader::operation() const { } +UninstallPluginLoader::UninstallPluginLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString UninstallPluginLoader::path(const UninstallPluginParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Plugins/") + Support::toString< QString>(params.pluginId()) ; +} + +QUrlQuery UninstallPluginLoader::query(const UninstallPluginParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray UninstallPluginLoader::body(const UninstallPluginParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation UninstallPluginLoader::operation() const { + // HTTP method Delete + return QNetworkAccessManager::DeleteOperation; + +} + +UninstallPluginByVersionLoader::UninstallPluginByVersionLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString UninstallPluginByVersionLoader::path(const UninstallPluginByVersionParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Plugins/") + Support::toString< QString>(params.pluginId()) + QStringLiteral("/") + Support::toString< QSharedPointer>(params.version()) ; +} + +QUrlQuery UninstallPluginByVersionLoader::query(const UninstallPluginByVersionParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray UninstallPluginByVersionLoader::body(const UninstallPluginByVersionParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation UninstallPluginByVersionLoader::operation() const { + // HTTP method Delete + return QNetworkAccessManager::DeleteOperation; + +} + +DisablePluginLoader::DisablePluginLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString DisablePluginLoader::path(const DisablePluginParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Plugins/") + Support::toString< QString>(params.pluginId()) + QStringLiteral("/") + Support::toString< QSharedPointer>(params.version()) + QStringLiteral("/Disable"); +} + +QUrlQuery DisablePluginLoader::query(const DisablePluginParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray DisablePluginLoader::body(const DisablePluginParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation DisablePluginLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +EnablePluginLoader::EnablePluginLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString EnablePluginLoader::path(const EnablePluginParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Plugins/") + Support::toString< QString>(params.pluginId()) + QStringLiteral("/") + Support::toString< QSharedPointer>(params.version()) + QStringLiteral("/Enable"); +} + +QUrlQuery EnablePluginLoader::query(const EnablePluginParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray EnablePluginLoader::body(const EnablePluginParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation EnablePluginLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + GetPluginConfigurationLoader::GetPluginConfigurationLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader(apiClient) {} @@ -93,6 +209,93 @@ QNetworkAccessManager::Operation GetPluginConfigurationLoader::operation() const } +UpdatePluginConfigurationLoader::UpdatePluginConfigurationLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString UpdatePluginConfigurationLoader::path(const UpdatePluginConfigurationParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Plugins/") + Support::toString< QString>(params.pluginId()) + QStringLiteral("/Configuration"); +} + +QUrlQuery UpdatePluginConfigurationLoader::query(const UpdatePluginConfigurationParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray UpdatePluginConfigurationLoader::body(const UpdatePluginConfigurationParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation UpdatePluginConfigurationLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +GetPluginManifestLoader::GetPluginManifestLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString GetPluginManifestLoader::path(const GetPluginManifestParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Plugins/") + Support::toString< QString>(params.pluginId()) + QStringLiteral("/Manifest"); +} + +QUrlQuery GetPluginManifestLoader::query(const GetPluginManifestParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray GetPluginManifestLoader::body(const GetPluginManifestParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation GetPluginManifestLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +UpdatePluginSecurityInfoLoader::UpdatePluginSecurityInfoLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString UpdatePluginSecurityInfoLoader::path(const UpdatePluginSecurityInfoParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Plugins/SecurityInfo"); +} + +QUrlQuery UpdatePluginSecurityInfoLoader::query(const UpdatePluginSecurityInfoParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray UpdatePluginSecurityInfoLoader::body(const UpdatePluginSecurityInfoParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation UpdatePluginSecurityInfoLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + } // NS HTTP } // NS Loader diff --git a/core/src/loader/http/quickconnect.cpp b/core/src/loader/http/quickconnect.cpp index 2286447..48c98b8 100644 --- a/core/src/loader/http/quickconnect.cpp +++ b/core/src/loader/http/quickconnect.cpp @@ -35,6 +35,35 @@ namespace HTTP { using namespace Jellyfin::DTO; +ActivateLoader::ActivateLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString ActivateLoader::path(const ActivateParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/QuickConnect/Activate"); +} + +QUrlQuery ActivateLoader::query(const ActivateParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray ActivateLoader::body(const ActivateParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation ActivateLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + AuthorizeLoader::AuthorizeLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader(apiClient) {} @@ -65,6 +94,38 @@ QNetworkAccessManager::Operation AuthorizeLoader::operation() const { } +AvailableLoader::AvailableLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString AvailableLoader::path(const AvailableParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/QuickConnect/Available"); +} + +QUrlQuery AvailableLoader::query(const AvailableParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.statusNull()) { + result.addQueryItem("status", Support::toString(params.status())); + } + + return result; +} + +QByteArray AvailableLoader::body(const AvailableParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation AvailableLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + ConnectLoader::ConnectLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader(apiClient) {} diff --git a/core/src/loader/http/remoteimage.cpp b/core/src/loader/http/remoteimage.cpp index ed2e59a..e092c75 100644 --- a/core/src/loader/http/remoteimage.cpp +++ b/core/src/loader/http/remoteimage.cpp @@ -79,6 +79,39 @@ QNetworkAccessManager::Operation GetRemoteImagesLoader::operation() const { } +DownloadRemoteImageLoader::DownloadRemoteImageLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString DownloadRemoteImageLoader::path(const DownloadRemoteImageParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Items/") + Support::toString< QString>(params.itemId()) + QStringLiteral("/RemoteImages/Download"); +} + +QUrlQuery DownloadRemoteImageLoader::query(const DownloadRemoteImageParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + result.addQueryItem("type", Support::toString(params.type())); + + // Optional parameters + if (!params.imageUrlNull()) { + result.addQueryItem("imageUrl", Support::toString(params.imageUrl())); + } + + return result; +} + +QByteArray DownloadRemoteImageLoader::body(const DownloadRemoteImageParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation DownloadRemoteImageLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + GetRemoteImageProvidersLoader::GetRemoteImageProvidersLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader, GetRemoteImageProvidersParams>(apiClient) {} diff --git a/core/src/loader/http/scheduledtasks.cpp b/core/src/loader/http/scheduledtasks.cpp index 0319518..c1ae9f9 100644 --- a/core/src/loader/http/scheduledtasks.cpp +++ b/core/src/loader/http/scheduledtasks.cpp @@ -99,6 +99,93 @@ QNetworkAccessManager::Operation GetTaskLoader::operation() const { } +UpdateTaskLoader::UpdateTaskLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString UpdateTaskLoader::path(const UpdateTaskParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/ScheduledTasks/") + Support::toString< QString>(params.taskId()) + QStringLiteral("/Triggers"); +} + +QUrlQuery UpdateTaskLoader::query(const UpdateTaskParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray UpdateTaskLoader::body(const UpdateTaskParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation UpdateTaskLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +StartTaskLoader::StartTaskLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString StartTaskLoader::path(const StartTaskParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/ScheduledTasks/Running/") + Support::toString< QString>(params.taskId()) ; +} + +QUrlQuery StartTaskLoader::query(const StartTaskParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray StartTaskLoader::body(const StartTaskParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation StartTaskLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +StopTaskLoader::StopTaskLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString StopTaskLoader::path(const StopTaskParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/ScheduledTasks/Running/") + Support::toString< QString>(params.taskId()) ; +} + +QUrlQuery StopTaskLoader::query(const StopTaskParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray StopTaskLoader::body(const StopTaskParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation StopTaskLoader::operation() const { + // HTTP method Delete + return QNetworkAccessManager::DeleteOperation; + +} + } // NS HTTP } // NS Loader diff --git a/core/src/loader/http/session.cpp b/core/src/loader/http/session.cpp index 498a14b..69ca54c 100644 --- a/core/src/loader/http/session.cpp +++ b/core/src/loader/http/session.cpp @@ -131,6 +131,429 @@ QNetworkAccessManager::Operation GetSessionsLoader::operation() const { } +SendFullGeneralCommandLoader::SendFullGeneralCommandLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SendFullGeneralCommandLoader::path(const SendFullGeneralCommandParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Sessions/") + Support::toString< QString>(params.sessionId()) + QStringLiteral("/Command"); +} + +QUrlQuery SendFullGeneralCommandLoader::query(const SendFullGeneralCommandParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray SendFullGeneralCommandLoader::body(const SendFullGeneralCommandParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation SendFullGeneralCommandLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +SendGeneralCommandLoader::SendGeneralCommandLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SendGeneralCommandLoader::path(const SendGeneralCommandParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Sessions/") + Support::toString< QString>(params.sessionId()) + QStringLiteral("/Command/") + Support::toString< GeneralCommandType>(params.command()) ; +} + +QUrlQuery SendGeneralCommandLoader::query(const SendGeneralCommandParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray SendGeneralCommandLoader::body(const SendGeneralCommandParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation SendGeneralCommandLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +SendMessageCommandLoader::SendMessageCommandLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SendMessageCommandLoader::path(const SendMessageCommandParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Sessions/") + Support::toString< QString>(params.sessionId()) + QStringLiteral("/Message"); +} + +QUrlQuery SendMessageCommandLoader::query(const SendMessageCommandParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + result.addQueryItem("text", Support::toString(params.text())); + + // Optional parameters + if (!params.headerNull()) { + result.addQueryItem("header", Support::toString(params.header())); + } + if (!params.timeoutMsNull()) { + result.addQueryItem("timeoutMs", Support::toString>(params.timeoutMs())); + } + + return result; +} + +QByteArray SendMessageCommandLoader::body(const SendMessageCommandParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation SendMessageCommandLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +PlayLoader::PlayLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString PlayLoader::path(const PlayParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Sessions/") + Support::toString< QString>(params.sessionId()) + QStringLiteral("/Playing"); +} + +QUrlQuery PlayLoader::query(const PlayParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + result.addQueryItem("playCommand", Support::toString(params.playCommand())); + result.addQueryItem("itemIds", Support::toString(params.itemIds())); + + // Optional parameters + if (!params.startPositionTicksNull()) { + result.addQueryItem("startPositionTicks", Support::toString>(params.startPositionTicks())); + } + + return result; +} + +QByteArray PlayLoader::body(const PlayParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation PlayLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +SendPlaystateCommandLoader::SendPlaystateCommandLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SendPlaystateCommandLoader::path(const SendPlaystateCommandParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Sessions/") + Support::toString< QString>(params.sessionId()) + QStringLiteral("/Playing/") + Support::toString< PlaystateCommand>(params.command()) ; +} + +QUrlQuery SendPlaystateCommandLoader::query(const SendPlaystateCommandParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.seekPositionTicksNull()) { + result.addQueryItem("seekPositionTicks", Support::toString>(params.seekPositionTicks())); + } + if (!params.controllingUserIdNull()) { + result.addQueryItem("controllingUserId", Support::toString(params.controllingUserId())); + } + + return result; +} + +QByteArray SendPlaystateCommandLoader::body(const SendPlaystateCommandParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation SendPlaystateCommandLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +SendSystemCommandLoader::SendSystemCommandLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SendSystemCommandLoader::path(const SendSystemCommandParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Sessions/") + Support::toString< QString>(params.sessionId()) + QStringLiteral("/System/") + Support::toString< GeneralCommandType>(params.command()) ; +} + +QUrlQuery SendSystemCommandLoader::query(const SendSystemCommandParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray SendSystemCommandLoader::body(const SendSystemCommandParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation SendSystemCommandLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +AddUserToSessionLoader::AddUserToSessionLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString AddUserToSessionLoader::path(const AddUserToSessionParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Sessions/") + Support::toString< QString>(params.sessionId()) + QStringLiteral("/User/") + Support::toString< QString>(params.userId()) ; +} + +QUrlQuery AddUserToSessionLoader::query(const AddUserToSessionParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray AddUserToSessionLoader::body(const AddUserToSessionParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation AddUserToSessionLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +RemoveUserFromSessionLoader::RemoveUserFromSessionLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString RemoveUserFromSessionLoader::path(const RemoveUserFromSessionParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Sessions/") + Support::toString< QString>(params.sessionId()) + QStringLiteral("/User/") + Support::toString< QString>(params.userId()) ; +} + +QUrlQuery RemoveUserFromSessionLoader::query(const RemoveUserFromSessionParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray RemoveUserFromSessionLoader::body(const RemoveUserFromSessionParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation RemoveUserFromSessionLoader::operation() const { + // HTTP method Delete + return QNetworkAccessManager::DeleteOperation; + +} + +DisplayContentLoader::DisplayContentLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString DisplayContentLoader::path(const DisplayContentParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Sessions/") + Support::toString< QString>(params.sessionId()) + QStringLiteral("/Viewing"); +} + +QUrlQuery DisplayContentLoader::query(const DisplayContentParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + result.addQueryItem("itemType", Support::toString(params.itemType())); + result.addQueryItem("itemId", Support::toString(params.itemId())); + result.addQueryItem("itemName", Support::toString(params.itemName())); + + // Optional parameters + + return result; +} + +QByteArray DisplayContentLoader::body(const DisplayContentParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation DisplayContentLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +PostCapabilitiesLoader::PostCapabilitiesLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString PostCapabilitiesLoader::path(const PostCapabilitiesParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Sessions/Capabilities"); +} + +QUrlQuery PostCapabilitiesLoader::query(const PostCapabilitiesParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.jellyfinIdNull()) { + result.addQueryItem("id", Support::toString(params.jellyfinId())); + } + if (!params.playableMediaTypesNull()) { + result.addQueryItem("playableMediaTypes", Support::toString(params.playableMediaTypes())); + } + if (!params.supportedCommandsNull()) { + result.addQueryItem("supportedCommands", Support::toString>(params.supportedCommands())); + } + if (!params.supportsMediaControlNull()) { + result.addQueryItem("supportsMediaControl", Support::toString>(params.supportsMediaControl())); + } + if (!params.supportsSyncNull()) { + result.addQueryItem("supportsSync", Support::toString>(params.supportsSync())); + } + if (!params.supportsPersistentIdentifierNull()) { + result.addQueryItem("supportsPersistentIdentifier", Support::toString>(params.supportsPersistentIdentifier())); + } + + return result; +} + +QByteArray PostCapabilitiesLoader::body(const PostCapabilitiesParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation PostCapabilitiesLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +PostFullCapabilitiesLoader::PostFullCapabilitiesLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString PostFullCapabilitiesLoader::path(const PostFullCapabilitiesParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Sessions/Capabilities/Full"); +} + +QUrlQuery PostFullCapabilitiesLoader::query(const PostFullCapabilitiesParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + if (!params.jellyfinIdNull()) { + result.addQueryItem("id", Support::toString(params.jellyfinId())); + } + + return result; +} + +QByteArray PostFullCapabilitiesLoader::body(const PostFullCapabilitiesParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation PostFullCapabilitiesLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +ReportSessionEndedLoader::ReportSessionEndedLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString ReportSessionEndedLoader::path(const ReportSessionEndedParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Sessions/Logout"); +} + +QUrlQuery ReportSessionEndedLoader::query(const ReportSessionEndedParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray ReportSessionEndedLoader::body(const ReportSessionEndedParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation ReportSessionEndedLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +ReportViewingLoader::ReportViewingLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString ReportViewingLoader::path(const ReportViewingParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Sessions/Viewing"); +} + +QUrlQuery ReportViewingLoader::query(const ReportViewingParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + result.addQueryItem("itemId", Support::toString(params.itemId())); + + // Optional parameters + if (!params.sessionIdNull()) { + result.addQueryItem("sessionId", Support::toString(params.sessionId())); + } + + return result; +} + +QByteArray ReportViewingLoader::body(const ReportViewingParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation ReportViewingLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + } // NS HTTP } // NS Loader diff --git a/core/src/loader/http/startup.cpp b/core/src/loader/http/startup.cpp index aecf547..ba544c6 100644 --- a/core/src/loader/http/startup.cpp +++ b/core/src/loader/http/startup.cpp @@ -35,6 +35,35 @@ namespace HTTP { using namespace Jellyfin::DTO; +CompleteWizardLoader::CompleteWizardLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString CompleteWizardLoader::path(const CompleteWizardParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Startup/Complete"); +} + +QUrlQuery CompleteWizardLoader::query(const CompleteWizardParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray CompleteWizardLoader::body(const CompleteWizardParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation CompleteWizardLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + GetStartupConfigurationLoader::GetStartupConfigurationLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader(apiClient) {} @@ -64,6 +93,35 @@ QNetworkAccessManager::Operation GetStartupConfigurationLoader::operation() cons } +UpdateInitialConfigurationLoader::UpdateInitialConfigurationLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString UpdateInitialConfigurationLoader::path(const UpdateInitialConfigurationParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Startup/Configuration"); +} + +QUrlQuery UpdateInitialConfigurationLoader::query(const UpdateInitialConfigurationParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray UpdateInitialConfigurationLoader::body(const UpdateInitialConfigurationParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation UpdateInitialConfigurationLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + GetFirstUser_2Loader::GetFirstUser_2Loader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader(apiClient) {} @@ -93,6 +151,35 @@ QNetworkAccessManager::Operation GetFirstUser_2Loader::operation() const { } +SetRemoteAccessLoader::SetRemoteAccessLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SetRemoteAccessLoader::path(const SetRemoteAccessParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Startup/RemoteAccess"); +} + +QUrlQuery SetRemoteAccessLoader::query(const SetRemoteAccessParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray SetRemoteAccessLoader::body(const SetRemoteAccessParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation SetRemoteAccessLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + GetFirstUserLoader::GetFirstUserLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader(apiClient) {} @@ -122,6 +209,35 @@ QNetworkAccessManager::Operation GetFirstUserLoader::operation() const { } +UpdateStartupUserLoader::UpdateStartupUserLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString UpdateStartupUserLoader::path(const UpdateStartupUserParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Startup/User"); +} + +QUrlQuery UpdateStartupUserLoader::query(const UpdateStartupUserParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray UpdateStartupUserLoader::body(const UpdateStartupUserParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation UpdateStartupUserLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + } // NS HTTP } // NS Loader diff --git a/core/src/loader/http/subtitle.cpp b/core/src/loader/http/subtitle.cpp index c8b7121..5239484 100644 --- a/core/src/loader/http/subtitle.cpp +++ b/core/src/loader/http/subtitle.cpp @@ -96,6 +96,93 @@ QNetworkAccessManager::Operation SearchRemoteSubtitlesLoader::operation() const } +DownloadRemoteSubtitlesLoader::DownloadRemoteSubtitlesLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString DownloadRemoteSubtitlesLoader::path(const DownloadRemoteSubtitlesParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Items/") + Support::toString< QString>(params.itemId()) + QStringLiteral("/RemoteSearch/Subtitles/") + Support::toString< QString>(params.subtitleId()) ; +} + +QUrlQuery DownloadRemoteSubtitlesLoader::query(const DownloadRemoteSubtitlesParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray DownloadRemoteSubtitlesLoader::body(const DownloadRemoteSubtitlesParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation DownloadRemoteSubtitlesLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +UploadSubtitleLoader::UploadSubtitleLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString UploadSubtitleLoader::path(const UploadSubtitleParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Videos/") + Support::toString< QString>(params.itemId()) + QStringLiteral("/Subtitles"); +} + +QUrlQuery UploadSubtitleLoader::query(const UploadSubtitleParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray UploadSubtitleLoader::body(const UploadSubtitleParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation UploadSubtitleLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +DeleteSubtitleLoader::DeleteSubtitleLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString DeleteSubtitleLoader::path(const DeleteSubtitleParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Videos/") + Support::toString< QString>(params.itemId()) + QStringLiteral("/Subtitles/") + Support::toString< qint32>(params.index()) ; +} + +QUrlQuery DeleteSubtitleLoader::query(const DeleteSubtitleParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray DeleteSubtitleLoader::body(const DeleteSubtitleParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation DeleteSubtitleLoader::operation() const { + // HTTP method Delete + return QNetworkAccessManager::DeleteOperation; + +} + } // NS HTTP } // NS Loader diff --git a/core/src/loader/http/syncplay.cpp b/core/src/loader/http/syncplay.cpp index 8632133..3fdd0b2 100644 --- a/core/src/loader/http/syncplay.cpp +++ b/core/src/loader/http/syncplay.cpp @@ -35,6 +35,93 @@ namespace HTTP { using namespace Jellyfin::DTO; +SyncPlayBufferingLoader::SyncPlayBufferingLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SyncPlayBufferingLoader::path(const SyncPlayBufferingParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/SyncPlay/Buffering"); +} + +QUrlQuery SyncPlayBufferingLoader::query(const SyncPlayBufferingParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray SyncPlayBufferingLoader::body(const SyncPlayBufferingParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation SyncPlayBufferingLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +SyncPlayJoinGroupLoader::SyncPlayJoinGroupLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SyncPlayJoinGroupLoader::path(const SyncPlayJoinGroupParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/SyncPlay/Join"); +} + +QUrlQuery SyncPlayJoinGroupLoader::query(const SyncPlayJoinGroupParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray SyncPlayJoinGroupLoader::body(const SyncPlayJoinGroupParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation SyncPlayJoinGroupLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +SyncPlayLeaveGroupLoader::SyncPlayLeaveGroupLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SyncPlayLeaveGroupLoader::path(const SyncPlayLeaveGroupParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/SyncPlay/Leave"); +} + +QUrlQuery SyncPlayLeaveGroupLoader::query(const SyncPlayLeaveGroupParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray SyncPlayLeaveGroupLoader::body(const SyncPlayLeaveGroupParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation SyncPlayLeaveGroupLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + SyncPlayGetGroupsLoader::SyncPlayGetGroupsLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader, SyncPlayGetGroupsParams>(apiClient) {} @@ -64,6 +151,499 @@ QNetworkAccessManager::Operation SyncPlayGetGroupsLoader::operation() const { } +SyncPlayMovePlaylistItemLoader::SyncPlayMovePlaylistItemLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SyncPlayMovePlaylistItemLoader::path(const SyncPlayMovePlaylistItemParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/SyncPlay/MovePlaylistItem"); +} + +QUrlQuery SyncPlayMovePlaylistItemLoader::query(const SyncPlayMovePlaylistItemParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray SyncPlayMovePlaylistItemLoader::body(const SyncPlayMovePlaylistItemParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation SyncPlayMovePlaylistItemLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +SyncPlayCreateGroupLoader::SyncPlayCreateGroupLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SyncPlayCreateGroupLoader::path(const SyncPlayCreateGroupParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/SyncPlay/New"); +} + +QUrlQuery SyncPlayCreateGroupLoader::query(const SyncPlayCreateGroupParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray SyncPlayCreateGroupLoader::body(const SyncPlayCreateGroupParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation SyncPlayCreateGroupLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +SyncPlayNextItemLoader::SyncPlayNextItemLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SyncPlayNextItemLoader::path(const SyncPlayNextItemParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/SyncPlay/NextItem"); +} + +QUrlQuery SyncPlayNextItemLoader::query(const SyncPlayNextItemParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray SyncPlayNextItemLoader::body(const SyncPlayNextItemParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation SyncPlayNextItemLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +SyncPlayPauseLoader::SyncPlayPauseLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SyncPlayPauseLoader::path(const SyncPlayPauseParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/SyncPlay/Pause"); +} + +QUrlQuery SyncPlayPauseLoader::query(const SyncPlayPauseParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray SyncPlayPauseLoader::body(const SyncPlayPauseParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation SyncPlayPauseLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +SyncPlayPingLoader::SyncPlayPingLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SyncPlayPingLoader::path(const SyncPlayPingParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/SyncPlay/Ping"); +} + +QUrlQuery SyncPlayPingLoader::query(const SyncPlayPingParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray SyncPlayPingLoader::body(const SyncPlayPingParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation SyncPlayPingLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +SyncPlayPreviousItemLoader::SyncPlayPreviousItemLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SyncPlayPreviousItemLoader::path(const SyncPlayPreviousItemParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/SyncPlay/PreviousItem"); +} + +QUrlQuery SyncPlayPreviousItemLoader::query(const SyncPlayPreviousItemParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray SyncPlayPreviousItemLoader::body(const SyncPlayPreviousItemParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation SyncPlayPreviousItemLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +SyncPlayQueueLoader::SyncPlayQueueLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SyncPlayQueueLoader::path(const SyncPlayQueueParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/SyncPlay/Queue"); +} + +QUrlQuery SyncPlayQueueLoader::query(const SyncPlayQueueParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray SyncPlayQueueLoader::body(const SyncPlayQueueParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation SyncPlayQueueLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +SyncPlayReadyLoader::SyncPlayReadyLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SyncPlayReadyLoader::path(const SyncPlayReadyParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/SyncPlay/Ready"); +} + +QUrlQuery SyncPlayReadyLoader::query(const SyncPlayReadyParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray SyncPlayReadyLoader::body(const SyncPlayReadyParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation SyncPlayReadyLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +SyncPlayRemoveFromPlaylistLoader::SyncPlayRemoveFromPlaylistLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SyncPlayRemoveFromPlaylistLoader::path(const SyncPlayRemoveFromPlaylistParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/SyncPlay/RemoveFromPlaylist"); +} + +QUrlQuery SyncPlayRemoveFromPlaylistLoader::query(const SyncPlayRemoveFromPlaylistParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray SyncPlayRemoveFromPlaylistLoader::body(const SyncPlayRemoveFromPlaylistParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation SyncPlayRemoveFromPlaylistLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +SyncPlaySeekLoader::SyncPlaySeekLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SyncPlaySeekLoader::path(const SyncPlaySeekParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/SyncPlay/Seek"); +} + +QUrlQuery SyncPlaySeekLoader::query(const SyncPlaySeekParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray SyncPlaySeekLoader::body(const SyncPlaySeekParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation SyncPlaySeekLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +SyncPlaySetIgnoreWaitLoader::SyncPlaySetIgnoreWaitLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SyncPlaySetIgnoreWaitLoader::path(const SyncPlaySetIgnoreWaitParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/SyncPlay/SetIgnoreWait"); +} + +QUrlQuery SyncPlaySetIgnoreWaitLoader::query(const SyncPlaySetIgnoreWaitParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray SyncPlaySetIgnoreWaitLoader::body(const SyncPlaySetIgnoreWaitParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation SyncPlaySetIgnoreWaitLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +SyncPlaySetNewQueueLoader::SyncPlaySetNewQueueLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SyncPlaySetNewQueueLoader::path(const SyncPlaySetNewQueueParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/SyncPlay/SetNewQueue"); +} + +QUrlQuery SyncPlaySetNewQueueLoader::query(const SyncPlaySetNewQueueParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray SyncPlaySetNewQueueLoader::body(const SyncPlaySetNewQueueParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation SyncPlaySetNewQueueLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +SyncPlaySetPlaylistItemLoader::SyncPlaySetPlaylistItemLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SyncPlaySetPlaylistItemLoader::path(const SyncPlaySetPlaylistItemParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/SyncPlay/SetPlaylistItem"); +} + +QUrlQuery SyncPlaySetPlaylistItemLoader::query(const SyncPlaySetPlaylistItemParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray SyncPlaySetPlaylistItemLoader::body(const SyncPlaySetPlaylistItemParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation SyncPlaySetPlaylistItemLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +SyncPlaySetRepeatModeLoader::SyncPlaySetRepeatModeLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SyncPlaySetRepeatModeLoader::path(const SyncPlaySetRepeatModeParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/SyncPlay/SetRepeatMode"); +} + +QUrlQuery SyncPlaySetRepeatModeLoader::query(const SyncPlaySetRepeatModeParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray SyncPlaySetRepeatModeLoader::body(const SyncPlaySetRepeatModeParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation SyncPlaySetRepeatModeLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +SyncPlaySetShuffleModeLoader::SyncPlaySetShuffleModeLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SyncPlaySetShuffleModeLoader::path(const SyncPlaySetShuffleModeParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/SyncPlay/SetShuffleMode"); +} + +QUrlQuery SyncPlaySetShuffleModeLoader::query(const SyncPlaySetShuffleModeParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray SyncPlaySetShuffleModeLoader::body(const SyncPlaySetShuffleModeParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation SyncPlaySetShuffleModeLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +SyncPlayStopLoader::SyncPlayStopLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SyncPlayStopLoader::path(const SyncPlayStopParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/SyncPlay/Stop"); +} + +QUrlQuery SyncPlayStopLoader::query(const SyncPlayStopParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray SyncPlayStopLoader::body(const SyncPlayStopParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation SyncPlayStopLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +SyncPlayUnpauseLoader::SyncPlayUnpauseLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString SyncPlayUnpauseLoader::path(const SyncPlayUnpauseParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/SyncPlay/Unpause"); +} + +QUrlQuery SyncPlayUnpauseLoader::query(const SyncPlayUnpauseParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray SyncPlayUnpauseLoader::body(const SyncPlayUnpauseParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation SyncPlayUnpauseLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + } // NS HTTP } // NS Loader diff --git a/core/src/loader/http/system.cpp b/core/src/loader/http/system.cpp index 6ecc09d..ddfddfc 100644 --- a/core/src/loader/http/system.cpp +++ b/core/src/loader/http/system.cpp @@ -209,6 +209,64 @@ QNetworkAccessManager::Operation PostPingSystemLoader::operation() const { } +RestartApplicationLoader::RestartApplicationLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString RestartApplicationLoader::path(const RestartApplicationParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/System/Restart"); +} + +QUrlQuery RestartApplicationLoader::query(const RestartApplicationParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray RestartApplicationLoader::body(const RestartApplicationParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation RestartApplicationLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +ShutdownApplicationLoader::ShutdownApplicationLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString ShutdownApplicationLoader::path(const ShutdownApplicationParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/System/Shutdown"); +} + +QUrlQuery ShutdownApplicationLoader::query(const ShutdownApplicationParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray ShutdownApplicationLoader::body(const ShutdownApplicationParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation ShutdownApplicationLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + GetWakeOnLanInfoLoader::GetWakeOnLanInfoLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader, GetWakeOnLanInfoParams>(apiClient) {} diff --git a/core/src/loader/http/user.cpp b/core/src/loader/http/user.cpp index 2b203ff..1bef710 100644 --- a/core/src/loader/http/user.cpp +++ b/core/src/loader/http/user.cpp @@ -99,6 +99,64 @@ QNetworkAccessManager::Operation GetUserByIdLoader::operation() const { } +DeleteUserLoader::DeleteUserLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString DeleteUserLoader::path(const DeleteUserParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Users/") + Support::toString< QString>(params.userId()) ; +} + +QUrlQuery DeleteUserLoader::query(const DeleteUserParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray DeleteUserLoader::body(const DeleteUserParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation DeleteUserLoader::operation() const { + // HTTP method Delete + return QNetworkAccessManager::DeleteOperation; + +} + +UpdateUserLoader::UpdateUserLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString UpdateUserLoader::path(const UpdateUserParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Users/") + Support::toString< QString>(params.userId()) ; +} + +QUrlQuery UpdateUserLoader::query(const UpdateUserParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray UpdateUserLoader::body(const UpdateUserParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation UpdateUserLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + AuthenticateUserLoader::AuthenticateUserLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader(apiClient) {} @@ -132,6 +190,122 @@ QNetworkAccessManager::Operation AuthenticateUserLoader::operation() const { } +UpdateUserConfigurationLoader::UpdateUserConfigurationLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString UpdateUserConfigurationLoader::path(const UpdateUserConfigurationParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Users/") + Support::toString< QString>(params.userId()) + QStringLiteral("/Configuration"); +} + +QUrlQuery UpdateUserConfigurationLoader::query(const UpdateUserConfigurationParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray UpdateUserConfigurationLoader::body(const UpdateUserConfigurationParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation UpdateUserConfigurationLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +UpdateUserEasyPasswordLoader::UpdateUserEasyPasswordLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString UpdateUserEasyPasswordLoader::path(const UpdateUserEasyPasswordParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Users/") + Support::toString< QString>(params.userId()) + QStringLiteral("/EasyPassword"); +} + +QUrlQuery UpdateUserEasyPasswordLoader::query(const UpdateUserEasyPasswordParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray UpdateUserEasyPasswordLoader::body(const UpdateUserEasyPasswordParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation UpdateUserEasyPasswordLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +UpdateUserPasswordLoader::UpdateUserPasswordLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString UpdateUserPasswordLoader::path(const UpdateUserPasswordParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Users/") + Support::toString< QString>(params.userId()) + QStringLiteral("/Password"); +} + +QUrlQuery UpdateUserPasswordLoader::query(const UpdateUserPasswordParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray UpdateUserPasswordLoader::body(const UpdateUserPasswordParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation UpdateUserPasswordLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + +UpdateUserPolicyLoader::UpdateUserPolicyLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString UpdateUserPolicyLoader::path(const UpdateUserPolicyParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Users/") + Support::toString< QString>(params.userId()) + QStringLiteral("/Policy"); +} + +QUrlQuery UpdateUserPolicyLoader::query(const UpdateUserPolicyParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray UpdateUserPolicyLoader::body(const UpdateUserPolicyParams ¶ms) const { + return Support::toString>(params.body()).toUtf8(); +} + +QNetworkAccessManager::Operation UpdateUserPolicyLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + AuthenticateUserByNameLoader::AuthenticateUserByNameLoader(ApiClient *apiClient) : Jellyfin::Support::HttpLoader(apiClient) {} diff --git a/core/src/loader/http/videos.cpp b/core/src/loader/http/videos.cpp index 2f3770e..c78b33b 100644 --- a/core/src/loader/http/videos.cpp +++ b/core/src/loader/http/videos.cpp @@ -67,6 +67,65 @@ QNetworkAccessManager::Operation GetAdditionalPartLoader::operation() const { } +DeleteAlternateSourcesLoader::DeleteAlternateSourcesLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString DeleteAlternateSourcesLoader::path(const DeleteAlternateSourcesParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Videos/") + Support::toString< QString>(params.itemId()) + QStringLiteral("/AlternateSources"); +} + +QUrlQuery DeleteAlternateSourcesLoader::query(const DeleteAlternateSourcesParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + + // Optional parameters + + return result; +} + +QByteArray DeleteAlternateSourcesLoader::body(const DeleteAlternateSourcesParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation DeleteAlternateSourcesLoader::operation() const { + // HTTP method Delete + return QNetworkAccessManager::DeleteOperation; + +} + +MergeVersionsLoader::MergeVersionsLoader(ApiClient *apiClient) + : Jellyfin::Support::HttpLoader(apiClient) {} + +QString MergeVersionsLoader::path(const MergeVersionsParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + return QStringLiteral("/Videos/MergeVersions"); +} + +QUrlQuery MergeVersionsLoader::query(const MergeVersionsParams ¶ms) const { + Q_UNUSED(params) // Might be overzealous, but I don't like theses kind of warnings + + QUrlQuery result; + result.addQueryItem("ids", Support::toString(params.ids())); + + // Optional parameters + + return result; +} + +QByteArray MergeVersionsLoader::body(const MergeVersionsParams ¶ms) const { + return QByteArray(); +} + +QNetworkAccessManager::Operation MergeVersionsLoader::operation() const { + // HTTP method Post + return QNetworkAccessManager::PostOperation; + +} + } // NS HTTP } // NS Loader From 7a7ddc7717c7646024de5b2feb2a65ad500efcaa Mon Sep 17 00:00:00 2001 From: Chris Josten Date: Wed, 4 Jan 2023 21:32:27 +0100 Subject: [PATCH 03/10] core: remote playback send commands and update state --- core/include/JellyfinQt/eventbus.h | 8 + .../JellyfinQt/model/controllablesession.h | 3 +- .../JellyfinQt/model/playbackmanager.h | 8 +- core/include/JellyfinQt/model/playlist.h | 5 + .../JellyfinQt/model/remotejellyfinplayback.h | 22 ++- .../include/JellyfinQt/support/jsonconvimpl.h | 2 + core/include/JellyfinQt/support/loader.h | 3 - core/include/JellyfinQt/viewmodel/playlist.h | 1 + core/include/JellyfinQt/websocket.h | 28 ++- core/src/model/controllablesession.cpp | 15 +- core/src/model/item.cpp | 4 +- core/src/model/playbackmanager.cpp | 21 ++- core/src/model/playlist.cpp | 8 + core/src/model/remotejellyfinplayback.cpp | 169 +++++++++++++++--- .../freedesktop/mediaplayer2player.cpp | 17 +- core/src/viewmodel/playbackmanager.cpp | 68 +++++-- core/src/viewmodel/playlist.cpp | 51 ++++-- core/src/websocket.cpp | 29 ++- 18 files changed, 371 insertions(+), 91 deletions(-) diff --git a/core/include/JellyfinQt/eventbus.h b/core/include/JellyfinQt/eventbus.h index 99a8888..3b94ac3 100644 --- a/core/include/JellyfinQt/eventbus.h +++ b/core/include/JellyfinQt/eventbus.h @@ -26,6 +26,7 @@ namespace Jellyfin { namespace DTO { class UserItemDataDto; class PlaystateRequest; + class SessionInfo; } /** @@ -44,6 +45,13 @@ signals: */ void itemUserDataUpdated(const QString &itemId, const DTO::UserItemDataDto &userData); + /** + * @brief The information about a session has been updated + * @param sessionId The id of the session + * @param sessionInfo The associated information + */ + void sessionInfoUpdated(const QString &sessionId, const DTO::SessionInfo &sessionInfo); + /** * @brief The server has requested to display an message to the user * @param header The header of the message. diff --git a/core/include/JellyfinQt/model/controllablesession.h b/core/include/JellyfinQt/model/controllablesession.h index 3860b48..a41c40a 100644 --- a/core/include/JellyfinQt/model/controllablesession.h +++ b/core/include/JellyfinQt/model/controllablesession.h @@ -105,7 +105,7 @@ private: class ControllableJellyfinSession : public ControllableSession { Q_OBJECT public: - ControllableJellyfinSession(QSharedPointer info, QObject *parent = nullptr); + ControllableJellyfinSession(QSharedPointer info, ApiClient &apiClient, QObject *parent = nullptr); QString id() const override; QString name() const override; QString appName() const override; @@ -114,6 +114,7 @@ public: PlaybackManager *createPlaybackManager() const override; private: QSharedPointer m_data; + ApiClient &m_apiClient; }; /** diff --git a/core/include/JellyfinQt/model/playbackmanager.h b/core/include/JellyfinQt/model/playbackmanager.h index 1b49bbc..84c5e9a 100644 --- a/core/include/JellyfinQt/model/playbackmanager.h +++ b/core/include/JellyfinQt/model/playbackmanager.h @@ -84,12 +84,11 @@ class PlaybackManager : public QObject { Q_PROPERTY(bool hasVideo READ hasVideo NOTIFY hasVideoChanged) Q_PROPERTY(Jellyfin::Model::PlayerStateClass::Value playbackState READ playbackState NOTIFY playbackStateChanged) Q_PROPERTY(Jellyfin::Model::MediaStatusClass::Value mediaStatus READ mediaStatus NOTIFY mediaStatusChanged) - Q_PROPERTY(Jellyfin::Model::Playlist *queue READ queue NOTIFY queueChanged) Q_PROPERTY(int queueIndex READ queueIndex NOTIFY queueIndexChanged) public: explicit PlaybackManager(QObject *parent = nullptr); virtual ~PlaybackManager(); - virtual void swap(PlaybackManager& other) = 0; + void swap(PlaybackManager& other); ApiClient * apiClient() const; void setApiClient(ApiClient *apiClient); @@ -129,6 +128,9 @@ public: * @param index Index of the item to play */ virtual void playItemInList(const QList> &items, int index) = 0; + static const qint64 MS_TICK_FACTOR = 10000; +protected: + void setItem(QSharedPointer item); signals: void playbackStateChanged(Jellyfin::Model::PlayerStateClass::Value newPlaybackState); @@ -190,8 +192,6 @@ class LocalPlaybackManager : public PlaybackManager { public: explicit LocalPlaybackManager(QObject *parent = nullptr); - void swap(PlaybackManager& other) override; - Player *player() const; QString sessionId() const; DTO::PlayMethod playMethod() const; diff --git a/core/include/JellyfinQt/model/playlist.h b/core/include/JellyfinQt/model/playlist.h index 49468f2..029b3cd 100644 --- a/core/include/JellyfinQt/model/playlist.h +++ b/core/include/JellyfinQt/model/playlist.h @@ -72,6 +72,11 @@ public: */ void next(); + /** + * @brief Returns all items in the queue + */ + QList> queueAndList() const; + int queueSize() { return m_queue.size(); }; int listSize() const { return m_list.size(); }; int totalSize() const { return m_queue.size() + m_list.size(); } diff --git a/core/include/JellyfinQt/model/remotejellyfinplayback.h b/core/include/JellyfinQt/model/remotejellyfinplayback.h index 2d123c3..292bbc0 100644 --- a/core/include/JellyfinQt/model/remotejellyfinplayback.h +++ b/core/include/JellyfinQt/model/remotejellyfinplayback.h @@ -20,10 +20,17 @@ #define JELLYFIN_MODEL_REMOTEJELLYFINPLAYBACK_H #include +#include +#include +#include #include +#include #include #include +#include + +#include namespace Jellyfin { @@ -33,11 +40,10 @@ namespace Model { class RemoteJellyfinPlayback : public PlaybackManager { public: - RemoteJellyfinPlayback(ApiClient &apiClient, QObject *parent = nullptr); - + RemoteJellyfinPlayback(ApiClient &apiClient, QString sessionId, QObject *parent = nullptr); + virtual ~RemoteJellyfinPlayback(); // PlaybackManager - void swap(PlaybackManager &other) override; PlayerState playbackState() const override; MediaStatus mediaStatus() const override; bool hasNext() const override; @@ -61,9 +67,19 @@ public slots: void goTo(int index) override; void stop() override; void seek(qint64 pos) override; +private slots: + void onPositionTimerFired(); + void onSessionInfoUpdated(const QString &sessionId, const DTO::SessionInfo &sessionInfo); private: + void sendPlaystateCommand(DTO::PlaystateCommand command, qint64 seekTicks = -1); void sendGeneralCommand(DTO::GeneralCommandType command, QJsonObject arguments = QJsonObject()); + void sendCommand(Support::LoaderBase *loader); + void playItemInList(const QStringList &items, int index, qint64 resumeTicks = -1); ApiClient &m_apiClient; + QString m_sessionId; + std::optional m_lastSessionInfo; + QTimer *m_positionTimer; + qint64 m_position = 0; }; diff --git a/core/include/JellyfinQt/support/jsonconvimpl.h b/core/include/JellyfinQt/support/jsonconvimpl.h index 5f77c9d..81c0e9d 100644 --- a/core/include/JellyfinQt/support/jsonconvimpl.h +++ b/core/include/JellyfinQt/support/jsonconvimpl.h @@ -155,6 +155,8 @@ QString toString(const T &source, convertType) { return QJsonDocument(val.toArray()).toJson(format); case QJsonValue::Object: return QJsonDocument(val.toObject()).toJson(format); + case QJsonValue::String: + return val.toString(); case QJsonValue::Null: default: return QString(); diff --git a/core/include/JellyfinQt/support/loader.h b/core/include/JellyfinQt/support/loader.h index df09ccf..3afd33d 100644 --- a/core/include/JellyfinQt/support/loader.h +++ b/core/include/JellyfinQt/support/loader.h @@ -334,9 +334,6 @@ private: int statusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); m_reply->deleteLater(); m_reply = nullptr; - /*m_parsedWatcher.setFuture(QtConcurrent::run([this, statusCode, array]() { - return this->parseResponse(statusCode, array); - }));*/ m_parsedWatcher.setFuture( QtConcurrent::run::ResultType, // Result HttpLoader, // class diff --git a/core/include/JellyfinQt/viewmodel/playlist.h b/core/include/JellyfinQt/viewmodel/playlist.h index cd902ab..3c3c502 100644 --- a/core/include/JellyfinQt/viewmodel/playlist.h +++ b/core/include/JellyfinQt/viewmodel/playlist.h @@ -71,6 +71,7 @@ public: QVariant data(const QModelIndex &parent, int role = Qt::DisplayRole) const override; int rowCount(const QModelIndex &parent) const override; QHash roleNames() const override; + void setPlaylistModel(Model::Playlist *data); private slots: diff --git a/core/include/JellyfinQt/websocket.h b/core/include/JellyfinQt/websocket.h index 889ba30..9c4a616 100644 --- a/core/include/JellyfinQt/websocket.h +++ b/core/include/JellyfinQt/websocket.h @@ -60,9 +60,30 @@ public: */ explicit WebSocket(ApiClient *client); enum MessageType { + /** + * @brief Server to client: instruct client to send periodical KeepAlive messages + */ ForceKeepAlive, + /** + * @brief Client to server: keep the connection alive + */ KeepAlive, - UserDataChanged + /** + * @brief Server to client: user data for an item has changed. + */ + UserDataChanged, + /** + * @brief Client to server: Subscribe to playback update sessions. + */ + SessionsStart, + /** + * @brief Client to server: unsubscribe from playback session updates + */ + SessionsStop, + /** + * @brief Server to client: session information has changed + */ + Sessions }; Q_PROPERTY(QAbstractSocket::SocketState state READ state NOTIFY stateChanged) Q_ENUM(MessageType) @@ -72,6 +93,8 @@ public: } public slots: void open(); + void subscribeToSessionInfo(); + void unsubscribeToSessionInfo(); private slots: void textMessageReceived(const QString &message); void onConnected(); @@ -80,7 +103,7 @@ private slots: void sendKeepAlive(); void onWebsocketStateChanged(QAbstractSocket::SocketState newState) { emit stateChanged(newState); } signals: - void commandReceived(QString arts, QVariantMap args); + void commandReceived(QString command, QVariantMap args); void stateChanged(QAbstractSocket::SocketState newState); protected: @@ -90,6 +113,7 @@ protected: QTimer m_keepAliveTimer; QTimer m_retryTimer; int m_reconnectAttempt = 0; + int m_sessionInfoSubscribeCount = 0; void setupKeepAlive(int data); diff --git a/core/src/model/controllablesession.cpp b/core/src/model/controllablesession.cpp index 1bec6a0..275fcd0 100644 --- a/core/src/model/controllablesession.cpp +++ b/core/src/model/controllablesession.cpp @@ -5,6 +5,7 @@ #include "JellyfinQt/loader/http/session.h" #include "JellyfinQt/loader/requesttypes.h" #include +#include namespace Jellyfin { @@ -39,13 +40,16 @@ QString LocalSession::userName() const { } PlaybackManager *LocalSession::createPlaybackManager() const { - return new LocalPlaybackManager(); + LocalPlaybackManager *playbackManager = new LocalPlaybackManager(); + playbackManager->setApiClient(&m_apiClient); + return playbackManager; } // ControllableJellyfinSession -ControllableJellyfinSession::ControllableJellyfinSession(const QSharedPointer info, QObject *parent) +ControllableJellyfinSession::ControllableJellyfinSession(const QSharedPointer info, ApiClient &apiClient, QObject *parent) : ControllableSession(parent), - m_data(info) {} + m_data(info), + m_apiClient(apiClient){} QString ControllableJellyfinSession::id() const { return m_data->jellyfinId(); @@ -68,8 +72,7 @@ QString ControllableJellyfinSession::userName() const { } PlaybackManager * ControllableJellyfinSession::createPlaybackManager() const { - // TODO: implement - return nullptr; + return new RemoteJellyfinPlayback(m_apiClient, m_data->jellyfinId()); } RemoteSessionScanner::RemoteSessionScanner(QObject *parent) @@ -114,7 +117,7 @@ void RemoteJellyfinSessionScanner::startScanning() { // Skip this device if (it->jellyfinId() == d->apiClient->deviceId()) continue; - emit sessionFound(new ControllableJellyfinSession(QSharedPointer::create(*it))); + emit sessionFound(new ControllableJellyfinSession(QSharedPointer::create(*it), *d->apiClient)); } }); d->loader->load(); diff --git a/core/src/model/item.cpp b/core/src/model/item.cpp index 30583f0..4687e68 100644 --- a/core/src/model/item.cpp +++ b/core/src/model/item.cpp @@ -41,8 +41,8 @@ Item::Item(ApiClient *apiClient, QObject *parent) } Item::Item(const DTO::BaseItemDto &data, ApiClient *apiClient, QObject *parent) - : DTO::BaseItemDto(data), - QObject(parent), + : QObject(parent), + DTO::BaseItemDto(data), m_apiClient(nullptr) { setApiClient(apiClient); } diff --git a/core/src/model/playbackmanager.cpp b/core/src/model/playbackmanager.cpp index 26fc8ea..5ed84e6 100644 --- a/core/src/model/playbackmanager.cpp +++ b/core/src/model/playbackmanager.cpp @@ -59,7 +59,7 @@ public: PlayerState m_state; - Model::Playlist *m_queue = nullptr; + Model::Playlist *m_queue; int m_queueIndex = 0; bool m_resumePlayback = false; @@ -153,6 +153,15 @@ int PlaybackManager::queueIndex() const { return d->m_queueIndex; } +void PlaybackManager::swap(PlaybackManager &other) { + other.queue()->clearList(); + other.queue()->appendToList(this->queue()->queueAndList()); + other.playItemInList(this->queue()->queueAndList(), this->queue()->currentItemIndexInList() >= 0 + ? this->queue()->currentItemIndexInList() + : 0); + other.seek(position()); +} + void PlaybackManager::playItemId(const QString &id) {} bool PlaybackManager::resumePlayback() const { @@ -188,6 +197,12 @@ void PlaybackManager::setSubtitleIndex(int newSubtitleIndex) { emit subtitleIndexChanged(newSubtitleIndex); } +void PlaybackManager::setItem(QSharedPointer item) { + Q_D(PlaybackManager); + d->m_item = item; + emit itemChanged(); +} + /***************************************************************************** * LocalPlaybackManagerPrivate * *****************************************************************************/ @@ -491,10 +506,6 @@ LocalPlaybackManager::LocalPlaybackManager(QObject *parent) }); } -void LocalPlaybackManager::swap(PlaybackManager &other) { - Q_UNIMPLEMENTED(); -} - Player* LocalPlaybackManager::player() const { const Q_D(LocalPlaybackManager); return d->m_mediaPlayer; diff --git a/core/src/model/playlist.cpp b/core/src/model/playlist.cpp index bca2c97..ce9e899 100644 --- a/core/src/model/playlist.cpp +++ b/core/src/model/playlist.cpp @@ -104,6 +104,14 @@ void Playlist::next() { emit currentItemChanged(); } +QList> Playlist::queueAndList() const { + QList> result; + result.reserve(totalSize()); + result.append(m_queue.toList()); + result.append(m_list.toList()); + return result; +} + QSharedPointer Playlist::listAt(int index) const { if (m_shuffler->canShuffleInAdvance()) { return m_list.at(m_shuffler->itemAt(index)); diff --git a/core/src/model/remotejellyfinplayback.cpp b/core/src/model/remotejellyfinplayback.cpp index 68bc84b..d895be7 100644 --- a/core/src/model/remotejellyfinplayback.cpp +++ b/core/src/model/remotejellyfinplayback.cpp @@ -20,90 +20,127 @@ #include #include +#include #include #include +#include +#include +#include +#include + +#include namespace Jellyfin { namespace Model { -RemoteJellyfinPlayback::RemoteJellyfinPlayback(ApiClient &apiClient, QObject *parent) - : PlaybackManager(parent), m_apiClient(apiClient) { +RemoteJellyfinPlayback::RemoteJellyfinPlayback(ApiClient &apiClient, QString sessionId, QObject *parent) + : PlaybackManager(parent), m_apiClient(apiClient), m_sessionId(sessionId), m_positionTimer(new QTimer(this)) { + setApiClient(&m_apiClient); + m_apiClient.websocket()->subscribeToSessionInfo(); + connect(m_apiClient.eventbus(), &EventBus::sessionInfoUpdated, this, &RemoteJellyfinPlayback::onSessionInfoUpdated); + // Arm the timer + m_positionTimer->setInterval(1000); + connect(m_positionTimer, &QTimer::timeout, this, &RemoteJellyfinPlayback::onPositionTimerFired); } -void RemoteJellyfinPlayback::swap(PlaybackManager &other) { - +RemoteJellyfinPlayback::~RemoteJellyfinPlayback() { + m_apiClient.websocket()->unsubscribeToSessionInfo(); } PlayerState RemoteJellyfinPlayback::playbackState() const { - + return m_lastSessionInfo.has_value() + ? m_lastSessionInfo.value().playState()->isPaused() + ? PlayerState::Paused + : PlayerState::Playing + : PlayerState::Stopped; } MediaStatus RemoteJellyfinPlayback::mediaStatus() const { - + return MediaStatus::Loaded; } bool RemoteJellyfinPlayback::hasNext() const { - + return true; } bool RemoteJellyfinPlayback::hasPrevious() const { - + return true; } PlaybackManagerError RemoteJellyfinPlayback::error() const { - + return PlaybackManagerError::NoError; } const QString &RemoteJellyfinPlayback::errorString() const { - + return m_sessionId; } qint64 RemoteJellyfinPlayback::position() const { - + return m_position; } qint64 RemoteJellyfinPlayback::duration() const { - + if (!m_lastSessionInfo.has_value() + || m_lastSessionInfo.value().nowPlayingItem().isNull()) { + return 0; + } + return m_lastSessionInfo.value().nowPlayingItem()->runTimeTicks().value_or(0) / 10000; } bool RemoteJellyfinPlayback::seekable() const { - + if (!m_lastSessionInfo.has_value() + || m_lastSessionInfo.value().playState().isNull()) { + return false; + } + return m_lastSessionInfo.value().playState()->canSeek(); } bool RemoteJellyfinPlayback::hasAudio() const { - + return false; } bool RemoteJellyfinPlayback::hasVideo() const { - + return false; } void RemoteJellyfinPlayback::playItem(QSharedPointer item) { - + return playItemInList({item}, 0); } void RemoteJellyfinPlayback::playItemInList(const QList > &items, int index) { + // Map items to their ID + QStringList itemIds; + itemIds.reserve(items.size()); + for(auto it = items.begin(); it < items.end(); it++) { + itemIds.append((*it)->jellyfinId()); + } + if (this->resumePlayback()) { + this->playItemInList(itemIds, index, items.at(index)->userData()->playbackPositionTicks()); + } else { + this->playItemInList(itemIds, index); + } } void RemoteJellyfinPlayback::pause() { + sendPlaystateCommand(DTO::PlaystateCommand::Pause); } void RemoteJellyfinPlayback::play() { - + sendPlaystateCommand(DTO::PlaystateCommand::Unpause); } void RemoteJellyfinPlayback::playItemId(const QString &id) { - + playItemInList({id}, 0); } void RemoteJellyfinPlayback::previous() { - + sendPlaystateCommand(DTO::PlaystateCommand::PreviousTrack); } void RemoteJellyfinPlayback::next() { - + sendPlaystateCommand(DTO::PlaystateCommand::NextTrack); } void RemoteJellyfinPlayback::goTo(int index) { @@ -111,21 +148,107 @@ void RemoteJellyfinPlayback::goTo(int index) { } void RemoteJellyfinPlayback::stop() { - + sendPlaystateCommand(DTO::PlaystateCommand::Stop); } void RemoteJellyfinPlayback::seek(qint64 pos) { + sendPlaystateCommand(DTO::PlaystateCommand::Seek, pos * PlaybackManager::MS_TICK_FACTOR); +} +void RemoteJellyfinPlayback::onPositionTimerFired() { + m_position += m_positionTimer->interval(); + emit positionChanged(position()); +} + +void RemoteJellyfinPlayback::onSessionInfoUpdated(const QString &sessionId, const SessionInfo &sessionInfo) { + if (sessionId != m_sessionId) return; + qDebug() << "Session info updated for " << sessionId; + m_lastSessionInfo = sessionInfo; + + if (m_lastSessionInfo->nowPlayingItem().isNull()) { + setItem(QSharedPointer::create()); + } else { + Jellyfin::BaseItemDto itemData = *m_lastSessionInfo->nowPlayingItem().data(); + setItem(QSharedPointer::create(itemData, &m_apiClient)); + } + + // Update current position and run timer if needed + if (m_lastSessionInfo.has_value() + && !m_lastSessionInfo.value().playState().isNull()) { + m_position = m_lastSessionInfo.value().playState()->positionTicks().value_or(0) / PlaybackManager::MS_TICK_FACTOR; + if (!m_positionTimer->isActive() && !m_lastSessionInfo.value().playState()->isPaused()) { + m_positionTimer->start(); + } else if (m_positionTimer->isActive() && m_lastSessionInfo.value().playState()->isPaused()) { + m_positionTimer->stop(); + } + } else if (m_positionTimer->isActive()){ + m_positionTimer->stop(); + m_position = 0; + } + + emit playbackStateChanged(playbackState()); + emit durationChanged(duration()); + emit positionChanged(position()); +} + +void RemoteJellyfinPlayback::sendPlaystateCommand(DTO::PlaystateCommand command, qint64 seekTicks) { + using Params = Loader::SendPlaystateCommandParams; + using CommandLoader = Loader::HTTP::SendPlaystateCommandLoader; + + Params params; + params.setCommand(command); + params.setSessionId(m_sessionId); + if (seekTicks >= 0) { + params.setSeekPositionTicks(seekTicks); + } + + auto loader = new CommandLoader(&m_apiClient); + loader->setParameters(params); + sendCommand(loader); } void RemoteJellyfinPlayback::sendGeneralCommand(DTO::GeneralCommandType command, QJsonObject arguments) { - Loader::SendFullGeneralCommandParams params; + using Params = Loader::SendFullGeneralCommandParams; + using CommandLoader = Loader::HTTP::SendFullGeneralCommandLoader; + + Params params; QSharedPointer fullCommand = QSharedPointer::create(command, m_apiClient.userId()); fullCommand->setArguments(arguments); - // FIXME: send command + params.setBody(fullCommand); + params.setSessionId(m_sessionId); + + auto loader = new CommandLoader(&m_apiClient); + loader->setParameters(params); + sendCommand(loader); } +void RemoteJellyfinPlayback::sendCommand(Support::LoaderBase *loader) { + connect(loader, &Support::LoaderBase::ready, this, [loader](){ + loader->deleteLater(); + }); + connect(loader, &Support::LoaderBase::error, this, [loader](QString message){ + loader->deleteLater(); + }); + loader->load(); +} +void RemoteJellyfinPlayback::playItemInList(const QStringList &items, int index, qint64 resumeTicks) { + using Params = Loader::PlayParams; + using CommandLoader = Loader::HTTP::PlayLoader; + + Params params; + params.setSessionId(m_sessionId); + if (resumeTicks >= 0) { + params.setStartPositionTicks(resumeTicks); + } + params.setPlayCommand(DTO::PlayCommand::PlayNow); + params.setItemIds(items); + //params.setStartIndex(index); + + CommandLoader *loader = new CommandLoader(&m_apiClient); + loader->setParameters(params); + sendCommand(loader); +} } // NS Model } // NS Jellyfin diff --git a/core/src/platform/freedesktop/mediaplayer2player.cpp b/core/src/platform/freedesktop/mediaplayer2player.cpp index 090237d..13c28d2 100644 --- a/core/src/platform/freedesktop/mediaplayer2player.cpp +++ b/core/src/platform/freedesktop/mediaplayer2player.cpp @@ -46,37 +46,37 @@ PlayerAdaptor::~PlayerAdaptor() { bool PlayerAdaptor::canControl() const { // get the value of property CanControl - return true; + return m_mediaControl->playbackManager() != nullptr; } bool PlayerAdaptor::canGoNext() const { // get the value of property CanGoNext - return canPlay() && m_mediaControl->playbackManager()->hasNext(); + return canControl() && canPlay() && m_mediaControl->playbackManager()->hasNext(); } bool PlayerAdaptor::canGoPrevious() const { // get the value of property CanGoPrevious - return canPlay() && m_mediaControl->playbackManager()->hasPrevious(); + return canControl() && canPlay() && m_mediaControl->playbackManager()->hasPrevious(); } bool PlayerAdaptor::canPause() const { // get the value of property CanPause - return canPlay(); + return canControl() && canPlay(); } bool PlayerAdaptor::canPlay() const { // get the value of property CanPlay - return m_mediaControl->playbackManager()->queue()->rowCount(QModelIndex()) > 0; + return canControl() && m_mediaControl->playbackManager()->queue()->rowCount(QModelIndex()) > 0; } bool PlayerAdaptor::canSeek() const { // get the value of property CanSeek - return m_mediaControl->playbackManager()->seekable(); + return canControl() && m_mediaControl->playbackManager()->seekable(); } QString PlayerAdaptor::loopStatus() const @@ -134,7 +134,10 @@ QVariantMap PlayerAdaptor::metadata() const } map[QStringLiteral("xesam:contentCreated")] = item->dateCreated(); map[QStringLiteral("xesam:genre")] = item->genres(); - map[QStringLiteral("xesam:lastUsed")] = item->userData()->lastPlayedDate(); + + if (!item->userData().isNull()) { + map[QStringLiteral("xesam:lastUsed")] = item->userData()->lastPlayedDate(); + } QJsonObject providers = item->providerIds(); if (providers.contains(QStringLiteral("MusicBrainzTrack"))) { diff --git a/core/src/viewmodel/playbackmanager.cpp b/core/src/viewmodel/playbackmanager.cpp index 8ca1496..b1912ef 100644 --- a/core/src/viewmodel/playbackmanager.cpp +++ b/core/src/viewmodel/playbackmanager.cpp @@ -75,25 +75,6 @@ PlaybackManager::PlaybackManager(QObject *parent) : QObject(parent) { QScopedPointer foo(new PlaybackManagerPrivate(this)); d_ptr.swap(foo); - - Q_D(PlaybackManager); - // Set up connections. - connect(d->m_impl.data(), &Model::PlaybackManager::positionChanged, this, &PlaybackManager::positionChanged); - connect(d->m_impl.data(), &Model::PlaybackManager::durationChanged, this, &PlaybackManager::durationChanged); - connect(d->m_impl.data(), &Model::PlaybackManager::hasNextChanged, this, &PlaybackManager::hasNextChanged); - connect(d->m_impl.data(), &Model::PlaybackManager::hasPreviousChanged, this, &PlaybackManager::hasPreviousChanged); - connect(d->m_impl.data(), &Model::PlaybackManager::seekableChanged, this, &PlaybackManager::seekableChanged); - connect(d->m_impl.data(), &Model::PlaybackManager::queueIndexChanged, this, &PlaybackManager::queueIndexChanged); - connect(d->m_impl.data(), &Model::PlaybackManager::itemChanged, this, &PlaybackManager::mediaPlayerItemChanged); - connect(d->m_impl.data(), &Model::PlaybackManager::playbackStateChanged, this, &PlaybackManager::playbackStateChanged); - - if (auto localImp = qobject_cast(d->m_impl.data())) { - connect(localImp, &Model::LocalPlaybackManager::streamUrlChanged, this, [this](const QUrl& newUrl){ - emit this->streamUrlChanged(newUrl.toString()); - }); - connect(localImp, &Model::LocalPlaybackManager::playMethodChanged, this, &PlaybackManager::playMethodChanged); - } - connect(d->m_impl.data(), &Model::PlaybackManager::mediaStatusChanged, this, &PlaybackManager::mediaStatusChanged); } PlaybackManager::~PlaybackManager() { @@ -175,12 +156,61 @@ void PlaybackManager::setControllingSession(QSharedPointername(); session->setParent(this); + + if (!d->m_impl.isNull()) { + disconnect(d->m_impl.data(), &Model::PlaybackManager::positionChanged, this, &PlaybackManager::positionChanged); + disconnect(d->m_impl.data(), &Model::PlaybackManager::durationChanged, this, &PlaybackManager::durationChanged); + disconnect(d->m_impl.data(), &Model::PlaybackManager::hasNextChanged, this, &PlaybackManager::hasNextChanged); + disconnect(d->m_impl.data(), &Model::PlaybackManager::hasPreviousChanged, this, &PlaybackManager::hasPreviousChanged); + disconnect(d->m_impl.data(), &Model::PlaybackManager::seekableChanged, this, &PlaybackManager::seekableChanged); + disconnect(d->m_impl.data(), &Model::PlaybackManager::queueIndexChanged, this, &PlaybackManager::queueIndexChanged); + disconnect(d->m_impl.data(), &Model::PlaybackManager::itemChanged, this, &PlaybackManager::mediaPlayerItemChanged); + disconnect(d->m_impl.data(), &Model::PlaybackManager::playbackStateChanged, this, &PlaybackManager::playbackStateChanged); + + if (auto localImp = qobject_cast(d->m_impl.data())) { + disconnect(localImp, &Model::LocalPlaybackManager::playMethodChanged, this, &PlaybackManager::playMethodChanged); + } + disconnect(d->m_impl.data(), &Model::PlaybackManager::mediaStatusChanged, this, &PlaybackManager::mediaStatusChanged); + } + + Model::PlaybackManager *other = session->createPlaybackManager(); + + if (!d->m_impl.isNull()) { + bool thisIsLocal = qobject_cast(d->m_impl.data()) != nullptr; + //bool otherIsLocal = qobject_cast(other) != nullptr; + + // Stop playing locally when switching to another session + if (thisIsLocal) { + d->m_impl->stop(); + } + } + d->m_displayQueue->setPlaylistModel(other->queue()); + d->m_impl.reset(other); d->m_session.swap(session); // TODO: swap out playback manager emit controllingSessionChanged(); emit controllingSessionIdChanged(); emit controllingSessionNameChanged(); emit controllingSessionLocalChanged(); + + if (other != nullptr) { + connect(d->m_impl.data(), &Model::PlaybackManager::positionChanged, this, &PlaybackManager::positionChanged); + connect(d->m_impl.data(), &Model::PlaybackManager::durationChanged, this, &PlaybackManager::durationChanged); + connect(d->m_impl.data(), &Model::PlaybackManager::hasNextChanged, this, &PlaybackManager::hasNextChanged); + connect(d->m_impl.data(), &Model::PlaybackManager::hasPreviousChanged, this, &PlaybackManager::hasPreviousChanged); + connect(d->m_impl.data(), &Model::PlaybackManager::seekableChanged, this, &PlaybackManager::seekableChanged); + connect(d->m_impl.data(), &Model::PlaybackManager::queueIndexChanged, this, &PlaybackManager::queueIndexChanged); + connect(d->m_impl.data(), &Model::PlaybackManager::itemChanged, this, &PlaybackManager::mediaPlayerItemChanged); + connect(d->m_impl.data(), &Model::PlaybackManager::playbackStateChanged, this, &PlaybackManager::playbackStateChanged); + + if (auto localImp = qobject_cast(d->m_impl.data())) { + connect(localImp, &Model::LocalPlaybackManager::streamUrlChanged, this, [this](const QUrl& newUrl){ + emit this->streamUrlChanged(newUrl.toString()); + }); + connect(localImp, &Model::LocalPlaybackManager::playMethodChanged, this, &PlaybackManager::playMethodChanged); + } + connect(d->m_impl.data(), &Model::PlaybackManager::mediaStatusChanged, this, &PlaybackManager::mediaStatusChanged); + } } QString PlaybackManager::controllingSessionId() const { diff --git a/core/src/viewmodel/playlist.cpp b/core/src/viewmodel/playlist.cpp index 99178ba..a0dc1b6 100644 --- a/core/src/viewmodel/playlist.cpp +++ b/core/src/viewmodel/playlist.cpp @@ -26,20 +26,8 @@ namespace ViewModel { Playlist::Playlist(Model::Playlist *data, QObject *parent) : QAbstractListModel(parent), - m_data(data) { - - connect(data, &Model::Playlist::beforeListCleared, this, &Playlist::onBeforePlaylistCleared); - connect(data, &Model::Playlist::listCleared, this, &Playlist::onPlaylistCleared); - connect(data, &Model::Playlist::beforeItemsAddedToList, this, &Playlist::onBeforeItemsAddedToList); - connect(data, &Model::Playlist::beforeItemsAddedToQueue, this, &Playlist::onBeforeItemsAddedToQueue); - connect(data, &Model::Playlist::itemsAddedToList, this, &Playlist::onItemsAddedToList); - connect(data, &Model::Playlist::itemsAddedToQueue, this, &Playlist::onItemsAddedToQueue); - connect(data, &Model::Playlist::beforeItemsRemovedFromList, this, &Playlist::onBeforeItemsRemovedFromList); - connect(data, &Model::Playlist::beforeItemsRemovedFromQueue, this, &Playlist::onBeforeItemsRemovedFromQueue); - connect(data, &Model::Playlist::itemsRemovedFromList, this, &Playlist::onItemsRemovedFromList); - connect(data, &Model::Playlist::itemsRemovedFromQueue, this, &Playlist::onItemsRemovedFromQueue); - connect(data, &Model::Playlist::listReshuffled, this, &Playlist::onReshuffled); - connect(data, &Model::Playlist::currentItemChanged, this, &Playlist::onPlayingItemChanged); + m_data(nullptr) { + setPlaylistModel(data); } int Playlist::rowCount(const QModelIndex &parent) const { @@ -55,6 +43,41 @@ QHash Playlist::roleNames() const { {RoleNames::section, "section"}, {RoleNames::playing, "playing"}, }; +} + +void Playlist::setPlaylistModel(Model::Playlist *data) { + if (m_data != nullptr) { + disconnect(data, &Model::Playlist::beforeListCleared, this, &Playlist::onBeforePlaylistCleared); + disconnect(data, &Model::Playlist::listCleared, this, &Playlist::onPlaylistCleared); + disconnect(data, &Model::Playlist::beforeItemsAddedToList, this, &Playlist::onBeforeItemsAddedToList); + disconnect(data, &Model::Playlist::beforeItemsAddedToQueue, this, &Playlist::onBeforeItemsAddedToQueue); + disconnect(data, &Model::Playlist::itemsAddedToList, this, &Playlist::onItemsAddedToList); + disconnect(data, &Model::Playlist::itemsAddedToQueue, this, &Playlist::onItemsAddedToQueue); + disconnect(data, &Model::Playlist::beforeItemsRemovedFromList, this, &Playlist::onBeforeItemsRemovedFromList); + disconnect(data, &Model::Playlist::beforeItemsRemovedFromQueue, this, &Playlist::onBeforeItemsRemovedFromQueue); + disconnect(data, &Model::Playlist::itemsRemovedFromList, this, &Playlist::onItemsRemovedFromList); + disconnect(data, &Model::Playlist::itemsRemovedFromQueue, this, &Playlist::onItemsRemovedFromQueue); + disconnect(data, &Model::Playlist::listReshuffled, this, &Playlist::onReshuffled); + disconnect(data, &Model::Playlist::currentItemChanged, this, &Playlist::onPlayingItemChanged); + } + beginResetModel(); + m_data = data; + endResetModel(); + + if (m_data != nullptr) { + connect(data, &Model::Playlist::beforeListCleared, this, &Playlist::onBeforePlaylistCleared); + connect(data, &Model::Playlist::listCleared, this, &Playlist::onPlaylistCleared); + connect(data, &Model::Playlist::beforeItemsAddedToList, this, &Playlist::onBeforeItemsAddedToList); + connect(data, &Model::Playlist::beforeItemsAddedToQueue, this, &Playlist::onBeforeItemsAddedToQueue); + connect(data, &Model::Playlist::itemsAddedToList, this, &Playlist::onItemsAddedToList); + connect(data, &Model::Playlist::itemsAddedToQueue, this, &Playlist::onItemsAddedToQueue); + connect(data, &Model::Playlist::beforeItemsRemovedFromList, this, &Playlist::onBeforeItemsRemovedFromList); + connect(data, &Model::Playlist::beforeItemsRemovedFromQueue, this, &Playlist::onBeforeItemsRemovedFromQueue); + connect(data, &Model::Playlist::itemsRemovedFromList, this, &Playlist::onItemsRemovedFromList); + connect(data, &Model::Playlist::itemsRemovedFromQueue, this, &Playlist::onItemsRemovedFromQueue); + connect(data, &Model::Playlist::listReshuffled, this, &Playlist::onReshuffled); + connect(data, &Model::Playlist::currentItemChanged, this, &Playlist::onPlayingItemChanged); + } }; QVariant Playlist::data(const QModelIndex &index, int role) const { diff --git a/core/src/websocket.cpp b/core/src/websocket.cpp index a4e7638..b616ddc 100644 --- a/core/src/websocket.cpp +++ b/core/src/websocket.cpp @@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include #include #include +#include #include Q_LOGGING_CATEGORY(jellyfinWebSocket, "jellyfin.websocket"); @@ -61,6 +62,21 @@ void WebSocket::open() { qCDebug(jellyfinWebSocket) << "Opening WebSocket connection to " << m_webSocket.requestUrl() << ", connect attempt " << m_reconnectAttempt; } +void WebSocket::subscribeToSessionInfo() { + if (m_sessionInfoSubscribeCount++ == 0) { + // First argument: initial delay in milliseconds + // Second argument: periodic update interval in milliseconds + // Reference: https://github.com/jellyfin/jellyfin/blob/f3c57e6a0ae015dc51cf548a0380d1bed33959c2/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs#L99 + sendMessage(MessageType::SessionsStart, QJsonValue(QStringLiteral("0,5000"))); + } +} + +void WebSocket::unsubscribeToSessionInfo() { + if (--m_sessionInfoSubscribeCount == 0) { + sendMessage(MessageType::SessionsStop); + } +} + void WebSocket::onConnected() { connect(&m_webSocket, &QWebSocket::textMessageReceived, this, &WebSocket::textMessageReceived); m_reconnectAttempt = 0; @@ -76,7 +92,6 @@ void WebSocket::onDisconnected() { } void WebSocket::textMessageReceived(const QString &message) { - qCDebug(jellyfinWebSocket) << "message received: " << message; QJsonDocument doc = QJsonDocument::fromJson(message.toUtf8()); if (doc.isNull() || !doc.isObject()) { qCWarning(jellyfinWebSocket()) << "Malformed message received over WebSocket: parse error or root not an object."; @@ -90,6 +105,7 @@ void WebSocket::textMessageReceived(const QString &message) { // Convert the type so we can use it in our enums. QString messageType = messageRoot["MessageType"].toString(); + qCDebug(jellyfinWebSocket) << "Message received: " << messageType; QJsonValue data = messageRoot["Data"]; if (messageType == QStringLiteral("ForceKeepAlive")) { setupKeepAlive(data.toInt()); @@ -136,8 +152,17 @@ void WebSocket::textMessageReceived(const QString &message) { qCWarning(jellyfinWebSocket) << "Unparseable UserData list received: " << e->what(); } } + } else if (messageType == QStringLiteral("Sessions")) { + try { + QList sessionInfoList = Support::fromJsonValue>(data); + for (auto it = sessionInfoList.cbegin(); it != sessionInfoList.cend(); it++) { + emit m_apiClient->eventbus()->sessionInfoUpdated(it->jellyfinId(), *it); + } + } catch(QException *e) { + qCWarning(jellyfinWebSocket) << "Unparseable SessionInfo list received: " << e->what(); + } } else { - qCDebug(jellyfinWebSocket) << messageType; + qCDebug(jellyfinWebSocket) << "Unhandled message: " << messageType; } } From 3783de9ce72f0155ca29a46cb0c68bfe751a98a0 Mon Sep 17 00:00:00 2001 From: Chris Josten Date: Thu, 5 Jan 2023 15:53:52 +0100 Subject: [PATCH 04/10] core: send start index when playing on remote session --- core/include/JellyfinQt/loader/requesttypes.h | 40 +++++++++ core/openapi.json | 37 +++++++- core/src/loader/http/session.cpp | 12 +++ core/src/loader/requesttypes.cpp | 84 +++++++++++++++++++ core/src/model/remotejellyfinplayback.cpp | 6 +- 5 files changed, 177 insertions(+), 2 deletions(-) diff --git a/core/include/JellyfinQt/loader/requesttypes.h b/core/include/JellyfinQt/loader/requesttypes.h index f5cbab7..f68f249 100644 --- a/core/include/JellyfinQt/loader/requesttypes.h +++ b/core/include/JellyfinQt/loader/requesttypes.h @@ -27728,6 +27728,33 @@ public: void setPlayCommand(PlayCommand newPlayCommand); + /** + * @brief Optional. The index of the audio stream to play. + */ + const qint32 &audioStreamIndex() const; + void setAudioStreamIndex(qint32 newAudioStreamIndex); + bool audioStreamIndexNull() const; + void setAudioStreamIndexNull(); + + + /** + * @brief Optional. The media source id. + */ + const QString &mediaSourceId() const; + void setMediaSourceId(QString newMediaSourceId); + bool mediaSourceIdNull() const; + void setMediaSourceIdNull(); + + + /** + * @brief Optional. The start index. + */ + const qint32 &startIndex() const; + void setStartIndex(qint32 newStartIndex); + bool startIndexNull() const; + void setStartIndexNull(); + + /** * @brief The starting position of the first item. */ @@ -27737,6 +27764,15 @@ public: void setStartPositionTicksNull(); + /** + * @brief Optional. The index of the subtitle stream to play. + */ + const qint32 &subtitleStreamIndex() const; + void setSubtitleStreamIndex(qint32 newSubtitleStreamIndex); + bool subtitleStreamIndexNull() const; + void setSubtitleStreamIndexNull(); + + private: // Required path parameters QString m_sessionId; @@ -27746,7 +27782,11 @@ private: PlayCommand m_playCommand; // Optional query parameters + std::optional m_audioStreamIndex = std::nullopt; + QString m_mediaSourceId; + std::optional m_startIndex = std::nullopt; std::optional m_startPositionTicks = std::nullopt; + std::optional m_subtitleStreamIndex = std::nullopt; }; diff --git a/core/openapi.json b/core/openapi.json index e015c54..09a057c 100644 --- a/core/openapi.json +++ b/core/openapi.json @@ -34508,6 +34508,41 @@ "format": "int64", "nullable": true } + }, + { + "name": "mediaSourceId", + "in": "query", + "description": "Optional. The media source id.", + "schema": { + "type": "string" + } + }, + { + "name": "audioStreamIndex", + "in": "query", + "description": "Optional. The index of the audio stream to play.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleStreamIndex", + "in": "query", + "description": "Optional. The index of the subtitle stream to play.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "startIndex", + "in": "query", + "description": "Optional. The start index.", + "schema": { + "type": "integer", + "format": "int32" + } } ], "responses": { @@ -55377,4 +55412,4 @@ } } } -} \ No newline at end of file +} diff --git a/core/src/loader/http/session.cpp b/core/src/loader/http/session.cpp index 69ca54c..939cfc3 100644 --- a/core/src/loader/http/session.cpp +++ b/core/src/loader/http/session.cpp @@ -245,6 +245,18 @@ QUrlQuery PlayLoader::query(const PlayParams ¶ms) const { if (!params.startPositionTicksNull()) { result.addQueryItem("startPositionTicks", Support::toString>(params.startPositionTicks())); } + if (!params.mediaSourceIdNull()) { + result.addQueryItem("mediaSourceId", Support::toString(params.mediaSourceId())); + } + if (!params.audioStreamIndexNull()) { + result.addQueryItem("audioStreamIndex", Support::toString>(params.audioStreamIndex())); + } + if (!params.subtitleStreamIndexNull()) { + result.addQueryItem("subtitleStreamIndex", Support::toString>(params.subtitleStreamIndex())); + } + if (!params.startIndexNull()) { + result.addQueryItem("startIndex", Support::toString>(params.startIndex())); + } return result; } diff --git a/core/src/loader/requesttypes.cpp b/core/src/loader/requesttypes.cpp index d1a2489..2c4b771 100644 --- a/core/src/loader/requesttypes.cpp +++ b/core/src/loader/requesttypes.cpp @@ -47966,6 +47966,69 @@ void PlayParams::setPlayCommand(PlayCommand newPlayCommand) { } +const qint32 &PlayParams::audioStreamIndex() const { + return m_audioStreamIndex.value(); +} + +void PlayParams::setAudioStreamIndex(qint32 newAudioStreamIndex) { + m_audioStreamIndex = newAudioStreamIndex; +} + +bool PlayParams::audioStreamIndexNull() const { + // Nullable: true + // Type Nullable: false + + + return !m_audioStreamIndex.has_value(); +} + +void PlayParams::setAudioStreamIndexNull() { + m_audioStreamIndex = std::nullopt; +} + + +const QString &PlayParams::mediaSourceId() const { + return m_mediaSourceId; +} + +void PlayParams::setMediaSourceId(QString newMediaSourceId) { + m_mediaSourceId = newMediaSourceId; +} + +bool PlayParams::mediaSourceIdNull() const { + // Nullable: true + // Type Nullable: true + + + return m_mediaSourceId.isNull(); +} + +void PlayParams::setMediaSourceIdNull() { + m_mediaSourceId.clear(); +} + + +const qint32 &PlayParams::startIndex() const { + return m_startIndex.value(); +} + +void PlayParams::setStartIndex(qint32 newStartIndex) { + m_startIndex = newStartIndex; +} + +bool PlayParams::startIndexNull() const { + // Nullable: true + // Type Nullable: false + + + return !m_startIndex.has_value(); +} + +void PlayParams::setStartIndexNull() { + m_startIndex = std::nullopt; +} + + const qint64 &PlayParams::startPositionTicks() const { return m_startPositionTicks.value(); } @@ -47987,6 +48050,27 @@ void PlayParams::setStartPositionTicksNull() { } +const qint32 &PlayParams::subtitleStreamIndex() const { + return m_subtitleStreamIndex.value(); +} + +void PlayParams::setSubtitleStreamIndex(qint32 newSubtitleStreamIndex) { + m_subtitleStreamIndex = newSubtitleStreamIndex; +} + +bool PlayParams::subtitleStreamIndexNull() const { + // Nullable: true + // Type Nullable: false + + + return !m_subtitleStreamIndex.has_value(); +} + +void PlayParams::setSubtitleStreamIndexNull() { + m_subtitleStreamIndex = std::nullopt; +} + + // PostParams diff --git a/core/src/model/remotejellyfinplayback.cpp b/core/src/model/remotejellyfinplayback.cpp index d895be7..1734423 100644 --- a/core/src/model/remotejellyfinplayback.cpp +++ b/core/src/model/remotejellyfinplayback.cpp @@ -243,7 +243,11 @@ void RemoteJellyfinPlayback::playItemInList(const QStringList &items, int index, } params.setPlayCommand(DTO::PlayCommand::PlayNow); params.setItemIds(items); - //params.setStartIndex(index); + params.setStartIndex(index); + params.setAudioStreamIndex(this->audioIndex()); + if (this->subtitleIndex() >= 0) { + params.setSubtitleStreamIndex(this->subtitleIndex()); + } CommandLoader *loader = new CommandLoader(&m_apiClient); loader->setParameters(params); From 7c6d8486de174539dbbf7788d172b539f98f7aeb Mon Sep 17 00:00:00 2001 From: Chris Josten Date: Wed, 11 Jan 2023 23:11:02 +0100 Subject: [PATCH 05/10] ui: improve empty state, add remote playback indicator --- sailfish/qml/Utils.js | 6 ++- sailfish/qml/components/PlaybackBar.qml | 49 ++++++++++++++++--- sailfish/qml/components/VideoPlayer.qml | 12 ++++- .../qml/components/videoplayer/VideoHud.qml | 3 ++ sailfish/qml/harbour-sailfin.qml | 6 ++- .../qml/pages/ControllableDevicesPage.qml | 2 +- sailfish/qml/pages/VideoPage.qml | 11 ++++- 7 files changed, 76 insertions(+), 13 deletions(-) diff --git a/sailfish/qml/Utils.js b/sailfish/qml/Utils.js index 049c5f5..96e464e 100644 --- a/sailfish/qml/Utils.js +++ b/sailfish/qml/Utils.js @@ -69,7 +69,11 @@ function randomBackdrop(baseUrl, item) { function itemBackdropUrl(baseUrl, item, idx, options) { var extraQuery = propsToQuery(options) - return baseUrl + "/Items/" + item.jellyfinId + "/Images/Backdrop/" + idx + "?tag=" + item.backdropImageTags[idx] + extraQuery; + if (item.backdropImageTags[idx]) { + return baseUrl + "/Items/" + item.jellyfinId + "/Images/Backdrop/" + idx + "?tag=" + item.backdropImageTags[idx] + extraQuery; + } else { + return baseUrl + "/Items/" + item.parentBackdropItemId + "/Images/Backdrop/" + idx + "?tag=" + item.parentBackdropImageTags[idx] + extraQuery; + } } diff --git a/sailfish/qml/components/PlaybackBar.qml b/sailfish/qml/components/PlaybackBar.qml index 5614521..beb1b80 100644 --- a/sailfish/qml/components/PlaybackBar.qml +++ b/sailfish/qml/components/PlaybackBar.qml @@ -48,6 +48,8 @@ PanelBackground { property bool showQueue: false property bool _pageWasShowingNavigationIndicator + readonly property bool _isItemSet: manager.item !== null && manager.item !== undefined && manager.item.jellyfinId.length > 0 + readonly property bool controllingRemote: !manager.controllingSessionLocal readonly property bool mediaLoading: [J.MediaStatus.Loading, J.MediaStatus.Buffering].indexOf(manager.mediaStatus) >= 0 @@ -67,9 +69,12 @@ PanelBackground { top: parent.top } width: height - Binding on blurhash { - when: manager.item !== null && "Primary" in manager.item.imageBlurHashes && "Primary" in manager.item.imageTags - value: manager.item.imageBlurHashes["Primary"][manager.item.imageTags["Primary"]] + blurhash: { + if (_isItemSet && "Primary" in manager.item.imageBlurHashes && "Primary" in manager.item.imageTags) { + return manager.item.imageBlurHashes["Primary"][manager.item.imageTags["Primary"]] + } else { + return "" + } } source: largeAlbumArt.source fillMode: Image.PreserveAspectCrop @@ -125,7 +130,10 @@ PanelBackground { Label { id: name - text: manager.item === null ? qsTr("No media selected") : manager.item.name + text: manager.item.jellyfinId + ? manager.item.name + //: Shown in a bright font when no media is playing in the bottom bar and now playing screen + : qsTr("Nothing is playing") width: Math.min(contentWidth, parent.width) font.pixelSize: Theme.fontSizeMedium maximumLineCount: 1 @@ -133,8 +141,23 @@ PanelBackground { } Label { id: artists + leftPadding: controllingRemote ? remoteIcon.width + Theme.paddingSmall : 0 text: { - if (manager.item === null) return qsTr("Play some media!") + if (!_isItemSet) { + if (controllingRemote) { + //: Shown when no media is being played, but the app is controlling another Jellyfin client + //: %1 is the name of said client + return qsTr("Connected to %1").arg(manager.controllingSessionName) + } else { + return qsTr("Start playing some media!") + } + } + var remoteText = ""; + + if (controllingRemote) { + remoteText = manager.controllingSessionName + " - " + } + switch(manager.item.mediaType) { case "Audio": var links = []; @@ -147,7 +170,7 @@ PanelBackground { .arg(Theme.secondaryColor) ) } - return links.join(", ") + return remoteText + links.join(", ") } return qsTr("No audio") } @@ -162,6 +185,16 @@ PanelBackground { appWindow.navigateToItem(link, "Audio", "MusicArtist", true) } textFormat: Text.StyledText + Icon { + id: remoteIcon + anchors { + left: parent.left + verticalCenter: parent.verticalCenter + } + height: parent + source: "image://theme/icon-s-device-upload" + visible: controllingRemote + } } } @@ -395,7 +428,9 @@ PanelBackground { }, State { name: "hidden" - when: ((manager.playbackState === J.PlayerState.Stopped && !mediaLoading) || "__hidePlaybackBar" in pageStack.currentPage) && !isFullPage + when: ((manager.playbackState === J.PlayerState.Stopped && !mediaLoading) + || ("__hidePlaybackBar" in pageStack.currentPage && pageStack.currentPage.__hidePlaybackBar)) + && !isFullPage PropertyChanges { target: playbackBarTranslate // + small padding since the ProgressBar otherwise would stick out diff --git a/sailfish/qml/components/VideoPlayer.qml b/sailfish/qml/components/VideoPlayer.qml index 602a2a0..2be0959 100644 --- a/sailfish/qml/components/VideoPlayer.qml +++ b/sailfish/qml/components/VideoPlayer.qml @@ -50,6 +50,16 @@ SilicaItem { color: Theme.overlayBackgroundColor } + RemoteImage { + id: backdrop + anchors.fill: parent + visible: !manager.controllingSessionLocal + || [J.MediaStatus.NoMedia, J.MediaStatus.Loading].indexOf(manager.mediaStatus) >= 0 + fillMode: Image.PreserveAspectFit + source: Utils.itemBackdropUrl(apiClient.baseUrl, item, 0, {"maxWidth": parent.width}) + blurhash: item.imageBlurHashes["Backdrop"][item.backdropImageTags[0]] + } + VideoOutput { id: videoOutput source: manager @@ -64,7 +74,7 @@ SilicaItem { anchors.fill: parent manager: playerRoot.manager title: videoPlayer.title - + alwaysVisible: !manager.controllingSessionLocal } VideoError { diff --git a/sailfish/qml/components/videoplayer/VideoHud.qml b/sailfish/qml/components/videoplayer/VideoHud.qml index 8f6c2d5..79c1c84 100644 --- a/sailfish/qml/components/videoplayer/VideoHud.qml +++ b/sailfish/qml/components/videoplayer/VideoHud.qml @@ -34,6 +34,8 @@ Item { property var manager property string title property bool _manuallyActivated: false + /// Don't allow the HUD to hide + property bool alwaysVisible: false readonly property bool hidden: opacity == 0.0 Behavior on opacity { FadeAnimator {} } @@ -174,6 +176,7 @@ Item { } function hide(manual) { + if (alwaysVisible) return // Don't hide if the user decided on their own to show the hud //if (!manual && _manuallyActivated) return; // Don't give in to the user if they want to hide the hud while it was forced upon them diff --git a/sailfish/qml/harbour-sailfin.qml b/sailfish/qml/harbour-sailfin.qml index f968b5b..d02a233 100644 --- a/sailfish/qml/harbour-sailfin.qml +++ b/sailfish/qml/harbour-sailfin.qml @@ -75,7 +75,7 @@ ApplicationWindow { //cover: CoverBackground {CoverPlaceholder { icon.source: "icon.png"; text: "Sailfin"}} cover: { // Disabled due to buggy Loader behaviour - if ([MediaPlayer.NoMedia, MediaPlayer.InvalidMedia, MediaPlayer.UnknownStatus].indexOf(_playbackManager.mediaStatus) >= 0 + if ([MediaStatus.NoMedia, MediaStatus.InvalidMedia].indexOf(_playbackManager.mediaStatus) >= 0 || _playbackManager.playbackState === MediaPlayer.StoppedState) { return Qt.resolvedUrl("cover/CollectionPage.qml") } else { @@ -134,7 +134,9 @@ ApplicationWindow { } DisplayBlanking { - preventBlanking: playbackManager.playbackState === MediaPlayer.PlayingState && playbackManager.hasVideo + preventBlanking: playbackManager.playbackState === MediaPlayer.PlayingState + && playbackManager.hasVideo + && playbackManager.controllingSessionLocal // Must be controlling a local session } PlaybackBar { diff --git a/sailfish/qml/pages/ControllableDevicesPage.qml b/sailfish/qml/pages/ControllableDevicesPage.qml index 2a40841..a6ec9cf 100644 --- a/sailfish/qml/pages/ControllableDevicesPage.qml +++ b/sailfish/qml/pages/ControllableDevicesPage.qml @@ -25,7 +25,7 @@ Page { property bool isConnected: model.jellyfinId === appWindow.playbackManager.controllingSessionId onClicked: deviceList.activateSession(appWindow.playbackManager, model.index) contentHeight: Theme.itemSizeMedium - HighlightImage { + Icon { id: deviceIcon anchors { left: parent.left diff --git a/sailfish/qml/pages/VideoPage.qml b/sailfish/qml/pages/VideoPage.qml index 9a3666c..d384c21 100644 --- a/sailfish/qml/pages/VideoPage.qml +++ b/sailfish/qml/pages/VideoPage.qml @@ -38,7 +38,16 @@ Page { property int subtitleTrack property bool resume: true - allowedOrientations: Orientation.All + allowedOrientations: { + if (itemData.width !== null && itemData.height !== null) { + return itemData.width / itemData.height > Screen.width / Screen.height + ? Orientation.LandscapeMask + : Orientation.PortraitMask + } else { + return Orientation.All + } + } + showNavigationIndicator: videoPlayer.hudVisible VideoPlayer { From 61a7eaf52e68284080fd7708c69f3aabaeb01903 Mon Sep 17 00:00:00 2001 From: Chris Josten Date: Wed, 11 Jan 2023 23:55:53 +0100 Subject: [PATCH 06/10] core: emit signals when playbackmanager changed --- core/src/model/remotejellyfinplayback.cpp | 13 ++++++++++--- core/src/viewmodel/playbackmanager.cpp | 10 ++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/core/src/model/remotejellyfinplayback.cpp b/core/src/model/remotejellyfinplayback.cpp index 1734423..6e673a7 100644 --- a/core/src/model/remotejellyfinplayback.cpp +++ b/core/src/model/remotejellyfinplayback.cpp @@ -49,7 +49,7 @@ RemoteJellyfinPlayback::~RemoteJellyfinPlayback() { } PlayerState RemoteJellyfinPlayback::playbackState() const { - return m_lastSessionInfo.has_value() + return m_lastSessionInfo.has_value() && !m_lastSessionInfo->nowPlayingItem().isNull() ? m_lastSessionInfo.value().playState()->isPaused() ? PlayerState::Paused : PlayerState::Playing @@ -149,6 +149,12 @@ void RemoteJellyfinPlayback::goTo(int index) { void RemoteJellyfinPlayback::stop() { sendPlaystateCommand(DTO::PlaystateCommand::Stop); + // Force update the UI, since the server will stop sending updates for some reason + /*if (m_lastSessionInfo.has_value()) { + m_lastSessionInfo->playState().clear(); + m_lastSessionInfo->nowPlayingItem().clear(); + onSessionInfoUpdated(m_sessionId, m_lastSessionInfo.value()); + }*/ } void RemoteJellyfinPlayback::seek(qint64 pos) { @@ -162,7 +168,6 @@ void RemoteJellyfinPlayback::onPositionTimerFired() { void RemoteJellyfinPlayback::onSessionInfoUpdated(const QString &sessionId, const SessionInfo &sessionInfo) { if (sessionId != m_sessionId) return; - qDebug() << "Session info updated for " << sessionId; m_lastSessionInfo = sessionInfo; if (m_lastSessionInfo->nowPlayingItem().isNull()) { @@ -174,7 +179,9 @@ void RemoteJellyfinPlayback::onSessionInfoUpdated(const QString &sessionId, cons // Update current position and run timer if needed if (m_lastSessionInfo.has_value() - && !m_lastSessionInfo.value().playState().isNull()) { + && !m_lastSessionInfo.value().playState().isNull() + // Apparently the nowPlayingItem should be null when the playback has stopped + && !m_lastSessionInfo.value().nowPlayingItem().isNull()) { m_position = m_lastSessionInfo.value().playState()->positionTicks().value_or(0) / PlaybackManager::MS_TICK_FACTOR; if (!m_positionTimer->isActive() && !m_lastSessionInfo.value().playState()->isPaused()) { m_positionTimer->start(); diff --git a/core/src/viewmodel/playbackmanager.cpp b/core/src/viewmodel/playbackmanager.cpp index b1912ef..d8e4303 100644 --- a/core/src/viewmodel/playbackmanager.cpp +++ b/core/src/viewmodel/playbackmanager.cpp @@ -195,13 +195,21 @@ void PlaybackManager::setControllingSession(QSharedPointerm_impl.data(), &Model::PlaybackManager::positionChanged, this, &PlaybackManager::positionChanged); + emit positionChanged(d->m_impl->position()); connect(d->m_impl.data(), &Model::PlaybackManager::durationChanged, this, &PlaybackManager::durationChanged); + emit durationChanged(d->m_impl->duration()); connect(d->m_impl.data(), &Model::PlaybackManager::hasNextChanged, this, &PlaybackManager::hasNextChanged); + emit hasNextChanged(d->m_impl->hasNext()); connect(d->m_impl.data(), &Model::PlaybackManager::hasPreviousChanged, this, &PlaybackManager::hasPreviousChanged); + emit hasPreviousChanged(d->m_impl->hasPrevious()); connect(d->m_impl.data(), &Model::PlaybackManager::seekableChanged, this, &PlaybackManager::seekableChanged); + emit seekableChanged(d->m_impl->seekable()); connect(d->m_impl.data(), &Model::PlaybackManager::queueIndexChanged, this, &PlaybackManager::queueIndexChanged); + emit queueIndexChanged(d->m_impl->queueIndex()); connect(d->m_impl.data(), &Model::PlaybackManager::itemChanged, this, &PlaybackManager::mediaPlayerItemChanged); + emit itemChanged(); connect(d->m_impl.data(), &Model::PlaybackManager::playbackStateChanged, this, &PlaybackManager::playbackStateChanged); + emit playbackStateChanged(d->m_impl->playbackState()); if (auto localImp = qobject_cast(d->m_impl.data())) { connect(localImp, &Model::LocalPlaybackManager::streamUrlChanged, this, [this](const QUrl& newUrl){ @@ -209,7 +217,9 @@ void PlaybackManager::setControllingSession(QSharedPointerm_impl.data(), &Model::PlaybackManager::mediaStatusChanged, this, &PlaybackManager::mediaStatusChanged); + emit mediaStatusChanged(d->m_impl->mediaStatus()); } } From 6ed623d0f84671bee66c5191efb705efcad4801c Mon Sep 17 00:00:00 2001 From: Chris Josten Date: Tue, 2 Jan 2024 00:19:13 +0100 Subject: [PATCH 07/10] core/RemoteJellyfinPlaybackManager: keep queue in sync The playback queue is now kept in sync with the playback queue of the remote jellyfin instance the manager is controlling. Some additional guards were added in place in the shuffle and playlist algorithm, since the situation can occur where the now playing index falls outside of the playing playlist. This happens because when the an playlist update is received, we need to do another HTTP request before we know which items are in the queue, while the now playing index has been updated. This is a not-optimal way to fix that, but it works well enough for now and a better solution can be implemented later. (Hello, person in the future reading the git blame output!) --- .gitignore | 1 + .../JellyfinQt/model/playbackmanager.h | 1 + .../JellyfinQt/model/remotejellyfinplayback.h | 11 +++ core/src/model/playbackmanager.cpp | 13 +++- core/src/model/playlist.cpp | 17 ++++- core/src/model/remotejellyfinplayback.cpp | 73 ++++++++++++++++++- core/src/model/shuffle.cpp | 8 +- 7 files changed, 114 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index ec1d4fe..77cd4f7 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ build-*/ # IDE files *.user CMakeLists.txt.user.* +compile_commands.json diff --git a/core/include/JellyfinQt/model/playbackmanager.h b/core/include/JellyfinQt/model/playbackmanager.h index 84c5e9a..03f6834 100644 --- a/core/include/JellyfinQt/model/playbackmanager.h +++ b/core/include/JellyfinQt/model/playbackmanager.h @@ -131,6 +131,7 @@ public: static const qint64 MS_TICK_FACTOR = 10000; protected: void setItem(QSharedPointer item); + void setQueueIndex(int index); signals: void playbackStateChanged(Jellyfin::Model::PlayerStateClass::Value newPlaybackState); diff --git a/core/include/JellyfinQt/model/remotejellyfinplayback.h b/core/include/JellyfinQt/model/remotejellyfinplayback.h index 292bbc0..835856c 100644 --- a/core/include/JellyfinQt/model/remotejellyfinplayback.h +++ b/core/include/JellyfinQt/model/remotejellyfinplayback.h @@ -75,6 +75,17 @@ private: void sendGeneralCommand(DTO::GeneralCommandType command, QJsonObject arguments = QJsonObject()); void sendCommand(Support::LoaderBase *loader); void playItemInList(const QStringList &items, int index, qint64 resumeTicks = -1); + /** + * @brief isQueueSame Checks if the items in the list are the same as in the queue + * @param items The item ids to compare to the queue + * @return True if the same, otherwise false + */ + bool isQueueSame(QList itemIds); + /** + * Updates the now playing queue, with the given items + * @param itemIds The item ids to load + */ + void updateQueue(QList itemIds); ApiClient &m_apiClient; QString m_sessionId; std::optional m_lastSessionInfo; diff --git a/core/src/model/playbackmanager.cpp b/core/src/model/playbackmanager.cpp index 5ed84e6..50a7e4c 100644 --- a/core/src/model/playbackmanager.cpp +++ b/core/src/model/playbackmanager.cpp @@ -203,6 +203,13 @@ void PlaybackManager::setItem(QSharedPointer item) { emit itemChanged(); } +void PlaybackManager::setQueueIndex(int index) +{ + Q_D(PlaybackManager); + d->m_queueIndex = index; + emit queueIndexChanged(index); +} + /***************************************************************************** * LocalPlaybackManagerPrivate * *****************************************************************************/ @@ -611,9 +618,8 @@ void LocalPlaybackManager::playItemInList(const QListm_queue->clearList(); d->m_queue->appendToList(items); d->m_queue->play(index); - d->m_queueIndex = index; - emit queueIndexChanged(d->m_queueIndex); + setQueueIndex(index); d->setItem(items.at(index)); emit hasNextChanged(d->m_queue->hasNext()); @@ -624,8 +630,7 @@ void LocalPlaybackManager::playItemInList(const QListm_queue->play(index); - d->m_queueIndex = index; - emit queueIndexChanged(index); + setQueueIndex(index); d->setItem(d->m_queue->currentItem()); emit hasNextChanged(d->m_queue->hasNext()); diff --git a/core/src/model/playlist.cpp b/core/src/model/playlist.cpp index ce9e899..cbfbbcd 100644 --- a/core/src/model/playlist.cpp +++ b/core/src/model/playlist.cpp @@ -180,17 +180,28 @@ void Playlist::reshuffle() { } void Playlist::play(int index) { + // We need to defend against indices that are outside of the playlist. + // The RemoteJellyfinPlaybackController will usually first update the now playing index + // before this playlist is updated. For example, if new playlist is bigger than + // the current and an item index out of range of the current playlist is requested. + m_shuffler->setIndex(index); if (!m_nextItemFromQueue) { int nextItemIdx = m_shuffler->nextItem(); if (nextItemIdx >= 0) { - m_nextItem = m_list[m_shuffler->nextItem()]; + m_nextItem = m_list[nextItemIdx]; } else { m_nextItem.clear(); } } - m_currentItem = m_list[m_shuffler->currentItem()]; - emit currentItemChanged(); + + if (m_shuffler->currentItem() >= 0) { + m_currentItem = m_list[m_shuffler->currentItem()]; + emit currentItemChanged(); + } else { + m_currentItem.clear(); + emit currentItemChanged(); + } } bool Playlist::playingFromQueue() const { diff --git a/core/src/model/remotejellyfinplayback.cpp b/core/src/model/remotejellyfinplayback.cpp index 6e673a7..ac45c47 100644 --- a/core/src/model/remotejellyfinplayback.cpp +++ b/core/src/model/remotejellyfinplayback.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -33,6 +34,7 @@ namespace Jellyfin { namespace Model { + RemoteJellyfinPlayback::RemoteJellyfinPlayback(ApiClient &apiClient, QString sessionId, QObject *parent) : PlaybackManager(parent), m_apiClient(apiClient), m_sessionId(sessionId), m_positionTimer(new QTimer(this)) { setApiClient(&m_apiClient); @@ -144,7 +146,8 @@ void RemoteJellyfinPlayback::next() { } void RemoteJellyfinPlayback::goTo(int index) { - + // This is the way Jellyfin does it as well: we send the entire queue to the server. + this->playItemInList(this->queue()->queueAndList(), index); } void RemoteJellyfinPlayback::stop() { @@ -193,6 +196,24 @@ void RemoteJellyfinPlayback::onSessionInfoUpdated(const QString &sessionId, cons m_position = 0; } + + // Handle the now playing queue + if (sessionInfo.nowPlayingQueueNull()) { + queue()->clearList(); + } else { + QList sessionQueue = sessionInfo.nowPlayingQueue(); + updateQueue(sessionQueue); + + int pos = 0; + for (pos = 0; pos < sessionQueue.size(); pos++) { + if (sessionQueue[pos].playlistItemId() == sessionInfo.playlistItemId()) break; + } + this->setQueueIndex(pos); + if (this->queue()->listSize() > 0) { + this->queue()->play(pos); + } + } + emit playbackStateChanged(playbackState()); emit durationChanged(duration()); emit positionChanged(position()); @@ -261,6 +282,56 @@ void RemoteJellyfinPlayback::playItemInList(const QStringList &items, int index, sendCommand(loader); } +bool RemoteJellyfinPlayback::isQueueSame(QList itemIds) { + Playlist *queue = this->queue(); + if (itemIds.length() == queue->listSize()) { + for (int i = 0; i < itemIds.length(); i++) { + if (queue->listAt(i)->jellyfinId() != itemIds[i].jellyfinId()) { + return false; + } + } + return true; + } else { + return false; + } +} + +void RemoteJellyfinPlayback::updateQueue(QList items) { + using GetItemsLoader = Loader::HTTP::GetItemsLoader; + using GetItemsParams = Loader::GetItemsParams; + + static GetItemsLoader *loader = new GetItemsLoader(&this->m_apiClient); + + if (!isQueueSame(items)) { + // Update queue + + QStringList itemIds; + for (QueueItem queueItem : items) { + itemIds.append(queueItem.jellyfinId()); + } + + if (loader->isRunning()) { + loader->cancel(); + } + + GetItemsParams params; + params.setIds(itemIds); + loader->setParameters(params); + connect(loader, &GetItemsLoader::ready, this, [this]() { + auto queue = this->queue(); + Loader::BaseItemDtoQueryResult result = loader->result(); + QList> items; + for (Item item : result.items()) { + items.append(QSharedPointer::create(item, &this->m_apiClient)); + } + + queue->clearList(); + queue->appendToList(items); + }); + loader->load(); + } +} + } // NS Model } // NS Jellyfin diff --git a/core/src/model/shuffle.cpp b/core/src/model/shuffle.cpp index f9aa1b7..cc6d23e 100644 --- a/core/src/model/shuffle.cpp +++ b/core/src/model/shuffle.cpp @@ -80,7 +80,7 @@ int NoShuffle::nextIndex() const { return (m_index + 1) % m_playlist->listSize(); } else { if (m_index + 1 >= m_playlist->listSize()) { - return 0; + return -1; } else { return m_index + 1; } @@ -88,7 +88,11 @@ int NoShuffle::nextIndex() const { } void NoShuffle::setIndex(int i) { - m_index = i; + if (i >= 0 && i < m_playlist->listSize()) { + m_index = i; + } else { + m_index = -1; + } } // ListShuffleBase From 1b27847c94ebee68a7af4a6c6f487074155a7564 Mon Sep 17 00:00:00 2001 From: Chris Josten Date: Tue, 2 Jan 2024 13:02:59 +0100 Subject: [PATCH 08/10] core/RemoteJellyfinPlaybackManager: send media source id If the mediaSourceId is not sent, Jellyfin Web will simply not take the audioStreamIndex and subtitleStreamIndex in account when playing the media. A bug also surfaced where the application would crash when playing a video, playing audio afterwards and then clicking on an item in the now playing queue. This has also been fixed. --- core/src/model/remotejellyfinplayback.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core/src/model/remotejellyfinplayback.cpp b/core/src/model/remotejellyfinplayback.cpp index ac45c47..213cc12 100644 --- a/core/src/model/remotejellyfinplayback.cpp +++ b/core/src/model/remotejellyfinplayback.cpp @@ -119,7 +119,12 @@ void RemoteJellyfinPlayback::playItemInList(const QList > & } if (this->resumePlayback()) { - this->playItemInList(itemIds, index, items.at(index)->userData()->playbackPositionTicks()); + QSharedPointer userData = items.at(index)->userData(); + if (userData) { + this->playItemInList(itemIds, index, items.at(index)->userData()->playbackPositionTicks()); + } else { + this->playItemInList(itemIds, index, 0); + } } else { this->playItemInList(itemIds, index); } @@ -271,6 +276,7 @@ void RemoteJellyfinPlayback::playItemInList(const QStringList &items, int index, } params.setPlayCommand(DTO::PlayCommand::PlayNow); params.setItemIds(items); + params.setMediaSourceId(items.at(index)); params.setStartIndex(index); params.setAudioStreamIndex(this->audioIndex()); if (this->subtitleIndex() >= 0) { From 9266f65c2f9e5233ba8e415b415e78252a5ab890 Mon Sep 17 00:00:00 2001 From: Chris Josten Date: Tue, 2 Jan 2024 15:14:23 +0100 Subject: [PATCH 09/10] Guess device icons Device icons for the local device is now determined by looking at what the value of the deviceType property of the ApiClient is. This property was newly introduced, so that applications using JellyfinQt can set their own device type. For other devices, a guess is made based on the client name. This guess has been derived from what Jellyfin Web does. --- core/include/JellyfinQt/apiclient.h | 6 +++ core/src/apiclient.cpp | 12 +++++ core/src/model/controllablesession.cpp | 49 ++++++++++++++++--- core/src/model/playbackmanager.cpp | 12 +++-- core/src/viewmodel/playbackmanager.cpp | 4 ++ sailfish/qml/harbour-sailfin.qml | 1 + .../qml/pages/ControllableDevicesPage.qml | 14 +++++- 7 files changed, 86 insertions(+), 12 deletions(-) diff --git a/core/include/JellyfinQt/apiclient.h b/core/include/JellyfinQt/apiclient.h index d5cbbe6..00175df 100644 --- a/core/include/JellyfinQt/apiclient.h +++ b/core/include/JellyfinQt/apiclient.h @@ -41,6 +41,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include "dto/generalcommandtype.h" #include "credentialmanager.h" +#include "model/controllablesession.h" #include "model/deviceprofile.h" #include "eventbus.h" @@ -97,6 +98,7 @@ public: virtual ~ApiClient(); Q_PROPERTY(QString baseUrl READ baseUrl WRITE setBaseUrl NOTIFY baseUrlChanged) Q_PROPERTY(QString appName READ appName WRITE setAppName NOTIFY appNameChanged) + Q_PROPERTY(Jellyfin::Model::DeviceTypeClass::Value deviceType READ deviceType WRITE setDeviceType NOTIFY deviceTypeChanged) Q_PROPERTY(bool authenticated READ authenticated WRITE setAuthenticated NOTIFY authenticatedChanged) Q_PROPERTY(QString userId READ userId NOTIFY userIdChanged) Q_PROPERTY(QJsonObject deviceProfile READ deviceProfileJson NOTIFY deviceProfileChanged) @@ -116,6 +118,8 @@ public: bool authenticated() const; void setBaseUrl(const QString &url); void setAppName(const QString &appName); + void setDeviceType(Model::DeviceType deviceType); + QNetworkReply *get(const QString &path, const QUrlQuery ¶ms = QUrlQuery()); QNetworkReply *post(const QString &path, const QJsonDocument &data, const QUrlQuery ¶ms = QUrlQuery()); QNetworkReply *post(const QString &path, const QByteArray &data = QByteArray(), const QUrlQuery ¶ms = QUrlQuery()); @@ -132,6 +136,7 @@ public: const QString &appName() const; const QString &userId() const; const QString &deviceId() const; + Model::DeviceType deviceType() const; /** * @brief QML applications can set this type to indicate which commands they support. * @@ -200,6 +205,7 @@ signals: void userIdChanged(QString userId); void deviceProfileChanged(); + void deviceTypeChanged(); void supportedCommandsChanged(); void onlineChanged(); diff --git a/core/src/apiclient.cpp b/core/src/apiclient.cpp index b607a0a..b69f3b5 100644 --- a/core/src/apiclient.cpp +++ b/core/src/apiclient.cpp @@ -47,6 +47,7 @@ public: QString appName; QString deviceName; QString deviceId; + Model::DeviceType deviceType = Model::DeviceType::Unknown; QString userId; bool online = true; @@ -135,6 +136,17 @@ const QString &ApiClient::deviceId() const { return d->deviceId; } +Model::DeviceType ApiClient::deviceType() const { + Q_D(const ApiClient); + return d->deviceType; +} + +void ApiClient::setDeviceType(Model::DeviceType newDeviceType) { + Q_D(ApiClient); + d->deviceType =newDeviceType; + emit deviceTypeChanged(); +} + EventBus *ApiClient::eventbus() const { Q_D(const ApiClient); return d->eventbus; diff --git a/core/src/model/controllablesession.cpp b/core/src/model/controllablesession.cpp index 275fcd0..a1b3b70 100644 --- a/core/src/model/controllablesession.cpp +++ b/core/src/model/controllablesession.cpp @@ -32,11 +32,11 @@ QString LocalSession::name() const { } DeviceType LocalSession::deviceType() const { - return DeviceType::Unknown; + return m_apiClient.deviceType(); } QString LocalSession::userName() const { - return m_apiClient.userId(); + return QString(); //m_apiClient.userId(); } PlaybackManager *LocalSession::createPlaybackManager() const { @@ -64,7 +64,42 @@ QString ControllableJellyfinSession::name() const { } DeviceType ControllableJellyfinSession::deviceType() const { - return DeviceType::Unknown; + // This is surely not the best way + // I based this of https://github.com/jellyfin/jellyfin-web/blob/45793052fa7c854ec97133878c75937065ae4650/src/utils/image.ts + const QStringList tvDevices = { + "Samsung Smart TV", + "Xbox One", + "Sony PS4", + "Kodi", + "Kodi JellyCon", + "AndroidTV", + "Android TV", + "Infuse", + "Jellyfin Roku", + "DLNA" + }; + + const QStringList pcDevices = { + "Jellyfin Web", + }; + + const QStringList phoneDevices = { + "FinAmp", + "Jellyfin Mobile (iOS)", + "Jellyfin Mobile (iPadOS)", + "Jellyfin Android", + "Sailfin" + }; + + if (tvDevices.contains(m_data->client())) { + return DeviceType::Tv; + } else if (pcDevices.contains(m_data->client())) { + return DeviceType::Computer; + } else if (phoneDevices.contains(m_data->client())) { + return DeviceType::Phone; + } else { + return DeviceType::Unknown; + } } QString ControllableJellyfinSession::userName() const { @@ -101,21 +136,23 @@ void RemoteJellyfinSessionScanner::startScanning() { Q_D(RemoteJellyfinSessionScanner); if (d->loader != nullptr) return; + LocalSession *localSession = new LocalSession(*d->apiClient); + emit resetSessions(); - emit sessionFound(new LocalSession(*d->apiClient)); + emit sessionFound(localSession); Loader::GetSessionsParams params; params.setControllableByUserId(d->apiClient->userId()); d->loader = new GetSessionsLoader(d->apiClient); d->loader->setParameters(params); - connect(d->loader, &Loader::HTTP::GetSessionsLoader::ready, this, [this, d]() { + connect(d->loader, &Loader::HTTP::GetSessionsLoader::ready, this, [this, d, localSession]() { if (d->loader == nullptr) return; QList sessions = d->loader->result(); for(auto it = sessions.begin(); it != sessions.end(); it++) { // Skip this device - if (it->jellyfinId() == d->apiClient->deviceId()) continue; + if (it->deviceId() == localSession->id()) continue; emit sessionFound(new ControllableJellyfinSession(QSharedPointer::create(*it), *d->apiClient)); } diff --git a/core/src/model/playbackmanager.cpp b/core/src/model/playbackmanager.cpp index 50a7e4c..5bd254c 100644 --- a/core/src/model/playbackmanager.cpp +++ b/core/src/model/playbackmanager.cpp @@ -155,11 +155,13 @@ int PlaybackManager::queueIndex() const { void PlaybackManager::swap(PlaybackManager &other) { other.queue()->clearList(); - other.queue()->appendToList(this->queue()->queueAndList()); - other.playItemInList(this->queue()->queueAndList(), this->queue()->currentItemIndexInList() >= 0 - ? this->queue()->currentItemIndexInList() - : 0); - other.seek(position()); + if (other.queue()->listSize() > 0) { + other.queue()->appendToList(this->queue()->queueAndList()); + other.playItemInList(this->queue()->queueAndList(), this->queue()->currentItemIndexInList() >= 0 + ? this->queue()->currentItemIndexInList() + : 0); + other.seek(position()); + } } void PlaybackManager::playItemId(const QString &id) {} diff --git a/core/src/viewmodel/playbackmanager.cpp b/core/src/viewmodel/playbackmanager.cpp index d8e4303..eb14dce 100644 --- a/core/src/viewmodel/playbackmanager.cpp +++ b/core/src/viewmodel/playbackmanager.cpp @@ -182,8 +182,12 @@ void PlaybackManager::setControllingSession(QSharedPointerm_impl->stop(); + if (other != nullptr) { + d->m_impl->swap(*other); + } } } + d->m_displayQueue->setPlaylistModel(other->queue()); d->m_impl.reset(other); d->m_session.swap(session); diff --git a/sailfish/qml/harbour-sailfin.qml b/sailfish/qml/harbour-sailfin.qml index d02a233..e11fc55 100644 --- a/sailfish/qml/harbour-sailfin.qml +++ b/sailfish/qml/harbour-sailfin.qml @@ -51,6 +51,7 @@ ApplicationWindow { id: _apiClient objectName: "Test" appName: "Sailfin" + deviceType: DeviceType.Phone supportedCommands: [GeneralCommandType.Play, GeneralCommandType.DisplayMessage] } diff --git a/sailfish/qml/pages/ControllableDevicesPage.qml b/sailfish/qml/pages/ControllableDevicesPage.qml index a6ec9cf..082c3ef 100644 --- a/sailfish/qml/pages/ControllableDevicesPage.qml +++ b/sailfish/qml/pages/ControllableDevicesPage.qml @@ -34,7 +34,19 @@ Page { } height: parent.contentHeight - 2 * Theme.paddingMedium width: height - source: "image://theme/icon-m-computer" + source: { + if (model.deviceType == J.DeviceType.Phone) { + return "image://theme/icon-m-device" + } else if (model.deviceType == J.DeviceType.Tv) { + // For the lack of a better icon + return "image://theme/icon-m-device-landscape" + } else if (model.deviceType == J.DeviceType.Computer) { + return "image://theme/icon-m-computer" + } else { + //case J.DeviceType.Unknown: + return "image://theme/icon-m-question" + } + } highlighted: parent.down || isConnected } Column { From f0328e2c801d8fc409e370ca6da51c1079ba77cd Mon Sep 17 00:00:00 2001 From: Chris Josten Date: Tue, 2 Jan 2024 15:23:39 +0100 Subject: [PATCH 10/10] Update changelog --- rpm/harbour-sailfin.changes | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rpm/harbour-sailfin.changes b/rpm/harbour-sailfin.changes index 365b893..9df3a05 100644 --- a/rpm/harbour-sailfin.changes +++ b/rpm/harbour-sailfin.changes @@ -14,6 +14,8 @@ # * Future version Chris Josten 0.??.??-1 - New features + - Allow remote controlling other Jellyfin clients. See the pulley item on the main screen named + "Remote Control" - New layout for artist pages - New layout for the music library - New layout for playlist pages