192 lines
6.4 KiB
C++
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]);
|
|
}
|