From 895731ae383d7be71e436c4999f75b314985f933 Mon Sep 17 00:00:00 2001 From: Chris Josten Date: Wed, 17 Feb 2021 19:42:10 +0100 Subject: [PATCH] Big C++ refractor - Removed "jellyfin" prefix from files, as they are already in a directory named Jellyfin - Split the former "jellyfinitem.{h,cpp}" into multiple files in the DTO directory, one for each class. The jellyfinitem files started to become enormous. - Use forward declarations in headers instead of including files wherever possible. - Updated copyright headers --- CMakeLists.txt | 4 +- core/CMakeLists.txt | 52 ++-- core/include/JellyfinQt/DTO/dto.h | 167 ++++++++++ .../JellyfinQt/{jellyfinitem.h => DTO/item.h} | 290 +----------------- core/include/JellyfinQt/DTO/mediastream.h | 74 +++++ core/include/JellyfinQt/DTO/namedguidpair.h | 50 +++ core/include/JellyfinQt/DTO/types.h | 41 +++ core/include/JellyfinQt/DTO/user.h | 61 ++++ core/include/JellyfinQt/DTO/userdata.h | 83 +++++ .../{jellyfinapiclient.h => apiclient.h} | 15 +- .../{jellyfinapimodel.h => apimodel.h} | 10 +- core/include/JellyfinQt/credentialmanager.h | 2 +- ...ellyfindeviceprofile.h => deviceprofile.h} | 2 +- core/include/JellyfinQt/jellyfin.h | 35 ++- core/include/JellyfinQt/jsonhelper.h | 18 ++ ...finplaybackmanager.h => playbackmanager.h} | 19 +- .../include/JellyfinQt/serverdiscoverymodel.h | 2 +- .../{jellyfinwebsocket.h => websocket.h} | 8 +- core/src/{jellyfinitem.cpp => DTO/dto.cpp} | 128 +------- core/src/DTO/item.cpp | 63 ++++ core/src/DTO/mediastream.cpp | 43 +++ core/src/DTO/namedguidpair.cpp | 27 ++ core/src/DTO/types.cpp | 36 +++ core/src/DTO/user.cpp | 36 +++ core/src/DTO/userdata.cpp | 58 ++++ .../{jellyfinapiclient.cpp => apiclient.cpp} | 6 +- .../{jellyfinapimodel.cpp => apimodel.cpp} | 8 +- core/src/credentialmanager.cpp | 2 +- ...findeviceprofile.cpp => deviceprofile.cpp} | 4 +- core/src/jellyfin.cpp | 4 +- core/src/jsonhelper.cpp | 3 +- ...laybackmanager.cpp => playbackmanager.cpp} | 15 +- core/src/serverdiscoverymodel.cpp | 2 +- .../{jellyfinwebsocket.cpp => websocket.cpp} | 9 +- 34 files changed, 914 insertions(+), 463 deletions(-) create mode 100644 core/include/JellyfinQt/DTO/dto.h rename core/include/JellyfinQt/{jellyfinitem.h => DTO/item.h} (59%) create mode 100644 core/include/JellyfinQt/DTO/mediastream.h create mode 100644 core/include/JellyfinQt/DTO/namedguidpair.h create mode 100644 core/include/JellyfinQt/DTO/types.h create mode 100644 core/include/JellyfinQt/DTO/user.h create mode 100644 core/include/JellyfinQt/DTO/userdata.h rename core/include/JellyfinQt/{jellyfinapiclient.h => apiclient.h} (98%) rename core/include/JellyfinQt/{jellyfinapimodel.h => apimodel.h} (98%) rename core/include/JellyfinQt/{jellyfindeviceprofile.h => deviceprofile.h} (97%) rename core/include/JellyfinQt/{jellyfinplaybackmanager.h => playbackmanager.h} (93%) rename core/include/JellyfinQt/{jellyfinwebsocket.h => websocket.h} (96%) rename core/src/{jellyfinitem.cpp => DTO/dto.cpp} (70%) create mode 100644 core/src/DTO/item.cpp create mode 100644 core/src/DTO/mediastream.cpp create mode 100644 core/src/DTO/namedguidpair.cpp create mode 100644 core/src/DTO/types.cpp create mode 100644 core/src/DTO/user.cpp create mode 100644 core/src/DTO/userdata.cpp rename core/src/{jellyfinapiclient.cpp => apiclient.cpp} (98%) rename core/src/{jellyfinapimodel.cpp => apimodel.cpp} (98%) rename core/src/{jellyfindeviceprofile.cpp => deviceprofile.cpp} (99%) rename core/src/{jellyfinplaybackmanager.cpp => playbackmanager.cpp} (97%) rename core/src/{jellyfinwebsocket.cpp => websocket.cpp} (96%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 07b2e47..b811080 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,8 +6,8 @@ set(CMAKE_AUTOMOC ON) cmake_policy(SET CMP0048 NEW) # Options -option(PLATFORM_SAILFISHOS "Build SailfishOS version of application") -option(PLATFORM_QTQUICK "Build QtQuick version of application") +option(PLATFORM_SAILFISHOS "Build SailfishOS version of application" OFF) +option(PLATFORM_QTQUICK "Build QtQuick version of application" ON) if(PLATFORM_SAILFISHOS) # Hardcode this less? diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 83f2aaa..e133832 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -3,28 +3,40 @@ find_package(Qt5 5.6 COMPONENTS Multimedia Network Qml WebSockets REQUIRED) include(GNUInstallDirs) set(jellyfin-qt_SOURCES - src/credentialmanager.cpp - src/jellyfin.cpp - src/jellyfinapiclient.cpp - src/jellyfinapimodel.cpp - src/jellyfindeviceprofile.cpp - src/jellyfinitem.cpp - src/jellyfinplaybackmanager.cpp - src/jellyfinwebsocket.cpp - src/jsonhelper.cpp - src/serverdiscoverymodel.cpp) + src/DTO/dto.cpp + src/DTO/item.cpp + src/DTO/namedguidpair.cpp + src/DTO/mediastream.cpp + src/DTO/types.cpp + src/DTO/user.cpp + src/DTO/userdata.cpp + src/apiclient.cpp + src/apimodel.cpp + src/credentialmanager.cpp + src/deviceprofile.cpp + src/jellyfin.cpp + src/jsonhelper.cpp + src/playbackmanager.cpp + src/serverdiscoverymodel.cpp + src/websocket.cpp) set(jellyfin-qt_HEADERS - include/JellyfinQt/credentialmanager.h - include/JellyfinQt/jellyfin.h - include/JellyfinQt/jellyfinapiclient.h - include/JellyfinQt/jellyfinapimodel.h - include/JellyfinQt/jellyfindeviceprofile.h - include/JellyfinQt/jellyfinitem.h - include/JellyfinQt/jellyfinplaybackmanager.h - include/JellyfinQt/jellyfinwebsocket.h - include/JellyfinQt/jsonhelper.h - include/JellyfinQt/serverdiscoverymodel.h) + include/JellyfinQt/DTO/dto.h + include/JellyfinQt/DTO/item.h + include/JellyfinQt/DTO/mediastream.h + include/JellyfinQt/DTO/namedguidpair.h + include/JellyfinQt/DTO/types.h + include/JellyfinQt/DTO/userdata.h + include/JellyfinQt/DTO/user.h + include/JellyfinQt/apiclient.h + include/JellyfinQt/apimodel.h + include/JellyfinQt/credentialmanager.h + include/JellyfinQt/deviceprofile.h + include/JellyfinQt/jellyfin.h + include/JellyfinQt/jsonhelper.h + include/JellyfinQt/playbackmanager.h + include/JellyfinQt/serverdiscoverymodel.h + include/JellyfinQt/websocket.h) add_definitions(-DSAILFIN_VERSION=\"${SAILFIN_VERSION}\") if (PLATFORM_SAILFISHOS) diff --git a/core/include/JellyfinQt/DTO/dto.h b/core/include/JellyfinQt/DTO/dto.h new file mode 100644 index 0000000..1118b75 --- /dev/null +++ b/core/include/JellyfinQt/DTO/dto.h @@ -0,0 +1,167 @@ +/* +Sailfin: a Jellyfin client written using Qt +Copyright (C) 2021 Chris Josten + +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_DTO_DTO +#define JELLYFIN_DTO_DTO + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../apiclient.h" +#include "../jsonhelper.h" + +namespace Jellyfin { +namespace DTO { +/** + * @brief Base class for a serializable object. + * + * This class will be (de)serialized based on its properties. + * Note: it must have a constructor without arguments marked with Q_INVOKABLE + */ +class JsonSerializable : public QObject { + Q_OBJECT +public: + Q_INVOKABLE JsonSerializable(QObject *parent); + + /** + * @brief Sets this objects properties based on obj. + * @param obj The data to load into this object. + */ + void deserialize(const QJsonObject &obj); + QJsonObject serialize(bool capitalize = true) const; +private: + QVariant jsonToVariant(QMetaProperty prop, const QJsonValue &val, const QJsonObject &root); + QJsonValue variantToJson(const QVariant var) const; + QVariant deserializeQobject(const QJsonObject &obj, const QMetaProperty &prop); + + /** + * @brief Sets the first letter of the string to lower case (to make it camelCase). + * @param str The string to modify + * @return THe modified string + */ + static QString fromPascalCase(QString str); + /** + * @brief Sets the first letter of the string to uper case (to make it PascalCase). + * @param str The string to modify + * @return THe modified string + */ + static QString toPascalCase(QString st); + + static const QRegularExpression m_listExpression; + /** + * @brief Qt is doing weird. I'll keep track of the metatypes myself. + */ + QHash m_nameMetatypeMap; +}; + + +/** + * @brief An "interface" for a remote data source + * + * This class is basically a base class for JSON data that can be fetched from over the network. + * Subclasses should reimplement reload and call setStatus to update the QML part of the code + * appropiatly. + */ +class RemoteData : public JsonSerializable { + Q_OBJECT +public: + enum Status { + /// The data is unitialized and not loading either. + Uninitialised, + /// The data is being loaded over the network + Loading, + /// The data is ready, the properties in this object are up to date. + Ready, + /// An error has occurred while loading the data. See error() for more details. + Error + }; + Q_ENUM(Status) + + explicit RemoteData(QObject *parent = nullptr); + + Q_PROPERTY(ApiClient *apiClient MEMBER m_apiClient WRITE setApiClient NOTIFY apiClientChanged STORED false) + Q_PROPERTY(Status status READ status NOTIFY statusChanged STORED false) + Q_PROPERTY(QNetworkReply::NetworkError error READ error NOTIFY errorChanged STORED false) + Q_PROPERTY(QString errorString READ errorString NOTIFY errorStringChanged STORED false) + + Status status() const { return m_status; } + QNetworkReply::NetworkError error() const { return m_error; } + QString errorString() const { return m_errorString; } + + void setApiClient(ApiClient *newApiClient); +signals: + void statusChanged(Status newStatus); + void apiClientChanged(ApiClient *newApiClient); + void errorChanged(QNetworkReply::NetworkError newError); + void errorStringChanged(QString newErrorString); + /** + * @brief Convenience signal for status == RemoteData.Ready. + */ + void ready(); +public slots: + + /** + * @brief Overload this method to reimplement the fetching mechanism to + * populate the RemoteData with data from the server. + * + * The default implementation makes a GET request to getDataUrl() and parses the resulting JSON, + * which should be enough for most cases. Consider overriding getDataUrl() and + * canRelaod() if possible. Manual overrides need to make sure that + * they're calling setStatus(Status), setError(QNetworkReply::NetworkError) and + * setErrorString() to let the QML side know what this thing is up to. + */ + virtual void reload(); +protected: + /** + * @brief Subclasses should implement this to determine if they can + * load data from the server. + * + * Usage cases include checking if the + * required properties, such as the item id are set. + */ + virtual bool canReload() const = 0; + + /** + * @brief Construct the URL to fetch the data from. + * @return The URL to load data from. + */ + virtual QString getDataUrl() const = 0; + + void setStatus(Status newStatus); + void setError(QNetworkReply::NetworkError error); + void setErrorString(const QString &newErrorString); + ApiClient *m_apiClient = nullptr; +private: + Status m_status = Uninitialised; + QNetworkReply::NetworkError m_error = QNetworkReply::NoError; + QString m_errorString; +}; + +} // NS DTO +} // NS Jellyfin + +#endif // JELLYFIN_DTO_DTO_H diff --git a/core/include/JellyfinQt/jellyfinitem.h b/core/include/JellyfinQt/DTO/item.h similarity index 59% rename from core/include/JellyfinQt/jellyfinitem.h rename to core/include/JellyfinQt/DTO/item.h index eb9e322..999d81a 100644 --- a/core/include/JellyfinQt/jellyfinitem.h +++ b/core/include/JellyfinQt/DTO/item.h @@ -1,6 +1,6 @@ /* Sailfin: a Jellyfin client written using Qt -Copyright (C) 2020 Chris Josten +Copyright (C) 2021 Chris Josten This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -25,278 +25,23 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include #include -#include -#include -#include #include +#include +#include #include -#include -#include - -#include #include #include -#include "jellyfinapiclient.h" -#include "jsonhelper.h" +#include "dto.h" +#include "mediastream.h" +#include "namedguidpair.h" +#include "userdata.h" namespace Jellyfin { class ApiClient; -/** - * @brief Base class for a serializable object. - * - * This class will be (de)serialized based on its properties. - * Note: it must have a constructor without arguments marked with Q_INVOKABLE - */ -class JsonSerializable : public QObject { - Q_OBJECT -public: - Q_INVOKABLE JsonSerializable(QObject *parent); - - /** - * @brief Sets this objects properties based on obj. - * @param obj The data to load into this object. - */ - void deserialize(const QJsonObject &obj); - QJsonObject serialize(bool capitalize = true) const; -private: - QVariant jsonToVariant(QMetaProperty prop, const QJsonValue &val, const QJsonObject &root); - QJsonValue variantToJson(const QVariant var) const; - QVariant deserializeQobject(const QJsonObject &obj, const QMetaProperty &prop); - - /** - * @brief Sets the first letter of the string to lower case (to make it camelCase). - * @param str The string to modify - * @return THe modified string - */ - static QString fromPascalCase(QString str); - /** - * @brief Sets the first letter of the string to uper case (to make it PascalCase). - * @param str The string to modify - * @return THe modified string - */ - static QString toPascalCase(QString st); - - static const QRegularExpression m_listExpression; - /** - * @brief Qt is doing weird. I'll keep track of the metatypes myself. - */ - QHash m_nameMetatypeMap; -}; - - -/** - * @brief An "interface" for a remote data source - * - * This class is basically a base class for JSON data that can be fetched from over the network. - * Subclasses should reimplement reload and call setStatus to update the QML part of the code - * appropiatly. - */ -class RemoteData : public JsonSerializable { - Q_OBJECT -public: - enum Status { - /// The data is unitialized and not loading either. - Uninitialised, - /// The data is being loaded over the network - Loading, - /// The data is ready, the properties in this object are up to date. - Ready, - /// An error has occurred while loading the data. See error() for more details. - Error - }; - Q_ENUM(Status) - - explicit RemoteData(QObject *parent = nullptr); - - Q_PROPERTY(ApiClient *apiClient MEMBER m_apiClient WRITE setApiClient NOTIFY apiClientChanged STORED false) - Q_PROPERTY(Status status READ status NOTIFY statusChanged STORED false) - Q_PROPERTY(QNetworkReply::NetworkError error READ error NOTIFY errorChanged STORED false) - Q_PROPERTY(QString errorString READ errorString NOTIFY errorStringChanged STORED false) - - Status status() const { return m_status; } - QNetworkReply::NetworkError error() const { return m_error; } - QString errorString() const { return m_errorString; } - - void setApiClient(ApiClient *newApiClient); -signals: - void statusChanged(Status newStatus); - void apiClientChanged(ApiClient *newApiClient); - void errorChanged(QNetworkReply::NetworkError newError); - void errorStringChanged(QString newErrorString); - /** - * @brief Convenience signal for status == RemoteData.Ready. - */ - void ready(); -public slots: - - /** - * @brief Overload this method to reimplement the fetching mechanism to - * populate the RemoteData with data from the server. - * - * The default implementation makes a GET request to getDataUrl() and parses the resulting JSON, - * which should be enough for most cases. Consider overriding getDataUrl() and - * canRelaod() if possible. Manual overrides need to make sure that - * they're calling setStatus(Status), setError(QNetworkReply::NetworkError) and - * setErrorString() to let the QML side know what this thing is up to. - */ - virtual void reload(); -protected: - /** - * @brief Subclasses should implement this to determine if they can - * load data from the server. - * - * Usage cases include checking if the - * required properties, such as the item id are set. - */ - virtual bool canReload() const = 0; - - /** - * @brief Construct the URL to fetch the data from. - * @return The URL to load data from. - */ - virtual QString getDataUrl() const = 0; - - void setStatus(Status newStatus); - void setError(QNetworkReply::NetworkError error); - void setErrorString(const QString &newErrorString); - ApiClient *m_apiClient = nullptr; -private: - Status m_status = Uninitialised; - QNetworkReply::NetworkError m_error = QNetworkReply::NoError; - QString m_errorString; -}; - -class NameGuidPair : public JsonSerializable { - Q_OBJECT -public: - Q_INVOKABLE NameGuidPair(QObject *parent = nullptr); - Q_PROPERTY(QString name MEMBER m_name NOTIFY nameChanged) - // Once again the Jellyfin id workaround - Q_PROPERTY(QString jellyfinId MEMBER m_id NOTIFY jellyfinIdChanged) -signals: - void nameChanged(const QString &newName); - void jellyfinIdChanged(const QString &newJellyfinId); -private: - QString m_name; - QString m_id; -}; - -class User : public RemoteData { - Q_OBJECT -public: - Q_INVOKABLE User(QObject *parent = nullptr); - - Q_PROPERTY(QString userId MEMBER m_userId WRITE setUserId NOTIFY userIdChanged) - Q_PROPERTY(QString name MEMBER m_name NOTIFY nameChanged) - Q_PROPERTY(QString primaryImageTag MEMBER m_primaryImageTag NOTIFY primaryImageTagChanged) - - void setUserId(const QString &newUserId) { - this->m_userId = newUserId; - emit userIdChanged(newUserId); - reload(); - } -signals: - void userIdChanged(const QString &newUserId); - void nameChanged(const QString &newName); - void primaryImageTagChanged(const QString &newPrimaryImageTag); -protected: - QString getDataUrl() const override; - bool canReload() const override; -private: - QString m_userId; - QString m_name; - QString m_primaryImageTag; -}; - -class MediaStream : public JsonSerializable { - Q_OBJECT -public: - Q_INVOKABLE explicit MediaStream(QObject *parent = nullptr); - MediaStream(const MediaStream &other); - bool operator==(const MediaStream &other); - virtual ~MediaStream() { qDebug() << "MediaStream destroyed"; } - - enum MediaStreamType { - Undefined, - Audio, - Video, - Subtitle, - EmbeddedImage - }; - Q_ENUM(MediaStreamType) - - Q_PROPERTY(QString codec MEMBER m_codec NOTIFY codecChanged) - Q_PROPERTY(QString codecTag MEMBER m_codecTag NOTIFY codecTagChanged) - Q_PROPERTY(QString language MEMBER m_language NOTIFY languageChanged) - Q_PROPERTY(QString displayTitle MEMBER m_displayTitle NOTIFY displayTitleChanged) - Q_PROPERTY(MediaStreamType type MEMBER m_type NOTIFY typeChanged) - Q_PROPERTY(int index MEMBER m_index NOTIFY indexChanged) -signals: - void codecChanged(const QString &newCodec); - void codecTagChanged(const QString &newCodecTag); - void languageChanged(const QString &newLanguage); - void displayTitleChanged(const QString &newDisplayTitle); - void typeChanged(MediaStreamType newType); - void indexChanged(int newIndex); -private: - QString m_codec; - QString m_codecTag; - QString m_language; - QString m_displayTitle; - MediaStreamType m_type = Undefined; - int m_index = -1; -}; - -class UserData : public JsonSerializable { - Q_OBJECT -public: - Q_INVOKABLE explicit UserData(QObject *parent = nullptr); - - Q_PROPERTY(double playedPercentage READ playedPercentage WRITE setPlayedPercentage RESET resetPlayedPercentage NOTIFY playedPercentageChanged) - Q_PROPERTY(qint64 playbackPositionTicks READ playbackPositionTicks WRITE setPlaybackPositionTicks NOTIFY playbackPositionTicksChanged) - Q_PROPERTY(bool isFavorite READ isFavorite WRITE setIsFavorite NOTIFY isFavoriteChanged) - Q_PROPERTY(bool likes READ likes WRITE setLikes RESET resetLikes NOTIFY likesChanged) - Q_PROPERTY(bool played READ played WRITE setPlayed NOTIFY playedChanged) - Q_PROPERTY(QString itemId READ itemId MEMBER m_itemId); - - double playedPercentage() const { return m_playedPercentage.value_or(0.0); } - void setPlayedPercentage(double newPlayedPercentage) { m_playedPercentage = newPlayedPercentage; emit playedPercentageChanged(newPlayedPercentage); } - void resetPlayedPercentage() { m_playedPercentage = std::nullopt; emit playedPercentageChanged(0.0); updateOnServer(); } - - qint64 playbackPositionTicks() const { return m_playbackPositionTicks; } - void setPlaybackPositionTicks(qint64 newPlaybackPositionTicks) { m_playbackPositionTicks = newPlaybackPositionTicks; emit playbackPositionTicksChanged(newPlaybackPositionTicks); } - - bool played() const { return m_played; } - void setPlayed(bool newPlayed) { m_played = newPlayed; emit playedChanged(newPlayed); updateOnServer(); } - - bool likes() const { return m_likes.value_or(false); } - void setLikes(bool newLikes) { m_likes = newLikes; emit likesChanged(newLikes); } - void resetLikes() { m_likes = std::nullopt; emit likesChanged(false); updateOnServer(); } - - bool isFavorite() const { return m_isFavorite; } - void setIsFavorite(bool newIsFavorite) { m_isFavorite = newIsFavorite; emit isFavoriteChanged(newIsFavorite); updateOnServer(); } - - const QString &itemId() const { return m_itemId; } -signals: - void playedPercentageChanged(double newPlayedPercentage); - void playbackPositionTicksChanged(qint64 playbackPositionTicks); - void isFavoriteChanged(bool newIsFavorite); - void likesChanged(bool newLikes); - void playedChanged(bool newPlayed); -public slots: - void updateOnServer(); - void onUpdated(QSharedPointer other); -private: - std::optional m_playedPercentage = std::nullopt; - qint64 m_playbackPositionTicks = 0; - bool m_isFavorite = false; - std::optional m_likes = std::nullopt; - bool m_played; - QString m_itemId; -}; +namespace DTO { class Item : public RemoteData { Q_OBJECT @@ -527,24 +272,9 @@ protected: QString m_mediaType; int m_width; int m_height; - - template - QQmlListProperty toReadOnlyQmlListProperty(QList &list) { - return QQmlListProperty(this, std::addressof(list), &qlist_count, &qlist_at); - } - - template - static int qlist_count(QQmlListProperty *p) { - return reinterpret_cast *>(p->data)->count(); - } - - template - static T *qlist_at(QQmlListProperty *p, int idx) { - return reinterpret_cast *>(p->data)->at(idx); - } }; -void registerSerializableJsonTypes(const char* URI); -} +} // NS DTO +} // NS Jellyfin #endif // JELLYFIN_ITEM_H diff --git a/core/include/JellyfinQt/DTO/mediastream.h b/core/include/JellyfinQt/DTO/mediastream.h new file mode 100644 index 0000000..a6cff69 --- /dev/null +++ b/core/include/JellyfinQt/DTO/mediastream.h @@ -0,0 +1,74 @@ +/* +Sailfin: a Jellyfin client written using Qt +Copyright (C) 2021 Chris Josten + +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_DTO_MEDIASTREAM_H +#define JELLYFIN_DTO_MEDIASTREAM_H + +#include +#include +#include + +#include "dto.h" + +namespace Jellyfin { +namespace DTO { + +class MediaStream : public JsonSerializable { + Q_OBJECT +public: + Q_INVOKABLE explicit MediaStream(QObject *parent = nullptr); + MediaStream(const MediaStream &other); + bool operator==(const MediaStream &other); + virtual ~MediaStream() { qDebug() << "MediaStream destroyed"; } + + enum MediaStreamType { + Undefined, + Audio, + Video, + Subtitle, + EmbeddedImage + }; + Q_ENUM(MediaStreamType) + + Q_PROPERTY(QString codec MEMBER m_codec NOTIFY codecChanged) + Q_PROPERTY(QString codecTag MEMBER m_codecTag NOTIFY codecTagChanged) + Q_PROPERTY(QString language MEMBER m_language NOTIFY languageChanged) + Q_PROPERTY(QString displayTitle MEMBER m_displayTitle NOTIFY displayTitleChanged) + Q_PROPERTY(MediaStreamType type MEMBER m_type NOTIFY typeChanged) + Q_PROPERTY(int index MEMBER m_index NOTIFY indexChanged) +signals: + void codecChanged(const QString &newCodec); + void codecTagChanged(const QString &newCodecTag); + void languageChanged(const QString &newLanguage); + void displayTitleChanged(const QString &newDisplayTitle); + void typeChanged(MediaStreamType newType); + void indexChanged(int newIndex); +private: + QString m_codec; + QString m_codecTag; + QString m_language; + QString m_displayTitle; + MediaStreamType m_type = Undefined; + int m_index = -1; +}; + +} +} + +#endif // JELLYFIN_DTO_MEDIASTREAM_H diff --git a/core/include/JellyfinQt/DTO/namedguidpair.h b/core/include/JellyfinQt/DTO/namedguidpair.h new file mode 100644 index 0000000..7f1dcf5 --- /dev/null +++ b/core/include/JellyfinQt/DTO/namedguidpair.h @@ -0,0 +1,50 @@ + +/* +Sailfin: a Jellyfin client written using Qt +Copyright (C) 2021 Chris Josten + +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_DTO_NAMEDGUIDPAIR_H +#define JELLYFIN_DTO_NAMEDGUIDPAIR_H + +#include +#include + +#include "dto.h" + +namespace Jellyfin { +namespace DTO { + +class NameGuidPair : public JsonSerializable { + Q_OBJECT +public: + Q_INVOKABLE NameGuidPair(QObject *parent = nullptr); + Q_PROPERTY(QString name MEMBER m_name NOTIFY nameChanged) + // Once again the Jellyfin id workaround + Q_PROPERTY(QString jellyfinId MEMBER m_id NOTIFY jellyfinIdChanged) +signals: + void nameChanged(const QString &newName); + void jellyfinIdChanged(const QString &newJellyfinId); +private: + QString m_name; + QString m_id; +}; + +} // NS DTO +} // NS JELLYFIN + +#endif // JELLYFIN_DTO_NAMEDGUIDPAIR_H diff --git a/core/include/JellyfinQt/DTO/types.h b/core/include/JellyfinQt/DTO/types.h new file mode 100644 index 0000000..ed4d9a2 --- /dev/null +++ b/core/include/JellyfinQt/DTO/types.h @@ -0,0 +1,41 @@ +/* +Sailfin: a Jellyfin client written using Qt +Copyright (C) 2021 Chris Josten + +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_DTO_TYPES_H +#define JELLYFIN_DTO_TYPES_H + +#include "dto.h" +#include "item.h" +#include "mediastream.h" +#include "namedguidpair.h" +#include "user.h" +#include "userdata.h" + +namespace Jellyfin { +namespace DTO { + +/** + * @brief registerTypes Registers all DTO types to the QML type system + * @param uri The uri to register the items under. + */ +void registerTypes(const char *uri); + +} // NS DTO +} // NS Jellyfin + +#endif // JELLYFIN_DTO_TYPES_H diff --git a/core/include/JellyfinQt/DTO/user.h b/core/include/JellyfinQt/DTO/user.h new file mode 100644 index 0000000..e2b59eb --- /dev/null +++ b/core/include/JellyfinQt/DTO/user.h @@ -0,0 +1,61 @@ +/* +Sailfin: a Jellyfin client written using Qt +Copyright (C) 2021 Chris Josten + +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_DTO_USER_H +#define JELLYFIN_DTO_USER_H + +#include +#include + +#include "dto.h" + +namespace Jellyfin { +namespace DTO { + +class User : public RemoteData { + Q_OBJECT +public: + Q_INVOKABLE User(QObject *parent = nullptr); + + Q_PROPERTY(QString userId MEMBER m_userId WRITE setUserId NOTIFY userIdChanged) + Q_PROPERTY(QString name MEMBER m_name NOTIFY nameChanged) + Q_PROPERTY(QString primaryImageTag MEMBER m_primaryImageTag NOTIFY primaryImageTagChanged) + + void setUserId(const QString &newUserId) { + this->m_userId = newUserId; + emit userIdChanged(newUserId); + reload(); + } +signals: + void userIdChanged(const QString &newUserId); + void nameChanged(const QString &newName); + void primaryImageTagChanged(const QString &newPrimaryImageTag); +protected: + QString getDataUrl() const override; + bool canReload() const override; +private: + QString m_userId; + QString m_name; + QString m_primaryImageTag; +}; + +} // NS DTO +} // NS Jellyfin + +#endif // JELLYFIN_DTO_USER diff --git a/core/include/JellyfinQt/DTO/userdata.h b/core/include/JellyfinQt/DTO/userdata.h new file mode 100644 index 0000000..3c9b1b5 --- /dev/null +++ b/core/include/JellyfinQt/DTO/userdata.h @@ -0,0 +1,83 @@ +/* +Sailfin: a Jellyfin client written using Qt +Copyright (C) 2021 Chris Josten + +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_DTO_USERDATA +#define JELLYFIN_DTO_USERDATA + +#include +#include +#include + +#include "dto.h" + +namespace Jellyfin { +namespace DTO { + +class UserData : public JsonSerializable { + Q_OBJECT +public: + Q_INVOKABLE explicit UserData(QObject *parent = nullptr); + + Q_PROPERTY(double playedPercentage READ playedPercentage WRITE setPlayedPercentage RESET resetPlayedPercentage NOTIFY playedPercentageChanged) + Q_PROPERTY(qint64 playbackPositionTicks READ playbackPositionTicks WRITE setPlaybackPositionTicks NOTIFY playbackPositionTicksChanged) + Q_PROPERTY(bool isFavorite READ isFavorite WRITE setIsFavorite NOTIFY isFavoriteChanged) + Q_PROPERTY(bool likes READ likes WRITE setLikes RESET resetLikes NOTIFY likesChanged) + Q_PROPERTY(bool played READ played WRITE setPlayed NOTIFY playedChanged) + Q_PROPERTY(QString itemId READ itemId MEMBER m_itemId) + + double playedPercentage() const { return m_playedPercentage.value_or(0.0); } + void setPlayedPercentage(double newPlayedPercentage) { m_playedPercentage = newPlayedPercentage; emit playedPercentageChanged(newPlayedPercentage); } + void resetPlayedPercentage() { m_playedPercentage = std::nullopt; emit playedPercentageChanged(0.0); updateOnServer(); } + + qint64 playbackPositionTicks() const { return m_playbackPositionTicks; } + void setPlaybackPositionTicks(qint64 newPlaybackPositionTicks) { m_playbackPositionTicks = newPlaybackPositionTicks; emit playbackPositionTicksChanged(newPlaybackPositionTicks); } + + bool played() const { return m_played; } + void setPlayed(bool newPlayed) { m_played = newPlayed; emit playedChanged(newPlayed); updateOnServer(); } + + bool likes() const { return m_likes.value_or(false); } + void setLikes(bool newLikes) { m_likes = newLikes; emit likesChanged(newLikes); } + void resetLikes() { m_likes = std::nullopt; emit likesChanged(false); updateOnServer(); } + + bool isFavorite() const { return m_isFavorite; } + void setIsFavorite(bool newIsFavorite) { m_isFavorite = newIsFavorite; emit isFavoriteChanged(newIsFavorite); updateOnServer(); } + + const QString &itemId() const { return m_itemId; } +signals: + void playedPercentageChanged(double newPlayedPercentage); + void playbackPositionTicksChanged(qint64 playbackPositionTicks); + void isFavoriteChanged(bool newIsFavorite); + void likesChanged(bool newLikes); + void playedChanged(bool newPlayed); +public slots: + void updateOnServer(); + void onUpdated(QSharedPointer other); +private: + std::optional m_playedPercentage = std::nullopt; + qint64 m_playbackPositionTicks = 0; + bool m_isFavorite = false; + std::optional m_likes = std::nullopt; + bool m_played; + QString m_itemId; +}; + +} +} + +#endif // JELLYFIN_DTO_USERDATA diff --git a/core/include/JellyfinQt/jellyfinapiclient.h b/core/include/JellyfinQt/apiclient.h similarity index 98% rename from core/include/JellyfinQt/jellyfinapiclient.h rename to core/include/JellyfinQt/apiclient.h index dbefcdc..ca982d2 100644 --- a/core/include/JellyfinQt/jellyfinapiclient.h +++ b/core/include/JellyfinQt/apiclient.h @@ -1,6 +1,6 @@ /* Sailfin: a Jellyfin client written using Qt -Copyright (C) 2020 Chris Josten +Copyright (C) 2021 Chris Josten This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -37,15 +37,20 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include #include "credentialmanager.h" -#include "jellyfindeviceprofile.h" -#include "jellyfinitem.h" -#include "jellyfinplaybackmanager.h" -#include "jellyfinwebsocket.h" +#include "deviceprofile.h" +#include "websocket.h" namespace Jellyfin { class MediaSource; class WebSocket; class PlaybackManager; + +namespace DTO { + class UserData; // Keep it as an opaque pointer +} + +using namespace DTO; + /** * @brief An Api client for Jellyfin. Handles requests and authentication. * diff --git a/core/include/JellyfinQt/jellyfinapimodel.h b/core/include/JellyfinQt/apimodel.h similarity index 98% rename from core/include/JellyfinQt/jellyfinapimodel.h rename to core/include/JellyfinQt/apimodel.h index 0ab5e06..40f360f 100644 --- a/core/include/JellyfinQt/jellyfinapimodel.h +++ b/core/include/JellyfinQt/apimodel.h @@ -1,6 +1,6 @@ /* Sailfin: a Jellyfin client written using Qt -Copyright (C) 2020 Chris Josten +Copyright (C) 2021 Chris Josten This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -29,10 +29,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include #include -#include "jellyfinapiclient.h" +#include "apiclient.h" #include "jsonhelper.h" namespace Jellyfin { + +namespace DTO { + class JsonSerializable; +} class SortOptions : public QObject{ Q_OBJECT public: @@ -267,7 +271,7 @@ class ItemModel : public ApiModel { public: explicit ItemModel (QString path, bool responseHasRecords, bool replaceUser, QObject *parent = nullptr); public slots: - void onUserDataChanged(const QString &itemId, QSharedPointer userData); + void onUserDataChanged(const QString &itemId, QSharedPointer userData); }; class UserViewModel : public ApiModel { diff --git a/core/include/JellyfinQt/credentialmanager.h b/core/include/JellyfinQt/credentialmanager.h index 9594671..15e2779 100644 --- a/core/include/JellyfinQt/credentialmanager.h +++ b/core/include/JellyfinQt/credentialmanager.h @@ -1,6 +1,6 @@ /* Sailfin: a Jellyfin client written using Qt -Copyright (C) 2020 Chris Josten +Copyright (C) 2021 Chris Josten This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/core/include/JellyfinQt/jellyfindeviceprofile.h b/core/include/JellyfinQt/deviceprofile.h similarity index 97% rename from core/include/JellyfinQt/jellyfindeviceprofile.h rename to core/include/JellyfinQt/deviceprofile.h index 7049287..cc3e1a0 100644 --- a/core/include/JellyfinQt/jellyfindeviceprofile.h +++ b/core/include/JellyfinQt/deviceprofile.h @@ -1,6 +1,6 @@ /* Sailfin: a Jellyfin client written using Qt -Copyright (C) 2020 Chris Josten +Copyright (C) 2021 Chris Josten This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/core/include/JellyfinQt/jellyfin.h b/core/include/JellyfinQt/jellyfin.h index fbd5f3e..eb75ff2 100644 --- a/core/include/JellyfinQt/jellyfin.h +++ b/core/include/JellyfinQt/jellyfin.h @@ -1,13 +1,38 @@ +/* +Sailfin: a Jellyfin client written using Qt +Copyright (C) 2021 Chris Josten + +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_H #define JELLYFIN_H #include -#include "JellyfinQt/jellyfinapiclient.h" -#include "JellyfinQt/jellyfinapimodel.h" -#include "JellyfinQt/jellyfinitem.h" -#include "JellyfinQt/serverdiscoverymodel.h" -#include "JellyfinQt/jellyfinplaybackmanager.h" +#include "DTO/dto.h" +#include "DTO/item.h" +#include "DTO/mediastream.h" +#include "DTO/namedguidpair.h" +#include "DTO/types.h" +#include "DTO/user.h" +#include "DTO/userdata.h" + +#include "apiclient.h" +#include "apimodel.h" +#include "serverdiscoverymodel.h" +#include "playbackmanager.h" namespace Jellyfin { void registerTypes(const char *uri = "nl.netsoj.chris.Jellyfin"); diff --git a/core/include/JellyfinQt/jsonhelper.h b/core/include/JellyfinQt/jsonhelper.h index 8ea5fe5..878738a 100644 --- a/core/include/JellyfinQt/jsonhelper.h +++ b/core/include/JellyfinQt/jsonhelper.h @@ -1,3 +1,21 @@ +/* +Sailfin: a Jellyfin client written using Qt +Copyright (C) 2021 Chris Josten + +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 JSON_SERIALIZER_H #define JSON_SERIALIZER_H diff --git a/core/include/JellyfinQt/jellyfinplaybackmanager.h b/core/include/JellyfinQt/playbackmanager.h similarity index 93% rename from core/include/JellyfinQt/jellyfinplaybackmanager.h rename to core/include/JellyfinQt/playbackmanager.h index 41d372e..b2d53fd 100644 --- a/core/include/JellyfinQt/jellyfinplaybackmanager.h +++ b/core/include/JellyfinQt/playbackmanager.h @@ -1,6 +1,6 @@ /* Sailfin: a Jellyfin client written using Qt -Copyright (C) 2020 Chris Josten +Copyright (C) 2021 Chris Josten This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -30,16 +30,15 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include +#include "JellyfinQt/DTO/item.h" -#include "jellyfinapiclient.h" -#include "jellyfinitem.h" +#include "apiclient.h" namespace Jellyfin { -// Forward declaration of Jellyfin::Item found in jellyfinitem.h -class Item; // Forward declaration of Jellyfin::ApiClient found in jellyfinapiclient.h class ApiClient; +using namespace DTO; /** * @brief The PlaybackManager class manages the playback of Jellyfin items. It fetches streams based on Jellyfin items, posts @@ -95,6 +94,16 @@ public slots: * @param itemId The id of the item to play. */ void playItem(const QString &itemId); + + /** + * @brief previous Play the previous track in the current playlist. + */ + void previous(); + + /** + * @brief next Play the next track in the current playlist. + */ + void next(); private slots: void mediaPlayerStateChanged(QMediaPlayer::State newState); void mediaPlayerPositionChanged(qint64 position); diff --git a/core/include/JellyfinQt/serverdiscoverymodel.h b/core/include/JellyfinQt/serverdiscoverymodel.h index 95b8165..d069445 100644 --- a/core/include/JellyfinQt/serverdiscoverymodel.h +++ b/core/include/JellyfinQt/serverdiscoverymodel.h @@ -1,6 +1,6 @@ /* Sailfin: a Jellyfin client written using Qt -Copyright (C) 2020 Chris Josten +Copyright (C) 2021 Chris Josten This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/core/include/JellyfinQt/jellyfinwebsocket.h b/core/include/JellyfinQt/websocket.h similarity index 96% rename from core/include/JellyfinQt/jellyfinwebsocket.h rename to core/include/JellyfinQt/websocket.h index ff1b2c6..7228c8a 100644 --- a/core/include/JellyfinQt/jellyfinwebsocket.h +++ b/core/include/JellyfinQt/websocket.h @@ -1,6 +1,6 @@ /* Sailfin: a Jellyfin client written using Qt -Copyright (C) 2020 Chris Josten +Copyright (C) 2021 Chris Josten This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -31,12 +31,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include -#include "jellyfinapiclient.h" -#include "jellyfinitem.h" +#include "apiclient.h" namespace Jellyfin { class ApiClient; + +namespace DTO { class UserData; +} /** * @brief Keeps a connection with the Jellyfin server to receive real time updates. * diff --git a/core/src/jellyfinitem.cpp b/core/src/DTO/dto.cpp similarity index 70% rename from core/src/jellyfinitem.cpp rename to core/src/DTO/dto.cpp index 25357c3..ddf1d48 100644 --- a/core/src/jellyfinitem.cpp +++ b/core/src/DTO/dto.cpp @@ -1,6 +1,6 @@ /* Sailfin: a Jellyfin client written using Qt -Copyright (C) 2020 Chris Josten +Copyright (C) 2021 Chris Josten This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -17,12 +17,15 @@ 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 "JellyfinQt/jellyfinitem.h" +#include "JellyfinQt/DTO/dto.h" + +#include "JellyfinQt/apiclient.h" namespace Jellyfin { +namespace DTO { + const QRegularExpression JsonSerializable::m_listExpression = QRegularExpression("^QList<\\s*([a-zA-Z0-9]*)\\s*\\*?\\s*>$"); -JsonSerializable::JsonSerializable(QObject *parent) : QObject(parent) { -} +JsonSerializable::JsonSerializable(QObject *parent) : QObject(parent) { } void JsonSerializable::deserialize(const QJsonObject &jObj) { const QMetaObject *obj = this->metaObject(); @@ -107,7 +110,7 @@ QVariant JsonSerializable::deserializeQobject(const QJsonObject &innerObj, const if (match.hasMatch()) { // It is a qList! Now extract the inner type // There should be an easier way, shouldn't there? - QString listType = match.captured(1).prepend("Jellyfin::").append("*"); + QString listType = match.captured(1).prepend("Jellyfin::DTO::").append("*"); // UGLY CODE HERE WE COME typeNo = QMetaType::type(listType.toUtf8()); if (typeNo == QMetaType::UnknownType) { @@ -254,116 +257,5 @@ void RemoteData::reload() { }); } -NameGuidPair::NameGuidPair(QObject *parent) : JsonSerializable (parent) {} - -// User -User::User(QObject *parent) : RemoteData (parent) {} - -QString User::getDataUrl() const { - return QString("/Users/") + m_apiClient->userId(); -} - -bool User::canReload() const { - return true; -} - -// MediaStream -MediaStream::MediaStream(QObject *parent) : JsonSerializable (parent) {} -MediaStream::MediaStream(const MediaStream &other) - : JsonSerializable (other.parent()), - m_codec(other.m_codec), - m_codecTag(other.m_codecTag), - m_language(other.m_language), - m_displayTitle(other.m_displayTitle), - m_type(other.m_type), - m_index(other.m_index){ -} -bool MediaStream::operator==(const MediaStream &other) { - // displayTitle is explicitly left out, since it's generated based on other properties - // in the Jellyfin source code. - return m_codec == other.m_codec && m_codecTag == other.m_codecTag - && m_language == other.m_language && m_type == other.m_type - && m_index == other.m_index; -} - -// UserData -UserData::UserData(QObject *parent) : JsonSerializable (parent) {} - -void UserData::updateOnServer() { - //TODO: implement -} - -void UserData::onUpdated(QSharedPointer other) { - // The reason I'm not using setLikes and similar is that they don't work with std::nullopt, - // since QML does not like it. - // THe other reason is that the setLikes method will send a post request to the server, to update the contents - // we don't want that to happen, obviously, since the application could end in an infinite loop. - if (this->m_playedPercentage != other->m_playedPercentage) { - this->m_playedPercentage = other->m_playedPercentage; - emit playedPercentageChanged(playedPercentage()); - } - if (m_playbackPositionTicks!= other->m_playbackPositionTicks) { - this->m_playbackPositionTicks = other->m_playbackPositionTicks; - emit playbackPositionTicksChanged(this->m_playbackPositionTicks); - } - if (m_isFavorite != other->m_isFavorite) { - this->m_isFavorite = other->m_isFavorite; - emit isFavoriteChanged(this->m_isFavorite); - } - if (this->m_likes != other->m_likes) { - this->m_likes = other->m_likes; - emit likesChanged(likes()); - } - if (this->m_played != other->m_played) { - this->m_played = other->m_played; - emit playedChanged(this->m_played); - } -} - -// Item - -Item::Item(QObject *parent) : RemoteData(parent) { - connect(this, &RemoteData::apiClientChanged, this, [this](ApiClient *newApiClient) { - connect(newApiClient, &ApiClient::userDataChanged, this, &Item::onUserDataChanged); - }); -} - -Item::Item(QString id, ApiClient *apiClient, QObject *parent) - : RemoteData(parent), m_id(id) { - connect(this, &RemoteData::apiClientChanged, this, [this](ApiClient *newApiClient) { - connect(newApiClient, &ApiClient::userDataChanged, this, &Item::onUserDataChanged); - }); - setApiClient(apiClient); -} - -QString Item::getDataUrl() const { - return QString("/Users/") + m_apiClient->userId() + "/Items/" + m_id; -} - -bool Item::canReload() const { - return !m_id.isNull(); -} - -void Item::setJellyfinId(QString newId) { - m_id = newId.trimmed(); - if (m_id != newId) { - emit jellyfinIdChanged(m_id); - reload(); - } -} - - - -void Item::onUserDataChanged(const QString &itemId, QSharedPointer userData) { - if (itemId != m_id || m_userData == nullptr) return; - m_userData->onUpdated(userData); -} - -void registerSerializableJsonTypes(const char* URI) { - qmlRegisterType(URI, 1, 0, "MediaStream"); - qmlRegisterType(URI, 1, 0, "NameGuidPair"); - qmlRegisterType(URI, 1, 0, "User"); - qmlRegisterType(URI, 1, 0, "UserData"); - qmlRegisterType(URI, 1, 0, "JellyfinItem"); -} -} +} // NS DTO +} // NS Jellyfin diff --git a/core/src/DTO/item.cpp b/core/src/DTO/item.cpp new file mode 100644 index 0000000..e634596 --- /dev/null +++ b/core/src/DTO/item.cpp @@ -0,0 +1,63 @@ +/* +Sailfin: a Jellyfin client written using Qt +Copyright (C) 2021 Chris Josten + +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 "JellyfinQt/DTO/item.h" + +#include "JellyfinQt/apiclient.h" + +namespace Jellyfin { +namespace DTO { + +Item::Item(QObject *parent) : RemoteData(parent) { + connect(this, &RemoteData::apiClientChanged, this, [this](ApiClient *newApiClient) { + connect(newApiClient, &ApiClient::userDataChanged, this, &Item::onUserDataChanged); + }); +} + +Item::Item(QString id, ApiClient *apiClient, QObject *parent) + : RemoteData(parent), m_id(id) { + connect(this, &RemoteData::apiClientChanged, this, [this](ApiClient *newApiClient) { + connect(newApiClient, &ApiClient::userDataChanged, this, &Item::onUserDataChanged); + }); + setApiClient(apiClient); +} + +QString Item::getDataUrl() const { + return QString("/Users/") + m_apiClient->userId() + "/Items/" + m_id; +} + +bool Item::canReload() const { + return !m_id.isNull(); +} + +void Item::setJellyfinId(QString newId) { + m_id = newId.trimmed(); + if (m_id != newId) { + emit jellyfinIdChanged(m_id); + reload(); + } +} + +void Item::onUserDataChanged(const QString &itemId, QSharedPointer userData) { + if (itemId != m_id || m_userData == nullptr) return; + m_userData->onUpdated(userData); +} + +} // NS DTO +} // NS Jellyfin diff --git a/core/src/DTO/mediastream.cpp b/core/src/DTO/mediastream.cpp new file mode 100644 index 0000000..791c14e --- /dev/null +++ b/core/src/DTO/mediastream.cpp @@ -0,0 +1,43 @@ +/* +Sailfin: a Jellyfin client written using Qt +Copyright (C) 2021 Chris Josten + +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 "JellyfinQt/DTO/mediastream.h" + +namespace Jellyfin { +namespace DTO { + +MediaStream::MediaStream(QObject *parent) : JsonSerializable (parent) {} +MediaStream::MediaStream(const MediaStream &other) + : JsonSerializable (other.parent()), + m_codec(other.m_codec), + m_codecTag(other.m_codecTag), + m_language(other.m_language), + m_displayTitle(other.m_displayTitle), + m_type(other.m_type), + m_index(other.m_index){ +} +bool MediaStream::operator==(const MediaStream &other) { + // displayTitle is explicitly left out, since it's generated based on other properties + // in the Jellyfin source code. + return m_codec == other.m_codec && m_codecTag == other.m_codecTag + && m_language == other.m_language && m_type == other.m_type + && m_index == other.m_index; +} + +} // NS DTO +} // NS Jellyfin diff --git a/core/src/DTO/namedguidpair.cpp b/core/src/DTO/namedguidpair.cpp new file mode 100644 index 0000000..ba97db8 --- /dev/null +++ b/core/src/DTO/namedguidpair.cpp @@ -0,0 +1,27 @@ +/* +Sailfin: a Jellyfin client written using Qt +Copyright (C) 2021 Chris Josten + +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 "JellyfinQt/DTO/namedguidpair.h" + +namespace Jellyfin { +namespace DTO { + +NameGuidPair::NameGuidPair(QObject *parent) : JsonSerializable (parent) {} + +} // NS DTO +} // NS Jellyfin diff --git a/core/src/DTO/types.cpp b/core/src/DTO/types.cpp new file mode 100644 index 0000000..4f9e4b7 --- /dev/null +++ b/core/src/DTO/types.cpp @@ -0,0 +1,36 @@ +/* +Sailfin: a Jellyfin client written using Qt +Copyright (C) 2021 Chris Josten + +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 "JellyfinQt/DTO/types.h" + +#include + +namespace Jellyfin { +namespace DTO { + +void registerTypes(const char *uri) { + qmlRegisterType(uri, 1, 0, "MediaStream"); + qmlRegisterType(uri, 1, 0, "NameGuidPair"); + qmlRegisterType(uri, 1, 0, "User"); + qmlRegisterType(uri, 1, 0, "UserData"); + qmlRegisterType(uri, 1, 0, "JellyfinItem"); +} + +} // NS DTO +} // NS Jellyfin diff --git a/core/src/DTO/user.cpp b/core/src/DTO/user.cpp new file mode 100644 index 0000000..b5e1949 --- /dev/null +++ b/core/src/DTO/user.cpp @@ -0,0 +1,36 @@ +/* +Sailfin: a Jellyfin client written using Qt +Copyright (C) 2021 Chris Josten + +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 "JellyfinQt/DTO/user.h" + +#include "JellyfinQt/apiclient.h" + +namespace Jellyfin { +namespace DTO { +User::User(QObject *parent) : RemoteData (parent) {} + +QString User::getDataUrl() const { + return QString("/Users/") + m_apiClient->userId(); +} + +bool User::canReload() const { + return true; +} + +} // NS DTO +} // NS Jellyfin diff --git a/core/src/DTO/userdata.cpp b/core/src/DTO/userdata.cpp new file mode 100644 index 0000000..73e28f2 --- /dev/null +++ b/core/src/DTO/userdata.cpp @@ -0,0 +1,58 @@ +/* +Sailfin: a Jellyfin client written using Qt +Copyright (C) 2021 Chris Josten + +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 "JellyfinQt/DTO/userdata.h" + +namespace Jellyfin { +namespace DTO { + +UserData::UserData(QObject *parent) : JsonSerializable (parent) {} + +void UserData::updateOnServer() { + //TODO: implement +} + +void UserData::onUpdated(QSharedPointer other) { + // The reason I'm not using setLikes and similar is that they don't work with std::nullopt, + // since QML does not like it. + // THe other reason is that the setLikes method will send a post request to the server, to update the contents + // we don't want that to happen, obviously, since the application could end in an infinite loop. + if (this->m_playedPercentage != other->m_playedPercentage) { + this->m_playedPercentage = other->m_playedPercentage; + emit playedPercentageChanged(playedPercentage()); + } + if (m_playbackPositionTicks!= other->m_playbackPositionTicks) { + this->m_playbackPositionTicks = other->m_playbackPositionTicks; + emit playbackPositionTicksChanged(this->m_playbackPositionTicks); + } + if (m_isFavorite != other->m_isFavorite) { + this->m_isFavorite = other->m_isFavorite; + emit isFavoriteChanged(this->m_isFavorite); + } + if (this->m_likes != other->m_likes) { + this->m_likes = other->m_likes; + emit likesChanged(likes()); + } + if (this->m_played != other->m_played) { + this->m_played = other->m_played; + emit playedChanged(this->m_played); + } +} + +} // NS DTO +} // NS Jellyfin diff --git a/core/src/jellyfinapiclient.cpp b/core/src/apiclient.cpp similarity index 98% rename from core/src/jellyfinapiclient.cpp rename to core/src/apiclient.cpp index 2fbfdab..cde5fbe 100644 --- a/core/src/jellyfinapiclient.cpp +++ b/core/src/apiclient.cpp @@ -1,6 +1,6 @@ /* Sailfin: a Jellyfin client written using Qt -Copyright (C) 2020 Chris Josten +Copyright (C) 2021 Chris Josten This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -17,7 +17,7 @@ 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 "JellyfinQt/jellyfinapiclient.h" +#include "JellyfinQt/apiclient.h" namespace Jellyfin { @@ -264,7 +264,7 @@ void ApiClient::defaultNetworkErrorHandler(QNetworkReply::NetworkError error) { } void ApiClient::onUserDataChanged(const QString &itemId, QSharedPointer userData) { - userDataChanged(itemId, userData); + emit userDataChanged(itemId, userData); } void ApiClient::setAuthenticated(bool authenticated) { diff --git a/core/src/jellyfinapimodel.cpp b/core/src/apimodel.cpp similarity index 98% rename from core/src/jellyfinapimodel.cpp rename to core/src/apimodel.cpp index 468b860..514d75a 100644 --- a/core/src/jellyfinapimodel.cpp +++ b/core/src/apimodel.cpp @@ -1,6 +1,6 @@ /* Sailfin: a Jellyfin client written using Qt -Copyright (C) 2020 Chris Josten +Copyright (C) 2021 Chris Josten This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -17,7 +17,9 @@ 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 "JellyfinQt/jellyfinapimodel.h" +#include "JellyfinQt/apimodel.h" + +#include "JellyfinQt/DTO/userdata.h" namespace Jellyfin { ApiModel::ApiModel(QString path, bool hasRecordResponse, bool addUserId, QObject *parent) @@ -229,7 +231,7 @@ ItemModel::ItemModel(QString path, bool hasRecordFields, bool replaceUser, QObje }); } -void ItemModel::onUserDataChanged(const QString &itemId, QSharedPointer userData) { +void ItemModel::onUserDataChanged(const QString &itemId, QSharedPointer userData) { int i = 0; for (QJsonValueRef val: m_array) { QJsonObject item = val.toObject(); diff --git a/core/src/credentialmanager.cpp b/core/src/credentialmanager.cpp index 37f540e..63aea27 100644 --- a/core/src/credentialmanager.cpp +++ b/core/src/credentialmanager.cpp @@ -1,6 +1,6 @@ /* Sailfin: a Jellyfin client written using Qt -Copyright (C) 2020 Chris Josten +Copyright (C) 2021 Chris Josten This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/core/src/jellyfindeviceprofile.cpp b/core/src/deviceprofile.cpp similarity index 99% rename from core/src/jellyfindeviceprofile.cpp rename to core/src/deviceprofile.cpp index 9b7342d..a46786c 100644 --- a/core/src/jellyfindeviceprofile.cpp +++ b/core/src/deviceprofile.cpp @@ -1,6 +1,6 @@ /* Sailfin: a Jellyfin client written using Qt -Copyright (C) 2020 Chris Josten +Copyright (C) 2021 Chris Josten This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -17,7 +17,7 @@ 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 "JellyfinQt/jellyfindeviceprofile.h" +#include "JellyfinQt/deviceprofile.h" namespace Jellyfin { diff --git a/core/src/jellyfin.cpp b/core/src/jellyfin.cpp index 877eaba..16c7e7e 100644 --- a/core/src/jellyfin.cpp +++ b/core/src/jellyfin.cpp @@ -1,6 +1,6 @@ /* Sailfin: a Jellyfin client written using Qt -Copyright (C) 2020 Chris Josten +Copyright (C) 2021 Chris Josten This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -31,6 +31,6 @@ void registerTypes(const char *uri) { // API models Jellyfin::registerModels(uri); - Jellyfin::registerSerializableJsonTypes(uri); + Jellyfin::DTO::registerTypes(uri); } } diff --git a/core/src/jsonhelper.cpp b/core/src/jsonhelper.cpp index e78a760..e214e0f 100644 --- a/core/src/jsonhelper.cpp +++ b/core/src/jsonhelper.cpp @@ -1,6 +1,6 @@ /* Sailfin: a Jellyfin client written using Qt -Copyright (C) 2020 Chris Josten +Copyright (C) 2021 Chris Josten This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include "JellyfinQt/jsonhelper.h" namespace Jellyfin { - namespace JsonHelper { void convertToCamelCase(QJsonValueRef val) { diff --git a/core/src/jellyfinplaybackmanager.cpp b/core/src/playbackmanager.cpp similarity index 97% rename from core/src/jellyfinplaybackmanager.cpp rename to core/src/playbackmanager.cpp index 4476472..e922f3c 100644 --- a/core/src/jellyfinplaybackmanager.cpp +++ b/core/src/playbackmanager.cpp @@ -1,6 +1,6 @@ /* Sailfin: a Jellyfin client written using Qt -Copyright (C) 2020 Chris Josten +Copyright (C) 2021 Chris Josten This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -17,7 +17,10 @@ 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 "JellyfinQt/jellyfinplaybackmanager.h" +#include "JellyfinQt/playbackmanager.h" + +#include "JellyfinQt/DTO/dto.h" +#include "JellyfinQt/DTO/userdata.h" namespace Jellyfin { @@ -213,6 +216,14 @@ void PlaybackManager::playItem(const QString &itemId) { setItem(newItem); } +void PlaybackManager::next() { + Q_UNIMPLEMENTED(); +} + +void PlaybackManager::previous() { + Q_UNIMPLEMENTED(); +} + void PlaybackManager::postPlaybackInfo(PlaybackInfoType type) { QJsonObject root; diff --git a/core/src/serverdiscoverymodel.cpp b/core/src/serverdiscoverymodel.cpp index daa21bf..56aafba 100644 --- a/core/src/serverdiscoverymodel.cpp +++ b/core/src/serverdiscoverymodel.cpp @@ -1,6 +1,6 @@ /* Sailfin: a Jellyfin client written using Qt -Copyright (C) 2020 Chris Josten +Copyright (C) 2021 Chris Josten This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/core/src/jellyfinwebsocket.cpp b/core/src/websocket.cpp similarity index 96% rename from core/src/jellyfinwebsocket.cpp rename to core/src/websocket.cpp index 803e1ed..fe07bd0 100644 --- a/core/src/jellyfinwebsocket.cpp +++ b/core/src/websocket.cpp @@ -1,6 +1,6 @@ /* Sailfin: a Jellyfin client written using Qt -Copyright (C) 2020 Chris Josten +Copyright (C) 2021 Chris Josten This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -16,7 +16,10 @@ 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 "JellyfinQt/jellyfinwebsocket.h" + +#include "JellyfinQt/websocket.h" + +#include "JellyfinQt/DTO/userdata.h" namespace Jellyfin { WebSocket::WebSocket(ApiClient *client) @@ -102,7 +105,7 @@ void WebSocket::textMessageReceived(const QString &message) { } QJsonArray userDataList = data2["UserDataList"].toArray(); for (QJsonValue val: userDataList) { - QSharedPointer userData(new UserData, &QObject::deleteLater); + QSharedPointer userData(new DTO::UserData, &QObject::deleteLater); userData->deserialize(val.toObject()); m_apiClient->onUserDataChanged(userData->itemId(), userData); }