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 }