From 5ee2869db9b545c03cd8dd8d1d4214fd0d00d502 Mon Sep 17 00:00:00 2001 From: Henk Kalkwater Date: Mon, 23 Aug 2021 01:48:35 +0200 Subject: [PATCH] Fix a few bugs regarding loaders and models * Properly keep track of the current offset and total recourd count in models. * Catch exceptions and store them in errorString properties wherever applicable in loaders. --- core/include/JellyfinQt/apimodel.h | 75 ++++++++++++++---------- core/include/JellyfinQt/jellyfin.h | 1 + core/include/JellyfinQt/support/loader.h | 12 ++-- core/src/apimodel.cpp | 23 ++++++++ core/src/jellyfin.cpp | 2 + 5 files changed, 77 insertions(+), 36 deletions(-) diff --git a/core/include/JellyfinQt/apimodel.h b/core/include/JellyfinQt/apimodel.h index 62f3ee3..48314c5 100644 --- a/core/include/JellyfinQt/apimodel.h +++ b/core/include/JellyfinQt/apimodel.h @@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #define JELLYFIN_API_MODEL #include +#include #include #include @@ -114,6 +115,7 @@ protected: ApiClient *m_apiClient = nullptr; bool m_autoReload = true; bool m_needsAuthentication = true; + bool m_manualLimitSet = false; // Query/record controlling properties int m_limit = -1; @@ -158,7 +160,6 @@ public: void reload() override { if (!canReload()) { - qDebug() << "Cannot yet reload ApiModel: canReload() returned false."; return; } m_startIndex = 0; @@ -169,7 +170,6 @@ public: void loadMore() { if (!canReload()) { - qDebug() << "Cannot yet reload ApiModel: canReload() returned false."; return; } loadMore(m_startIndex, m_limit, ViewModel::ModelStatus::LoadingMore); @@ -198,10 +198,6 @@ protected: * Either LOADING or LOAD_MORE. */ virtual void loadMore(int offset, int limit, ViewModel::ModelStatus suggestedStatus) = 0; - void updatePosition(int startIndex, int totalRecordCount) { - m_startIndex = startIndex; - m_totalRecordCount = totalRecordCount; - } std::pair, int> m_result; }; @@ -211,21 +207,21 @@ protected: template QList extractRecords(const R &result) { Q_UNUSED(result) - Q_UNIMPLEMENTED(); + qDebug() << "extractRecords not implemented for type " << typeid(R).name(); return QList(); } template int extractTotalRecordCount(const R &result) { Q_UNUSED(result) - Q_UNIMPLEMENTED(); + qDebug() << "extractTotalRecourdCount not implemented for type " << typeid(R).name(); return -1; } -template -void setRequestLimit(R ¶meters, int limit) { +template +void setRequestLimit(P ¶meters, int limit) { Q_UNUSED(parameters) Q_UNUSED(limit) - Q_UNIMPLEMENTED(); + qDebug() << "setRequestLimit not implemented for type " << typeid(P).name(); } /** @@ -235,7 +231,7 @@ template bool setRequestStartIndex(P ¶meters, int startIndex) { Q_UNUSED(parameters) Q_UNUSED(startIndex) - Q_UNIMPLEMENTED(); + qDebug() << "setRequestStartIndex not implemented for type " << typeid(P).name(); return false; } @@ -248,6 +244,10 @@ extern template QList extractRecords(const QList &result); extern template void setRequestLimit(Loader::GetLatestMediaParams ¶ms, int limit); extern template bool setRequestStartIndex(Loader::GetLatestMediaParams ¶ms, int offset); +extern template void setRequestLimit(Loader::GetItemsByUserIdParams ¶ms, int limit); +extern template bool setRequestStartIndex(Loader::GetItemsByUserIdParams ¶ms, int offset); +extern template void setRequestLimit(Loader::GetResumeItemsParams ¶ms, int limit); +extern template bool setRequestStartIndex(Loader::GetResumeItemsParams ¶ms, int offset); extern template QList extractRecords(const QList &result); extern template int extractTotalRecordCount(const QList &result); @@ -285,8 +285,16 @@ protected: // meaning loadMore is not supported. return; } + if (limit > 0) { - setRequestLimit

