From 0c72906f88a614dec41bc787032092da6e435cb1 Mon Sep 17 00:00:00 2001
From: Henk Kalkwater <chris+dev@netsoj.nl>
Date: Thu, 13 Mar 2025 02:51:19 +0100
Subject: [PATCH] [3/3] update openapi spec: update code interacting with
 generated code

Adjusted C++ code to handle with new and renamed objects, as well as
properties with different types.

As a result of changing types, the QML side had to be updated as well.
I hope I found everything by manually testing.

Additionally, the Qt Quick application has been updated to test the
remote sessions more easily and to make it launch again.
---
 core/include/JellyfinQt/apimodel.h            |   6 +-
 core/include/JellyfinQt/eventbus.h            |   6 +-
 .../JellyfinQt/model/controllablesession.h    |   6 +-
 .../JellyfinQt/model/remotejellyfinplayback.h |   6 +-
 core/include/JellyfinQt/viewmodel/item.h      |  20 +-
 core/include/JellyfinQt/viewmodel/itemmodel.h |  42 ++--
 .../JellyfinQt/viewmodel/mediastream.h        |   6 +-
 core/src/apiclient.cpp                        |  23 +-
 core/src/apimodel.cpp                         |   5 +-
 core/src/jellyfin.cpp                         |  11 +-
 core/src/model/controllablesession.cpp        |   7 +-
 core/src/model/deviceprofile.cpp              | 235 +++++++++---------
 core/src/model/item.cpp                       |   6 +-
 core/src/model/playbackmanager.cpp            |  11 +-
 core/src/model/playbackreporter.cpp           |   4 +-
 core/src/model/remotejellyfinplayback.cpp     |   7 +-
 core/src/viewmodel/item.cpp                   |   2 +-
 core/src/viewmodel/itemmodel.cpp              |   2 +-
 core/src/viewmodel/userdata.cpp               |   6 +-
 core/src/websocket.cpp                        |   4 +-
 qtquick/qml/ApiClient.qml                     |   1 +
 qtquick/qml/main.qml                          |   2 +-
 qtquick/qml/pages/MainPage.qml                |  19 +-
 sailfish/qml/Utils.js                         |  63 ++---
 .../qml/components/ItemChildrenShowcase.qml   |   2 +-
 sailfish/qml/components/PlaybackBar.qml       |   4 +-
 .../qml/components/music/SongDelegate.qml     |   3 +-
 sailfish/qml/cover/CollectionPage.qml         |   2 +-
 sailfish/qml/cover/PosterCover.qml            |   2 +-
 sailfish/qml/harbour-sailfin.qml              |   2 +-
 sailfish/qml/pages/AboutPage.qml              |   2 +-
 sailfish/qml/pages/MainPage.qml               |   4 +-
 .../qml/pages/itemdetails/CollectionPage.qml  |  18 +-
 .../qml/pages/itemdetails/MusicAlbumPage.qml  |   2 +-
 .../qml/pages/itemdetails/MusicArtistPage.qml |  26 +-
 .../pages/itemdetails/MusicLibraryPage.qml    |  20 +-
 sailfish/translations/harbour-sailfin-de.ts   |  32 +--
 sailfish/translations/harbour-sailfin-ru.ts   |  32 +--
 sailfish/translations/harbour-sailfin.ts      |  32 +--
 39 files changed, 366 insertions(+), 317 deletions(-)

