File indexing completed on 2024-05-12 16:21:18
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 "searchmodel.h" 0006 #include "playlistutils.h" 0007 0008 #include <ranges> 0009 0010 SearchModel::SearchModel(QObject *parent) 0011 : AbstractYTMusicModel(parent) 0012 { 0013 connect(this, &SearchModel::searchQueryChanged, this, [this] { 0014 if (m_searchQuery.isEmpty()) { 0015 beginResetModel(); 0016 m_searchResults.clear(); 0017 endResetModel(); 0018 return; 0019 } 0020 0021 setLoading(true); 0022 auto future = YTMusicThread::instance()->search(m_searchQuery); 0023 QCoro::connect(std::move(future), this, [=, this](const std::vector<search::SearchResultItem> &&results) { 0024 beginResetModel(); 0025 setLoading(false); 0026 m_searchResults = std::move(results); 0027 0028 endResetModel(); 0029 }); 0030 }); 0031 connect(&YTMusicThread::instance().get(), &AsyncYTMusic::errorOccurred, this, [this] { 0032 setLoading(false); 0033 }); 0034 } 0035 0036 int SearchModel::rowCount(const QModelIndex &parent) const 0037 { 0038 return parent.isValid() ? 0 : int(m_searchResults.size()); 0039 } 0040 0041 QVariant SearchModel::data(const QModelIndex &index, int role) const 0042 { 0043 switch (role) { 0044 case Title: 0045 return QString::fromStdString(std::visit([&](auto&& arg) { 0046 using T = std::decay_t<decltype(arg)>; 0047 if constexpr (std::is_same_v<T, search::Album>) { 0048 return arg.title; 0049 } else if constexpr (std::is_same_v<T, search::Artist>) { 0050 return arg.artist; 0051 } else if constexpr (std::is_same_v<T, search::Playlist>) { 0052 return arg.title; 0053 } else if constexpr (std::is_same_v<T, search::Song>) { 0054 return arg.title; 0055 } else if constexpr (std::is_same_v<T, search::Video>) { 0056 return arg.title; 0057 } else if constexpr (std::is_same_v<T, search::TopResult>) { 0058 if (arg.title) { 0059 return *arg.title; 0060 } else { 0061 if (!arg.artists.empty()) { 0062 return arg.artists.front().name; 0063 } else { 0064 return std::string(); 0065 } 0066 } 0067 } else { 0068 Q_UNREACHABLE(); 0069 } 0070 }, m_searchResults.at(index.row()))); 0071 case TypeRole: 0072 return std::visit([&](auto&& arg) { 0073 using T = std::decay_t<decltype(arg)>; 0074 if constexpr (std::is_same_v<T, search::Album>) { 0075 return Type::Album; 0076 } else if constexpr (std::is_same_v<T, search::Artist>) { 0077 return Type::Artist; 0078 } else if constexpr (std::is_same_v<T, search::Playlist>) { 0079 return Type::Playlist; 0080 } else if constexpr (std::is_same_v<T, search::Song>) { 0081 return Type::Song; 0082 } else if constexpr (std::is_same_v<T, search::Video>) { 0083 return Type::Video; 0084 } else if constexpr (std::is_same_v<T, search::TopResult>) { 0085 return Type::TopResult; 0086 } else { 0087 Q_UNREACHABLE(); 0088 } 0089 }, m_searchResults.at(index.row())); 0090 case VideoId: 0091 return std::visit([&](auto&& arg) { 0092 using T = std::decay_t<decltype(arg)>; 0093 if constexpr (std::is_same_v<T, search::Album>) { 0094 return QString(); 0095 } else if constexpr (std::is_same_v<T, search::Artist>) { 0096 return QString(); 0097 } else if constexpr (std::is_same_v<T, search::Playlist>) { 0098 return QString(); 0099 } else if constexpr (std::is_same_v<T, search::Song>) { 0100 return QString::fromStdString(arg.video_id); 0101 } else if constexpr (std::is_same_v<T, search::Video>) { 0102 return QString::fromStdString(arg.video_id); 0103 } else if constexpr (std::is_same_v<T, search::TopResult>) { 0104 if (arg.video_id) { 0105 return QString::fromStdString(*arg.video_id); 0106 } else { 0107 return QString(); 0108 } 0109 } else { 0110 Q_UNREACHABLE(); 0111 } 0112 }, m_searchResults.at(index.row())); 0113 case Artists: 0114 return QVariant::fromValue(std::visit([&](auto&& arg) { 0115 using T = std::decay_t<decltype(arg)>; 0116 if constexpr (std::is_same_v<T, search::Album>) { 0117 return std::vector<meta::Artist>(); 0118 } else if constexpr (std::is_same_v<T, search::Artist>) { 0119 return std::vector<meta::Artist>(); 0120 } else if constexpr (std::is_same_v<T, search::Playlist>) { 0121 return std::vector<meta::Artist>(); 0122 } else if constexpr (std::is_same_v<T, search::Song>) { 0123 return arg.artists; 0124 } else if constexpr (std::is_same_v<T, search::Video>) { 0125 return arg.artists; 0126 } else if constexpr (std::is_same_v<T, search::TopResult>) { 0127 return arg.artists; 0128 } else { 0129 Q_UNREACHABLE(); 0130 } 0131 }, m_searchResults.at(index.row()))); 0132 case RadioPlaylistId: 0133 return std::visit([&](auto &&arg) { 0134 using T = std::decay_t<decltype(arg)>; 0135 0136 if constexpr (std::is_same_v<T, search::Artist>) { 0137 if (arg.radio_id) { 0138 return QString::fromStdString(*arg.radio_id); 0139 } 0140 } 0141 0142 return QString(); 0143 }, m_searchResults.at(index.row())); 0144 case ThumbnailUrl: 0145 return std::visit([&](auto &&arg) { 0146 if (!arg.thumbnails.empty()) { 0147 return QString::fromStdString(arg.thumbnails.front().url); 0148 } 0149 0150 return QString(); 0151 }, m_searchResults.at(index.row())); 0152 case ArtistsDisplayString: 0153 return QVariant::fromValue(std::visit([&](auto&& arg) { 0154 using T = std::decay_t<decltype(arg)>; 0155 if constexpr (std::is_same_v<T, search::Song> || std::is_same_v<T, search::Video> || std::is_same_v<T, search::Album>) { 0156 return PlaylistUtils::artistsToString(arg.artists); 0157 } else if constexpr(std::is_same_v<T, search::TopResult>) { 0158 if (arg.title) { 0159 return PlaylistUtils::artistsToString(arg.artists); 0160 } 0161 } 0162 return QString(); 0163 }, m_searchResults.at(index.row()))); 0164 } 0165 0166 Q_UNREACHABLE(); 0167 0168 return {}; 0169 } 0170 0171 QHash<int, QByteArray> SearchModel::roleNames() const 0172 { 0173 return { 0174 {Title, "title"}, 0175 {TypeRole, "type"}, 0176 {VideoId, "videoId"}, 0177 {Artists, "artists"}, 0178 {ArtistsDisplayString, "artistsDisplayString"}, 0179 {RadioPlaylistId, "radioPlaylistId"}, 0180 {ThumbnailUrl, "thumbnailUrl"} 0181 }; 0182 } 0183 0184 QString SearchModel::searchQuery() const 0185 { 0186 return m_searchQuery; 0187 } 0188 0189 void SearchModel::setSearchQuery(const QString &searchQuery) 0190 { 0191 m_searchQuery = searchQuery; 0192 Q_EMIT searchQueryChanged(); 0193 } 0194 0195 void SearchModel::triggerItem(int row) 0196 { 0197 std::visit([&](auto&& arg) { 0198 using T = std::decay_t<decltype(arg)>; 0199 if constexpr (std::is_same_v<T, search::Album>) { 0200 if (arg.browse_id) { 0201 Q_EMIT openAlbum(QString::fromStdString(*arg.browse_id)); 0202 } 0203 } else if constexpr (std::is_same_v<T, search::Artist>) { 0204 Q_EMIT openArtist(QString::fromStdString(arg.browse_id), QString::fromStdString(arg.radio_id.value_or("")), QString::fromStdString(arg.shuffle_id.value_or(""))); 0205 } else if constexpr (std::is_same_v<T, search::Playlist>) { 0206 Q_EMIT openPlaylist(QString::fromStdString(arg.browse_id)); 0207 } else if constexpr (std::is_same_v<T, search::Song>) { 0208 Q_EMIT openSong(QString::fromStdString(arg.video_id)); 0209 } else if constexpr (std::is_same_v<T, search::Video>) { 0210 Q_EMIT openVideo(QString::fromStdString(arg.video_id), QString::fromStdString(arg.title)); 0211 } else if constexpr (std::is_same_v<T, search::TopResult>) { 0212 if (arg.video_id) { 0213 Q_EMIT openSong(QString::fromStdString(*arg.video_id)); 0214 } else { 0215 if (!arg.artists.empty() && arg.artists.front().id) { 0216 Q_EMIT openArtist(QString::fromStdString(*arg.artists.front().id), {}, {}); 0217 } 0218 } 0219 } else { 0220 Q_UNREACHABLE(); 0221 } 0222 }, m_searchResults.at(row)); 0223 } 0224 0225 0226 int SearchModel::itemType(search::SearchResultItem const &item) 0227 { 0228 return std::visit([&](auto &&arg) { 0229 using T = std::decay_t<decltype(arg)>; 0230 if constexpr(std::is_same_v<T, search::Album>) { 0231 return SearchModel::Type::Album; 0232 } else if constexpr(std::is_same_v<T, search::Artist>) { 0233 return SearchModel::Type::Artist; 0234 } else if constexpr(std::is_same_v<T, search::Playlist>) { 0235 return SearchModel::Type::Playlist; 0236 } else if constexpr(std::is_same_v<T, search::Song>) { 0237 return SearchModel::Type::Song; 0238 } else if constexpr(std::is_same_v<T, search::Video>) { 0239 return SearchModel::Type::Video; 0240 } else if constexpr(std::is_same_v<T, search::TopResult>) { 0241 return SearchModel::Type::TopResult; 0242 } else { 0243 Q_UNREACHABLE(); 0244 } 0245 }, item); 0246 }