1
0
Fork 0
mirror of https://github.com/HenkKalkwater/harbour-sailfin.git synced 2024-11-22 09:15:18 +00:00

Resume playback once again

This commit is contained in:
Chris Josten 2021-09-10 03:06:42 +02:00
parent 2a3bd51def
commit 5d521ee189
No known key found for this signature in database
GPG key ID: A69C050E9FD9FF6A
2 changed files with 66 additions and 19 deletions

View file

@ -209,6 +209,7 @@ private slots:
void mediaPlayerMediaStatusChanged(QMediaPlayer::MediaStatus newStatus); void mediaPlayerMediaStatusChanged(QMediaPlayer::MediaStatus newStatus);
void mediaPlayerError(QMediaPlayer::Error error); void mediaPlayerError(QMediaPlayer::Error error);
void mediaPlayerDurationChanged(qint64 newDuration); void mediaPlayerDurationChanged(qint64 newDuration);
void mediaPlayerSeekableChanged(bool seekable);
/** /**
* @brief updatePlaybackInfo Updates the Jellyfin server with the current playback progress etc. * @brief updatePlaybackInfo Updates the Jellyfin server with the current playback progress etc.
*/ */
@ -264,6 +265,8 @@ private:
*/ */
bool m_autoOpen = false; bool m_autoOpen = false;
bool m_seekToResumedPosition = false;
QMediaPlayer::State m_oldState = QMediaPlayer::StoppedState; QMediaPlayer::State m_oldState = QMediaPlayer::StoppedState;
/// State of the playbackManager. While the internal media player stops after a /// State of the playbackManager. While the internal media player stops after a
/// song has ended, this will not do so. /// song has ended, this will not do so.
@ -274,8 +277,7 @@ private:
Model::Playlist *m_queue = nullptr; Model::Playlist *m_queue = nullptr;
int m_queueIndex = 0; int m_queueIndex = 0;
bool m_resumePlayback = true; bool m_resumePlayback = false;
bool m_handlePlaystateCommands = true; bool m_handlePlaystateCommands = true;
// Helper methods // Helper methods
@ -300,6 +302,7 @@ private:
/// Time in ms at what moment this playbackmanager should start loading the next item. /// Time in ms at what moment this playbackmanager should start loading the next item.
const qint64 PRELOAD_DURATION = 15 * 1000; const qint64 PRELOAD_DURATION = 15 * 1000;
QTimer m_forceSeekTimer;
}; };
} // NS ViewModel } // NS ViewModel

View file

