refactor: resync with qbqt baseline and restore genre browser
Some checks failed
Build for Windows / build-windows (push) Has been cancelled
Some checks failed
Build for Windows / build-windows (push) Has been cancelled
This commit is contained in:
@@ -4,6 +4,10 @@
|
||||
#include "util/settings.hpp"
|
||||
#include "util/icon.hpp"
|
||||
|
||||
#ifdef USE_DBUS
|
||||
#include "backend/mpris.hpp"
|
||||
#endif
|
||||
|
||||
#include <QApplication>
|
||||
#include <QMenuBar>
|
||||
#include <QMenu>
|
||||
@@ -61,17 +65,37 @@ MainWindow::MainWindow(QobuzBackend *backend, QWidget *parent)
|
||||
statusBar()->showMessage(tr("Ready"));
|
||||
|
||||
// ---- Scrobbler ----
|
||||
m_scrobbler = new LastFmScrobbler(this);
|
||||
connect(m_backend, &QobuzBackend::trackChanged,
|
||||
m_scrobbler, &LastFmScrobbler::onTrackStarted);
|
||||
connect(m_backend, &QobuzBackend::positionChanged,
|
||||
m_scrobbler, &LastFmScrobbler::onPositionChanged);
|
||||
connect(m_backend, &QobuzBackend::trackFinished,
|
||||
m_scrobbler, &LastFmScrobbler::onTrackFinished);
|
||||
m_scrobbler = new LastFmScrobbler(this);
|
||||
connect(m_backend, &QobuzBackend::trackChanged,
|
||||
m_scrobbler, &LastFmScrobbler::onTrackStarted);
|
||||
connect(m_backend, &QobuzBackend::positionChanged,
|
||||
m_scrobbler, &LastFmScrobbler::onPositionChanged);
|
||||
connect(m_backend, &QobuzBackend::trackFinished,
|
||||
m_scrobbler, &LastFmScrobbler::onTrackFinished);
|
||||
|
||||
// Scrobble the finished track during a gapless transition
|
||||
connect(m_backend, &QobuzBackend::trackTransitioned,
|
||||
m_scrobbler, &LastFmScrobbler::onTrackFinished);
|
||||
// 1. Scrobble the finished track during a gapless transition
|
||||
connect(m_backend, &QobuzBackend::trackTransitioned,
|
||||
m_scrobbler, &LastFmScrobbler::onTrackFinished);
|
||||
|
||||
// ---- Gapless Signal ----
|
||||
connect(m_backend, &QobuzBackend::positionChanged, this, [this](quint64 pos, quint64 dur) {
|
||||
if (!AppSettings::instance().gaplessEnabled() || dur == 0) return;
|
||||
|
||||
// Trigger prefetch if we pass the 50% mark OR are within 60 seconds of the end
|
||||
if ((pos > dur / 2) || (dur > 60 && (dur - pos) <= 60)) {
|
||||
if (!m_nextTrackPrefetched && m_queue->canGoNext()) {
|
||||
m_nextTrackPrefetched = true; // Lock it so it only fires once
|
||||
|
||||
const auto upcoming = m_queue->upcomingTracks(1);
|
||||
if (!upcoming.isEmpty()) {
|
||||
const qint64 nextId = static_cast<qint64>(upcoming.first()["id"].toDouble());
|
||||
if (nextId > 0) {
|
||||
m_backend->prefetchTrack(nextId, AppSettings::instance().preferredFormat());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// ---- Backend signals ----
|
||||
connect(m_backend, &QobuzBackend::loginSuccess, this, &MainWindow::onLoginSuccess);
|
||||
@@ -122,6 +146,52 @@ MainWindow::MainWindow(QobuzBackend *backend, QWidget *parent)
|
||||
m_backend->getFavTracks();
|
||||
statusBar()->showMessage(tr("Loading favorite tracks…"));
|
||||
});
|
||||
|
||||
#ifdef USE_DBUS
|
||||
m_mpris = new Mpris(this);
|
||||
connect(m_mpris->player(), &MprisPlayerAdaptor::playRequested, m_backend, [this] {
|
||||
if (m_backend->state() == 2) m_backend->resume();
|
||||
});
|
||||
connect(m_mpris->player(), &MprisPlayerAdaptor::pauseRequested, m_backend, &QobuzBackend::pause);
|
||||
connect(m_mpris->player(), &MprisPlayerAdaptor::playPauseRequested, m_backend, [this] {
|
||||
if (m_backend->state() == 1)
|
||||
m_backend->pause();
|
||||
else
|
||||
m_backend->resume();
|
||||
});
|
||||
connect(m_mpris->player(), &MprisPlayerAdaptor::stopRequested, m_backend, &QobuzBackend::stop);
|
||||
connect(m_mpris->player(), &MprisPlayerAdaptor::nextRequested, this, [this] {
|
||||
if (!m_queue->canGoNext()) return;
|
||||
const qint64 id = static_cast<qint64>(m_queue->advance()["id"].toDouble());
|
||||
if (id > 0) m_backend->playTrack(id);
|
||||
});
|
||||
connect(m_mpris->player(), &MprisPlayerAdaptor::previousRequested, this, [this] {
|
||||
if (!m_queue->canGoPrev()) return;
|
||||
const qint64 id = static_cast<qint64>(m_queue->stepBack()["id"].toDouble());
|
||||
if (id > 0) m_backend->playTrack(id);
|
||||
});
|
||||
connect(m_mpris->player(), &MprisPlayerAdaptor::seekRequested, m_backend, [this](qlonglong offsetMicroseconds) {
|
||||
qint64 newPos = m_backend->position() + (offsetMicroseconds / 1000000LL);
|
||||
if (newPos < 0) newPos = 0;
|
||||
m_backend->seek(newPos);
|
||||
});
|
||||
connect(m_mpris->player(), &MprisPlayerAdaptor::seekToRequested, m_backend, [this](qlonglong positionMicroseconds) {
|
||||
m_backend->seek(positionMicroseconds / 1000000LL);
|
||||
});
|
||||
connect(m_mpris->player(), &MprisPlayerAdaptor::volumeChangeRequested, m_backend, [this](double vol) {
|
||||
m_backend->setVolume(vol * 100);
|
||||
});
|
||||
|
||||
connect(m_backend, &QobuzBackend::stateChanged, this, [this](const QString &state) {
|
||||
if (state == "playing") m_mpris->player()->setPlaybackStatus("Playing");
|
||||
else if (state == "paused") m_mpris->player()->setPlaybackStatus("Paused");
|
||||
else m_mpris->player()->setPlaybackStatus("Stopped");
|
||||
});
|
||||
connect(m_backend, &QobuzBackend::positionChanged, this, [this](quint64 pos) {
|
||||
m_mpris->player()->updatePosition(pos);
|
||||
});
|
||||
#endif
|
||||
|
||||
connect(m_library, &List::Library::favAlbumsRequested, this, [this] {
|
||||
m_backend->getFavAlbums();
|
||||
statusBar()->showMessage(tr("Loading favorite albums…"));
|
||||
@@ -136,6 +206,10 @@ MainWindow::MainWindow(QobuzBackend *backend, QWidget *parent)
|
||||
m_backend->getPlaylist(id);
|
||||
statusBar()->showMessage(tr("Loading playlist: %1…").arg(name));
|
||||
});
|
||||
connect(m_library, &List::Library::browseGenresRequested, this, [this] {
|
||||
m_content->showGenreBrowser();
|
||||
statusBar()->showMessage(tr("Browse Genres"));
|
||||
});
|
||||
|
||||
// ---- Track list → playback / playlist management ----
|
||||
connect(m_content->tracksList(), &List::Tracks::playTrackRequested,
|
||||
@@ -289,6 +363,7 @@ void MainWindow::onLoginError(const QString &error)
|
||||
|
||||
void MainWindow::onTrackChanged(const QJsonObject &track)
|
||||
{
|
||||
m_nextTrackPrefetched = false;
|
||||
// Update playing row highlight in the track list
|
||||
const qint64 id = static_cast<qint64>(track["id"].toDouble());
|
||||
m_content->tracksList()->setPlayingTrackId(id);
|
||||
@@ -301,15 +376,25 @@ void MainWindow::onTrackChanged(const QJsonObject &track)
|
||||
statusBar()->showMessage(
|
||||
artist.isEmpty() ? title : QStringLiteral("▶ %1 — %2").arg(artist, title));
|
||||
|
||||
// Prefetch next track URL when gapless is enabled
|
||||
if (AppSettings::instance().gaplessEnabled() && m_queue->canGoNext()) {
|
||||
const auto upcoming = m_queue->upcomingTracks(1);
|
||||
if (!upcoming.isEmpty()) {
|
||||
const qint64 nextId = static_cast<qint64>(upcoming.first()["id"].toDouble());
|
||||
if (nextId > 0)
|
||||
m_backend->prefetchTrack(nextId, AppSettings::instance().preferredFormat());
|
||||
}
|
||||
#ifdef USE_DBUS
|
||||
QVariantMap metadata;
|
||||
metadata["mpris:trackid"] = QVariant::fromValue(QDBusObjectPath(QString("/org/qobuz/track/%1").arg(id)));
|
||||
metadata["mpris:length"] = QVariant::fromValue(qlonglong(track["duration"].toDouble() * 1000000LL));
|
||||
metadata["xesam:title"] = title;
|
||||
|
||||
QJsonObject album = track["album"].toObject();
|
||||
metadata["xesam:album"] = album["title"].toString();
|
||||
|
||||
if (!artist.isEmpty()) {
|
||||
metadata["xesam:artist"] = QStringList{artist};
|
||||
}
|
||||
|
||||
if (album.contains("image") && album["image"].toObject().contains("large")) {
|
||||
metadata["mpris:artUrl"] = album["image"].toObject()["large"].toString();
|
||||
}
|
||||
|
||||
m_mpris->player()->setMetadata(metadata);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainWindow::onFavTracksLoaded(const QJsonObject &result)
|
||||
@@ -420,4 +505,3 @@ void MainWindow::onUserPlaylistsChanged(const QVector<QPair<qint64, QString>> &p
|
||||
m_content->tracksList()->setUserPlaylists(playlists);
|
||||
m_sidePanel->searchTab()->setUserPlaylists(playlists);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user