Initial implementation of qobuz-qt
- Rust backend (qobuz-backend static lib): Qobuz API client (reqwest/tokio), Symphonia audio decoder, CPAL audio output, extern "C" FFI bridge - Qt 6 frontend mirroring spotify-qt layout: toolbar with playback controls, left library dock, central track list, right search panel - Auth: email/password login with MD5-signed requests; session token persisted via QSettings - Playback: double-click a track → Rust fetches stream URL → Symphonia decodes → CPAL outputs to default audio device - Dark Fusion palette matching spotify-qt feel Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
110
src/list/library.cpp
Normal file
110
src/list/library.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
#include "library.hpp"
|
||||
|
||||
#include <QHeaderView>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace List
|
||||
{
|
||||
|
||||
static constexpr int TypeRole = Qt::UserRole + 1;
|
||||
static constexpr int IdRole = Qt::UserRole + 2;
|
||||
static constexpr int NameRole = Qt::UserRole + 3;
|
||||
|
||||
enum NodeType {
|
||||
NodeFavTracks,
|
||||
NodeFavAlbums,
|
||||
NodeFavArtists,
|
||||
NodePlaylist,
|
||||
};
|
||||
|
||||
Library::Library(QobuzBackend *backend, QWidget *parent)
|
||||
: QTreeWidget(parent)
|
||||
, m_backend(backend)
|
||||
{
|
||||
setHeaderHidden(true);
|
||||
setRootIsDecorated(true);
|
||||
setContextMenuPolicy(Qt::NoContextMenu);
|
||||
|
||||
buildStaticNodes();
|
||||
|
||||
connect(m_backend, &QobuzBackend::userPlaylistsLoaded,
|
||||
this, &Library::onUserPlaylistsLoaded);
|
||||
connect(this, &QTreeWidget::itemClicked,
|
||||
this, &Library::onItemClicked);
|
||||
connect(this, &QTreeWidget::itemDoubleClicked,
|
||||
this, &Library::onItemDoubleClicked);
|
||||
}
|
||||
|
||||
void Library::buildStaticNodes()
|
||||
{
|
||||
// My Library
|
||||
m_myLibNode = new QTreeWidgetItem(this, QStringList{tr("My Library")});
|
||||
m_myLibNode->setExpanded(true);
|
||||
|
||||
auto *tracksItem = new QTreeWidgetItem(m_myLibNode, QStringList{tr("Favorite Tracks")});
|
||||
tracksItem->setData(0, TypeRole, NodeFavTracks);
|
||||
|
||||
auto *albumsItem = new QTreeWidgetItem(m_myLibNode, QStringList{tr("Favorite Albums")});
|
||||
albumsItem->setData(0, TypeRole, NodeFavAlbums);
|
||||
|
||||
auto *artistsItem = new QTreeWidgetItem(m_myLibNode, QStringList{tr("Favorite Artists")});
|
||||
artistsItem->setData(0, TypeRole, NodeFavArtists);
|
||||
|
||||
// Playlists
|
||||
m_playlistsNode = new QTreeWidgetItem(this, QStringList{tr("Playlists")});
|
||||
m_playlistsNode->setExpanded(true);
|
||||
}
|
||||
|
||||
void Library::refresh()
|
||||
{
|
||||
// Remove old playlist children
|
||||
while (m_playlistsNode->childCount() > 0)
|
||||
delete m_playlistsNode->takeChild(0);
|
||||
|
||||
m_backend->getUserPlaylists();
|
||||
}
|
||||
|
||||
void Library::onUserPlaylistsLoaded(const QJsonObject &result)
|
||||
{
|
||||
while (m_playlistsNode->childCount() > 0)
|
||||
delete m_playlistsNode->takeChild(0);
|
||||
|
||||
const QJsonArray items = result["items"].toArray();
|
||||
for (const auto &v : items) {
|
||||
const QJsonObject pl = v.toObject();
|
||||
const QString name = pl["name"].toString();
|
||||
const qint64 id = static_cast<qint64>(pl["id"].toDouble());
|
||||
|
||||
auto *item = new QTreeWidgetItem(m_playlistsNode, QStringList{name});
|
||||
item->setData(0, TypeRole, NodePlaylist);
|
||||
item->setData(0, IdRole, id);
|
||||
item->setData(0, NameRole, name);
|
||||
}
|
||||
}
|
||||
|
||||
void Library::onItemClicked(QTreeWidgetItem *item, int)
|
||||
{
|
||||
if (!item) return;
|
||||
const int type = item->data(0, TypeRole).toInt();
|
||||
|
||||
switch (type) {
|
||||
case NodeFavTracks: emit favTracksRequested(); break;
|
||||
case NodeFavAlbums: emit favAlbumsRequested(); break;
|
||||
case NodeFavArtists: emit favArtistsRequested(); break;
|
||||
case NodePlaylist: {
|
||||
const qint64 id = item->data(0, IdRole).toLongLong();
|
||||
const QString name = item->data(0, NameRole).toString();
|
||||
emit playlistRequested(id, name);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void Library::onItemDoubleClicked(QTreeWidgetItem *item, int column)
|
||||
{
|
||||
onItemClicked(item, column);
|
||||
}
|
||||
|
||||
} // namespace List
|
||||
Reference in New Issue
Block a user