File indexing completed on 2024-05-19 15:54:39
0001 // SPDX-FileCopyrightText: 2022 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 #pragma once 0006 0007 #include <QObject> 0008 #include <QQuickAsyncImageProvider> 0009 #include <QNetworkAccessManager> 0010 #include <QAbstractListModel> 0011 #include <QSortFilterProxyModel> 0012 0013 #include <ThreadedDatabase> 0014 0015 #include <memory> 0016 0017 #include "asyncytmusic.h" 0018 0019 class FavouriteWatcher; 0020 class WasPlayedWatcher; 0021 0022 struct Song { 0023 using ColumnTypes = std::tuple<QString, QString, QString, QString>; 0024 0025 static Song fromSql(ColumnTypes tuple) { 0026 auto [videoId, title, artist, album] = tuple; 0027 return Song {videoId, title, artist, album}; 0028 } 0029 0030 QString videoId; 0031 QString title; 0032 QString artist; 0033 QString album; 0034 }; 0035 0036 class FavouritesModel : public QAbstractListModel { 0037 Q_OBJECT 0038 0039 enum Roles { 0040 VideoId = Qt::UserRole + 1, 0041 Title, 0042 Artists, 0043 ArtistsDisplayString 0044 }; 0045 0046 public: 0047 FavouritesModel(QFuture<std::vector<Song>> &&songs, QObject *parent = nullptr); 0048 0049 QHash<int, QByteArray> roleNames() const override; 0050 int rowCount(const QModelIndex &parent) const override; 0051 QVariant data(const QModelIndex &index, int role) const override; 0052 std::vector<Song> getFavouriteSongs() const; 0053 0054 private: 0055 std::vector<Song> m_favouriteSongs; 0056 }; 0057 0058 struct PlayedSong { 0059 using ColumnTypes = std::tuple<QString, int, QString, QString, QString>; 0060 0061 static PlayedSong fromSql(ColumnTypes tuple) { 0062 auto [videoId, plays, title, artist, album] = tuple; 0063 return PlayedSong {videoId, title, artist, album, plays}; 0064 } 0065 0066 QString videoId; 0067 QString title; 0068 QString artist; 0069 QString album; 0070 int plays; 0071 }; 0072 0073 class PlaybackHistoryModel : public QAbstractListModel { 0074 Q_OBJECT 0075 0076 public: 0077 enum Roles { 0078 VideoId = Qt::UserRole + 1, 0079 Title, 0080 Artists, 0081 ArtistsDisplayString, 0082 Plays 0083 }; 0084 Q_ENUM(Roles); 0085 0086 PlaybackHistoryModel(QFuture<std::vector<PlayedSong>> &&songs, QObject *parent = nullptr); 0087 PlaybackHistoryModel(QObject *parent = nullptr); 0088 0089 QHash<int, QByteArray> roleNames() const override; 0090 int rowCount(const QModelIndex &parent) const override; 0091 QVariant data(const QModelIndex &index, int role) const override; 0092 std::vector<PlayedSong> getPlayedSong() const; 0093 0094 protected: 0095 std::vector<PlayedSong> m_playedSongs; 0096 }; 0097 0098 /// 0099 /// Provides a list of recently played songs matching a search query. 0100 /// 0101 class LocalSearchModel : public PlaybackHistoryModel { 0102 Q_OBJECT 0103 0104 Q_PROPERTY(QString searchQuery MEMBER m_searchQuery NOTIFY searchQueryChanged) 0105 0106 Q_SIGNAL void searchQueryChanged(); 0107 0108 public: 0109 LocalSearchModel(QObject *parent = nullptr); 0110 0111 QString m_searchQuery; 0112 }; 0113 0114 class Library; 0115 0116 class SearchHistoryModel : public QAbstractListModel { 0117 Q_OBJECT 0118 0119 Q_PROPERTY(QString filter MEMBER m_filter NOTIFY filterChanged) 0120 0121 public: 0122 SearchHistoryModel(Library *library); 0123 QHash<int, QByteArray> roleNames() const override; 0124 int rowCount(const QModelIndex &parent) const override; 0125 void removeSearch(const QString &search); 0126 QVariant data(const QModelIndex &index, int role) const override; 0127 void addSearch(QString const& search); 0128 const QString & temporarySearch() const; 0129 void setTemporarySearch(QString const& text); 0130 0131 Q_SIGNAL void filterChanged(); 0132 0133 private: 0134 size_t getRow(QString const &search) const; 0135 std::vector<SingleValue<QString>> m_history; 0136 QString m_temporarySearch; 0137 QString m_filter; 0138 }; 0139 0140 class Library : public QObject 0141 { 0142 Q_OBJECT 0143 Q_PROPERTY(QAbstractListModel *favourites READ favourites NOTIFY favouritesChanged) 0144 Q_PROPERTY(QAbstractListModel *searches READ searches CONSTANT) 0145 Q_PROPERTY(QAbstractListModel *playbackHistory READ playbackHistory NOTIFY playbackHistoryChanged) 0146 Q_PROPERTY(QAbstractListModel *mostPlayed READ mostPlayed NOTIFY playbackHistoryChanged) 0147 Q_PROPERTY(QString temporarySearch READ temporarySearch WRITE setTemporarySearch NOTIFY temporarySearchChanged) 0148 0149 public: 0150 explicit Library(QObject *parent = nullptr); 0151 ~Library(); 0152 0153 static Library &instance(); 0154 0155 FavouritesModel *favourites(); 0156 Q_SIGNAL void favouritesChanged(); 0157 void refreshFavourites(); 0158 Q_INVOKABLE void addFavourite(const QString &videoId, const QString &title, const QString &artist, const QString &album); 0159 Q_INVOKABLE void removeFavourite(const QString &videoId); 0160 Q_INVOKABLE FavouriteWatcher *favouriteWatcher(const QString &videoId); 0161 0162 SearchHistoryModel *searches(); 0163 Q_SIGNAL void searchesChanged(); 0164 Q_INVOKABLE void addSearch(const QString &text); 0165 Q_INVOKABLE void removeSearch(const QString &text); 0166 const QString& temporarySearch(); 0167 void setTemporarySearch(const QString& text); 0168 Q_SIGNAL void temporarySearchChanged(); 0169 0170 PlaybackHistoryModel *playbackHistory(); 0171 Q_SIGNAL void playbackHistoryChanged(); 0172 void refreshPlaybackHistory(); 0173 Q_INVOKABLE void addPlaybackHistoryItem(const QString &videoId, const QString &title, const QString &artist, const QString &album); 0174 Q_INVOKABLE void removePlaybackHistoryItem(const QString &videoId); 0175 Q_INVOKABLE WasPlayedWatcher *wasPlayedWatcher(const QString &videoId); 0176 0177 Q_SIGNAL void playlistsChanged(); 0178 0179 PlaybackHistoryModel *mostPlayed(); 0180 0181 QNetworkAccessManager &nam(); 0182 ThreadedDatabase &database() { 0183 return *m_database; 0184 } 0185 QFuture<void> addSong(const QString &videoId, const QString &title, const QString &artist, const QString &album); 0186 0187 private: 0188 0189 QNetworkAccessManager m_networkImageCacher; 0190 std::unique_ptr<ThreadedDatabase> m_database; 0191 SearchHistoryModel *m_searches; 0192 FavouritesModel *m_favourites; 0193 PlaybackHistoryModel *m_mostPlayed; 0194 PlaybackHistoryModel *m_playbackHistory; 0195 }; 0196 0197 class FavouriteWatcher : public QObject { 0198 Q_OBJECT 0199 0200 Q_PROPERTY(bool isFavourite READ isFavourite NOTIFY isFavouriteChanged) 0201 0202 public: 0203 FavouriteWatcher(Library *library, const QString &videoId); 0204 0205 bool isFavourite() const; 0206 Q_SIGNAL void isFavouriteChanged(); 0207 0208 Q_SIGNAL void videoIdChanged(); 0209 0210 private: 0211 QString m_videoId; 0212 Library *m_library; 0213 bool m_isFavourite = false; 0214 }; 0215 0216 class WasPlayedWatcher : public QObject { 0217 Q_OBJECT 0218 0219 Q_PROPERTY(bool wasPlayed READ wasPlayed NOTIFY wasPlayedChanged) 0220 0221 public: 0222 WasPlayedWatcher(Library *Library, const QString &VideoId); 0223 0224 bool wasPlayed() const; 0225 0226 Q_SIGNAL void wasPlayedChanged(); 0227 0228 private: 0229 bool m_wasPlayed = false; 0230 QString m_videoId; 0231 Library *m_library; 0232 Q_SLOT void update(std::optional<SingleValue<bool> > result); 0233 Q_SLOT void query(); 0234 };