File indexing completed on 2024-05-12 16:21:17
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 #include "localplaylistsmodel.h" 0006 #include "playlistutils.h" 0007 0008 #include "library.h" 0009 #include <qglobal.h> 0010 #include <qsqldatabase.h> 0011 #include <threadeddatabase.h> 0012 0013 #include <KLocalizedString> 0014 0015 Q_DECLARE_METATYPE(std::vector<QString>); 0016 0017 LocalPlaylistsModel::LocalPlaylistsModel(QObject *parent) 0018 : QAbstractListModel(parent) 0019 { 0020 importer = new PlaylistImporter(this); 0021 connect(importer, &PlaylistImporter::playlistEntriesChanged, this, &LocalPlaylistsModel::playlistEntriesChanged); 0022 connect(importer,&PlaylistImporter::importFinished, this, &LocalPlaylistsModel::importFinished); 0023 connect(importer, &PlaylistImporter::refreshModel, this, &LocalPlaylistsModel::refreshModel); 0024 connect(&Library::instance(), &Library::playlistsChanged, 0025 this, &LocalPlaylistsModel::refreshModel); 0026 refreshModel(); 0027 } 0028 0029 int LocalPlaylistsModel::rowCount(const QModelIndex &index) const 0030 { 0031 return index.isValid() ? 0 : m_playlists.size(); 0032 } 0033 0034 QHash<int, QByteArray> LocalPlaylistsModel::roleNames() const 0035 { 0036 return { 0037 {Roles::PlaylistId, "playlistId"}, 0038 {Roles::Title, "title"}, 0039 {Roles::Description, "description"}, 0040 {Roles::CreatedOn, "createdOn"}, 0041 {Roles::ThumbnailIds, "thumbnailIds"}, 0042 }; 0043 } 0044 0045 QVariant LocalPlaylistsModel::data(const QModelIndex &index, int role) const 0046 { 0047 switch (role) { 0048 case Roles::PlaylistId: 0049 return m_playlists[index.row()].playlistId; 0050 case Roles::Title: 0051 return m_playlists[index.row()].title; 0052 case Roles::Description: 0053 return m_playlists[index.row()].description; 0054 case Roles::CreatedOn: 0055 return m_playlists[index.row()].createdOn; 0056 case Roles::ThumbnailIds: 0057 return QVariant::fromValue(m_thumbnailIds.at(index.row())); 0058 } 0059 0060 Q_UNREACHABLE(); 0061 } 0062 0063 void LocalPlaylistsModel::refreshModel() 0064 { 0065 QCoro::connect(Library::instance().database().getResults<Playlist>("select * from playlists"), this, [this](const auto &&playlists) { 0066 m_thumbnailIds.resize(playlists.size()); 0067 for (size_t i = 0; i < playlists.size(); i++) { 0068 auto future = Library::instance().database().getResults<SingleValue<QString>>("select video_id from playlist_entries where playlist_id = ? order by random() limit 4", playlists.at(i).playlistId); 0069 QCoro::connect(std::move(future), this, [this, playlists, i](auto &&ids) { 0070 std::ranges::transform(ids, std::back_inserter(m_thumbnailIds[i]), [](auto &&id) { return id.value; }); 0071 dataChanged(index(i), index(i), {Roles::ThumbnailIds}); 0072 }); 0073 } 0074 0075 beginResetModel(); 0076 m_playlists = playlists; 0077 endResetModel(); 0078 }); 0079 } 0080 void LocalPlaylistsModel::addPlaylist(const QString &title, const QString &description) 0081 { 0082 QCoro::connect(Library::instance().database().execute("insert into playlists (title, description) values (?, ?)", title, description), &Library::instance(), &Library::playlistsChanged); 0083 } 0084 0085 void LocalPlaylistsModel::addPlaylistEntry(qint64 playlistId, const QString &videoId, const QString &title, const QString &artist, const QString &album) 0086 { 0087 importer->addPlaylistEntry(playlistId, videoId, title, artist, album); 0088 } 0089 0090 void LocalPlaylistsModel::addPlaylistEntry(qint64 playlistId, const playlist::Track &track) 0091 { 0092 importer->addPlaylistEntry(playlistId, track); 0093 } 0094 0095 void LocalPlaylistsModel::importPlaylist(const QString &url) 0096 { 0097 importer->importPlaylist(url); 0098 } 0099 0100 void LocalPlaylistsModel::renamePlaylist(qint64 playlistId, const QString &name, const QString &description) 0101 { 0102 importer->renamePlaylist(playlistId, name, description); 0103 } 0104 0105 void LocalPlaylistsModel::deletePlaylist(qint64 playlistId) 0106 { 0107 QCoro::connect(Library::instance().database().execute("delete from playlists where playlist_id = ?", playlistId), this, &LocalPlaylistsModel::refreshModel); 0108 } 0109 0110 QStringView LocalPlaylistsModel::cropURL(QStringView srcUrl) 0111 { 0112 // Find entry point 0113 constexpr auto urlFragment = QStringView(u"?list="); 0114 qsizetype urlPos = srcUrl.indexOf(urlFragment); 0115 if (urlPos != -1) { 0116 urlPos += urlFragment.size(); 0117 } else { 0118 urlPos = 0; 0119 } 0120 auto mid = srcUrl.mid(urlPos); 0121 0122 // Find exit point 0123 urlPos = std::min(mid.indexOf(u"?"), mid.indexOf(u"&")); 0124 return mid.mid(0, urlPos); 0125 }