Skip to content

Commit

Permalink
sailfish: add LiveTvChannels page
Browse files Browse the repository at this point in the history
This ocmmit adds a LiveTvChannels page for displaying the programs that
are now playing.

The section Live TV Channels on the main page now shows the TV channel
list in order of the channel number.

Additionally, it fixes an issue in ApiModel, where it would not reload
when a new loader was assigned. This is now fixed and some code on pages
that worked around this fix has been removed.
  • Loading branch information
HenkKalkwater committed Jun 3, 2024
1 parent edcd3a9 commit 57b6729
Show file tree
Hide file tree
Showing 23 changed files with 344 additions and 54 deletions.
1 change: 1 addition & 0 deletions core/3rdparty/qtpromise
Submodule qtpromise added at f7639e
11 changes: 11 additions & 0 deletions core/include/JellyfinQt/apimodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,23 +239,33 @@ bool setRequestStartIndex(P &parameters, int startIndex) {
#ifndef JELLYFIN_APIMODEL_CPP
extern template bool setRequestStartIndex(Loader::GetUserViewsParams &params, int startIndex);
extern template void setRequestLimit(Loader::GetUserViewsParams &params, int limit);

extern template QList<DTO::BaseItemDto> extractRecords(const DTO::BaseItemDtoQueryResult &result);
extern template int extractTotalRecordCount(const DTO::BaseItemDtoQueryResult &result);
extern template QList<DTO::BaseItemDto> extractRecords(const QList<DTO::BaseItemDto> &result);
extern template int extractTotalRecordCount(const QList<DTO::BaseItemDto> &result);

extern template void setRequestLimit(Loader::GetLatestMediaParams &params, int limit);
extern template bool setRequestStartIndex(Loader::GetLatestMediaParams &params, int offset);

extern template void setRequestLimit(Loader::GetItemsByUserIdParams &params, int limit);
extern template bool setRequestStartIndex(Loader::GetItemsByUserIdParams &params, int offset);

extern template void setRequestLimit(Loader::GetResumeItemsParams &params, int limit);
extern template bool setRequestStartIndex(Loader::GetResumeItemsParams &params, int offset);

extern template void setRequestLimit(Loader::GetPublicUsersParams &params, int limit);
extern template bool setRequestStartIndex(Loader::GetPublicUsersParams &params, int offset);

extern template void setRequestLimit(Loader::GetNextUpParams &params, int limit);
extern template bool setRequestStartIndex(Loader::GetNextUpParams &params, int offset);

extern template void setRequestLimit(Loader::GetAlbumArtistsParams &params, int limit);
extern template bool setRequestStartIndex(Loader::GetAlbumArtistsParams &params, int offset);

extern template void setRequestLimit(Loader::GetLiveTvChannelsParams &params, int limit);
extern template bool setRequestStartIndex(Loader::GetLiveTvChannelsParams &params, int offset);

extern template QList<DTO::UserDto> extractRecords(const QList<DTO::UserDto> &result);
extern template int extractTotalRecordCount(const QList<DTO::UserDto> &result);
#endif
Expand Down Expand Up @@ -519,6 +529,7 @@ class ApiModel : public BaseApiModel {
BaseApiModel::setLoader(newLoader);
BaseApiModel::disconnectOldLoader(m_loader);
m_loader = castedLoader;
reload();
} else {
qWarning() << "Somehow set a BaseModelLoader on ApiModel instead of a ModelLoader<T>";
}
Expand Down
12 changes: 11 additions & 1 deletion core/include/JellyfinQt/viewmodel/item.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,12 @@ class Item : public QObject {
Q_PROPERTY(int albumCount READ albumCount NOTIFY albumCountChanged)
Q_PROPERTY(int artistCount READ artistCount NOTIFY artistCountChanged)
Q_PROPERTY(int musicVideoCount READ musicVideoCount NOTIFY musicVideoCountChanged)
Q_PROPERTY(QString mediaType READ mediaType READ mediaType NOTIFY mediaTypeChanged)
Q_PROPERTY(QString mediaType READ mediaType NOTIFY mediaTypeChanged)
Q_PROPERTY(QDateTime endDate READ endDate NOTIFY endDateChanged)
Q_PROPERTY(QDateTime startDate READ startDate NOTIFY startDateChanged)
Q_PROPERTY(int width READ width NOTIFY widthChanged)
Q_PROPERTY(int height READ height NOTIFY heightChanged)
Q_PROPERTY(Jellyfin::ViewModel::Item *currentProgram READ currentProgram NOTIFY currentProgramChanged)

QString jellyfinId() const { return m_data->jellyfinId(); }
QString name() const { return m_data->name(); }
Expand Down Expand Up @@ -225,6 +228,9 @@ class Item : public QObject {
QStringList backdropImageTags() const { return m_data->backdropImageTags(); }
QJsonObject imageBlurHashes() const { return m_data->imageBlurHashes(); }
QString mediaType() const { return m_data->mediaType(); }
QDateTime endDate() const { return m_data->endDate(); }
QDateTime startDate() const { return m_data->startDate(); }
Item *currentProgram() const { return m_currentProgram; }

int trailerCount() const { return m_data->trailerCount().value_or(0); }
int movieCount() const { return m_data->movieCount().value_or(0); }
Expand Down Expand Up @@ -308,8 +314,11 @@ class Item : public QObject {
void artistCountChanged(int newArtistCount);
void musicVideoCountChanged(int newMusicVideoCount);
void mediaTypeChanged(const QString &newMediaType);
void endDateChanged();
void startDateChanged();
void widthChanged(int newWidth);
void heightChanged(int newHeight);
void currentProgramChanged();
protected:
void setUserData(DTO::UserItemDataDto &newData);
void setUserData(QSharedPointer<DTO::UserItemDataDto> newData);
Expand All @@ -322,6 +331,7 @@ class Item : public QObject {
QObjectList m_videoStreams;
QObjectList m_subtitleStreams;
QObjectList m_artistItems;
Item *m_currentProgram = nullptr;
private slots:
void onUserDataChanged(const DTO::UserItemDataDto &userData);
};
Expand Down
34 changes: 34 additions & 0 deletions core/include/JellyfinQt/viewmodel/itemmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,32 @@ class AlbumArtistLoader : public AlbumArtistLoaderBase {
FWDLISTPROP(int, years, Years);
};

using LiveTvChannelsLoaderBase = AbstractUserParameterLoader<Model::Item, DTO::BaseItemDto, DTO::BaseItemDtoQueryResult, Jellyfin::Loader::GetLiveTvChannelsParams>;
class LiveTvChannelsLoader : public LiveTvChannelsLoaderBase {
Q_OBJECT
public:
explicit LiveTvChannelsLoader(QObject *parent = nullptr);

FWDPROP(Jellyfin::DTO::ChannelTypeClass::Value, type, Type)
FWDPROP(bool, isMovie, IsMovie)
FWDPROP(bool, isSeries, IsSeries)
FWDPROP(bool, isNews, IsNews)
FWDPROP(bool, isKids, IsKids)
FWDPROP(bool, isSports, IsSports)
FWDPROP(bool, isFavorite, IsFavorite)
FWDPROP(bool, isLiked, IsLiked)
FWDPROP(bool, isDisliked, IsDisliked)
FWDPROP(bool, enableImages, EnableImages)
FWDPROP(int, imageTypeLimit, ImageTypeLimit)
FWDLISTPROP(Jellyfin::DTO::ImageTypeClass::Value, enableImageTypes, EnableImageTypes)
FWDLISTPROP(Jellyfin::DTO::ItemFieldsClass::Value, fields, Fields)
FWDPROP(bool, enableUserData, EnableUserData)
FWDPROP(QStringList, sortBy, SortBy)
FWDPROP(Jellyfin::DTO::SortOrderClass::Value, sortOrder, SortOrder)
FWDPROP(bool, enableFavoriteSorting, EnableFavoriteSorting)
FWDPROP(bool, addCurrentProgram, AddCurrentProgram)
};

/**
* @brief Base class for each model that works with items.
*/
Expand Down Expand Up @@ -369,6 +395,10 @@ class ItemModel : public ApiModel<Model::Item> {
userDataLastPlayedDate,
userDataPlayed,
userDataKey,
currentProgramName,
currentProgramOverview,
currentProgramStartDate,
currentProgramEndDate,

jellyfinExtendModelAfterHere = Qt::UserRole + 300 // Should be enough for now
};
Expand Down Expand Up @@ -410,6 +440,10 @@ class ItemModel : public ApiModel<Model::Item> {
JFRN(userDataLastPlayedDate),
JFRN(userDataPlayed),
JFRN(userDataKey),
JFRN(currentProgramName),
JFRN(currentProgramOverview),
JFRN(currentProgramStartDate),
JFRN(currentProgramEndDate),
};
}
QVariant data(const QModelIndex &index, int role) const override;
Expand Down
12 changes: 12 additions & 0 deletions core/src/apimodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,18 @@ bool setRequestStartIndex(Loader::GetAlbumArtistsParams &params, int offset) {
return true;
}

template<>
void setRequestLimit(Loader::GetLiveTvChannelsParams &params, int limit) {
params.setLimit(limit);
}

template<>
bool setRequestStartIndex(Loader::GetLiveTvChannelsParams &params, int offset) {
params.setStartIndex(offset);
return true;
}


template<>
QList<DTO::UserDto> extractRecords(const QList<DTO::UserDto> &result) {
return result;
Expand Down
1 change: 1 addition & 0 deletions core/src/jellyfin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ void JellyfinPlugin::registerTypes(const char *uri) {
qmlRegisterType<ViewModel::NextUpLoader>(uri, 1, 0, "NextUpLoader");
qmlRegisterType<ViewModel::PublicUsersLoader>(uri, 1, 0, "PublicUsersLoader");
qmlRegisterType<ViewModel::AlbumArtistLoader>(uri, 1, 0, "AlbumArtistLoader");
qmlRegisterType<ViewModel::LiveTvChannelsLoader>(uri, 1, 0, "LiveTvChannelsLoader");

// Enumerations
qmlRegisterUncreatableType<Jellyfin::DTO::GeneralCommandTypeClass>(uri, 1, 0, "GeneralCommandType", "Is an enum");
Expand Down
14 changes: 11 additions & 3 deletions core/src/viewmodel/item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,7 @@ Item::Item(QObject *parent, QSharedPointer<Model::Item> data)
: QObject(parent),
m_data(data),
m_userData(new UserData(this)){
connect(m_data.data(), &Model::Item::userDataChanged, this, &Item::onUserDataChanged);
m_userData->setData(data->userData());
updateMediaStreams();
this->setData(data);
}

void Item::setData(QSharedPointer<Model::Item> newData) {
Expand All @@ -50,8 +48,18 @@ void Item::setData(QSharedPointer<Model::Item> newData) {
connect(m_data.data(), &Model::Item::userDataChanged, this, &Item::onUserDataChanged);
updateMediaStreams();
setUserData(m_data->userData());

if (m_data->currentProgram().isNull()) {
m_currentProgram = nullptr;
} else {
QSharedPointer<DTO::BaseItemDto> dataDto = m_data->currentProgram();
QSharedPointer<Model::Item> data = QSharedPointer<Model::Item>::create(*dataDto.data());
m_currentProgram = new Item(this, data);
}
emit currentProgramChanged();
}


emit userDataChanged(m_userData);
}

Expand Down
46 changes: 37 additions & 9 deletions core/src/viewmodel/itemmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,19 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "JellyfinQt/viewmodel/itemmodel.h"
#include <JellyfinQt/viewmodel/itemmodel.h>

#include "JellyfinQt/viewmodel/item.h"
#include <JellyfinQt/viewmodel/item.h>

#include "JellyfinQt/loader/http/artists.h"
#include "JellyfinQt/loader/http/items.h"
#include "JellyfinQt/loader/http/userlibrary.h"
#include "JellyfinQt/loader/http/userviews.h"
#include "JellyfinQt/loader/http/tvshows.h"
#include <JellyfinQt/loader/http/artists.h>
#include <JellyfinQt/loader/http/items.h>
#include <JellyfinQt/loader/http/livetv.h>
#include <JellyfinQt/loader/http/userlibrary.h>
#include <JellyfinQt/loader/http/userviews.h>
#include <JellyfinQt/loader/http/tvshows.h>

#include "JellyfinQt/viewmodel/userdata.h"
#include "JellyfinQt/viewmodel/utils.h"
#include <JellyfinQt/viewmodel/userdata.h>
#include <JellyfinQt/viewmodel/utils.h>

#define JF_CASE(roleName) case roleName: \
try { \
Expand Down Expand Up @@ -64,6 +65,9 @@ NextUpLoader::NextUpLoader(QObject *parent)
AlbumArtistLoader::AlbumArtistLoader(QObject *parent)
: AlbumArtistLoaderBase(new Jellyfin::Loader::HTTP::GetAlbumArtistsLoader(), parent) {}

LiveTvChannelsLoader::LiveTvChannelsLoader(QObject *parent)
: LiveTvChannelsLoaderBase(new Jellyfin::Loader::HTTP::GetLiveTvChannelsLoader(), parent) {}

ItemModel::ItemModel(QObject *parent)
: ApiModel<Model::Item>(parent) {
connect(this, &QAbstractItemModel::rowsInserted, this, &ItemModel::onInsertItems);
Expand Down Expand Up @@ -126,6 +130,30 @@ QVariant ItemModel::data(const QModelIndex &index, int role) const {
return QVariant(item->userData()->played());
case RoleNames::userDataKey:
return QVariant(item->userData()->key());
case RoleNames::currentProgramName:
if (item->currentProgram()) {
return QVariant(item->currentProgram()->name());
} else {
return QVariant();
}
case RoleNames::currentProgramOverview:
if (item->currentProgram()) {
return QVariant(item->currentProgram()->overview());
} else {
return QVariant();
}
case RoleNames::currentProgramStartDate:
if (item->currentProgram()) {
return QVariant(item->currentProgram()->startDate());
} else {
return QVariant();
}
case RoleNames::currentProgramEndDate:
if (item->currentProgram()) {
return QVariant(item->currentProgram()->endDate());
} else {
return QVariant();
}
default:
return QVariant();
}
Expand Down
6 changes: 6 additions & 0 deletions rpm/harbour-sailfin.changes
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@
# * date Author's Name <author's email> version-release
# - Summary of changes
#
* ??? ??? ? ???? Chris Josten <[email protected]> ?.?.?-?
- New features:
- Added a page that shows a list of Live TV channels with details about currently running
programs.
- Changes:
- TV CHannels on the main page are now sorted by channel number, instead of recently added
* Tue Jan 2 2024 Chris Josten <[email protected]> 0.5.0-1
- New features
- Allow remote controlling other Jellyfin clients. See the pulley item on the main screen named
Expand Down
6 changes: 4 additions & 2 deletions sailfish/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,12 @@ set(sailfin_QML_SOURCES
qml/pages/itemdetails/CollectionPage.qml
qml/pages/itemdetails/EpisodePage.qml
qml/pages/itemdetails/FilmPage.qml
qml/pages/itemdetails/MusicAlbumPage.qml
qml/pages/itemdetails/LiveTvChannelPage.qml
qml/pages/itemdetails/LiveTvChannelsPage.qml
qml/pages/itemdetails/MusicAlbumPage.qml
qml/pages/itemdetails/MusicArtistPage.qml
qml/pages/itemdetails/MusicLibraryPage.qml
qml/pages/itemdetails/PhotoPage.qml
qml/pages/itemdetails/PhotoPage.qml
qml/pages/itemdetails/SeasonPage.qml
qml/pages/itemdetails/SeriesPage.qml
qml/pages/itemdetails/UnsupportedPage.qml
Expand Down
4 changes: 4 additions & 0 deletions sailfish/qml/Utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ function getPageUrl(mediaType, itemType, isFolder) {
return Qt.resolvedUrl("pages/itemdetails/MusicAlbumPage.qml")
case "photo":
return Qt.resolvedUrl("pages/itemdetails/PhotoPage.qml")
case "tvchannel":
return Qt.resolvedUrl("pages/itemdetails/LiveTvChannelPage.qml")
case "collectionfolder":
// TODO: support for other collection folders
switch(mediaType.toLowerCase()) {
Expand All @@ -124,6 +126,8 @@ function getPageUrl(mediaType, itemType, isFolder) {
// FALLTRHOUGH
default:
switch (mediaType ? mediaType.toLowerCase() : isFolder ? "folder" : "") {
case "livetv":
return Qt.resolvedUrl("pages/itemdetails/LiveTvChannelsPage.qml")
case "folder":
return Qt.resolvedUrl("pages/itemdetails/CollectionPage.qml")
case "video":
Expand Down
2 changes: 1 addition & 1 deletion sailfish/qml/components/PlaybackBar.qml
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ PanelBackground {
left: parent.left
verticalCenter: parent.verticalCenter
}
height: parent
height: parent.height
source: "image://theme/icon-s-device-upload"
visible: controllingRemote
}
Expand Down
3 changes: 3 additions & 0 deletions sailfish/qml/components/RemoteImage.qml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ SilicaItem {
BusyIndicator {
anchors.centerIn: parent
running: realImage.status === Image.Loading
size: root.height <= Theme.fontSizeLarge
? BusyIndicatorSize.Small
: BusyIndicatorSize.Medium
}

HighlightImage {
Expand Down
6 changes: 6 additions & 0 deletions sailfish/qml/pages/MainPage.qml
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,12 @@ Page {
apiClient: appWindow.apiClient
parentId: jellyfinId
}
Binding on loader {
when: model.collectionType == "livetv"
value: J.LiveTvChannelsLoader{
apiClient: appWindow.apiClient
}
}
Connections {
target: mediaLibraryLoader
onReady: loader.reload()
Expand Down
23 changes: 23 additions & 0 deletions sailfish/qml/pages/itemdetails/LiveTvChannelPage.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import QtQuick 2.0
import Sailfish.Silica 1.0

import "../../components"

VideoPage {
title: itemData.currentProgram.name
subtitle: qsTr("%1 | %2 - %3")
.arg(itemData.name)
.arg(Qt.formatTime(itemData.currentProgram.startDate))
.arg(Qt.formatTime(itemData.currentProgram.endDate))

SectionHeader {
text: qsTr("Program info")
}

PlainLabel {
id: overviewText
text: itemData.currentProgram.overview || qsTr("No program info available")
font.pixelSize: Theme.fontSizeSmall
color: Theme.secondaryHighlightColor
}
}
Loading

0 comments on commit 57b6729

Please sign in to comment.