@ -61,10 +61,27 @@ PlaybackManager::PlaybackManager(QObject *parent)
connect(m_mediaPlayer, &QMediaPlayer::durationChanged, this, &PlaybackManager::mediaPlayerDurationChanged); connect(m_mediaPlayer, &QMediaPlayer::durationChanged, this, &PlaybackManager::mediaPlayerDurationChanged);
connect(m_mediaPlayer, &QMediaPlayer::mediaStatusChanged, this, &PlaybackManager::mediaPlayerMediaStatusChanged); connect(m_mediaPlayer, &QMediaPlayer::mediaStatusChanged, this, &PlaybackManager::mediaPlayerMediaStatusChanged);
connect(m_mediaPlayer, &QMediaPlayer::videoAvailableChanged, this, &PlaybackManager::hasVideoChanged); connect(m_mediaPlayer, &QMediaPlayer::videoAvailableChanged, this, &PlaybackManager::hasVideoChanged);
connect(m_mediaPlayer, &QMediaPlayer::seekableChanged, this, &PlaybackManager::seekableChanged); connect(m_mediaPlayer, &QMediaPlayer::seekableChanged, this, &PlaybackManager::mediaPlayerSeekableChanged);
// I do not like the complicated overload cast // I do not like the complicated overload cast
connect(m_mediaPlayer, SIGNAL(error(QMediaPlayer::Error)), this, SLOT(mediaPlayerError(QMediaPlayer::Error))); connect(m_mediaPlayer, SIGNAL(error(QMediaPlayer::Error)), this, SLOT(mediaPlayerError(QMediaPlayer::Error)));
m_forceSeekTimer.setInterval(500);
m_forceSeekTimer.setSingleShot(false);
// Yes, this is a very ugly way of forcing the video player to seek to the resume position
connect(&m_forceSeekTimer, &QTimer::timeout, this, [this]() {
if (m_seekToResumedPosition && m_mediaPlayer->isSeekable()) {
qCDebug(playbackManager) << "Trying to seek to the resume position" << (m_resumePosition / MS_TICK_FACTOR);
if (m_mediaPlayer->position() > m_resumePosition / MS_TICK_FACTOR - 500) {
m_seekToResumedPosition = false;
m_forceSeekTimer.stop();
} else {
m_mediaPlayer->setPosition(m_resumePosition / MS_TICK_FACTOR);
}
}
});
} }
void PlaybackManager::setApiClient(ApiClient *apiClient) { void PlaybackManager::setApiClient(ApiClient *apiClient) {
@ -96,12 +113,17 @@ void PlaybackManager::setItem(QSharedPointer<Model::Item> newItem) {
m_displayItem->setData(QSharedPointer<Model::Item>::create()); m_displayItem->setData(QSharedPointer<Model::Item>::create());
} else { } else {
m_displayItem->setData(newItem); m_displayItem->setData(newItem);
if (!newItem->userData().isNull()) {
this->m_resumePosition = newItem->userData()->playbackPositionTicks();
}
} }
emit itemChanged(m_displayItem); emit itemChanged(m_displayItem);
emit hasNextChanged(m_queue->hasNext()); emit hasNextChanged(m_queue->hasNext());
emit hasPreviousChanged(m_queue->hasPrevious()); emit hasPreviousChanged(m_queue->hasPrevious());
this->m_seekToResumedPosition = m_resumePlayback;
if (m_apiClient == nullptr) { if (m_apiClient == nullptr) {
qCWarning(playbackManager) << "apiClient is not set on this MediaSource instance! Aborting."; qCWarning(playbackManager) << "apiClient is not set on this MediaSource instance! Aborting.";
@ -161,12 +183,23 @@ void PlaybackManager::mediaPlayerPositionChanged(qint64 position) {
void PlaybackManager::mediaPlayerStateChanged(QMediaPlayer::State newState) { void PlaybackManager::mediaPlayerStateChanged(QMediaPlayer::State newState) {
if (m_oldState == newState) return; if (m_oldState == newState) return;
if (newState == QMediaPlayer::PlayingState) {
if (m_seekToResumedPosition) {
if (m_mediaPlayer->isSeekable()) {
qCDebug(playbackManager) << "Resuming playback by seeking to " << (m_resumePosition / MS_TICK_FACTOR);
m_mediaPlayer->setPosition(m_resumePosition / MS_TICK_FACTOR);
m_seekToResumedPosition = false;
}
}
}
if (m_oldState == QMediaPlayer::StoppedState) { if (m_oldState == QMediaPlayer::StoppedState) {
// We're transitioning from stopped to either playing or paused. // We're transitioning from stopped to either playing or paused.
// Set up the recurring timer // Set up the recurring timer
m_updateTimer.start(); m_updateTimer.start();
postPlaybackInfo(Started); postPlaybackInfo(Started);
} else if (newState == QMediaPlayer::StoppedState) { } else if (newState == QMediaPlayer::StoppedState && m_playbackState == QMediaPlayer::StoppedState) {
// We've stopped playing the media. Post a stop signal. // We've stopped playing the media. Post a stop signal.
m_updateTimer.stop(); m_updateTimer.stop();
postPlaybackInfo(Stopped); postPlaybackInfo(Stopped);
@ -181,11 +214,7 @@ void PlaybackManager::mediaPlayerMediaStatusChanged(QMediaPlayer::MediaStatus ne
emit mediaStatusChanged(newStatus); emit mediaStatusChanged(newStatus);
if (m_playbackState == QMediaPlayer::StoppedState) return; if (m_playbackState == QMediaPlayer::StoppedState) return;
if (newStatus == QMediaPlayer::LoadedMedia) { if (newStatus == QMediaPlayer::LoadedMedia) {
m_mediaPlayer->play(); m_mediaPlayer->play();
if (m_resumePlayback) {
qCDebug(playbackManager) << "Resuming playback by seeking to " << (m_resumePosition / MS_TICK_FACTOR);
m_mediaPlayer->setPosition(m_resumePosition / MS_TICK_FACTOR);
}
} else if (newStatus == QMediaPlayer::EndOfMedia) { } else if (newStatus == QMediaPlayer::EndOfMedia) {
if (m_queue->hasNext() && m_queue->totalSize() > 1) { if (m_queue->hasNext() && m_queue->totalSize() > 1) {
next(); next();
@ -204,6 +233,21 @@ void PlaybackManager::mediaPlayerDurationChanged(qint64 newDuration) {
} }
} }
void PlaybackManager::mediaPlayerSeekableChanged(bool newSeekable) {
emit seekableChanged(newSeekable);
if (m_seekToResumedPosition) {
m_forceSeekTimer.start();
}
/*if (m_seekToResumedPosition && newSeekable) {
qCDebug(playbackManager) << "Trying to seek to the resume position";
m_mediaPlayer->setPosition(m_resumePosition / MS_TICK_FACTOR);
if (m_mediaPlayer->position() > 1000) {
m_seekToResumedPosition = false;
}
}*/
}
void PlaybackManager::mediaPlayerError(QMediaPlayer::Error error) { void PlaybackManager::mediaPlayerError(QMediaPlayer::Error error) {
emit errorChanged(error); emit errorChanged(error);
emit errorStringChanged(m_mediaPlayer->errorString()); emit errorStringChanged(m_mediaPlayer->errorString());
@ -403,7 +447,7 @@ void PlaybackManager::postPlaybackInfo(PlaybackInfoType type) {
break; break;
} }
case Stopped: case Stopped:
progress.setPositionTicks(m_mediaPlayer->position() * MS_TICK_FACTOR); progress.setPositionTicks(m_stopPosition * MS_TICK_FACTOR);
break; break;
} }
@ -428,7 +472,7 @@ void PlaybackManager::postPlaybackInfo(PlaybackInfoType type) {
} }
void PlaybackManager::componentComplete() { void PlaybackManager::componentComplete() {
if (m_apiClient == nullptr) qWarning() << "No ApiClient set for PlaybackManager"; if (m_apiClient == nullptr) qCWarning(playbackManager) << "No ApiClient set for PlaybackManager";
m_qmlIsParsingComponent = false; m_qmlIsParsingComponent = false;
} }
@ -513,11 +557,11 @@ void PlaybackManager::handlePlaybackInfoResponse(QString itemId, QString mediaTy
} }
qDebug() << "Media source: " << source.name() << "\n" qCDebug(playbackManager()) << "Media source: " << source.name() << "\n"
<< "Prefer transcoding: " << transcodePreferred << "\n" << "Prefer transcoding: " << transcodePreferred << "\n"
<< "DirectPlay supported: " << source.supportsDirectPlay() << "\n" << "DirectPlay supported: " << source.supportsDirectPlay() << "\n"
<< "DirectStream supported: " << source.supportsDirectStream() << "\n" << "DirectStream supported: " << source.supportsDirectStream() << "\n"
<< "Transcode supported: " << source.supportsTranscoding(); << "Transcode supported: " << source.supportsTranscoding();
if (source.supportsDirectPlay() && QFile::exists(source.path())) { if (source.supportsDirectPlay() && QFile::exists(source.path())) {
resultingUrl = QUrl::fromLocalFile(source.path()); resultingUrl = QUrl::fromLocalFile(source.path());
@ -535,16 +579,16 @@ void PlaybackManager::handlePlaybackInfoResponse(QString itemId, QString mediaTy
+ "/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) {
qDebug() << "Transcoding url: " << source.transcodingUrl(); qCDebug(playbackManager) << "Transcoding url: " << source.transcodingUrl();
resultingUrl = QUrl(m_apiClient->baseUrl() + source.transcodingUrl()); resultingUrl = QUrl(m_apiClient->baseUrl() + source.transcodingUrl());
playMethod = PlayMethod::Transcode; playMethod = PlayMethod::Transcode;
} else { } else {
qDebug() << "No suitable sources for item " << itemId; qCDebug(playbackManager) << "No suitable sources for item " << itemId;
} }
if (!resultingUrl.isEmpty()) break; if (!resultingUrl.isEmpty()) break;
} }
if (resultingUrl.isEmpty()) { if (resultingUrl.isEmpty()) {
qWarning() << "Could not find suitable media source for item " << itemId; qCWarning(playbackManager) << "Could not find suitable media source for item " << itemId;
onItemErrorReceived(itemId, tr("Could not find a suitable media source.")); onItemErrorReceived(itemId, tr("Could not find a suitable media source."));
} else { } else {
emit playMethodChanged(playMethod); emit playMethodChanged(playMethod);