1
0
Fork 0
mirror of https://github.com/HenkKalkwater/harbour-sailfin.git synced 2025-09-04 01:42:44 +00:00

core: remote playback send commands and update state

This commit is contained in:
Chris Josten 2023-01-04 21:32:27 +01:00
parent 77cb5d5957
commit 7a7ddc7717
18 changed files with 371 additions and 91 deletions

View file

@ -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.

View file

@ -105,7 +105,7 @@ private:
class ControllableJellyfinSession : public ControllableSession {
Q_OBJECT
public:
ControllableJellyfinSession(QSharedPointer<DTO::SessionInfo> info, QObject *parent = nullptr);
ControllableJellyfinSession(QSharedPointer<DTO::SessionInfo> 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<DTO::SessionInfo> m_data;
ApiClient &m_apiClient;
};
/**

View file

@ -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<QSharedPointer<Model::Item>> &items, int index) = 0;
static const qint64 MS_TICK_FACTOR = 10000;
protected:
void setItem(QSharedPointer<Item> 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;

View file

@ -72,6 +72,11 @@ public:
*/
void next();
/**
* @brief Returns all items in the queue
*/
QList<QSharedPointer<Item>> 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(); }

View file

@ -20,10 +20,17 @@
#define JELLYFIN_MODEL_REMOTEJELLYFINPLAYBACK_H
#include <JellyfinQt/dto/generalcommandtype.h>
#include <JellyfinQt/dto/playcommand.h>
#include <JellyfinQt/dto/playstatecommand.h>
#include <JellyfinQt/dto/sessioninfo.h>
#include <JellyfinQt/model/playbackmanager.h>
#include <JellyfinQt/support/loader.h>
#include <QJsonObject>
#include <QSharedPointer>
#include <QTimer>
#include <optional>
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<DTO::SessionInfo> m_lastSessionInfo;
QTimer *m_positionTimer;
qint64 m_position = 0;
};

View file

@ -155,6 +155,8 @@ QString toString(const T &source, convertType<T>) {
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();

View file

@ -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<typename HttpLoader<R, P>::ResultType, // Result
HttpLoader<R, P>, // class

View file

@ -71,6 +71,7 @@ public:
QVariant data(const QModelIndex &parent, int role = Qt::DisplayRole) const override;
int rowCount(const QModelIndex &parent) const override;
QHash<int, QByteArray> roleNames() const override;
void setPlaylistModel(Model::Playlist *data);
private slots:

View file

@ -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);