File indexing completed on 2025-02-16 04:25:52
0001 #include "playlistsmodel.h" 0002 #include "db/collectionDB.h" 0003 0004 #include <QDateTime> 0005 0006 #include <MauiKit3/FileBrowsing/fmstatic.h> 0007 #include <MauiKit3/FileBrowsing/tagging.h> 0008 0009 #include <KI18n/KLocalizedString> 0010 0011 PlaylistsModel::PlaylistsModel(QObject *parent) 0012 : MauiList(parent) 0013 { 0014 connect(Tagging::getInstance(), &Tagging::tagged, [this](QVariantMap tag) { 0015 Q_EMIT this->preItemAppended(); 0016 this->list << (this->packPlaylist(tag.value("tag").toString())); 0017 Q_EMIT this->postItemAppended(); 0018 }); 0019 0020 connect(Tagging::getInstance(), &Tagging::urlTagged, [this](QUrl, QString tag) { 0021 const auto index = this->indexOf(FMH::MODEL_KEY::PLAYLIST, tag); 0022 auto item = this->list[index]; 0023 item[FMH::MODEL_KEY::PREVIEW] = playlistArtworkPreviews(tag); 0024 this->list[index] = item; 0025 Q_EMIT this->updateModel(index, {}); 0026 }); 0027 } 0028 0029 const FMH::MODEL_LIST &PlaylistsModel::items() const 0030 { 0031 return this->list; 0032 } 0033 0034 void PlaylistsModel::setList() 0035 { 0036 Q_EMIT this->preListChanged(); 0037 if(m_limit == 9999) 0038 { 0039 this->list << this->defaultPlaylists(); 0040 } 0041 this->list << this->tags(); 0042 Q_EMIT this->postListChanged(); 0043 } 0044 0045 FMH::MODEL PlaylistsModel::packPlaylist(const QString &playlist) 0046 { 0047 return FMH::MODEL{ 0048 {FMH::MODEL_KEY::KEY, playlist}, 0049 {FMH::MODEL_KEY::PLAYLIST, playlist}, 0050 {FMH::MODEL_KEY::ICON, "tag"}, 0051 {FMH::MODEL_KEY::TYPE, "personal"}, 0052 {FMH::MODEL_KEY::PREVIEW, playlistArtworkPreviews(playlist)}}; 0053 } 0054 0055 QString PlaylistsModel::playlistArtworkPreviews(const QString &playlist) 0056 { 0057 QStringList res; 0058 0059 auto extractor = [&res](FMH::MODEL &item) -> bool 0060 { 0061 res << QString("image://artwork/album:%1:%2").arg(item[FMH::MODEL_KEY::ARTIST], item[FMH::MODEL_KEY::ALBUM]); 0062 return true; 0063 }; 0064 0065 if (playlist == "mostPlayed") { 0066 CollectionDB::getInstance()->getDBData(QString("select t.* from tracks t inner join albums al on t.album = al.album and t.artist = al.artist WHERE t.count >= 3 order by strftime(\"%s\", t.addDate) desc, t.count asc LIMIT 4"), extractor); 0067 0068 return res.join(","); 0069 } 0070 0071 if (playlist == "randomTracks") { 0072 CollectionDB::getInstance()->getDBData(QString("select t.* from tracks t inner join albums al on t.album = al.album and t.artist = al.artist where t.count <= 4 order by RANDOM()"), extractor); 0073 0074 return res.join(","); 0075 } 0076 0077 if (playlist == "recentTracks") { 0078 CollectionDB::getInstance()->getDBData(QString("select t.* from (select * from tracks order by strftime(\"%s\", lastsync) desc limit 10) t inner join albums al on t.album = al.album and t.artist = al.artist order by t.title asc LIMIT 4"), extractor); 0079 0080 return res.join(","); 0081 } 0082 0083 if (playlist == "neverPlayed") { 0084 CollectionDB::getInstance()->getDBData(QString("select t.* from tracks t inner join albums al on t.album = al.album and t.artist = al.artist where t.count <= 1 order by RANDOM()"), extractor); 0085 0086 return res.join(","); 0087 } 0088 0089 if (playlist == "classicTracks") { 0090 CollectionDB::getInstance()->getDBData(QString("select t.* from (select * from tracks where releasedate > 0 order by releasedate asc limit 100) t inner join albums al on t.album = al.album and t.artist = al.artist order by t.title asc LIMIT 4"), extractor); 0091 0092 return res.join(","); 0093 } 0094 0095 const auto urls = Tagging::getInstance()->getTagUrls(playlist, {}, true, 4, "audio"); 0096 for (const auto &url : urls) { 0097 const auto data = CollectionDB::getInstance()->getDBData(QString("select t.* from tracks t inner join albums al on al.album = t.album and al.artist = t.artist where t.url = %1").arg("\"" + url.toString() + "\"")); 0098 0099 for (const auto &item : data) { 0100 res << QString("image://artwork/album:%1:%2").arg(item[FMH::MODEL_KEY::ARTIST], item[FMH::MODEL_KEY::ALBUM]); 0101 } 0102 } 0103 0104 return res.join(","); 0105 } 0106 0107 FMH::MODEL_LIST PlaylistsModel::defaultPlaylists() 0108 { 0109 const FMH::MODEL mostPlayed = {{FMH::MODEL_KEY::TYPE, "default"}, 0110 {FMH::MODEL_KEY::PLAYLIST, i18n("Most Played")}, 0111 {FMH::MODEL_KEY::KEY, "mostPlayed"}, 0112 {FMH::MODEL_KEY::PREVIEW, playlistArtworkPreviews("mostPlayed")}, 0113 {FMH::MODEL_KEY::ICON, "view-media-playcount"}, 0114 {FMH::MODEL_KEY::ADDDATE, QDateTime::currentDateTime().toString(Qt::DateFormat::TextDate)}}; 0115 0116 const FMH::MODEL randomTracks = {{FMH::MODEL_KEY::TYPE, "default"}, 0117 {FMH::MODEL_KEY::PLAYLIST, i18n("Random Tracks")}, 0118 {FMH::MODEL_KEY::KEY, "randomTracks"}, 0119 {FMH::MODEL_KEY::PREVIEW, playlistArtworkPreviews("randomTracks")}, 0120 {FMH::MODEL_KEY::ICON, "view-media-playcount"}, 0121 {FMH::MODEL_KEY::ADDDATE, QDateTime::currentDateTime().toString(Qt::DateFormat::TextDate)}}; 0122 0123 const FMH::MODEL recentTracks = {{FMH::MODEL_KEY::TYPE, "default"}, 0124 {FMH::MODEL_KEY::PLAYLIST, i18n("Recent Tracks")}, 0125 {FMH::MODEL_KEY::KEY, "recentTracks"}, 0126 {FMH::MODEL_KEY::PREVIEW, playlistArtworkPreviews("recentTracks")}, 0127 {FMH::MODEL_KEY::ICON, "view-media-playcount"}, 0128 {FMH::MODEL_KEY::ADDDATE, QDateTime::currentDateTime().toString(Qt::DateFormat::TextDate)}}; 0129 0130 const FMH::MODEL neverPlayed = {{FMH::MODEL_KEY::TYPE, "default"}, 0131 {FMH::MODEL_KEY::PLAYLIST, i18n("Never Played")}, 0132 {FMH::MODEL_KEY::KEY, "neverPlayed"}, 0133 {FMH::MODEL_KEY::PREVIEW, playlistArtworkPreviews("neverPlayed")}, 0134 {FMH::MODEL_KEY::ICON, "view-media-playcount"}, 0135 {FMH::MODEL_KEY::ADDDATE, QDateTime::currentDateTime().toString(Qt::DateFormat::TextDate)}}; 0136 0137 const FMH::MODEL classicTracks = {{FMH::MODEL_KEY::TYPE, "default"}, 0138 {FMH::MODEL_KEY::PLAYLIST, i18n("Classic Tracks")}, 0139 {FMH::MODEL_KEY::KEY, "classicTracks"}, 0140 {FMH::MODEL_KEY::PREVIEW, playlistArtworkPreviews("classicTracks")}, 0141 {FMH::MODEL_KEY::ICON, "view-media-playcount"}, 0142 {FMH::MODEL_KEY::ADDDATE, QDateTime::currentDateTime().toString(Qt::DateFormat::TextDate)}}; 0143 0144 return FMH::MODEL_LIST () << mostPlayed << randomTracks << recentTracks << neverPlayed << classicTracks; 0145 } 0146 0147 FMH::MODEL_LIST PlaylistsModel::tags() 0148 { 0149 FMH::MODEL_LIST res; 0150 const auto tags = Tagging::getInstance()->getUrlsTags(true); 0151 0152 return std::accumulate(tags.constBegin(), tags.constEnd(), res, [this](FMH::MODEL_LIST &list, const QVariant &item) { 0153 0154 const auto map = item.toMap(); 0155 0156 auto res = packPlaylist(map.value("tag").toString()); 0157 0158 res[FMH::MODEL_KEY::ICON] = map.value("icon").toString(); 0159 0160 if(list.count() <= m_limit) 0161 { 0162 list << res; 0163 } 0164 return list; 0165 }); 0166 } 0167 0168 void PlaylistsModel::insert(const QString &playlist) 0169 { 0170 if (playlist.isEmpty()) 0171 return; 0172 0173 Tagging::getInstance()->tag(playlist); 0174 } 0175 0176 void PlaylistsModel::addTrack(const QString &playlist, const QStringList &urls) 0177 { 0178 for (const auto &url : urls) 0179 Tagging::getInstance()->tagUrl(url, playlist); 0180 } 0181 0182 void PlaylistsModel::removeTrack(const QString &playlist, const QString &url) 0183 { 0184 qDebug() << "trying to remove" << playlist << url; 0185 Tagging::getInstance()->removeUrlTag(url, playlist); 0186 } 0187 0188 void PlaylistsModel::removePlaylist(const int &index) // TODO 0189 { 0190 if (index >= this->list.size() || index < 0) 0191 { 0192 return; 0193 } 0194 0195 if(Tagging::getInstance()->removeTag(this->list.at(index)[FMH::MODEL_KEY::PLAYLIST], true)) 0196 { 0197 Q_EMIT this->preItemRemoved(index); 0198 this->list.removeAt(index); 0199 Q_EMIT this->postItemRemoved(); 0200 } 0201 } 0202 0203 void PlaylistsModel::componentComplete() 0204 { 0205 this->setList(); 0206 } 0207 0208 int PlaylistsModel::limit() const 0209 { 0210 return m_limit; 0211 } 0212 0213 void PlaylistsModel::setLimit(int newLimit) 0214 { 0215 if (m_limit == newLimit) 0216 return; 0217 m_limit = newLimit; 0218 Q_EMIT limitChanged(); 0219 }