1
0
Fork 0
mirror of https://github.com/HenkKalkwater/harbour-sailfin.git synced 2024-11-10 19:45:18 +00:00
harbour-sailfin/src/jellyfinapimodel.cpp

207 lines
6.8 KiB
C++
Raw Normal View History

#include "jellyfinapimodel.h"
namespace Jellyfin {
2020-09-27 01:14:05 +00:00
ApiModel::ApiModel(QString path, bool hasRecordResponse, bool addUserId, QObject *parent)
: QAbstractListModel (parent),
m_path(path),
2020-09-27 01:14:05 +00:00
m_hasRecordResponse(hasRecordResponse),
m_addUserId(addUserId){
}
void ApiModel::reload() {
2020-09-27 01:14:05 +00:00
load(RELOAD);
}
void ApiModel::load(LoadType type) {
qDebug() << (type == RELOAD ? "RELOAD" : "LOAD_MORE");
switch(type) {
case RELOAD:
this->setStatus(Loading);
break;
case LOAD_MORE:
this->setStatus(LoadingMore);
break;
}
if (m_apiClient == nullptr) {
qWarning() << "Please set the apiClient property before (re)loading";
return;
}
if (m_path.contains("{{user}}")) {
m_path = m_path.replace("{{user}}", m_apiClient->userId());
}
if (m_path.contains("{{show}}") && !m_show.isEmpty()) {
m_path = m_path.replace("{{show}}", m_show);
}
QUrlQuery query;
if (m_limit >= 0) {
query.addQueryItem("Limit", QString::number(m_limit));
2020-09-27 01:14:05 +00:00
} else {
query.addQueryItem("Limit", QString::number(DEFAULT_LIMIT));
}
if (m_startIndex > 0) {
query.addQueryItem("StartIndex", QString::number(m_startIndex));
}
if (!m_parentId.isEmpty()) {
query.addQueryItem("ParentId", m_parentId);
}
if (!m_sortBy.empty()) {
query.addQueryItem("SortBy", m_sortBy.join(","));
}
if (!m_imageTypes.empty()) {
query.addQueryItem("ImageTypes", m_imageTypes.join(","));
}
if (!m_fields.empty()) {
query.addQueryItem("Fields", m_fields.join(","));
}
if (!m_seasonId.isEmpty()) {
query.addQueryItem("seasonId", m_seasonId);
}
if (m_addUserId) {
query.addQueryItem("userId", m_apiClient->userId());
}
if (m_recursive) {
query.addQueryItem("Recursive", "true");
}
2020-09-27 01:14:05 +00:00
addQueryParameters(query);
QNetworkReply *rep = m_apiClient->get(m_path, query);
2020-09-27 01:14:05 +00:00
connect(rep, &QNetworkReply::finished, this, [this, type, rep]() {
QJsonDocument doc = QJsonDocument::fromJson(rep->readAll());
2020-09-27 01:14:05 +00:00
if (!m_hasRecordResponse) {
if (!doc.isArray()) {
qWarning() << "Object is not an array!";
this->setStatus(Error);
return;
}
this->m_array = doc.array();
} else {
if (!doc.isObject()) {
qWarning() << "Object is not an object!";
this->setStatus(Error);
return;
}
QJsonObject obj = doc.object();
2020-09-27 01:14:05 +00:00
if (!obj.contains("Items")) {
qWarning() << "Object doesn't contain items!";
this->setStatus(Error);
return;
}
2020-09-27 01:14:05 +00:00
if (m_limit < 0) {
// Javascript is beautiful
if (obj.contains("TotalRecordCount") && obj["TotalRecordCount"].isDouble()) {
m_totalRecordCount = obj["TotalRecordCount"].toInt();
m_startIndex += DEFAULT_LIMIT;
} else {
qWarning() << "Record-response does not have a total record count";
this->setStatus(Error);
return;
}
}
if (!obj["Items"].isArray()) {
qWarning() << "Items is not an array!";
this->setStatus(Error);
return;
}
2020-09-27 01:14:05 +00:00
QJsonArray items = obj["Items"].toArray();
switch(type) {
case RELOAD:
this->m_array = items;
break;
case LOAD_MORE:
this->beginInsertRows(QModelIndex(), m_array.size(), m_array.size() + items.size() - 1);
// QJsonArray apparently doesn't allow concatenating lists like QList or std::vector
foreach (const QJsonValue &val, items) {
m_array.append(val);
}
this->endInsertRows();
break;
}
}
if (type == RELOAD) {
generateFields();
}
this->setStatus(Ready);
rep->deleteLater();
});
}
void ApiModel::generateFields() {
if (m_array.size() == 0) return;
this->beginResetModel();
m_roles.clear();
int i = Qt::UserRole + 1;
if (!m_array[0].isObject()) {
qWarning() << "Iterator is not an object?";
return;
}
// Walks over the keys in the first record and adds them to the rolenames.
// This assumes the back-end has the same keys for every record. I could technically
// go over all records to be really sure, but no-one got time for a O(n²) algorithm, so
// this heuristic hopefully suffices.
QJsonObject ob = m_array[0].toObject();
for (auto jt = ob.begin(); jt != ob.end(); jt++) {
QString keyName = jt.key();
keyName[0] = keyName[0].toLower();
QByteArray keyArr = keyName.toUtf8();
if (!m_roles.values().contains(keyArr)) {
m_roles.insert(i++, keyArr);
//qDebug() << m_path << " adding " << keyName << " as " << ( i - 1);
}
}
this->endResetModel();
}
QVariant ApiModel::data(const QModelIndex &index, int role) const {
// Ignore roles we don't know
if (role <= Qt::UserRole || role >= Qt::UserRole + m_roles.size()) return QVariant();
// Ignore invalid indices.
if (!index.isValid()) return QVariant();
QJsonObject obj = m_array.at(index.row()).toObject();
QString key = m_roles[role];
key[0] = key[0].toUpper();
if (obj.contains(key)) {
return obj[key].toVariant();
}
return QVariant();
}
2020-09-27 01:14:05 +00:00
bool ApiModel::canFetchMore(const QModelIndex &parent) const {
if (parent.isValid()) return false;
switch(m_status) {
case Uninitialised:
case Loading:
return false;
default:
break;
}
if (m_limit < 0) {
return m_startIndex <= m_totalRecordCount;
} else {
return false;
}
}
void ApiModel::fetchMore(const QModelIndex &parent) {
if (parent.isValid()) return;
load(LOAD_MORE);
}
void ApiModel::addQueryParameters(QUrlQuery &query) { Q_UNUSED(query)}
void registerModels(const char *URI) {
qmlRegisterUncreatableType<ApiModel>(URI, 1, 0, "ApiModel", "Is enum and base class");
qmlRegisterUncreatableType<SortOrder>(URI, 1, 0, "SortOrder", "Is enum");
qmlRegisterType<PublicUserModel>(URI, 1, 0, "PublicUserModel");
qmlRegisterType<UserViewModel>(URI, 1, 0, "UserViewModel");
qmlRegisterType<UserItemModel>(URI, 1, 0, "UserItemModel");
qmlRegisterType<UserItemLatestModel>(URI, 1, 0, "UserItemLatestModel");
qmlRegisterType<ShowSeasonsModel>(URI, 1, 0, "ShowSeasonsModel");
qmlRegisterType<ShowEpisodesModel>(URI, 1, 0, "ShowEpisodesModel");
}
}