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:
parent
2a3bd51def
commit
5d521ee189
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue