From 4ebd5ed3f07200b9cf6b660482f4507b7afea130 Mon Sep 17 00:00:00 2001 From: joren Date: Tue, 31 Mar 2026 02:02:31 +0200 Subject: [PATCH] fix: detect followed playlists correctly in header Load owner+subscriber playlists, track all playlist IDs for follow-state resolution, and keep audio ring buffer at 32k as requested. --- rust/src/api/client.rs | 1 + rust/src/player/output.rs | 4 +--- src/backend/qobuzbackend.hpp | 2 +- src/list/library.cpp | 5 +++++ src/list/library.hpp | 3 +++ src/mainwindow.cpp | 18 ++++++++++++------ src/mainwindow.hpp | 1 + 7 files changed, 24 insertions(+), 10 deletions(-) diff --git a/rust/src/api/client.rs b/rust/src/api/client.rs index 03a56c4..4988c49 100644 --- a/rust/src/api/client.rs +++ b/rust/src/api/client.rs @@ -609,6 +609,7 @@ impl QobuzClient { let resp = self .get_request("playlist/getUserPlaylists") .query(&[ + ("filter", "owner,subscriber"), ("offset", &offset.to_string()), ("limit", &limit.to_string()), ]) diff --git a/rust/src/player/output.rs b/rust/src/player/output.rs index 096325b..0f6e91a 100644 --- a/rust/src/player/output.rs +++ b/rust/src/player/output.rs @@ -10,9 +10,7 @@ use std::sync::{ }; use symphonia::core::audio::AudioBufferRef; -// Bigger output buffer gives the decoder/network pipeline more headroom, -// reducing audible underruns on transient CPU/network stalls. -const RING_BUFFER_SIZE: usize = 256 * 1024; +const RING_BUFFER_SIZE: usize = 32 * 1024; pub struct AudioOutput { _ring: SpscRb, diff --git a/src/backend/qobuzbackend.hpp b/src/backend/qobuzbackend.hpp index 557df1f..2399586 100644 --- a/src/backend/qobuzbackend.hpp +++ b/src/backend/qobuzbackend.hpp @@ -45,7 +45,7 @@ public: void getFavTracks(quint32 offset = 0, quint32 limit = 500); void getFavAlbums(quint32 offset = 0, quint32 limit = 200); void getFavArtists(quint32 offset = 0, quint32 limit = 200); - void getUserPlaylists(quint32 offset = 0, quint32 limit = 200); + void getUserPlaylists(quint32 offset = 0, quint32 limit = 350); // --- playback options --- void setReplayGain(bool enabled); diff --git a/src/list/library.cpp b/src/list/library.cpp index 672d05a..d7ad980 100644 --- a/src/list/library.cpp +++ b/src/list/library.cpp @@ -99,6 +99,7 @@ void Library::onUserPlaylistsLoaded(const QJsonObject &result) while (m_playlistsNode->childCount() > 0) delete m_playlistsNode->takeChild(0); + QSet allPlaylistIds; QVector> editablePlaylists; const qint64 myUserId = AppSettings::instance().userId(); const QJsonArray items = result["items"].toArray(); @@ -109,6 +110,9 @@ void Library::onUserPlaylistsLoaded(const QJsonObject &result) const qint64 ownId = static_cast(pl["owner"].toObject()["id"].toDouble()); const bool isOwner = (myUserId > 0 && ownId == myUserId); + if (id > 0) + allPlaylistIds.insert(id); + auto *item = new QTreeWidgetItem(m_playlistsNode, QStringList{name}); item->setData(0, TypeRole, NodePlaylist); item->setData(0, IdRole, id); @@ -120,6 +124,7 @@ void Library::onUserPlaylistsLoaded(const QJsonObject &result) editablePlaylists.append({id, name}); } + emit userPlaylistIdsChanged(allPlaylistIds); emit userPlaylistsChanged(editablePlaylists); } diff --git a/src/list/library.hpp b/src/list/library.hpp index 43d828a..985f8d7 100644 --- a/src/list/library.hpp +++ b/src/list/library.hpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace List { @@ -31,6 +32,8 @@ namespace List void playlistRequested(qint64 playlistId, const QString &name); /// Emitted after playlists are loaded so others can cache the list. void userPlaylistsChanged(const QVector> &playlists); + /// Emitted with all user playlist IDs (owned + subscribed). + void userPlaylistIdsChanged(const QSet &playlistIds); /// Emitted when the currently open playlist was deleted. void openPlaylistDeleted(); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 3fc7ae8..70ab008 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -128,12 +128,14 @@ MainWindow::MainWindow(QobuzBackend *backend, QWidget *parent) statusBar()->showMessage(tr("Track added to playlist"), 3000); }); connect(m_backend, &QobuzBackend::playlistSubscribed, this, [this](qint64 playlistId) { + m_userPlaylistIds.insert(playlistId); m_library->refresh(); if (m_content->tracksList()->playlistId() == playlistId) m_content->setCurrentPlaylistFollowed(true); statusBar()->showMessage(tr("Playlist followed"), 3000); }); connect(m_backend, &QobuzBackend::playlistUnsubscribed, this, [this](qint64 playlistId) { + m_userPlaylistIds.remove(playlistId); m_library->refresh(); if (m_content->tracksList()->playlistId() == playlistId) m_content->setCurrentPlaylistFollowed(false); @@ -145,6 +147,10 @@ MainWindow::MainWindow(QobuzBackend *backend, QWidget *parent) }); // ---- Library signals ---- + connect(m_library, &List::Library::userPlaylistIdsChanged, + this, [this](const QSet &playlistIds) { + m_userPlaylistIds = playlistIds; + }); connect(m_library, &List::Library::userPlaylistsChanged, this, &MainWindow::onUserPlaylistsChanged); connect(m_library, &List::Library::openPlaylistDeleted, @@ -536,12 +542,12 @@ void MainWindow::onPlaylistLoaded(const QJsonObject &playlist) const qint64 myId = AppSettings::instance().userId(); const bool isOwned = (myId > 0 && ownerId == myId); - bool isFollowed = false; - for (const auto &pl : m_userPlaylists) { - if (pl.first == id) { - isFollowed = true; - break; - } + bool isFollowed = isOwned || m_userPlaylistIds.contains(id); + if (!isFollowed) { + if (playlist.contains("is_subscribed")) + isFollowed = playlist["is_subscribed"].toBool(); + else if (playlist.contains("subscribed_at")) + isFollowed = !playlist["subscribed_at"].isNull(); } m_content->showPlaylist(playlist, isFollowed, isOwned); diff --git a/src/mainwindow.hpp b/src/mainwindow.hpp index 81b5b77..a8eba76 100644 --- a/src/mainwindow.hpp +++ b/src/mainwindow.hpp @@ -55,6 +55,7 @@ private: QobuzBackend *m_backend = nullptr; PlayQueue *m_queue = nullptr; QVector> m_userPlaylists; + QSet m_userPlaylistIds; QSet m_favAlbumIds; QSet m_favArtistIds; bool m_showFavAlbumsOnLoad = false;