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