(this->m_parameters, limit); + if (suggestedModelStatus == ViewModel::ModelStatus::Loading) { + setRequestLimit

(this->m_parameters, limit); + } else { + // If an explicit limit is set, we should load no more + return; + } + } else { + setRequestLimit

(this->m_parameters, this->DEFAULT_LIMIT); } this->setStatus(suggestedModelStatus); @@ -301,25 +309,32 @@ protected: P m_parameters; void loaderReady() { - R result = m_loader->result(); - QList records = extractRecords(result); - int totalRecordCount = extractTotalRecordCount(result); - qDebug() << "Total record count: " << totalRecordCount << ", records in request: " << records.size(); - // If totalRecordCount < 0, it is not supported for this endpoint - if (totalRecordCount < 0) { - totalRecordCount = records.size(); - } - QList models; - models.reserve(records.size()); + try { + R result = m_loader->result(); + QList records = extractRecords(result); + int totalRecordCount = extractTotalRecordCount(result); + qDebug() << "Total record count: " << totalRecordCount << ", records in request: " << records.size(); + // If totalRecordCount < 0, it is not supported for this endpoint + if (totalRecordCount < 0) { + totalRecordCount = records.size(); + } + QList models; + models.reserve(records.size()); - // Convert the DTOs into models - for (int i = 0; i < records.size(); i++) { - models.append(new T(records[i], m_loader->apiClient())); + // Convert the DTOs into models + for (int i = 0; i < records.size(); i++) { + models.append(new T(records[i], m_loader->apiClient())); + } + this->setStatus(ViewModel::ModelStatus::Ready); + this->m_result = { models, this->m_startIndex}; + this->m_startIndex += records.size(); + this->m_totalRecordCount = totalRecordCount; + this->emitItemsLoaded(); + + } catch(QException &e) { + qWarning() << "Error while loading data: " << e.what(); + this->setStatus(ViewModel::ModelStatus::Error); } - this->setStatus(ViewModel::ModelStatus::Ready); - this->m_result = { models, this->m_startIndex}; - this->m_startIndex += totalRecordCount; - this->emitItemsLoaded(); } void loaderError(QString error) { diff --git a/core/include/JellyfinQt/jellyfin.h b/core/include/JellyfinQt/jellyfin.h index 6729060..4cc4612 100644 --- a/core/include/JellyfinQt/jellyfin.h +++ b/core/include/JellyfinQt/jellyfin.h @@ -34,6 +34,7 @@ #include "viewmodel/item.h" #include "viewmodel/itemmodel.h" #include "viewmodel/loader.h" +#include "viewmodel/mediastream.h" #include "viewmodel/modelstatus.h" #include "viewmodel/playbackmanager.h" #include "viewmodel/playlist.h" diff --git a/core/include/JellyfinQt/support/loader.h b/core/include/JellyfinQt/support/loader.h index b150739..549e03b 100644 --- a/core/include/JellyfinQt/support/loader.h +++ b/core/include/JellyfinQt/support/loader.h @@ -225,16 +225,16 @@ private: void onResponseParsed() { Q_ASSERT(m_parsedWatcher.isFinished()); - if (m_parsedWatcher.result().has_value()) { - try { + try { + if (m_parsedWatcher.result().has_value()) { this->m_result = m_parsedWatcher.result().value(); this->m_isRunning = false; emit this->ready(); - } catch (QException &e) { - this->stopWithError(e.what()); + } else { + this->m_isRunning = false; } - } else { - this->m_isRunning = false; + } catch (QException &e) { + this->stopWithError(e.what()); } } }; diff --git a/core/src/apimodel.cpp b/core/src/apimodel.cpp index 2336242..7107d8d 100644 --- a/core/src/apimodel.cpp +++ b/core/src/apimodel.cpp @@ -141,6 +141,29 @@ bool setRequestStartIndex(Loader::GetLatestMediaParams ¶ms, int offset) { return false; } +template<> +void setRequestLimit(Loader::GetItemsByUserIdParams ¶ms, int limit) { + params.setLimit(limit); +} + +template<> +bool setRequestStartIndex(Loader::GetItemsByUserIdParams ¶ms, int index) { + params.setLimit(index); + return true; +} + +template<> +void setRequestLimit(Loader::GetResumeItemsParams ¶ms, int limit) { + params.setLimit(limit); +} + +template<> +bool setRequestStartIndex(Loader::GetResumeItemsParams ¶ms, int index) { + params.setLimit(index); + return true; +} + + template<> QList extractRecords(const QList &result) { return result; diff --git a/core/src/jellyfin.cpp b/core/src/jellyfin.cpp index 89cda45..9b30de5 100644 --- a/core/src/jellyfin.cpp +++ b/core/src/jellyfin.cpp @@ -27,6 +27,7 @@ void registerTypes(const char *uri) { qmlRegisterUncreatableType(uri, 1, 0, "User", "Acquire one via UserLoader or exposed properties"); qmlRegisterUncreatableType(uri, 1, 0, "EventBus", "Obtain one via your ApiClient"); qmlRegisterUncreatableType(uri, 1, 0, "WebSocket", "Obtain one via your ApiClient"); + qmlRegisterUncreatableType(uri, 1, 0, "MediaStream", "Obtain one via an Item"); qmlRegisterUncreatableType(uri, 1, 0, "UserData", "Obtain one via an Item"); // AbstractItemModels @@ -53,6 +54,7 @@ void registerTypes(const char *uri) { qmlRegisterUncreatableType(uri, 1, 0, "ModelStatus", "Is an enum"); qmlRegisterUncreatableType(uri, 1, 0, "PlayMethod", "Is an enum"); qmlRegisterUncreatableType(uri, 1, 0, "ItemFields", "Is an enum"); + qmlRegisterUncreatableType(uri, 1, 0, "ImageType", "Is an enum"); qmlRegisterUncreatableType(uri, 1, 0, "NowPlayingSection", "Is an enum"); qRegisterMetaType();