File indexing completed on 2024-05-12 16:21:15
0001 // SPDX-FileCopyrightText: 2021 Jonah BrĂ¼chert <jbb@kaidan.im> 0002 // 0003 // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0004 0005 #include "artistmodel.h" 0006 0007 #include <QStringBuilder> 0008 0009 #include <asyncytmusic.h> 0010 0011 ArtistModel::ArtistModel(QObject *parent) 0012 : AbstractYTMusicModel(parent) 0013 , m_view(albums, singles, songs, videos) 0014 { 0015 connect(this, &ArtistModel::channelIdChanged, this, [this] { 0016 if (m_channelId.isEmpty()) { 0017 return; 0018 } 0019 0020 setLoading(true); 0021 0022 auto future = YTMusicThread::instance()->fetchArtist(m_channelId); 0023 QCoro::connect(std::move(future), this, [=, this](artist::Artist &&artist) { 0024 setLoading(false); 0025 0026 beginResetModel(); 0027 m_artist = std::move(artist); 0028 std::sort(m_artist.thumbnails.begin(), m_artist.thumbnails.end()); 0029 0030 albums = m_artist.albums ? m_artist.albums->results : std::vector<artist::Artist::Album>(); 0031 for (auto &album : albums) { 0032 std::sort(album.thumbnails.begin(), album.thumbnails.end()); 0033 } 0034 singles = m_artist.singles ? m_artist.singles->results : std::vector<artist::Artist::Single>(); 0035 for (auto &single : singles) { 0036 std::sort(single.thumbnails.begin(), single.thumbnails.end()); 0037 } 0038 songs = m_artist.songs ? m_artist.songs->results : std::vector<artist::Artist::Song>(); 0039 for (auto &song : songs) { 0040 std::sort(song.thumbnails.begin(), song.thumbnails.end()); 0041 } 0042 videos = m_artist.videos ? m_artist.videos->results : std::vector<artist::Artist::Video>(); 0043 for (auto &video : videos) { 0044 std::sort(video.thumbnails.begin(), video.thumbnails.end()); 0045 } 0046 0047 // std::span can't know if the data pointer underneath it was changed, so re-create 0048 m_view = MultiIterableView(albums, singles, songs, videos); 0049 endResetModel(); 0050 0051 Q_EMIT titleChanged(); 0052 Q_EMIT thumbnailUrlChanged(); 0053 }); 0054 }); 0055 connect(&YTMusicThread::instance().get(), &AsyncYTMusic::errorOccurred, this, [this] { 0056 setLoading(false); 0057 }); 0058 } 0059 0060 int ArtistModel::rowCount(const QModelIndex &parent) const 0061 { 0062 return parent.isValid() ? 0 : m_view.size(); 0063 } 0064 0065 QVariant ArtistModel::data(const QModelIndex &index, int role) const 0066 { 0067 switch (role) { 0068 case Title: 0069 return QString::fromStdString(std::visit([&](auto&& item) { 0070 using T = std::decay_t<decltype(item)>; 0071 if constexpr(std::is_same_v<T, artist::Artist::Album>) { 0072 return item.title; 0073 } else if constexpr(std::is_same_v<T, artist::Artist::Single>) { 0074 return item.title; 0075 } else if constexpr(std::is_same_v<T, artist::Artist::Song>) { 0076 return item.title; 0077 } else if constexpr(std::is_same_v<T, artist::Artist::Video>) { 0078 return item.title; 0079 } 0080 0081 Q_UNREACHABLE(); 0082 }, m_view[index.row()])); 0083 case TypeRole: 0084 return std::visit([&](auto&& item) { 0085 using T = std::decay_t<decltype(item)>; 0086 if constexpr(std::is_same_v<T, artist::Artist::Album>) { 0087 return Type::Album; 0088 } else if constexpr(std::is_same_v<T, artist::Artist::Single>) { 0089 return Type::Single; 0090 } else if constexpr(std::is_same_v<T, artist::Artist::Song>) { 0091 return Type::Song; 0092 } else if constexpr(std::is_same_v<T, artist::Artist::Video>) { 0093 return Type::Video; 0094 } 0095 0096 Q_UNREACHABLE(); 0097 }, m_view[index.row()]); 0098 case Artists: 0099 return QVariant::fromValue(std::vector<meta::Artist> { 0100 { 0101 m_artist.name, 0102 m_artist.channel_id 0103 } 0104 }); 0105 case VideoId: 0106 return std::visit([&](auto&& item) { 0107 using T = std::decay_t<decltype(item)>; 0108 if constexpr(std::is_same_v<T, artist::Artist::Album>) { 0109 return QVariant(); 0110 } else if constexpr(std::is_same_v<T, artist::Artist::Single>) { 0111 return QVariant(); 0112 } else if constexpr(std::is_same_v<T, artist::Artist::Song>) { 0113 return QVariant(QString::fromStdString(item.video_id)); 0114 } else if constexpr(std::is_same_v<T, artist::Artist::Video>) { 0115 return QVariant(QString::fromStdString(item.video_id)); 0116 } 0117 0118 Q_UNREACHABLE(); 0119 }, m_view[index.row()]); 0120 case ThumbnailUrl: 0121 return std::visit([&](auto&& item) { 0122 if (!item.thumbnails.empty()) { 0123 return QString::fromStdString(item.thumbnails.front().url); 0124 } 0125 return QString(); 0126 }, m_view[index.row()]); 0127 } 0128 0129 Q_UNREACHABLE(); 0130 0131 return {}; 0132 } 0133 0134 QHash<int, QByteArray> ArtistModel::roleNames() const 0135 { 0136 return { 0137 {Title, "title"}, 0138 {TypeRole, "type"}, 0139 {Artists, "artists"}, 0140 {VideoId, "videoId"}, 0141 {ThumbnailUrl, "thumbnailUrl"} 0142 }; 0143 } 0144 0145 QString ArtistModel::channelId() const 0146 { 0147 return m_channelId; 0148 } 0149 0150 void ArtistModel::setChannelId(const QString &channelId) 0151 { 0152 m_channelId = channelId; 0153 Q_EMIT channelIdChanged(); 0154 } 0155 0156 QString ArtistModel::title() const 0157 { 0158 return QString::fromStdString(m_artist.name); 0159 } 0160 0161 QUrl ArtistModel::thumbnailUrl() const 0162 { 0163 if (m_artist.thumbnails.empty()) { 0164 return QUrl(); 0165 } 0166 0167 return QUrl(QString::fromStdString(m_artist.thumbnails.back().url)); 0168 } 0169 0170 QUrl ArtistModel::webUrl() const 0171 { 0172 return QUrl(YTMUSIC_WEB_BASE_URL % u"channel/" % m_channelId); 0173 } 0174 0175 void ArtistModel::triggerItem(int row) 0176 { 0177 std::visit([&](auto&& item) { 0178 using T = std::decay_t<decltype(item)>; 0179 if constexpr(std::is_same_v<T, artist::Artist::Album>) { 0180 Q_EMIT openAlbum(QString::fromStdString(item.browse_id)); 0181 } else if constexpr(std::is_same_v<T, artist::Artist::Single>) { 0182 Q_EMIT openAlbum(QString::fromStdString(item.browse_id)); 0183 } else if constexpr(std::is_same_v<T, artist::Artist::Song>) { 0184 Q_EMIT openSong(QString::fromStdString(item.video_id)); 0185 } else if constexpr(std::is_same_v<T, artist::Artist::Video>) { 0186 Q_EMIT openVideo(QString::fromStdString(item.video_id), QString::fromStdString(item.title)); 0187 } else { 0188 Q_UNREACHABLE(); 0189 } 0190 }, m_view[row]); 0191 }