diff --git a/core/include/JellyfinQt/apimodel.h b/core/include/JellyfinQt/apimodel.h
index a0bff30..9b85df2 100644
--- a/core/include/JellyfinQt/apimodel.h
+++ b/core/include/JellyfinQt/apimodel.h
@@ -248,8 +248,8 @@ extern template int extractTotalRecordCount(const QList<DTO::BaseItemDto> &resul
 extern template void setRequestLimit(Loader::GetLatestMediaParams &params, int limit);
 extern template bool setRequestStartIndex(Loader::GetLatestMediaParams &params, int offset);
 
-extern template void setRequestLimit(Loader::GetItemsByUserIdParams &params, int limit);
-extern template bool setRequestStartIndex(Loader::GetItemsByUserIdParams &params, int offset);
+extern template void setRequestLimit(Loader::GetItemsParams &params, int limit);
+extern template bool setRequestStartIndex(Loader::GetItemsParams &params, int offset);
 
 extern template void setRequestLimit(Loader::GetResumeItemsParams &params, int limit);
 extern template bool setRequestStartIndex(Loader::GetResumeItemsParams &params, int offset);
@@ -332,7 +332,6 @@ protected:
             R result = m_loader->result();
             QList<D> records = extractRecords<D, R>(result);
             int totalRecordCount = extractTotalRecordCount<R>(result);
-            qDebug() << "Total record count: " << totalRecordCount << ", records in request: " << records.size();
             // If totalRecordCount < 0, it is not supported for this endpoint
             if (totalRecordCount < 0) {
                 totalRecordCount = records.size();
@@ -549,7 +548,6 @@ protected:
     void loadingFinished() override {
         Q_ASSERT(m_loader != nullptr);
         std::pair<QList<T*>, int> result = m_loader->result();
-        qDebug() << "Results loaded: index: " << result.second << ", count: " << result.first.size();
         if (result.second == -1) {
             clear();
         } else if (result.second == m_array.size()) {
diff --git a/core/include/JellyfinQt/eventbus.h b/core/include/JellyfinQt/eventbus.h
index 3b94ac3..755ac32 100644
--- a/core/include/JellyfinQt/eventbus.h
+++ b/core/include/JellyfinQt/eventbus.h
@@ -26,7 +26,7 @@ namespace Jellyfin {
 namespace DTO {
     class UserItemDataDto;
     class PlaystateRequest;
-    class SessionInfo;
+    class SessionInfoDto;
 }
 
 /**
@@ -43,14 +43,14 @@ signals:
      * @param itemId The id of the item which was updated.
      * @param userData The new userData
      */
-    void itemUserDataUpdated(const QString &itemId, const DTO::UserItemDataDto &userData);
+    void itemUserDataUpdated(const QString &itemId, const Jellyfin::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);
+    void sessionInfoUpdated(const QString &sessionId, const Jellyfin::DTO::SessionInfoDto &sessionInfo);
 
     /**
      * @brief The server has requested to display an message to the user
diff --git a/core/include/JellyfinQt/model/controllablesession.h b/core/include/JellyfinQt/model/controllablesession.h
index a41c40a..5d3aa6a 100644
--- a/core/include/JellyfinQt/model/controllablesession.h
+++ b/core/include/JellyfinQt/model/controllablesession.h
@@ -5,7 +5,7 @@
 #include <QScopedPointer>
 #include <QSharedPointer>
 
-#include "JellyfinQt/dto/sessioninfo.h"
+#include "JellyfinQt/dto/sessioninfodto.h"
 
 namespace Jellyfin {
 
@@ -105,7 +105,7 @@ private:
 class ControllableJellyfinSession : public ControllableSession {
     Q_OBJECT
 public:
-    ControllableJellyfinSession(QSharedPointer<DTO::SessionInfo> info, ApiClient &apiClient, QObject *parent = nullptr);
+    ControllableJellyfinSession(QSharedPointer<DTO::SessionInfoDto> info, ApiClient &apiClient, QObject *parent = nullptr);
     QString id() const override;
     QString name() const override;
     QString appName() const override;
@@ -113,7 +113,7 @@ public:
     QString userName() const override;
     PlaybackManager *createPlaybackManager() const override;
 private:
-    QSharedPointer<DTO::SessionInfo> m_data;
+    QSharedPointer<DTO::SessionInfoDto> m_data;
     ApiClient &m_apiClient;
 };
 
diff --git a/core/include/JellyfinQt/model/remotejellyfinplayback.h b/core/include/JellyfinQt/model/remotejellyfinplayback.h
index 835856c..15068ce 100644
--- a/core/include/JellyfinQt/model/remotejellyfinplayback.h
+++ b/core/include/JellyfinQt/model/remotejellyfinplayback.h
@@ -22,7 +22,7 @@
 #include <JellyfinQt/dto/generalcommandtype.h>
 #include <JellyfinQt/dto/playcommand.h>
 #include <JellyfinQt/dto/playstatecommand.h>
-#include <JellyfinQt/dto/sessioninfo.h>
+#include <JellyfinQt/dto/sessioninfodto.h>
 #include <JellyfinQt/model/playbackmanager.h>
 #include <JellyfinQt/support/loader.h>
 
@@ -69,7 +69,7 @@ public slots:
     void seek(qint64 pos) override;
 private slots:
     void onPositionTimerFired();
-    void onSessionInfoUpdated(const QString &sessionId, const DTO::SessionInfo &sessionInfo);
+    void onSessionInfoUpdated(const QString &sessionId, const DTO::SessionInfoDto &sessionInfo);
 private:
     void sendPlaystateCommand(DTO::PlaystateCommand command, qint64 seekTicks = -1);
     void sendGeneralCommand(DTO::GeneralCommandType command, QJsonObject arguments = QJsonObject());
@@ -88,7 +88,7 @@ private:
     void updateQueue(QList<QueueItem> itemIds);
     ApiClient &m_apiClient;
     QString m_sessionId;
-    std::optional<DTO::SessionInfo> m_lastSessionInfo;
+    std::optional<DTO::SessionInfoDto> m_lastSessionInfo;
     QTimer *m_positionTimer;
     qint64 m_position = 0;
 };
diff --git a/core/include/JellyfinQt/viewmodel/item.h b/core/include/JellyfinQt/viewmodel/item.h
index 2cff478..1ae23bc 100644
--- a/core/include/JellyfinQt/viewmodel/item.h
+++ b/core/include/JellyfinQt/viewmodel/item.h
@@ -116,7 +116,7 @@ public:
     Q_PROPERTY(QString playlistItemId READ playlistItemId NOTIFY playlistItemIdChanged)
     Q_PROPERTY(QDateTime dateCreated READ dateCreated NOTIFY dateCreatedChanged)
     Q_PROPERTY(QDateTime dateLastMediaAdded READ dateLastMediaAdded NOTIFY dateLastMediaAddedChanged)
-    Q_PROPERTY(QString extraType READ extraType NOTIFY extraTypeChanged)
+    Q_PROPERTY(Jellyfin::DTO::ExtraTypeClass::Value extraType READ extraType NOTIFY extraTypeChanged)
     Q_PROPERTY(int airsBeforeSeasonNumber READ airsBeforeSeasonNumber NOTIFY airsBeforeSeasonNumberChanged)
     Q_PROPERTY(int airsAfterSeasonNumber READ airsAfterSeasonNumber NOTIFY airsAfterSeasonNumberChanged)
     Q_PROPERTY(int airsBeforeEpisodeNumber READ airsBeforeEpisodeNumber NOTIFY airsBeforeEpisodeNumberChanged)
@@ -143,7 +143,7 @@ public:
     Q_PROPERTY(int indexNumber READ indexNumber NOTIFY indexNumberChanged)
     Q_PROPERTY(int indexNumberEnd READ indexNumberEnd NOTIFY indexNumberEndChanged)
     Q_PROPERTY(bool isFolder READ isFolder NOTIFY isFolderChanged)
-    Q_PROPERTY(QString type READ type NOTIFY typeChanged)
+    Q_PROPERTY(Jellyfin::DTO::BaseItemKindClass::Value type READ type NOTIFY typeChanged)
     Q_PROPERTY(QString parentBackdropItemId READ parentBackdropItemId NOTIFY parentBackdropItemIdChanged)
     Q_PROPERTY(QStringList parentBackdropImageTags READ parentBackdropImageTags NOTIFY parentBackdropImageTagsChanged)
     Q_PROPERTY(Jellyfin::ViewModel::UserData *userData READ userData NOTIFY userDataChanged)
@@ -163,7 +163,7 @@ public:
     Q_PROPERTY(double primaryImageAspectRatio READ primaryImageAspectRatio NOTIFY primaryImageAspectRatioChanged)
     Q_PROPERTY(QStringList artists READ artists NOTIFY artistsChanged)
     Q_PROPERTY(QList<QObject *> artistItems READ artistItems NOTIFY artistItemsChanged);
-    Q_PROPERTY(QString collectionType READ collectionType NOTIFY collectionTypeChanged)
+    Q_PROPERTY(Jellyfin::DTO::CollectionTypeClass::Value collectionType READ collectionType NOTIFY collectionTypeChanged)
     // Why is this a QJsonObject? Well, because I couldn't be bothered to implement the deserialisations of
     // a QHash at the moment.
     Q_PROPERTY(QJsonObject imageTags READ imageTags NOTIFY imageTagsChanged)
@@ -178,7 +178,7 @@ public:
     Q_PROPERTY(int albumCount READ albumCount NOTIFY albumCountChanged)
     Q_PROPERTY(int artistCount READ artistCount NOTIFY artistCountChanged)
     Q_PROPERTY(int musicVideoCount READ musicVideoCount NOTIFY musicVideoCountChanged)
-    Q_PROPERTY(QString mediaType READ mediaType NOTIFY mediaTypeChanged)
+    Q_PROPERTY(Jellyfin::DTO::MediaTypeClass::Value mediaType READ mediaType NOTIFY mediaTypeChanged)
     Q_PROPERTY(QDateTime endDate READ endDate NOTIFY endDateChanged)
     Q_PROPERTY(QDateTime startDate READ startDate NOTIFY startDateChanged)
     Q_PROPERTY(int width READ width NOTIFY widthChanged)
@@ -194,7 +194,7 @@ public:
     QString playlistItemId() const { return m_data->playlistItemId(); }
     QDateTime dateCreated() const { return m_data->dateCreated(); }
     QDateTime dateLastMediaAdded() const { return m_data->dateLastMediaAdded(); }
-    QString extraType() const { return m_data->extraType(); }
+    ExtraType extraType() const { return m_data->extraType(); }
     int airsBeforeSeasonNumber() const { return m_data->airsBeforeSeasonNumber().value_or(0); }
     int airsAfterSeasonNumber() const { return m_data->airsAfterSeasonNumber().value_or(999); }
     int airsBeforeEpisodeNumber() const { return m_data->airsBeforeEpisodeNumber().value_or(0); }
@@ -204,7 +204,7 @@ public:
     int indexNumber() const { return m_data->indexNumber().value_or(-1); }
     int indexNumberEnd() const { return m_data->indexNumberEnd().value_or(-1); }
     bool isFolder() const { return m_data->isFolder().value_or(false); }
-    QString type() const { return m_data->type(); }
+    BaseItemKind type() const { return m_data->type(); }
     QString parentBackdropItemId() const { return m_data->parentBackdropItemId(); }
     QStringList parentBackdropImageTags() const { return m_data->parentBackdropImageTags(); }
     UserData *userData() const { return m_userData; }
@@ -223,11 +223,11 @@ public:
     double primaryImageAspectRatio() const { return m_data->primaryImageAspectRatio().value_or(1.0); }
     QStringList artists() const { return m_data->artists(); }
     QList<QObject *> artistItems() const{ return this->m_artistItems; }
-    QString collectionType() const { return this->m_data->collectionType(); }
+    CollectionType collectionType() const { return this->m_data->collectionType(); }
     QJsonObject imageTags() const { return m_data->imageTags(); }
     QStringList backdropImageTags() const { return m_data->backdropImageTags(); }
     QJsonObject imageBlurHashes() const { return m_data->imageBlurHashes(); }
-    QString mediaType() const { return m_data->mediaType(); }
+    MediaType mediaType() const { return m_data->mediaType(); }
     QDateTime endDate() const { return m_data->endDate(); }
     QDateTime startDate() const { return m_data->startDate(); }
     Item *currentProgram() const { return m_currentProgram; }
@@ -281,7 +281,7 @@ signals:
     void indexNumberChanged(int newIndexNumber);
     void indexNumberEndChanged(int newIndexNumberEnd);
     void isFolderChanged(bool newIsFolder);
-    void typeChanged(const QString &newType);
+    void typeChanged(const BaseItemKind &newType);
     void parentBackdropItemIdChanged();
     void parentBackdropImageTagsChanged();
     void userDataChanged(UserData *newUserData);
@@ -313,7 +313,7 @@ signals:
     void albumCountChanged(int newAlbumCount);
     void artistCountChanged(int newArtistCount);
     void musicVideoCountChanged(int newMusicVideoCount);
-    void mediaTypeChanged(const QString &newMediaType);
+    void mediaTypeChanged(const MediaType &newMediaType);
     void endDateChanged();
     void startDateChanged();
     void widthChanged(int newWidth);
diff --git a/core/include/JellyfinQt/viewmodel/itemmodel.h b/core/include/JellyfinQt/viewmodel/itemmodel.h
index 5c9e9c3..30792c6 100644
--- a/core/include/JellyfinQt/viewmodel/itemmodel.h
+++ b/core/include/JellyfinQt/viewmodel/itemmodel.h
@@ -38,7 +38,7 @@
     public: \
         Q_PROPERTY(type propName READ propName WRITE set##propSetName NOTIFY propName##Changed) \
         type propName() const { return this->m_parameters.propName(); } \
-        void set##propSetName(type newValue) { \
+        void set##propSetName(const type &newValue) { \
             this->m_parameters.set##propSetName( newValue ); \
             emit propName##Changed(); \
             autoReloadIfNeeded(); \
@@ -92,7 +92,7 @@ public:
         this->connect(this, &BaseModelLoader::apiClientChanged, this, &AbstractUserParameterLoader<T, D, R, P>::apiClientChanged);
     }
 protected:
-    virtual bool canReload() const override {
+    bool canReload() const override {
         return BaseModelLoader::canReload() && !this->m_parameters.userId().isNull();
     }
 private:
@@ -125,7 +125,7 @@ public:
 
     FWDPROP(bool, includeExternalContent, IncludeExternalContent)
     FWDPROP(bool, includeHidden, IncludeHidden)
-    FWDPROP(QStringList, presetViews, PresetViews)
+    FWDLISTPROP(Jellyfin::DTO::CollectionType, presetViews, PresetViews)
 };
 
 using LatestMediaBase = AbstractUserParameterLoader<Model::Item, DTO::BaseItemDto, QList<DTO::BaseItemDto>, Jellyfin::Loader::GetLatestMediaParams>;
@@ -141,12 +141,12 @@ public:
     FWDLISTPROP(Jellyfin::DTO::ItemFieldsClass::Value, fields, Fields)
     FWDPROP(bool, groupItems, GroupItems)
     FWDPROP(qint32, imageTypeLimit, ImageTypeLimit)
-    FWDPROP(QStringList, includeItemTypes, IncludeItemTypes)
+    FWDLISTPROP(Jellyfin::DTO::BaseItemKindClass::Value, includeItemTypes, IncludeItemTypes)
     FWDPROP(bool, isPlayed, IsPlayed)
     FWDPROP(QString, parentId, ParentId)
 };
 
-using UserItemsLoaderBase = AbstractUserParameterLoader<Model::Item, DTO::BaseItemDto, DTO::BaseItemDtoQueryResult, Jellyfin::Loader::GetItemsByUserIdParams>;
+using UserItemsLoaderBase = AbstractUserParameterLoader<Model::Item, DTO::BaseItemDto, DTO::BaseItemDtoQueryResult, Jellyfin::Loader::GetItemsParams>;
 class UserItemsLoader : public UserItemsLoaderBase {
     Q_OBJECT
 public:
@@ -166,7 +166,7 @@ public:
     FWDPROP(bool, enableUserData, EnableUserData)
     FWDPROP(QStringList, excludeArtistIds, ExcludeArtistIds)
     FWDPROP(QStringList, excludeItemIds, ExcludeItemIds)
-    FWDPROP(QStringList, excludeItemTypes, ExcludeItemTypes)
+    FWDLISTPROP(Jellyfin::DTO::BaseItemKindClass::Value, excludeItemTypes, ExcludeItemTypes)
     FWDPROP(QList<Jellyfin::DTO::LocationTypeClass::Value>, excludeLocationTypes, ExcludeLocationTypes)
     FWDLISTPROP(Jellyfin::DTO::ItemFieldsClass::Value, fields, Fields)
     FWDLISTPROP(Jellyfin::DTO::ItemFilterClass::Value, filters, Filters)
@@ -186,7 +186,7 @@ public:
     FWDPROP(QStringList, ids, Ids)
     FWDPROP(qint32, imageTypeLimit, ImageTypeLimit)
     FWDLISTPROP(Jellyfin::DTO::ImageTypeClass::Value, imageTypes, ImageTypes)
-    FWDPROP(QStringList, includeItemTypes, IncludeItemTypes)
+    FWDLISTPROP(Jellyfin::DTO::BaseItemKindClass::Value, includeItemTypes, IncludeItemTypes)
     FWDPROP(bool, is3D, Is3D)
     FWDPROP(bool, is4K, Is4K)
     FWDPROP(bool, isFavorite, IsFavorite)
@@ -201,13 +201,13 @@ public:
     FWDPROP(QString, maxOfficialRating, MaxOfficialRating)
     FWDPROP(QDateTime, maxPremiereDate, MaxPremiereDate)
     FWDPROP(qint32, maxWidth, MaxWidth)
-    FWDPROP(QStringList, mediaTypes, MediaTypes)
+    FWDLISTPROP(Jellyfin::DTO::MediaTypeClass::Value, mediaTypes, MediaTypes)
     FWDPROP(qint32, minHeight, MinHeight)
     FWDPROP(QString, minOfficialRating, MinOfficialRating)
     FWDPROP(QDateTime, minPremiereDate, MinPremiereDate)
     FWDPROP(qint32, minWidth, MinWidth)
-    FWDPROP(QString, sortBy, SortBy)
-    FWDPROP(QString, sortOrder, SortOrder)
+    FWDLISTPROP(Jellyfin::DTO::ItemSortByClass::Value, sortBy, SortBy)
+    FWDLISTPROP(Jellyfin::DTO::SortOrderClass::Value, sortOrder, SortOrder)
     FWDPROP(QStringList, tags, Tags)
     FWDPROP(QList<qint32>, years, Years)
 
@@ -227,11 +227,11 @@ public:
     FWDPROP(bool, enableImages, EnableImages)
     FWDPROP(bool, enableTotalRecordCount, EnableTotalRecordCount)
     FWDPROP(bool, enableUserData, EnableUserData)
-    FWDPROP(QStringList, excludeItemTypes, ExcludeItemTypes)
+    FWDLISTPROP(Jellyfin::DTO::BaseItemKindClass::Value, excludeItemTypes, ExcludeItemTypes)
     FWDLISTPROP(Jellyfin::DTO::ItemFieldsClass::Value, fields, Fields)
     FWDPROP(qint32, imageTypeLimit, ImageTypeLimit)
-    FWDPROP(QStringList, includeItemTypes, IncludeItemTypes)
-    FWDPROP(QStringList, mediaTypes, MediaTypes)
+    FWDLISTPROP(Jellyfin::DTO::BaseItemKindClass::Value, includeItemTypes, IncludeItemTypes)
+    FWDLISTPROP(Jellyfin::DTO::MediaTypeClass::Value, mediaTypes, MediaTypes)
     FWDPROP(QString, parentId, ParentId)
     FWDPROP(QString, searchTerm, SearchTerm)
 };
@@ -269,7 +269,7 @@ public:
     FWDPROP(bool, isMissing, IsMissing)
     FWDPROP(qint32, season, Season)
     FWDPROP(QString, seasonId, SeasonId)
-    FWDPROP(QString, sortBy, SortBy)
+    FWDPROP(Jellyfin::DTO::ItemSortByClass::Value, sortBy, SortBy)
     FWDPROP(QString, startItemId, StartItemId)
 };
 
@@ -281,7 +281,7 @@ public:
 
     FWDPROP(bool, disableFirstEpisode, DisableFirstEpisode)
     FWDLISTPROP(Jellyfin::DTO::ImageTypeClass::Value, enableImageTypes, EnableImageTypes);
-    FWDPROP(bool, enableImges, EnableImges)
+    FWDPROP(bool, enableImages, EnableImages)
     FWDPROP(bool, enableTotalRecordCount, EnableTotalRecordCount)
     FWDPROP(bool, enableUserData, EnableUserData)
     FWDLISTPROP(Jellyfin::DTO::ItemFieldsClass::Value, fields, Fields)
@@ -300,16 +300,16 @@ public:
     FWDPROP(bool, enableImages, EnableImages)
     FWDPROP(bool, enableTotalRecordCount, EnableTotalRecordCount)
     FWDPROP(bool, enableUserData, EnableUserData)
-    FWDPROP(QStringList, excludeItemTypes, ExcludeItemTypes)
+    FWDLISTPROP(Jellyfin::DTO::BaseItemKindClass::Value, excludeItemTypes, ExcludeItemTypes)
     FWDLISTPROP(Jellyfin::DTO::ItemFieldsClass::Value, fields, Fields)
     FWDLISTPROP(Jellyfin::DTO::ItemFilterClass::Value, filters, Filters)
     FWDPROP(QStringList, genreIds, GenreIds)
     FWDPROP(QStringList, genres, Genres)
     FWDPROP(qint32, imageTypeLimit, ImageTypeLimit)
-    FWDPROP(QStringList, includeItemTypes, IncludeItemTypes)
+    FWDLISTPROP(Jellyfin::DTO::BaseItemKindClass::Value, includeItemTypes, IncludeItemTypes)
     FWDPROP(bool, isFavorite, IsFavorite)
     FWDPROP(int, limit, Limit)
-    FWDPROP(QStringList, mediaTypes, MediaTypes)
+    FWDLISTPROP(Jellyfin::DTO::MediaTypeClass::Value, mediaTypes, MediaTypes)
     FWDPROP(double, minCommunityRating, MinCommunityRating)
     FWDPROP(QString, nameLessThan, NameLessThan)
     FWDPROP(QString, nameStartsWith, NameStartsWith)
@@ -347,7 +347,7 @@ public:
     FWDLISTPROP(Jellyfin::DTO::ImageTypeClass::Value, enableImageTypes, EnableImageTypes)
     FWDLISTPROP(Jellyfin::DTO::ItemFieldsClass::Value, fields, Fields)
     FWDPROP(bool, enableUserData, EnableUserData)
-    FWDPROP(QStringList, sortBy, SortBy)
+    FWDLISTPROP(Jellyfin::DTO::ItemSortByClass::Value, sortBy, SortBy)
     FWDPROP(Jellyfin::DTO::SortOrderClass::Value, sortOrder, SortOrder)
     FWDPROP(bool, enableFavoriteSorting, EnableFavoriteSorting)
     FWDPROP(bool, addCurrentProgram, AddCurrentProgram)
@@ -405,7 +405,7 @@ public:
 
     explicit ItemModel (QObject *parent = nullptr);
 
-    virtual QHash<int, QByteArray> roleNames() const override {
+    QHash<int, QByteArray> roleNames() const override {
         return {
             JFRN(jellyfinId),
             JFRN(name),
@@ -450,7 +450,7 @@ public:
     QSharedPointer<Model::Item> itemAt(int index);
 private slots:
     void onInsertItems(const QModelIndex &parent, int start, int end);
-    void onUserDataUpdated(const DTO::UserItemDataDto &newUserData);
+    void onUserDataUpdated(const Jellyfin::DTO::UserItemDataDto &newUserData);
 };
 #undef JFRN
 
diff --git a/core/include/JellyfinQt/viewmodel/mediastream.h b/core/include/JellyfinQt/viewmodel/mediastream.h
index 0728fdf..6a4b706 100644
--- a/core/include/JellyfinQt/viewmodel/mediastream.h
+++ b/core/include/JellyfinQt/viewmodel/mediastream.h
@@ -41,7 +41,7 @@ public:
     Q_PROPERTY(QString comment READ comment NOTIFY commentChanged);
     Q_PROPERTY(QString timeBase READ timeBase NOTIFY timeBaseChanged);
     Q_PROPERTY(QString title READ title NOTIFY titleChanged);
-    Q_PROPERTY(QString videoRange READ videoRange NOTIFY videoRangeChanged);
+    Q_PROPERTY(Jellyfin::DTO::VideoRangeClass::Value videoRange READ videoRange NOTIFY videoRangeChanged);
     Q_PROPERTY(QString localizedUndefined READ localizedUndefined NOTIFY localizedUndefinedChanged);
     Q_PROPERTY(QString localizedDefault READ localizedDefault NOTIFY localizedDefaultChanged);
     Q_PROPERTY(QString localizedForced READ localizedForced NOTIFY localizedForcedChanged);
@@ -78,7 +78,7 @@ public:
     QString comment() const { return m_data->comment(); }
     QString timeBase() const { return m_data->timeBase(); }
     QString title() const { return m_data->title(); }
-    QString videoRange() const { return m_data->videoRange(); }
+    DTO::VideoRange videoRange() const { return m_data->videoRange(); }
     QString localizedUndefined() const { return m_data->localizedUndefined(); }
     QString localizedDefault() const { return m_data->localizedDefault(); }
     QString localizedForced() const { return m_data->localizedForced(); }
@@ -116,7 +116,7 @@ signals:
     void commentChanged(const QString &newComment);
     void timeBaseChanged(const QString &newTimeBase);
     void titleChanged(const QString &newTitle);
-    void videoRangeChanged(const QString &newVideoRanged);
+    void videoRangeChanged(const DTO::VideoRange &newVideoRanged);
     void localizedUndefinedChanged(const QString &newLocalizedUndefined);
     void localizedDefaultChanged(const QString &newLocalizedDefault);
     void localizedForcedChanged(const QString &newLocalizedForced);
diff --git a/core/src/apiclient.cpp b/core/src/apiclient.cpp
index 6ccb740..d510559 100644
--- a/core/src/apiclient.cpp
+++ b/core/src/apiclient.cpp
@@ -430,15 +430,15 @@ void ApiClient::authenticate(QString username, QString password, bool storeCrede
 }
 
 void ApiClient::submitQuickConnectCode(const QString &code) {
-    using QQAuthorizeLoader = Loader::HTTP::AuthorizeLoader;
-    Loader::AuthorizeParams params;
+    using QQAuthorizeLoader = Loader::HTTP::AuthorizeQuickConnectLoader;
+    Loader::AuthorizeQuickConnectParams params;
     params.setCode(code);
 
     QQAuthorizeLoader *loader = new QQAuthorizeLoader(this);
     loader->setParameters(params);
     loader->load();
 
-    loader->connect(loader, &QQAuthorizeLoader::error, this, [this, loader](QString message) {
+    loader->connect(loader, &QQAuthorizeLoader::error, this, [this, loader](const QString &message) {
         qDebug() << "QQ error: " << message;
         emit this->quickConnectRejected();
         loader->deleteLater();
@@ -475,17 +475,18 @@ void ApiClient::generateDeviceProfile() {
     Q_D(ApiClient);
     QSharedPointer<DTO::DeviceProfile> deviceProfile = QSharedPointer<DTO::DeviceProfile>::create(Model::DeviceProfile::generateProfile());
     deviceProfile->setJellyfinId(d->deviceId);
-    deviceProfile->setFriendlyName(QSysInfo::prettyProductName());
+    deviceProfile->setName(QSysInfo::prettyProductName());
     deviceProfile->setMaxStreamingBitrate(d->settings->maxStreamingBitRate());
     d->deviceProfile = deviceProfile;
 
-    QSharedPointer<DTO::ClientCapabilitiesDto> clientCapabilities = QSharedPointer<DTO::ClientCapabilitiesDto>::create(true,  // supports mediaControl
-                                                                                                                       false, // supports content uploading
-                                                                                                                       true,  // supports persistent identifier
-                                                                                                                       false, // supports sync
-                                                                                                                       deviceProfile);
-    clientCapabilities->setPlayableMediaTypes({"Audio", "Video", "Photo"});
-    clientCapabilities->setSupportedCommands(d->supportedCommands);
+    QSharedPointer<DTO::ClientCapabilitiesDto> clientCapabilities = QSharedPointer<DTO::ClientCapabilitiesDto>::create(
+        QList({ MediaType::Audio, MediaType::Video, MediaType::Photo }),
+        d->supportedCommands,
+        true,  // supports mediaControl
+        true,  // supports persistent identifier
+        deviceProfile
+    );
+
     clientCapabilities->setAppStoreUrl("https://chris.netsoj.nl/projects/harbour-sailfin");
     clientCapabilities->setIconUrl("https://chris.netsoj.nl/static/img/logo.png");
 
diff --git a/core/src/apimodel.cpp b/core/src/apimodel.cpp
index 20113d9..36b43d9 100644
--- a/core/src/apimodel.cpp
+++ b/core/src/apimodel.cpp
@@ -64,7 +64,6 @@ void BaseModelLoader::setApiClient(ApiClient *newApiClient) {
 
 void BaseModelLoader::setLimit(int newLimit) {
     m_explicitLimitSet = newLimit >= 0;
-    qCDebug(jellyfinApiModel) << "Limit explicitly set to " << newLimit;
     this->m_limit = newLimit;
     emit limitChanged(newLimit);
 }
@@ -144,12 +143,12 @@ bool setRequestStartIndex(Loader::GetLatestMediaParams &params, int offset) {
 }
 
 template<>
-void setRequestLimit(Loader::GetItemsByUserIdParams &params, int limit) {
+void setRequestLimit(Loader::GetItemsParams &params, int limit) {
     params.setLimit(limit);
 }
 
 template<>
-bool setRequestStartIndex(Loader::GetItemsByUserIdParams &params, int index) {
+bool setRequestStartIndex(Loader::GetItemsParams &params, int index) {
     params.setStartIndex(index);
     return true;
 }
diff --git a/core/src/jellyfin.cpp b/core/src/jellyfin.cpp
index 8efcca3..c15d13f 100644
--- a/core/src/jellyfin.cpp
+++ b/core/src/jellyfin.cpp
@@ -18,7 +18,9 @@
 */
 #include "JellyfinQt/jellyfin.h"
 
+#include "JellyfinQt/dto/collectiontype.h"
 #include "JellyfinQt/model/item.h"
+#include "JellyfinQt/dto/itemsortby.h"
 #include "JellyfinQt/dto/itemfields.h"
 #include "JellyfinQt/dto/mediastream.h"
 #include "JellyfinQt/dto/nameguidpair.h"
@@ -92,11 +94,16 @@ void JellyfinPlugin::registerTypes(const char *uri) {
     qmlRegisterType<ViewModel::LiveTvChannelsLoader>(uri, 1, 0, "LiveTvChannelsLoader");
 
     // Enumerations
+    qmlRegisterUncreatableType<Jellyfin::DTO::CollectionTypeClass>(uri, 1, 0, "CollectionType", "Is an enum");
     qmlRegisterUncreatableType<Jellyfin::DTO::GeneralCommandTypeClass>(uri, 1, 0, "GeneralCommandType", "Is an enum");
-    qmlRegisterUncreatableType<Jellyfin::ViewModel::ModelStatusClass>(uri, 1, 0, "ModelStatus", "Is an enum");
-    qmlRegisterUncreatableType<Jellyfin::DTO::PlayMethodClass>(uri, 1, 0, "PlayMethod", "Is an enum");
     qmlRegisterUncreatableType<Jellyfin::DTO::ItemFieldsClass>(uri, 1, 0, "ItemFields", "Is an enum");
     qmlRegisterUncreatableType<Jellyfin::DTO::ImageTypeClass>(uri, 1, 0, "ImageType", "Is an enum");
+    qmlRegisterUncreatableType<Jellyfin::DTO::MediaTypeClass>(uri, 1, 0, "MediaType", "Is an enum");
+    qmlRegisterUncreatableType<Jellyfin::DTO::BaseItemKindClass>(uri, 1, 0, "ItemType", "Is an enum");
+    qmlRegisterUncreatableType<Jellyfin::DTO::PlayMethodClass>(uri, 1, 0, "PlayMethod", "Is an enum");
+    qmlRegisterUncreatableType<Jellyfin::DTO::ItemSortByClass>(uri, 1, 0, "SortBy", "Is an enum");
+    qmlRegisterUncreatableType<Jellyfin::DTO::SortOrderClass>(uri, 1, 0, "SortOrder", "Is an enum");
+    qmlRegisterUncreatableType<Jellyfin::ViewModel::ModelStatusClass>(uri, 1, 0, "ModelStatus", "Is an enum");
     qmlRegisterUncreatableType<Jellyfin::ViewModel::NowPlayingSection>(uri, 1, 0, "NowPlayingSection", "Is an enum");
     qmlRegisterUncreatableType<Jellyfin::Model::PlayerStateClass>(uri, 1, 0, "PlayerState", "Is an enum");
     qmlRegisterUncreatableType<Jellyfin::Model::MediaStatusClass>(uri, 1, 0, "MediaStatus", "Is an enum");
diff --git a/core/src/model/controllablesession.cpp b/core/src/model/controllablesession.cpp
index a1b3b70..c499575 100644
--- a/core/src/model/controllablesession.cpp
+++ b/core/src/model/controllablesession.cpp
@@ -46,7 +46,7 @@ PlaybackManager *LocalSession::createPlaybackManager() const {
 }
 
 // ControllableJellyfinSession
-ControllableJellyfinSession::ControllableJellyfinSession(const QSharedPointer<DTO::SessionInfo> info, ApiClient &apiClient, QObject *parent)
+ControllableJellyfinSession::ControllableJellyfinSession(const QSharedPointer<DTO::SessionInfoDto> info, ApiClient &apiClient, QObject *parent)
     : ControllableSession(parent),
       m_data(info),
       m_apiClient(apiClient){}
@@ -147,14 +147,15 @@ void RemoteJellyfinSessionScanner::startScanning() {
     d->loader->setParameters(params);
     connect(d->loader, &Loader::HTTP::GetSessionsLoader::ready, this, [this, d, localSession]() {
         if (d->loader == nullptr) return;
-        QList<DTO::SessionInfo> sessions = d->loader->result();
+        QList<DTO::SessionInfoDto> sessions = d->loader->result();
+        qDebug() << "Found " << sessions.count() << " sessions";
 
         for(auto it = sessions.begin(); it != sessions.end(); it++) {
 
             // Skip this device
             if (it->deviceId() == localSession->id()) continue;
 
-            emit sessionFound(new ControllableJellyfinSession(QSharedPointer<DTO::SessionInfo>::create(*it), *d->apiClient));
+            emit sessionFound(new ControllableJellyfinSession(QSharedPointer<DTO::SessionInfoDto>::create(*it), *d->apiClient));
         }
     });
     d->loader->load();
diff --git a/core/src/model/deviceprofile.cpp b/core/src/model/deviceprofile.cpp
index ba5363a..8c6fdf1 100644
--- a/core/src/model/deviceprofile.cpp
+++ b/core/src/model/deviceprofile.cpp
@@ -53,8 +53,6 @@ int DeviceProfile::maxStreamingBitrate() {
 }
 
 DTO::DeviceProfile DeviceProfile::generateProfile() {
-    using JsonPair = QPair<QString, QJsonValue>;
-
     QStringList audioCodes = {
         "aac",
         "flac",
@@ -94,130 +92,138 @@ DTO::DeviceProfile DeviceProfile::generateProfile() {
 
 
     // AAC
-    DTO::CodecProfile codecProfile1(DTO::CodecType::VideoAudio);
+    DTO::CodecProfile codecProfile1(
+        DTO::CodecType::VideoAudio,
+        {
+            createCondition(CondVal::IsSecondaryAudio,
+                            Condition::Equals,
+                            "false",
+                            false)
+        },
+        {}
+    );
     codecProfile1.setCodec("aac");
-    QList<DTO::ProfileCondition> codecProfile1Conditions;
-    codecProfile1Conditions.append(createCondition(CondVal::IsSecondaryAudio,
-                                                   Condition::Equals,
-                                                   "false",
-                                                   false));
-    codecProfile1.setConditions(codecProfile1Conditions);
 
-
-    DTO::CodecProfile codecProfile2(DTO::CodecType::Video);
-    codecProfile2.setCodec("h264");
-    codecProfile2.setConditions({
-                    createCondition(CondVal::IsAnamorphic,
+    DTO::CodecProfile codecProfile2(
+        DTO::CodecType::Video,
+        {
+            createCondition(CondVal::IsAnamorphic,
                                     Condition::NotEquals,
                                     "true", false),
-                    createCondition(CondVal::VideoProfile,
-                                    Condition::EqualsAny,
-                                    "baseline|constrained baseline", false), //"high|main|baseline|constrained baseline"
-                    createCondition(CondVal::VideoLevel,
-                                    Condition::LessThanEqual,
-                                    "51", false),
-                    createCondition(CondVal::IsInterlaced,
-                                    Condition::NotEquals,
-                                    "true", false)
-                });
+            createCondition(CondVal::VideoProfile,
+                            Condition::EqualsAny,
+                            "baseline|constrained baseline", false), //"high|main|baseline|constrained baseline"
+            createCondition(CondVal::VideoLevel,
+                            Condition::LessThanEqual,
+                            "51", false),
+            createCondition(CondVal::IsInterlaced,
+                            Condition::NotEquals,
+                            "true", false)
+        },
+        {}
+    );
+    codecProfile2.setCodec("h264");
 
     QList<DTO::CodecProfile> codecProfiles = {
         codecProfile1,
         codecProfile2
     };
     // Hard coded nr 1:
-    DTO::TranscodingProfile transcoding1(DTO::DlnaProfileType::Audio,
-                                         false, // estimeateContentLength
-                                         false,  // enable MPEG2 TS M2 mode
-                                         DTO::TranscodeSeekInfo::Auto,
-                                         false, // copyTimestamps
-                                         DTO::EncodingContext::Streaming,
-                                         false, // enable subtitles in manifest
-                                         0, // minSegments
-                                         0, // minSegmentLength
-                                         true // set break on nonkeyframes
-                                         );
-    transcoding1.setAudioCodec("aac");
-    transcoding1.setContainer("ts");
+    DTO::TranscodingProfile transcoding1(
+        QStringLiteral("ts"),
+        DTO::DlnaProfileType::Audio,
+        QStringLiteral("h264"),
+        QStringLiteral("aac"),
+        DTO::MediaStreamProtocol::Hls,
+        false, // estimeateContentLength
+        false,  // enable MPEG2 TS M2 mode
+        DTO::TranscodeSeekInfo::Auto,
+        false, // copyTimestamps
+        DTO::EncodingContext::Streaming,
+        false, // enable subtitles in manifest
+        0, // minSegments
+        0, // minSegmentLength
+        true, // set break on nonkeyframes,
+        {}, // conditions
+        true // Enable audio VBR encoding
+    );
     transcoding1.setMaxAudioChannels("2");
-    transcoding1.setProtocol("hls");
 
     // Hard code nr 2
-    DTO::TranscodingProfile transcoding2(DTO::DlnaProfileType::Video,
-                                         false, // estimate content length
-                                         false, // enable MPEG2 ts M2 mode
-                                         DTO::TranscodeSeekInfo::Auto,
-                                         false, // copy timestamps
-                                         DTO::EncodingContext::Streaming,
-                                         false, // enable subtitles in manifest
-                                         0, // minSegments
-                                         0, // minSegmentLength
-                                         true // set break on non-keyframes
-                                         );
-    transcoding2.setAudioCodec("mp3,aac");
-    transcoding2.setContainer("ts");
+    DTO::TranscodingProfile transcoding2(
+        QStringLiteral("ts"),
+        DTO::DlnaProfileType::Video,
+        QStringLiteral("h264"),
+        QStringLiteral("mp3,aac"),
+        DTO::MediaStreamProtocol::Hls,
+        false, // estimate content length
+        false, // enable MPEG2 ts M2 mode
+        DTO::TranscodeSeekInfo::Auto,
+        false, // copy timestamps
+        DTO::EncodingContext::Streaming,
+        false, // enable subtitles in manifest
+        0, // minSegments
+        0, // minSegmentLength
+        true, // set break on non-keyframes
+        {}, // conditions
+        true// enableAudioVbrEncoding
+    );
     transcoding2.setMaxAudioChannels("2");
-    transcoding2.setProtocol("hls");
-    transcoding2.setVideoCodec("h264");
 
     // Fallback
-    DTO::TranscodingProfile transcoding3(DTO::DlnaProfileType::Video,
-                                         false, // estimate content length
-                                         false, // enable MPEG2 ts M2 mode
-                                         DTO::TranscodeSeekInfo::Auto,
-                                         false, // copy timestamps
-                                         DTO::EncodingContext::Static,
-                                         false, // enable subtitles in manifest
-                                         0, // minSegments
-                                         0, // minSegmentLength
-                                         true // set break on non-keyframes
-                                         );
-    transcoding3.setContainer("mp4");
-    transcoding3.setAudioCodec(videoAudioCodecs.join(','));
-    transcoding3.setVideoCodec("h264");
-    transcoding3.setProtocol("http");
+    DTO::TranscodingProfile transcoding3(
+        QStringLiteral("mp4"),
+        DTO::DlnaProfileType::Video,
+        QStringLiteral("h264"),
+        videoAudioCodecs.join(","),
+        DTO::MediaStreamProtocol::Http,
+        false, // estimate content length
+        false, // enable MPEG2 ts M2 mode
+        DTO::TranscodeSeekInfo::Auto,
+        false, // copy timestamps
+        DTO::EncodingContext::Static,
+        false, // enable subtitles in manifest
+        0, // minSegments
+        0, // minSegmentLength
+        true, // set break on non-keyframes
+        {},
+        true
+    );
 
     QList<DTO::TranscodingProfile> transcodingProfiles = {
         transcoding1, transcoding2, transcoding3
     };
 
     if (supportsHls() && !hlsVideoAudioCodecs.isEmpty()) {
-        DTO::TranscodingProfile transcoding4(DTO::DlnaProfileType::Video,
-                                             false, // estimate content length
-                                             false, // enable MPEG2 ts M2 mode
-                                             DTO::TranscodeSeekInfo::Auto,
-                                             false, // copy timestamps
-                                             DTO::EncodingContext::Streaming,
-                                             false, // enable subtitles in manifest
-                                             1, // minSegments
-                                             0, // minSegmentLength
-                                             true // set break on non-keyframes
-                                             );
-        transcoding4.setContainer("ts");
-        transcoding4.setAudioCodec(hlsVideoAudioCodecs.join(','));
-        transcoding4.setVideoCodec(hlsVideoCodecs.join(','));
-        transcoding4.setProtocol("hls");
+        DTO::TranscodingProfile transcoding4(
+            QStringLiteral("ts"),
+            DTO::DlnaProfileType::Video,
+            hlsVideoAudioCodecs.join(","),
+            hlsVideoAudioCodecs.join(","),
+            DTO::MediaStreamProtocol::Hls,
+            false, // estimate content length
+            false, // enable MPEG2 ts M2 mode
+            DTO::TranscodeSeekInfo::Auto,
+            false, // copy timestamps
+            DTO::EncodingContext::Streaming,
+            false, // enable subtitles in manifest
+            1, // minSegments
+            0, // minSegmentLength
+            true, // set break on non-keyframes
+            {},
+            true
+         );
         transcoding4.setMaxAudioChannels("2");
         transcodingProfiles.append(transcoding4);
     }
 
-    // Response profiles (or whatever it actually does?)
-    DTO::ResponseProfile responseProfile1(DTO::DlnaProfileType::Video);
-    responseProfile1.setContainer("m4v");
-    responseProfile1.setMimeType("video/mp4");
-    QList<DTO::ResponseProfile> responseProfiles = {
-        responseProfile1
-    };
-
     // Direct play profiles
     // Video
-    DTO::DirectPlayProfile directPlayProfile1(DTO::DlnaProfileType::Video);
-    directPlayProfile1.setContainer("mp4,m4v");
+    DTO::DirectPlayProfile directPlayProfile1("mp4,m4v", DTO::DlnaProfileType::Video);
     directPlayProfile1.setVideoCodec(mp4VideoCodecs.join(','));
     directPlayProfile1.setAudioCodec(videoAudioCodecs.join(','));
 
-    DTO::DirectPlayProfile directPlayProfile2(DTO::DlnaProfileType::Video);
-    directPlayProfile2.setContainer("mkv");
+    DTO::DirectPlayProfile directPlayProfile2("mkv", DTO::DlnaProfileType::Video);
     directPlayProfile2.setVideoCodec(mp4VideoCodecs.join(','));
     directPlayProfile2.setAudioCodec(videoAudioCodecs.join(','));
 
@@ -227,43 +233,36 @@ DTO::DeviceProfile DeviceProfile::generateProfile() {
     // Audio
     for (auto it = audioCodes.begin(); it != audioCodes.end(); it++) {
         if (*it == "mp2") {
-            DTO::DirectPlayProfile profile(DTO::DlnaProfileType::Audio);
-            profile.setContainer("mp2,mp3");
+            DTO::DirectPlayProfile profile("mp2,mp3", DTO::DlnaProfileType::Audio);
             profile.setAudioCodec("mp2");
             directPlayProfiles.append(profile);
         } else if(*it == "mp3") {
-            DTO::DirectPlayProfile profile(DTO::DlnaProfileType::Audio);
-            profile.setContainer("mp3");
+            DTO::DirectPlayProfile profile("mp3", DTO::DlnaProfileType::Audio);
             profile.setAudioCodec("mp3");
             directPlayProfiles.append(profile);
         } else if (*it == "webma") {
-            DTO::DirectPlayProfile profile(DTO::DlnaProfileType::Audio);
-            profile.setContainer("webma,webm");
+            DTO::DirectPlayProfile profile("webma,webm", DTO::DlnaProfileType::Audio);
             directPlayProfiles.append(profile);
         } else {
-            DTO::DirectPlayProfile profile(DTO::DlnaProfileType::Audio);
-            profile.setContainer(*it);
+            DTO::DirectPlayProfile profile(*it, DTO::DlnaProfileType::Audio);
             directPlayProfiles.append(profile);
         }
     }
 
+    QList<DTO::ContainerProfile> containerProfiles = { };
+
+    QList<DTO::SubtitleProfile> subtitleProfiles = {
+        DTO::SubtitleProfile(DTO::SubtitleDeliveryMethodClass::Hls),
+        DTO::SubtitleProfile(DTO::SubtitleDeliveryMethodClass::Encode)
+    };
+
     DTO::DeviceProfile profile(
-                QSharedPointer<DTO::DeviceIdentification>::create(),
-                false, // enableAlbumArtInDidl
-                false, // enableSingleAlbumArtLimit
-                false, // enableSingleSubtitleLimit
-                std::numeric_limits<qint32>().max(), // max album art width
-                std::numeric_limits<qint32>().max(), // max album art height
-                0,     // timeline offset seconds
-                false, // request plain video items
-                false, // request plain folders
-                false, // enableMSMediaReceiverRegistrar,
-                false  //ignoreTranscodeByteRangeRequests
+        directPlayProfiles,
+        transcodingProfiles,
+        containerProfiles,
+        codecProfiles,
+        subtitleProfiles
     );
-    profile.setCodecProfiles(codecProfiles);
-    profile.setDirectPlayProfiles(directPlayProfiles);
-    profile.setResponseProfiles(responseProfiles);
-    profile.setTranscodingProfiles(transcodingProfiles);
     profile.setMaxStreamingBitrate(std::make_optional<qint32>(maxStreamingBitrate()));
     return profile;
 }
diff --git a/core/src/model/item.cpp b/core/src/model/item.cpp
index 4687e68..496dcc7 100644
--- a/core/src/model/item.cpp
+++ b/core/src/model/item.cpp
@@ -26,12 +26,16 @@ namespace Model {
 Item::Item(ApiClient *apiClient, QObject *parent)
     : Item(DTO::BaseItemDto(
                 QString(), // id
+                ExtraType::Unknown,
                 Video3DFormat::EnumNotSet,
                 PlayAccess::Full,
-                QSharedPointer<UserItemDataDto>::create(0, 0, false, false),
+                BaseItemKind::EnumNotSet,
+                QSharedPointer<UserItemDataDto>::create(0, 0, false, false, QString(), QString()),
+                CollectionType::EnumNotSet,
                 VideoType::EnumNotSet,
                 LocationType::Virtual,
                 IsoType::EnumNotSet,
+                MediaType::EnumNotSet,
                 ImageOrientation::EnumNotSet,
                 ChannelType::EnumNotSet,
                 ProgramAudio::EnumNotSet,
diff --git a/core/src/model/playbackmanager.cpp b/core/src/model/playbackmanager.cpp
index 5bd254c..2cb65b7 100644
--- a/core/src/model/playbackmanager.cpp
+++ b/core/src/model/playbackmanager.cpp
@@ -232,7 +232,7 @@ public:
     void requestItemUrl(QSharedPointer<Model::Item> item);
 
     // slots
-    void handlePlaybackInfoResponse(QString itemId, QString mediaType, DTO::PlaybackInfoResponse &response);
+    void handlePlaybackInfoResponse(QString itemId, MediaType mediaType, DTO::PlaybackInfoResponse &response);
     /// Called when we have fetched the playback URL and playSession
     void onItemUrlReceived(const QString &itemId, const QUrl &url, const QString &playSession,
                                  // Fully specify class to please MOC
@@ -352,7 +352,7 @@ void LocalPlaybackManagerPrivate::setItem(QSharedPointer<Model::Item> newItem) {
     }
 }
 
-void LocalPlaybackManagerPrivate::handlePlaybackInfoResponse(QString itemId, QString mediaType, DTO::PlaybackInfoResponse &response) {
+void LocalPlaybackManagerPrivate::handlePlaybackInfoResponse(QString itemId, MediaType mediaType, DTO::PlaybackInfoResponse &response) {
     Q_Q(LocalPlaybackManager);
     //TODO: move the item URL fetching logic out of this function, into MediaSourceInfo?
     QList<DTO::MediaSourceInfo> mediaSources = response.mediaSources();
@@ -394,15 +394,16 @@ void LocalPlaybackManagerPrivate::handlePlaybackInfoResponse(QString itemId, QSt
             resultingUrl = QUrl::fromLocalFile(source.path());
             playMethod = PlayMethod::DirectPlay;
         } else if (source.supportsDirectStream() && !transcodePreferred) {
-            if (mediaType == "Video") {
-                mediaType.append('s');
+            QString mediaTypeUrl = Support::toString(mediaType);
+            if (mediaType == MediaType::Video) {
+                mediaTypeUrl.append('s');
             }
             QUrlQuery query;
             query.addQueryItem("mediaSourceId", source.jellyfinId());
             query.addQueryItem("deviceId", m_apiClient->deviceId());
             query.addQueryItem("api_key", m_apiClient->token());
             query.addQueryItem("Static", "True");
-            resultingUrl = QUrl(m_apiClient->baseUrl() + "/" + mediaType + "/" + itemId
+            resultingUrl = QUrl(m_apiClient->baseUrl() + "/" + mediaTypeUrl + "/" + itemId
                     + "/stream." + source.container() + "?" + query.toString(QUrl::EncodeReserved));
             playMethod = PlayMethod::DirectStream;
         } else if (source.supportsTranscoding() && !source.transcodingUrlNull() && transcodingAllowed) {
diff --git a/core/src/model/playbackreporter.cpp b/core/src/model/playbackreporter.cpp
index 8d26b10..1b27fb3 100644
--- a/core/src/model/playbackreporter.cpp
+++ b/core/src/model/playbackreporter.cpp
@@ -149,7 +149,9 @@ void PlaybackReporterPrivate::postPlaybackInfo(PlaybackInfoType type) {
                 m_playbackManager->player()->state() == PlayerState::Paused,
                 false, // is muted?
                 m_playbackManager->playMethod(),
-                DTO::RepeatMode::RepeatNone);
+                DTO::RepeatMode::RepeatNone,
+                DTO::PlaybackOrder::Default
+                );
 
     progress.setSessionId(m_playbackManager->sessionId());
 
diff --git a/core/src/model/remotejellyfinplayback.cpp b/core/src/model/remotejellyfinplayback.cpp
index 213cc12..76d6e6b 100644
--- a/core/src/model/remotejellyfinplayback.cpp
+++ b/core/src/model/remotejellyfinplayback.cpp
@@ -20,7 +20,7 @@
 #include <JellyfinQt/model/remotejellyfinplayback.h>
 
 #include <JellyfinQt/apiclient.h>
-#include <JellyfinQt/dto/sessioninfo.h>
+#include <JellyfinQt/dto/sessioninfodto.h>
 #include <JellyfinQt/loader/http/items.h>
 #include <JellyfinQt/loader/http/session.h>
 #include <JellyfinQt/loader/requesttypes.h>
@@ -174,7 +174,7 @@ void RemoteJellyfinPlayback::onPositionTimerFired() {
     emit positionChanged(position());
 }
 
-void RemoteJellyfinPlayback::onSessionInfoUpdated(const QString &sessionId, const SessionInfo &sessionInfo) {
+void RemoteJellyfinPlayback::onSessionInfoUpdated(const QString &sessionId, const SessionInfoDto &sessionInfo) {
     if (sessionId != m_sessionId) return;
     m_lastSessionInfo = sessionInfo;
 
@@ -245,8 +245,7 @@ void RemoteJellyfinPlayback::sendGeneralCommand(DTO::GeneralCommandType command,
     using CommandLoader = Loader::HTTP::SendFullGeneralCommandLoader;
 
     Params params;
-    QSharedPointer<DTO::GeneralCommand> fullCommand = QSharedPointer<DTO::GeneralCommand>::create(command, m_apiClient.userId());
-    fullCommand->setArguments(arguments);
+    QSharedPointer<DTO::GeneralCommand> fullCommand = QSharedPointer<DTO::GeneralCommand>::create(command, m_apiClient.userId(), arguments);
     params.setBody(fullCommand);
     params.setSessionId(m_sessionId);
 
diff --git a/core/src/viewmodel/item.cpp b/core/src/viewmodel/item.cpp
index 85a452f..cfa54fa 100644
--- a/core/src/viewmodel/item.cpp
+++ b/core/src/viewmodel/item.cpp
@@ -101,7 +101,7 @@ void Item::setUserData(DTO::UserItemDataDto &newData) {
 
 void Item::setUserData(QSharedPointer<DTO::UserItemDataDto> newData)  {
     if (m_data.isNull() || m_data->userData().isNull()) {
-        m_userData->setData(QSharedPointer<DTO::UserData>::create(0, 0, false, false));
+        m_userData->setData(QSharedPointer<DTO::UserData>::create(0, 0, false, false, QString(), QString()));
     } else {
         m_userData->setData(newData);
     }
diff --git a/core/src/viewmodel/itemmodel.cpp b/core/src/viewmodel/itemmodel.cpp
index 10c648b..24c2902 100644
--- a/core/src/viewmodel/itemmodel.cpp
+++ b/core/src/viewmodel/itemmodel.cpp
@@ -48,7 +48,7 @@ LatestMediaLoader::LatestMediaLoader(QObject *parent)
     : LatestMediaBase(new Jellyfin::Loader::HTTP::GetLatestMediaLoader(), parent){ }
 
 UserItemsLoader::UserItemsLoader(QObject *parent)
-    : UserItemsLoaderBase(new Jellyfin::Loader::HTTP::GetItemsByUserIdLoader(), parent) {}
+    : UserItemsLoaderBase(new Jellyfin::Loader::HTTP::GetItemsLoader(), parent) {}
 
 ResumeItemsLoader::ResumeItemsLoader(QObject *parent)
     : ResumeItemsLoaderBase(new Jellyfin::Loader::HTTP::GetResumeItemsLoader(), parent) {}
diff --git a/core/src/viewmodel/userdata.cpp b/core/src/viewmodel/userdata.cpp
index a4dda54..184b428 100644
--- a/core/src/viewmodel/userdata.cpp
+++ b/core/src/viewmodel/userdata.cpp
@@ -22,7 +22,7 @@ namespace Jellyfin {
 namespace ViewModel {
 
 UserData::UserData(QObject *parent)
-    : UserData(QSharedPointer<DTO::UserItemDataDto>::create(0, 0, false, false), parent) {
+    : UserData(QSharedPointer<DTO::UserItemDataDto>::create(0, 0, false, false, QString(), QString()), parent) {
 
 }
 
@@ -30,13 +30,13 @@ UserData::UserData(QSharedPointer<DTO::UserItemDataDto> data, QObject *parent)
     : QObject(parent),
       m_data(data) {
     if (m_data.isNull()) {
-        m_data = QSharedPointer<DTO::UserItemDataDto>::create(0, 0, false, false);
+        m_data = QSharedPointer<DTO::UserItemDataDto>::create(0, 0, false, false, QString(), QString());
     }
 }
 
 void UserData::setData(QSharedPointer<DTO::UserItemDataDto> data) {
     if (data.isNull()) {
-        m_data = QSharedPointer<DTO::UserItemDataDto>::create(0, 0, false, false);
+        m_data = QSharedPointer<DTO::UserItemDataDto>::create(0, 0, false, false, QString(), QString());
     } else {
         m_data = data;
     }
diff --git a/core/src/websocket.cpp b/core/src/websocket.cpp
index bc7a99f..16e3eac 100644
--- a/core/src/websocket.cpp
+++ b/core/src/websocket.cpp
@@ -22,7 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 #include <JellyfinQt/dto/generalcommand.h>
 #include <JellyfinQt/dto/generalcommandtype.h>
 #include <JellyfinQt/dto/playstaterequest.h>
-#include <JellyfinQt/dto/sessioninfo.h>
+#include <JellyfinQt/dto/sessioninfodto.h>
 #include <JellyfinQt/dto/useritemdatadto.h>
 
 Q_LOGGING_CATEGORY(jellyfinWebSocket, "jellyfin.websocket");
@@ -157,7 +157,7 @@ void WebSocket::textMessageReceived(const QString &message) {
         }
     } else if (messageType == QStringLiteral("Sessions")) {
         try {
-            QList<DTO::SessionInfo> sessionInfoList = Support::fromJsonValue<QList<DTO::SessionInfo>>(data);
+            QList<DTO::SessionInfoDto> sessionInfoList = Support::fromJsonValue<QList<DTO::SessionInfoDto>>(data);
             for (auto it = sessionInfoList.cbegin(); it != sessionInfoList.cend(); it++) {
                 emit m_apiClient->eventbus()->sessionInfoUpdated(it->jellyfinId(), *it);
             }
diff --git a/qtquick/qml/ApiClient.qml b/qtquick/qml/ApiClient.qml
index 643e0d3..0d3edbb 100644
--- a/qtquick/qml/ApiClient.qml
+++ b/qtquick/qml/ApiClient.qml
@@ -3,5 +3,6 @@ import QtQuick 2.12
 import nl.netsoj.chris.Jellyfin 1.0 as J
 
 J.ApiClient {
+    appName: "Sailfin QtQuick"
     supportedCommands: [J.GeneralCommandType.Play, J.GeneralCommandType.DisplayContent, J.GeneralCommandType.DisplayMessage]
 }
diff --git a/qtquick/qml/main.qml b/qtquick/qml/main.qml
index cec66b3..7104305 100644
--- a/qtquick/qml/main.qml
+++ b/qtquick/qml/main.qml
@@ -110,7 +110,7 @@ ApplicationWindow {
                 enabled: playbackManager.hasPrevious
             }
             Button {
-                readonly property bool _playing: playbackManager.playbackState === PlayerState.Playing
+                readonly property bool _playing: playbackManager.playbackState === J.PlayerState.Playing
                 anchors.verticalCenter: parent.verticalCenter
                 text:  _playing ? "Pause" : "Play"
                 onClicked: _playing ? playbackManager.pause() : playbackManager.play()
diff --git a/qtquick/qml/pages/MainPage.qml b/qtquick/qml/pages/MainPage.qml
index b58e33b..49d01e8 100644
--- a/qtquick/qml/pages/MainPage.qml
+++ b/qtquick/qml/pages/MainPage.qml
@@ -34,10 +34,21 @@ Page {
         Column {
             id: content
             width: parent.width
-            CheckBox {
-                checked: ApiClient.settings.allowTranscoding
-                text: "allow transcoding"
-                onCheckedChanged: ApiClient.settings.allowTranscoding = checked
+            Row {
+                CheckBox {
+                    checked: ApiClient.settings.allowTranscoding
+                    text: "allow transcoding"
+                    onCheckedChanged: ApiClient.settings.allowTranscoding = checked
+                }
+                ComboBox {
+                    model: J.RemoteDeviceList {
+                        id: deviceList
+                        apiClient: ApiClient
+                        scanning: _modelsLoaded == true
+                    }
+                    textRole: "deviceName"
+                    width: 400
+                }
             }
             Repeater {
                 model: mediaLibraryModel
diff --git a/sailfish/qml/Utils.js b/sailfish/qml/Utils.js
index 3b702fa..268b003 100644
--- a/sailfish/qml/Utils.js
+++ b/sailfish/qml/Utils.js
@@ -18,6 +18,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
 
 .pragma library
+.import nl.netsoj.chris.Jellyfin 1.0 as J
 
 /**
  * Converts miliseconds to a h:mm:ss format
@@ -89,54 +90,60 @@ function itemModelImageUrl(baseUrl, itemId, tag, type, options) {
 }
 
 function usePortraitCover(itemType) {
-    return ["Series", "Movie", "tvshows", "movies"].indexOf(itemType) >= 0
+    var portraitTypes = [J.ItemType.Series, J.ItemType.Movie, J.CollectionType.Tvshows, J.CollectionType.Movies]
+    console.log("UsePortraitCover itemType: ", itemType)
+    return portraitTypes.indexOf(itemType) >= 0
 }
 
 /**
  * Returns the page url for a certain item type.
  */
 function getPageUrl(mediaType, itemType, isFolder) {
-    switch (itemType.toLowerCase()) {
-    case "series":
+    switch (itemType) {
+    case J.ItemType.Series:
         return Qt.resolvedUrl("pages/itemdetails/SeriesPage.qml")
-    case "movie":
+    case J.ItemType.Movie:
         return Qt.resolvedUrl("pages/itemdetails/FilmPage.qml")
-    case "collection":
-    case "photoalbum":
+    case J.ItemType.Folder:
+    case J.ItemType.PhotoAlbum:
         return Qt.resolvedUrl("pages/itemdetails/CollectionPage.qml")
-    case "season":
+    case J.ItemType.Season:
         return Qt.resolvedUrl("pages/itemdetails/SeasonPage.qml")
-    case "episode":
+    case J.ItemType.Episode:
         return Qt.resolvedUrl("pages/itemdetails/EpisodePage.qml")
-    case "musicartist":
+    case J.ItemType.MusicArtist:
         return Qt.resolvedUrl("pages/itemdetails/MusicArtistPage.qml")
-    case "musicalbum":
-    case "playlist":
+    case J.ItemType.MusicAlbum:
+    case J.ItemType.Playlist:
         return Qt.resolvedUrl("pages/itemdetails/MusicAlbumPage.qml")
-    case "photo":
+    case J.ItemType.Photo:
         return Qt.resolvedUrl("pages/itemdetails/PhotoPage.qml")
-    case "tvchannel":
+    case J.ItemType.TvChannel:
         return Qt.resolvedUrl("pages/itemdetails/LiveTvChannelPage.qml")
-    case "collectionfolder":
+    case J.ItemType.CollectionFolder:
         // TODO: support for other collection folders
-        switch(mediaType.toLowerCase()) {
-        case "music":
+        switch(mediaType) {
+        case J.CollectionType.Music:
             return Qt.resolvedUrl("pages/itemdetails/MusicLibraryPage.qml")
         }
         // FALLTRHOUGH
     default:
-        switch (mediaType ? mediaType.toLowerCase() : isFolder ? "folder" : "") {
-        case "livetv":
-            return Qt.resolvedUrl("pages/itemdetails/LiveTvChannelsPage.qml")
-        case "folder":
-            return Qt.resolvedUrl("pages/itemdetails/CollectionPage.qml")
-        case "video":
-            return Qt.resolvedUrl("pages/itemdetails/VideoPage.qml")
-        case "photo":
-            return Qt.resolvedUrl("pages/itemdetails/PhotoPage.qml")
-        default:
-            if (isFolder) return Qt.resolvedUrl("pages/itemdetails/CollectionPage.qml")
-            return Qt.resolvedUrl("pages/itemdetails/UnsupportedPage.qml")
+        if (isFolder) {
+            switch (mediaType) {
+            case J.CollectionType.Livetv:
+                return Qt.resolvedUrl("pages/itemdetails/LiveTvChannelsPage.qml")
+            default:
+                return Qt.resolvedUrl("pages/itemdetails/CollectionPage.qml")
+            }
+        } else {
+            switch (mediaType) {
+            case J.MediaType.Photo:
+                return Qt.resolvedUrl("pages/itemdetails/PhotoPage.qml")
+            case J.MediaType.Video:
+                return Qt.resolvedUrl("pages/itemdetails/VideoPage.qml")
+            default:
+                return Qt.resolvedUrl("pages/itemdetails/UnsupportedPage.qml")
+            }
         }
     }
 }
diff --git a/sailfish/qml/components/ItemChildrenShowcase.qml b/sailfish/qml/components/ItemChildrenShowcase.qml
index 93084e5..cc91a68 100644
--- a/sailfish/qml/components/ItemChildrenShowcase.qml
+++ b/sailfish/qml/components/ItemChildrenShowcase.qml
@@ -10,7 +10,7 @@ MoreSection {
     busy: itemModel.loader.status === J.ModelStatus.Loading || extraBusy
     property bool extraBusy: false
     property alias loader: itemModel.loader
-    property string collectionType
+    property int collectionType
     property bool collapseWhenEmpty: true
 
     J.ItemModel {
diff --git a/sailfish/qml/components/PlaybackBar.qml b/sailfish/qml/components/PlaybackBar.qml
index dcfc2e1..c4f1f32 100644
--- a/sailfish/qml/components/PlaybackBar.qml
+++ b/sailfish/qml/components/PlaybackBar.qml
@@ -158,7 +158,7 @@ PanelBackground {
                     }
 
                     switch(manager.item.mediaType) {
-                    case "Audio":
+                    case J.MediaType.Audio:
                         var links = [];
                         var items = manager.item.artistItems;
                         console.log(items)
@@ -181,7 +181,7 @@ PanelBackground {
                 color: highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor
                 linkColor: Theme.secondaryColor
                 onLinkActivated: {
-                    appWindow.navigateToItem(link, "Audio", "MusicArtist", true)
+                    appWindow.navigateToItem(link, J.MediaType.Audio, J.ItemType.MusicArtist, true)
                 }
                 textFormat: Text.StyledText
                 Icon {
diff --git a/sailfish/qml/components/music/SongDelegate.qml b/sailfish/qml/components/music/SongDelegate.qml
index 3d85e61..73ce4be 100644
--- a/sailfish/qml/components/music/SongDelegate.qml
+++ b/sailfish/qml/components/music/SongDelegate.qml
@@ -18,6 +18,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
 import QtQuick 2.6
 import Sailfish.Silica 1.0
+import nl.netsoj.chris.Jellyfin 1.0 as J
 
 import "../.."
 
@@ -106,7 +107,7 @@ ListItem {
     }
 
     function goToArtist(id) {
-        appWindow.navigateToItem(id, "audio", "MusicArtist", true)
+        appWindow.navigateToItem(id, J.MediaType.Audio, J.ItemType.MusicArtist, true)
     }
 
     Component {
diff --git a/sailfish/qml/cover/CollectionPage.qml b/sailfish/qml/cover/CollectionPage.qml
index b81178b..d90591d 100644
--- a/sailfish/qml/cover/CollectionPage.qml
+++ b/sailfish/qml/cover/CollectionPage.qml
@@ -41,7 +41,7 @@ CoverBackground {
             apiClient: appWindow.apiClient
             limit: cover.rowCount * 2 - 2
             imageTypes: [J.ImageType.Primary]
-            sortBy: "IsFavoriteOrLiked,Random"
+            sortBy: [J.SortBy.IsFavoriteOrLiked, J.SortBy.Random]
             recursive: true
             parentId: itemId
             autoReload:  false
diff --git a/sailfish/qml/cover/PosterCover.qml b/sailfish/qml/cover/PosterCover.qml
index 2bd769e..5972df0 100644
--- a/sailfish/qml/cover/PosterCover.qml
+++ b/sailfish/qml/cover/PosterCover.qml
@@ -38,7 +38,7 @@ CoverBackground {
     Shim {
         // Movies usually show their name on the poster,
         // so showing it here as well is a bit double
-        visible: mData.type !== "Movie"
+        visible: mData.type !== J.ItemType.Movie
         anchors {
             left: parent.left
             right: parent.right
diff --git a/sailfish/qml/harbour-sailfin.qml b/sailfish/qml/harbour-sailfin.qml
index 7651dcf..483f995 100644
--- a/sailfish/qml/harbour-sailfin.qml
+++ b/sailfish/qml/harbour-sailfin.qml
@@ -156,7 +156,7 @@ ApplicationWindow {
     }
 
     function navigateToItem(jellyfinId, mediaType, type, isFolder) {
-        if (mediaType === "Audio" && !isFolder) {
+        if (mediaType === MediaType.Audio && !isFolder) {
             playbackManager.playItemId(jellyfinId)
         } else {
             var url = Utils.getPageUrl(mediaType, type, isFolder)
diff --git a/sailfish/qml/pages/AboutPage.qml b/sailfish/qml/pages/AboutPage.qml
index 5099792..e8b0356 100644
--- a/sailfish/qml/pages/AboutPage.qml
+++ b/sailfish/qml/pages/AboutPage.qml
@@ -56,7 +56,7 @@ Page {
                       "You can <a href=\"github\">view its source code on GitHub</a>. " +
                       "Parts of the code of Sailfin are from other libraries. <a href='3rdparty'>View their licenses here</a>.</p>")
                         .arg(apiClient.version)
-                        .arg(2024)
+                        .arg(2025)
                 textFormat: Text.StyledText
                 color: Theme.secondaryHighlightColor
                 linkColor: Theme.primaryColor
diff --git a/sailfish/qml/pages/MainPage.qml b/sailfish/qml/pages/MainPage.qml
index 34f38a6..e619e09 100644
--- a/sailfish/qml/pages/MainPage.qml
+++ b/sailfish/qml/pages/MainPage.qml
@@ -109,13 +109,13 @@ Page {
                 ItemChildrenShowcase {
                     text: model.name
                     onHeaderClicked: appWindow.navigateToItem(model.jellyfinId, model.collectionType, model.type, model.isFolder);
-                    collectionType: model.collectionType || ""
+                    collectionType: model.collectionType || 0
                     loader: J.LatestMediaLoader {
                         apiClient: appWindow.apiClient
                         parentId: jellyfinId
                     }
                     Binding on loader {
-                        when: model.collectionType == "livetv"
+                        when: model.collectionType == J.CollectionType.Livetv
                         value: J.LiveTvChannelsLoader{
                             apiClient: appWindow.apiClient
                         }
diff --git a/sailfish/qml/pages/itemdetails/CollectionPage.qml b/sailfish/qml/pages/itemdetails/CollectionPage.qml
index afb9104..8014477 100644
--- a/sailfish/qml/pages/itemdetails/CollectionPage.qml
+++ b/sailfish/qml/pages/itemdetails/CollectionPage.qml
@@ -39,7 +39,7 @@ BaseDetailPage {
             id: collectionLoader
             apiClient: appWindow.apiClient
             parentId: itemData.jellyfinId
-            sortBy: "SortName"
+            sortBy: [ J.SortBy.SortName ]
             autoReload: itemData.jellyfinId.length > 0 && (pageRoot.status == PageStatus.Active || _collectionModelLoaded)
         }
     }
@@ -107,7 +107,7 @@ BaseDetailPage {
                 id: itemImage
                 anchors.fill: parent
                 source: Utils.itemModelImageUrl(apiClient.baseUrl, model.jellyfinId, model.imageTags.Primary, "Primary", {"maxWidth": width})
-                blurhash: model.imageBlurHashes.Primary[model.imageTags.Primary]
+                blurhash: model.imageBlurHashes.Primary !== undefined ? model.imageBlurHashes.Primary[model.imageTags.Primary] : undefined
                 fallbackColor: Utils.colorFromString(model.name)
                 fillMode: Image.PreserveAspectCrop
                 clip: true
@@ -152,8 +152,14 @@ BaseDetailPage {
 
     Component {
         id: sortPageComponent
+
         Page {
             id: sortPage
+            readonly property var sortMap: {
+                "SortName": [J.SortBy.SortName],
+                "PlayCount": [J.SortBy.PlayCount],
+                "DateCreated": [J.SortBy.DateCreated]
+            };
 
             ListModel {
                 id: sortOptions
@@ -183,19 +189,19 @@ BaseDetailPage {
                         MenuItem {
                             //: Sort order
                             text: qsTr("Ascending")
-                            onClicked: apply(model.value, "Ascending")
+                            onClicked: apply(model.value, J.SortOrder.Ascending)
                         }
                         MenuItem {
                             //: Sort order
                             text: qsTr("Descending")
-                            onClicked: apply(model.value, "Descending")
+                            onClicked: apply(model.value, J.SortOrder.Descending)
                         }
                     }
                     onClicked: openMenu()
 
                     function apply(field, order) {
-                        collectionModel.loader.sortBy = field;
-                        collectionModel.loader.sortOrder = order;
+                        collectionModel.loader.sortBy = sortMap[field];
+                        collectionModel.loader.sortOrder = [order];
                         collectionModel.loader.reload()
                         pageStack.pop()
                     }
diff --git a/sailfish/qml/pages/itemdetails/MusicAlbumPage.qml b/sailfish/qml/pages/itemdetails/MusicAlbumPage.qml
index cf8f618..4cecad9 100644
--- a/sailfish/qml/pages/itemdetails/MusicAlbumPage.qml
+++ b/sailfish/qml/pages/itemdetails/MusicAlbumPage.qml
@@ -51,7 +51,7 @@ BaseDetailPage {
         id: collectionModel
         loader: J.UserItemsLoader {
             apiClient: appWindow.apiClient
-            sortBy: itemData.type === "MusicAlbum" ? "ParentIndexNumber,IndexNumber,SortName" : ""
+            sortBy: itemData.type === J.ItemType.MusicAlbum ? [J.SortBy.ParentIndexNumber, J.SortBy.IndexNumber,J.SortBy.SortName] : []
             fields: [J.ItemFields.ItemCounts, J.ItemFields.PrimaryImageAspectRatio]
             parentId: itemData.jellyfinId
             autoReload: itemData.jellyfinId.length > 0
diff --git a/sailfish/qml/pages/itemdetails/MusicArtistPage.qml b/sailfish/qml/pages/itemdetails/MusicArtistPage.qml
index 48ce3e1..017630a 100644
--- a/sailfish/qml/pages/itemdetails/MusicArtistPage.qml
+++ b/sailfish/qml/pages/itemdetails/MusicArtistPage.qml
@@ -33,11 +33,11 @@ BaseDetailPage {
         id: albumsModel
         loader: J.UserItemsLoader {
             apiClient: appWindow.apiClient
-            sortBy: "PremiereDate,ProductionYear,SortName"
-            sortOrder: "Descending"
+            sortBy: [J.SortBy.PremiereDate, J.SortBy.ProductionYear, J.SortBy.SortName]
+            sortOrder: [J.SortOrder.Descending]
             fields: [J.ItemFields.ItemCounts, J.ItemFields.PrimaryImageAspectRatio]
-            includeItemTypes: ["MusicAlbum"]
-            albumArtistIds: itemData.jellyfinId
+            includeItemTypes: [J.ItemType.MusicAlbum]
+            albumArtistIds: [itemData.jellyfinId]
             recursive: true
             autoReload: itemData.jellyfinId.length > 0
             limit: _maxItems
@@ -48,10 +48,10 @@ BaseDetailPage {
         id: fullAlbumsModelComponent
         J.UserItemsLoader {
             apiClient: appWindow.apiClient
-            sortBy: "PremiereDate,ProductionYear,SortName"
-            sortOrder: "Descending"
+            sortBy: [J.SortBy.PremiereDate, J.SortBy.ProductionYear, J.SortBy.SortName]
+            sortOrder: [J.SortOrder.Descending]
             fields: [J.ItemFields.ItemCounts, J.ItemFields.PrimaryImageAspectRatio]
-            includeItemTypes: ["MusicAlbum"]
+            includeItemTypes: [J.ItemType.MusicAlbum]
             albumArtistIds: itemData.jellyfinId
             recursive: true
             autoReload: false
@@ -62,10 +62,10 @@ BaseDetailPage {
         id: appearsOnModel
         loader: J.UserItemsLoader {
             apiClient: appWindow.apiClient
-            sortBy: "PremiereDate,ProductionYear,SortName"
-            sortOrder: "Descending"
+            sortBy: [J.SortBy.PremiereDate, J.SortBy.ProductionYear, J.SortBy.SortName]
+            sortOrder: [J.SortOrder.Descending]
             fields: [J.ItemFields.ItemCounts, J.ItemFields.PrimaryImageAspectRatio]
-            includeItemTypes: ["MusicAlbum"]
+            includeItemTypes: [J.ItemType.MusicAlbum]
             contributingArtistIds: itemData.jellyfinId
             recursive: true
             autoReload: itemData.jellyfinId.length > 0
@@ -76,10 +76,10 @@ BaseDetailPage {
         id: fullAppearsOnModelComponent
         J.UserItemsLoader {
             apiClient: appWindow.apiClient
-            sortBy: "PremiereDate,ProductionYear,SortName"
-            sortOrder: "Descending"
+            sortBy: [J.SortBy.PremiereDate, J.SortBy.ProductionYear, J.SortBy.SortName]
+            sortOrder: [J.SortOrder.Descending]
             fields: [J.ItemFields.ItemCounts, J.ItemFields.PrimaryImageAspectRatio]
-            includeItemTypes: ["MusicAlbum"]
+            includeItemTypes: [J.ItemType.MusicAlbum]
             contributingArtistIds: itemData.jellyfinId
             recursive: true
             autoReload: false
diff --git a/sailfish/qml/pages/itemdetails/MusicLibraryPage.qml b/sailfish/qml/pages/itemdetails/MusicLibraryPage.qml
index 965f488..7dbf95e 100644
--- a/sailfish/qml/pages/itemdetails/MusicLibraryPage.qml
+++ b/sailfish/qml/pages/itemdetails/MusicLibraryPage.qml
@@ -56,7 +56,7 @@ BaseDetailPage {
             J.LatestMediaLoader {
                 apiClient: appWindow.apiClient
                 parentId: itemData.jellyfinId
-                includeItemTypes: "Audio"
+                includeItemTypes: [J.ItemType.Audio]
                 autoReload: false
             }
         }
@@ -74,9 +74,9 @@ BaseDetailPage {
             J.UserItemsLoader {
                 apiClient: appWindow.apiClient
                 parentId: itemData.jellyfinId
-                includeItemTypes: "MusicAlbum"
+                includeItemTypes: [J.ItemType.MusicAlbum]
                 recursive: true
-                sortBy: "SortName"
+                sortBy: [J.SortBy.SortName]
                 autoReload: false
             }
         }
@@ -85,9 +85,9 @@ BaseDetailPage {
             J.UserItemsLoader {
                 apiClient: appWindow.apiClient
                 parentId: itemData.jellyfinId
-                includeItemTypes: "Playlist"
+                includeItemTypes: [J.ItemType.Playlist]
                 recursive: true
-                sortBy: "SortName"
+                sortBy: [J.SortBy.SortName]
                 autoReload: false
             }
         }
@@ -109,7 +109,7 @@ BaseDetailPage {
                     apiClient: appWindow.apiClient
                     parentId: itemData.jellyfinId
                     autoReload: _firstTimeLoaded && itemData.jellyfinId.length > 0
-                    includeItemTypes: "Audio"
+                    includeItemTypes: [J.ItemType.Audio]
                     limit: 12
                 }
                 onHeaderClicked: pageStack.push(Qt.resolvedUrl("CollectionPage.qml"), {
@@ -128,9 +128,9 @@ BaseDetailPage {
                 loader: J.UserItemsLoader {
                     apiClient: appWindow.apiClient
                     parentId: itemData.jellyfinId
-                    includeItemTypes: "MusicAlbum"
+                    includeItemTypes: [J.ItemType.MusicAlbum]
                     autoReload: _firstTimeLoaded && itemData.jellyfinId.length > 0
-                    sortBy: "Random"
+                    sortBy: [J.SortBy.Random]
                     recursive: true
                     limit: 12
                 }
@@ -148,9 +148,9 @@ BaseDetailPage {
                 loader: J.UserItemsLoader {
                     apiClient: appWindow.apiClient
                     parentId: itemData.jellyfinId
-                    includeItemTypes: "Playlist"
+                    includeItemTypes: [J.ItemType.Playlist]
                     autoReload: _firstTimeLoaded && itemData.jellyfinId.length > 0
-                    sortBy: "Random"
+                    sortBy: [J.SortBy.Random]
                     recursive: true
                     limit: 12
                 }
diff --git a/sailfish/translations/harbour-sailfin-de.ts b/sailfish/translations/harbour-sailfin-de.ts
index a20e489..62255ba 100644
--- a/sailfish/translations/harbour-sailfin-de.ts
+++ b/sailfish/translations/harbour-sailfin-de.ts
@@ -110,7 +110,7 @@
     </message>
     <message>
         <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="90"/>
-        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="169"/>
+        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="175"/>
         <source>Sort by</source>
         <extracomment>Menu item for selecting the sort order of a collection</extracomment>
         <translation type="unfinished"></translation>
@@ -126,28 +126,28 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="160"/>
+        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="166"/>
         <source>Name</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="161"/>
+        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="167"/>
         <source>Play count</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="162"/>
+        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="168"/>
         <source>Date added</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="185"/>
+        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="191"/>
         <source>Ascending</source>
         <extracomment>Sort order</extracomment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="190"/>
+        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="196"/>
         <source>Descending</source>
         <extracomment>Sort order</extracomment>
         <translation type="unfinished"></translation>
@@ -268,14 +268,17 @@
 <context>
     <name>LiveTvChannelPage</name>
     <message>
+        <location filename="../qml/pages/itemdetails/LiveTvChannelPage.qml" line="8"/>
         <source>%1 | %2 - %3</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
+        <location filename="../qml/pages/itemdetails/LiveTvChannelPage.qml" line="14"/>
         <source>Program info</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
+        <location filename="../qml/pages/itemdetails/LiveTvChannelPage.qml" line="19"/>
         <source>No program info available</source>
         <translation type="unfinished"></translation>
     </message>
@@ -283,6 +286,7 @@
 <context>
     <name>LiveTvChannelsPage</name>
     <message>
+        <location filename="../qml/pages/itemdetails/LiveTvChannelsPage.qml" line="80"/>
         <source>No program information available</source>
         <extracomment>Shown in the channel list when the name of the current program is unknown</extracomment>
         <translation type="unfinished"></translation>
@@ -362,12 +366,12 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../qml/pages/MainPage.qml" line="136"/>
+        <location filename="../qml/pages/MainPage.qml" line="142"/>
         <source>Network error</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../qml/pages/MainPage.qml" line="139"/>
+        <location filename="../qml/pages/MainPage.qml" line="145"/>
         <source>Pull down to retry again</source>
         <translation type="unfinished"></translation>
     </message>
@@ -394,7 +398,7 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../qml/pages/itemdetails/MusicAlbumPage.qml" line="78"/>
+        <location filename="../qml/pages/itemdetails/MusicAlbumPage.qml" line="77"/>
         <source>Disc %1</source>
         <translation type="unfinished"></translation>
     </message>
@@ -546,7 +550,7 @@ Page title for the list of all artists within the music library</extracomment>
 <context>
     <name>QObject</name>
     <message>
-        <location filename="../src/harbour-sailfin.cpp" line="53"/>
+        <location filename="../src/harbour-sailfin.cpp" line="54"/>
         <source>Sailfin</source>
         <extracomment>Application display name</extracomment>
         <translation type="unfinished"></translation>
@@ -585,7 +589,7 @@ Placeholder text for textfield for entering the Quick Connect codeyy</extracomme
 <context>
     <name>SeasonPage</name>
     <message>
-        <location filename="../qml/pages/itemdetails/SeasonPage.qml" line="143"/>
+        <location filename="../qml/pages/itemdetails/SeasonPage.qml" line="138"/>
         <source>No overview available</source>
         <extracomment>No overview/summary text of an episode available</extracomment>
         <translation type="unfinished"></translation>
@@ -674,13 +678,13 @@ Placeholder text for textfield for entering the Quick Connect codeyy</extracomme
 <context>
     <name>SongDelegate</name>
     <message>
-        <location filename="../qml/components/music/SongDelegate.qml" line="119"/>
+        <location filename="../qml/components/music/SongDelegate.qml" line="120"/>
         <source>Go to %1</source>
         <extracomment>Context menu item for navigating to the artist of the selected track</extracomment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../qml/components/music/SongDelegate.qml" line="122"/>
+        <location filename="../qml/components/music/SongDelegate.qml" line="123"/>
         <source>Go to artists</source>
         <extracomment>Context menu item for navigating to one of the artists of the selected track (opens submenu)</extracomment>
         <translation type="unfinished"></translation>
@@ -801,7 +805,7 @@ This is still an alpha version :)</source>
 <context>
     <name>VideoPage</name>
     <message>
-        <location filename="../qml/pages/itemdetails/VideoPage.qml" line="57"/>
+        <location filename="../qml/pages/itemdetails/VideoPage.qml" line="58"/>
         <source>Run time: %2</source>
         <translation type="unfinished"></translation>
     </message>
diff --git a/sailfish/translations/harbour-sailfin-ru.ts b/sailfish/translations/harbour-sailfin-ru.ts
index a20e489..62255ba 100644
--- a/sailfish/translations/harbour-sailfin-ru.ts
+++ b/sailfish/translations/harbour-sailfin-ru.ts
@@ -110,7 +110,7 @@
     </message>
     <message>
         <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="90"/>
-        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="169"/>
+        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="175"/>
         <source>Sort by</source>
         <extracomment>Menu item for selecting the sort order of a collection</extracomment>
         <translation type="unfinished"></translation>
@@ -126,28 +126,28 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="160"/>
+        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="166"/>
         <source>Name</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="161"/>
+        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="167"/>
         <source>Play count</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="162"/>
+        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="168"/>
         <source>Date added</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="185"/>
+        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="191"/>
         <source>Ascending</source>
         <extracomment>Sort order</extracomment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="190"/>
+        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="196"/>
         <source>Descending</source>
         <extracomment>Sort order</extracomment>
         <translation type="unfinished"></translation>
@@ -268,14 +268,17 @@
 <context>
     <name>LiveTvChannelPage</name>
     <message>
+        <location filename="../qml/pages/itemdetails/LiveTvChannelPage.qml" line="8"/>
         <source>%1 | %2 - %3</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
+        <location filename="../qml/pages/itemdetails/LiveTvChannelPage.qml" line="14"/>
         <source>Program info</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
+        <location filename="../qml/pages/itemdetails/LiveTvChannelPage.qml" line="19"/>
         <source>No program info available</source>
         <translation type="unfinished"></translation>
     </message>
@@ -283,6 +286,7 @@
 <context>
     <name>LiveTvChannelsPage</name>
     <message>
+        <location filename="../qml/pages/itemdetails/LiveTvChannelsPage.qml" line="80"/>
         <source>No program information available</source>
         <extracomment>Shown in the channel list when the name of the current program is unknown</extracomment>
         <translation type="unfinished"></translation>
@@ -362,12 +366,12 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../qml/pages/MainPage.qml" line="136"/>
+        <location filename="../qml/pages/MainPage.qml" line="142"/>
         <source>Network error</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../qml/pages/MainPage.qml" line="139"/>
+        <location filename="../qml/pages/MainPage.qml" line="145"/>
         <source>Pull down to retry again</source>
         <translation type="unfinished"></translation>
     </message>
@@ -394,7 +398,7 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../qml/pages/itemdetails/MusicAlbumPage.qml" line="78"/>
+        <location filename="../qml/pages/itemdetails/MusicAlbumPage.qml" line="77"/>
         <source>Disc %1</source>
         <translation type="unfinished"></translation>
     </message>
@@ -546,7 +550,7 @@ Page title for the list of all artists within the music library</extracomment>
 <context>
     <name>QObject</name>
     <message>
-        <location filename="../src/harbour-sailfin.cpp" line="53"/>
+        <location filename="../src/harbour-sailfin.cpp" line="54"/>
         <source>Sailfin</source>
         <extracomment>Application display name</extracomment>
         <translation type="unfinished"></translation>
@@ -585,7 +589,7 @@ Placeholder text for textfield for entering the Quick Connect codeyy</extracomme
 <context>
     <name>SeasonPage</name>
     <message>
-        <location filename="../qml/pages/itemdetails/SeasonPage.qml" line="143"/>
+        <location filename="../qml/pages/itemdetails/SeasonPage.qml" line="138"/>
         <source>No overview available</source>
         <extracomment>No overview/summary text of an episode available</extracomment>
         <translation type="unfinished"></translation>
@@ -674,13 +678,13 @@ Placeholder text for textfield for entering the Quick Connect codeyy</extracomme
 <context>
     <name>SongDelegate</name>
     <message>
-        <location filename="../qml/components/music/SongDelegate.qml" line="119"/>
+        <location filename="../qml/components/music/SongDelegate.qml" line="120"/>
         <source>Go to %1</source>
         <extracomment>Context menu item for navigating to the artist of the selected track</extracomment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../qml/components/music/SongDelegate.qml" line="122"/>
+        <location filename="../qml/components/music/SongDelegate.qml" line="123"/>
         <source>Go to artists</source>
         <extracomment>Context menu item for navigating to one of the artists of the selected track (opens submenu)</extracomment>
         <translation type="unfinished"></translation>
@@ -801,7 +805,7 @@ This is still an alpha version :)</source>
 <context>
     <name>VideoPage</name>
     <message>
-        <location filename="../qml/pages/itemdetails/VideoPage.qml" line="57"/>
+        <location filename="../qml/pages/itemdetails/VideoPage.qml" line="58"/>
         <source>Run time: %2</source>
         <translation type="unfinished"></translation>
     </message>
diff --git a/sailfish/translations/harbour-sailfin.ts b/sailfish/translations/harbour-sailfin.ts
index a20e489..62255ba 100644
--- a/sailfish/translations/harbour-sailfin.ts
+++ b/sailfish/translations/harbour-sailfin.ts
@@ -110,7 +110,7 @@
     </message>
     <message>
         <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="90"/>
-        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="169"/>
+        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="175"/>
         <source>Sort by</source>
         <extracomment>Menu item for selecting the sort order of a collection</extracomment>
         <translation type="unfinished"></translation>
@@ -126,28 +126,28 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="160"/>
+        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="166"/>
         <source>Name</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="161"/>
+        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="167"/>
         <source>Play count</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="162"/>
+        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="168"/>
         <source>Date added</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="185"/>
+        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="191"/>
         <source>Ascending</source>
         <extracomment>Sort order</extracomment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="190"/>
+        <location filename="../qml/pages/itemdetails/CollectionPage.qml" line="196"/>
         <source>Descending</source>
         <extracomment>Sort order</extracomment>
         <translation type="unfinished"></translation>
@@ -268,14 +268,17 @@
 <context>
     <name>LiveTvChannelPage</name>
     <message>
+        <location filename="../qml/pages/itemdetails/LiveTvChannelPage.qml" line="8"/>
         <source>%1 | %2 - %3</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
+        <location filename="../qml/pages/itemdetails/LiveTvChannelPage.qml" line="14"/>
         <source>Program info</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
+        <location filename="../qml/pages/itemdetails/LiveTvChannelPage.qml" line="19"/>
         <source>No program info available</source>
         <translation type="unfinished"></translation>
     </message>
@@ -283,6 +286,7 @@
 <context>
     <name>LiveTvChannelsPage</name>
     <message>
+        <location filename="../qml/pages/itemdetails/LiveTvChannelsPage.qml" line="80"/>
         <source>No program information available</source>
         <extracomment>Shown in the channel list when the name of the current program is unknown</extracomment>
         <translation type="unfinished"></translation>
@@ -362,12 +366,12 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../qml/pages/MainPage.qml" line="136"/>
+        <location filename="../qml/pages/MainPage.qml" line="142"/>
         <source>Network error</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../qml/pages/MainPage.qml" line="139"/>
+        <location filename="../qml/pages/MainPage.qml" line="145"/>
         <source>Pull down to retry again</source>
         <translation type="unfinished"></translation>
     </message>
@@ -394,7 +398,7 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../qml/pages/itemdetails/MusicAlbumPage.qml" line="78"/>
+        <location filename="../qml/pages/itemdetails/MusicAlbumPage.qml" line="77"/>
         <source>Disc %1</source>
         <translation type="unfinished"></translation>
     </message>
@@ -546,7 +550,7 @@ Page title for the list of all artists within the music library</extracomment>
 <context>
     <name>QObject</name>
     <message>
-        <location filename="../src/harbour-sailfin.cpp" line="53"/>
+        <location filename="../src/harbour-sailfin.cpp" line="54"/>
         <source>Sailfin</source>
         <extracomment>Application display name</extracomment>
         <translation type="unfinished"></translation>
@@ -585,7 +589,7 @@ Placeholder text for textfield for entering the Quick Connect codeyy</extracomme
 <context>
     <name>SeasonPage</name>
     <message>
-        <location filename="../qml/pages/itemdetails/SeasonPage.qml" line="143"/>
+        <location filename="../qml/pages/itemdetails/SeasonPage.qml" line="138"/>
         <source>No overview available</source>
         <extracomment>No overview/summary text of an episode available</extracomment>
         <translation type="unfinished"></translation>
@@ -674,13 +678,13 @@ Placeholder text for textfield for entering the Quick Connect codeyy</extracomme
 <context>
     <name>SongDelegate</name>
     <message>
-        <location filename="../qml/components/music/SongDelegate.qml" line="119"/>
+        <location filename="../qml/components/music/SongDelegate.qml" line="120"/>
         <source>Go to %1</source>
         <extracomment>Context menu item for navigating to the artist of the selected track</extracomment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../qml/components/music/SongDelegate.qml" line="122"/>
+        <location filename="../qml/components/music/SongDelegate.qml" line="123"/>
         <source>Go to artists</source>
         <extracomment>Context menu item for navigating to one of the artists of the selected track (opens submenu)</extracomment>
         <translation type="unfinished"></translation>
@@ -801,7 +805,7 @@ This is still an alpha version :)</source>
 <context>
     <name>VideoPage</name>
     <message>
-        <location filename="../qml/pages/itemdetails/VideoPage.qml" line="57"/>
+        <location filename="../qml/pages/itemdetails/VideoPage.qml" line="58"/>
         <source>Run time: %2</source>
         <translation type="unfinished"></translation>
     </message>