mirror of
https://github.com/HenkKalkwater/harbour-sailfin.git
synced 2025-09-04 01:42:44 +00:00
parent
f028e38b7a
commit
4bbc86d31c
6 changed files with 205 additions and 334 deletions
|
@ -153,24 +153,24 @@ public:
|
|||
|
||||
Loader(ApiClient *apiClient, Support::Loader<R, P> *loaderImpl, QObject *parent = nullptr)
|
||||
: LoaderBase(apiClient, parent),
|
||||
m_loader(loaderImpl),
|
||||
m_futureWatcher(new QFutureWatcher<std::optional<R>>(this)) {
|
||||
m_loader(loaderImpl) {
|
||||
|
||||
m_dataViewModel = new T(this);
|
||||
connect(m_futureWatcher, &RFutureWatcher::finished, this, &Loader<T, R, P>::updateData);
|
||||
connect(m_loader.data(), &Support::LoaderBase::ready, this, &Loader<T, R, P>::onLoaderReady);
|
||||
connect(m_loader.data(), &Support::LoaderBase::error, this, &Loader<T, R, P>::onLoaderError);
|
||||
}
|
||||
|
||||
T *dataViewModel() const { return m_dataViewModel; }
|
||||
QObject *data() const override { return m_dataViewModel; }
|
||||
|
||||
void reload() override {
|
||||
if (m_futureWatcher->isRunning()) return;
|
||||
if (m_loader->isRunning()) {
|
||||
m_loader->cancel();
|
||||
};
|
||||
setStatus(Loading);
|
||||
this->m_loader->setApiClient(m_apiClient);
|
||||
m_loader->setApiClient(m_apiClient);
|
||||
m_loader->setParameters(m_parameters);
|
||||
m_loader->prepareLoad();
|
||||
QFuture<std::optional<R>> future = QtConcurrent::run(this, &Loader<T, R, P>::invokeLoader);
|
||||
m_futureWatcher->setFuture(future);
|
||||
m_loader->load();
|
||||
}
|
||||
protected:
|
||||
T* m_dataViewModel;
|
||||
|
@ -180,46 +180,28 @@ protected:
|
|||
*/
|
||||
QScopedPointer<Support::Loader<R, P>> m_loader = nullptr;
|
||||
private:
|
||||
QFutureWatcher<std::optional<R>> *m_futureWatcher;
|
||||
|
||||
/**
|
||||
* @brief Callback for QtConcurrent::run()
|
||||
* @param self Pointer to this class
|
||||
* @param parameters Parameters to forward to the loader
|
||||
* @return empty optional if an error occured, otherwise the result.
|
||||
*/
|
||||
std::optional<R> invokeLoader() {
|
||||
QMutexLocker(&this->m_mutex);
|
||||
try {
|
||||
return this->m_loader->load();
|
||||
} catch (Support::LoadException &e) {
|
||||
qWarning() << "Exception while loading an item: " << e.what();
|
||||
this->setErrorString(QString(e.what()));
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief Updates the data when finished.
|
||||
*/
|
||||
void updateData() {
|
||||
std::optional<R> newDataOpt = m_futureWatcher->result();
|
||||
if (newDataOpt.has_value()) {
|
||||
R newData = newDataOpt.value();
|
||||
if (m_dataViewModel->data()->sameAs(newData)) {
|
||||
// Replace the data the model holds
|
||||
m_dataViewModel->data()->replaceData(newData);
|
||||
} else {
|
||||
// Replace the model
|
||||
using PointerType = typename decltype(m_dataViewModel->data())::Type;
|
||||
m_dataViewModel = new T(this, QSharedPointer<PointerType>::create(newData, m_apiClient));
|
||||
}
|
||||
setStatus(Ready);
|
||||
emitDataChanged();
|
||||
void onLoaderReady() {
|
||||
R newData = m_loader->result();
|
||||
if (m_dataViewModel->data()->sameAs(newData)) {
|
||||
// Replace the data the model holds
|
||||
m_dataViewModel->data()->replaceData(newData);
|
||||
} else {
|
||||
setStatus(Error);
|
||||
// Replace the model
|
||||
using PointerType = typename decltype(m_dataViewModel->data())::Type;
|
||||
m_dataViewModel = new T(this, QSharedPointer<PointerType>::create(newData, m_apiClient));
|
||||
}
|
||||
setStatus(Ready);
|
||||
emitDataChanged();
|
||||
}
|
||||
|
||||
void onLoaderError(QString message) {
|
||||
setStatus(Error);
|
||||
setErrorString(message);
|
||||
}
|
||||
QMutex m_mutex;
|
||||
};
|
||||
|
||||
void registerRemoteTypes(const char *uri);
|
||||
|
|
|
@ -70,7 +70,7 @@ class PlaybackManager : public QObject, public QQmlParserStatus {
|
|||
Q_OBJECT
|
||||
Q_INTERFACES(QQmlParserStatus)
|
||||
public:
|
||||
using FetchCallback = std::function<void(QUrl &&, PlayMethod)>;
|
||||
using ItemUrlLoader = Support::Loader<DTO::PlaybackInfoResponse, Jellyfin::Loader::GetPostedPlaybackInfoParams>;
|
||||
|
||||
explicit PlaybackManager(QObject *parent = nullptr);
|
||||
|
||||
|
@ -179,13 +179,12 @@ private slots:
|
|||
*/
|
||||
void updatePlaybackInfo();
|
||||
|
||||
/// Called when the fetcherThread has fetched the playback URL and playSession
|
||||
void onItemExtraDataReceived(const QString &itemId, const QUrl &url, const QString &playSession,
|
||||
/// Called when we have fetched the playback URL and playSession
|
||||
void onItemUrlReceived(const QString &itemId, const QUrl &url, const QString &playSession,
|
||||
// Fully specify class to please MOC
|
||||
Jellyfin::DTO::PlayMethodClass::Value playMethod);
|
||||
/// Called when the fetcherThread encountered an error
|
||||
/// Called when we have encountered an error
|
||||
void onItemErrorReceived(const QString &itemId, const QString &errorString);
|
||||
void onDestroyed();
|
||||
|
||||
private:
|
||||
/// Factor to multiply with when converting from milliseconds to ticks.
|
||||
|
@ -228,9 +227,6 @@ private:
|
|||
*/
|
||||
bool m_autoOpen = false;
|
||||
|
||||
// Playback-related members
|
||||
ItemUrlFetcherThread *m_urlFetcherThread;
|
||||
|
||||
QMediaPlayer::State m_oldState = QMediaPlayer::StoppedState;
|
||||
PlayMethod m_playMethod = PlayMethod::Transcode;
|
||||
QMediaPlayer::State m_playbackState = QMediaPlayer::StoppedState;
|
||||
|
@ -252,6 +248,9 @@ private:
|
|||
*/
|
||||
void postPlaybackInfo(PlaybackInfoType type);
|
||||
|
||||
void requestItemUrl(QSharedPointer<Model::Item> item);
|
||||
void handlePlaybackInfoResponse(QString itemId, QString mediaType, DTO::PlaybackInfoResponse &response);
|
||||
|
||||
|
||||
// QQmlParserListener interface
|
||||
void classBegin() override { m_qmlIsParsingComponent = true; }
|
||||
|
@ -262,57 +261,6 @@ private:
|
|||
const qint64 PRELOAD_DURATION = 15 * 1000;
|
||||
};
|
||||
|
||||
/// Thread that fetches the Item's stream URL always in the given order they were requested
|
||||
class ItemUrlFetcherThread : public QThread {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ItemUrlFetcherThread(PlaybackManager *manager);
|
||||
|
||||
/**
|
||||
* @brief Adds an item to the queue of items that should be requested
|
||||
* @param item The item to fetch the URL of
|
||||
*/
|
||||
void addItemToQueue(QSharedPointer<Model::Item> item);
|
||||
|
||||
signals:
|
||||
/**
|
||||
* @brief Emitted when the url of the item with the itemId has been retrieved.
|
||||
* @param itemId The id of the item of which the URL has been retrieved
|
||||
* @param itemUrl The retrieved url
|
||||
* @param playSession The playsession set by the Jellyfin Server
|
||||
*/
|
||||
void itemUrlFetched(QString itemId, QUrl itemUrl, QString playSession, Jellyfin::DTO::PlayMethodClass::Value playMethod);
|
||||
void itemUrlFetchError(QString itemId, QString errorString);
|
||||
|
||||
void prepareLoaderRequested(QPrivateSignal);
|
||||
public slots:
|
||||
/**
|
||||
* @brief Ask the thread nicely to stop running.
|
||||
*/
|
||||
void cleanlyStop();
|
||||
private slots:
|
||||
void onPrepareLoader();
|
||||
protected:
|
||||
void run() override;
|
||||
private:
|
||||
PlaybackManager *m_parent;
|
||||
Support::Loader<DTO::PlaybackInfoResponse, Jellyfin::Loader::GetPostedPlaybackInfoParams> *m_loader;
|
||||
|
||||
QMutex m_queueModifyMutex;
|
||||
QQueue<QSharedPointer<Model::Item>> m_queue;
|
||||
|
||||
QMutex m_urlWaitConditionMutex;
|
||||
/// WaitCondition on which this threads waits until an Item is put into the queue
|
||||
QWaitCondition m_urlWaitCondition;
|
||||
|
||||
QMutex m_waitLoaderPreparedMutex;
|
||||
/// WaitCondition on which this threads waits until the loader has been prepared.
|
||||
QWaitCondition m_waitLoaderPrepared;
|
||||
|
||||
bool m_keepRunning = true;
|
||||
bool m_loaderPrepared = false;
|
||||
};
|
||||
|
||||
} // NS ViewModel
|
||||
} // NS Jellyfin
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue