Files
audiotube/src/artistmodel.cpp

192 lines
6.4 KiB
C++

// SPDX-FileCopyrightText: 2021 Jonah Brüchert <[email protected]>
//
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#include "artistmodel.h"
#include <QStringBuilder>
#include <asyncytmusic.h>
ArtistModel::ArtistModel(QObject *parent)
: AbstractYTMusicModel(parent)
, m_view(albums, singles, songs, videos)
{
connect(this, &ArtistModel::channelIdChanged, this, [this] {
if (m_channelId.isEmpty()) {
return;
}
setLoading(true);
auto future = YTMusicThread::instance()->fetchArtist(m_channelId);
QCoro::connect(std::move(future), this, [=, this](artist::Artist &&artist) {
setLoading(false);
beginResetModel();
m_artist = std::move(artist);
std::sort(m_artist.thumbnails.begin(), m_artist.thumbnails.end());
albums = m_artist.albums ? m_artist.albums->results : std::vector<artist::Artist::Album>();
for (auto &album : albums) {
std::sort(album.thumbnails.begin(), album.thumbnails.end());
}
singles = m_artist.singles ? m_artist.singles->results : std::vector<artist::Artist::Single>();
for (auto &single : singles) {
std::sort(single.thumbnails.begin(), single.thumbnails.end());
}
songs = m_artist.songs ? m_artist.songs->results : std::vector<artist::Artist::Song>();
for (auto &song : songs) {
std::sort(song.thumbnails.begin(), song.thumbnails.end());
}
videos = m_artist.videos ? m_artist.videos->results : std::vector<artist::Artist::Video>();
for (auto &video : videos) {
std::sort(video.thumbnails.begin(), video.thumbnails.end());
}
// std::span can't know if the data pointer underneath it was changed, so re-create
m_view = MultiIterableView(albums, singles, songs, videos);
endResetModel();
Q_EMIT titleChanged();
Q_EMIT thumbnailUrlChanged();
});
});
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::errorOccurred, this, [this] {
setLoading(false);
});
}
int ArtistModel::rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : m_view.size();
}
QVariant ArtistModel::data(const QModelIndex &index, int role) const
{
switch (role) {
case Title:
return QString::fromStdString(std::visit([&](auto&& item) {
using T = std::decay_t<decltype(item)>;
if constexpr(std::is_same_v<T, artist::Artist::Album>) {
return item.title;
} else if constexpr(std::is_same_v<T, artist::Artist::Single>) {
return item.title;
} else if constexpr(std::is_same_v<T, artist::Artist::Song>) {
return item.title;
} else if constexpr(std::is_same_v<T, artist::Artist::Video>) {
return item.title;
}
Q_UNREACHABLE();
}, m_view[index.row()]));
case TypeRole:
return std::visit([&](auto&& item) {
using T = std::decay_t<decltype(item)>;
if constexpr(std::is_same_v<T, artist::Artist::Album>) {
return Type::Album;
} else if constexpr(std::is_same_v<T, artist::Artist::Single>) {
return Type::Single;
} else if constexpr(std::is_same_v<T, artist::Artist::Song>) {
return Type::Song;
} else if constexpr(std::is_same_v<T, artist::Artist::Video>) {
return Type::Video;
}
Q_UNREACHABLE();
}, m_view[index.row()]);
case Artists:
return QVariant::fromValue(std::vector<meta::Artist> {
{
m_artist.name,
m_artist.channel_id
}
});
case VideoId:
return std::visit([&](auto&& item) {
using T = std::decay_t<decltype(item)>;
if constexpr(std::is_same_v<T, artist::Artist::Album>) {
return QVariant();
} else if constexpr(std::is_same_v<T, artist::Artist::Single>) {
return QVariant();
} else if constexpr(std::is_same_v<T, artist::Artist::Song>) {
return QVariant(QString::fromStdString(item.video_id));
} else if constexpr(std::is_same_v<T, artist::Artist::Video>) {
return QVariant(QString::fromStdString(item.video_id));
}
Q_UNREACHABLE();
}, m_view[index.row()]);
case ThumbnailUrl:
return std::visit([&](auto&& item) {
if (!item.thumbnails.empty()) {
return QString::fromStdString(item.thumbnails.front().url);
}
return QString();
}, m_view[index.row()]);
}
Q_UNREACHABLE();
return {};
}
QHash<int, QByteArray> ArtistModel::roleNames() const
{
return {
{Title, "title"},
{TypeRole, "type"},
{Artists, "artists"},
{VideoId, "videoId"},
{ThumbnailUrl, "thumbnailUrl"}
};
}
QString ArtistModel::channelId() const
{
return m_channelId;
}
void ArtistModel::setChannelId(const QString &channelId)
{
m_channelId = channelId;
Q_EMIT channelIdChanged();
}
QString ArtistModel::title() const
{
return QString::fromStdString(m_artist.name);
}
QUrl ArtistModel::thumbnailUrl() const
{
if (m_artist.thumbnails.empty()) {
return QUrl();
}
return QUrl(QString::fromStdString(m_artist.thumbnails.back().url));
}
QUrl ArtistModel::webUrl() const
{
return QUrl(YTMUSIC_WEB_BASE_URL % u"channel/" % m_channelId);
}
void ArtistModel::triggerItem(int row)
{
std::visit([&](auto&& item) {
using T = std::decay_t<decltype(item)>;
if constexpr(std::is_same_v<T, artist::Artist::Album>) {
Q_EMIT openAlbum(QString::fromStdString(item.browse_id));
} else if constexpr(std::is_same_v<T, artist::Artist::Single>) {
Q_EMIT openAlbum(QString::fromStdString(item.browse_id));
} else if constexpr(std::is_same_v<T, artist::Artist::Song>) {
Q_EMIT openSong(QString::fromStdString(item.video_id));
} else if constexpr(std::is_same_v<T, artist::Artist::Video>) {
Q_EMIT openVideo(QString::fromStdString(item.video_id), QString::fromStdString(item.title));
} else {
Q_UNREACHABLE();
}
}, m_view[row]);
}