File indexing completed on 2024-04-21 04:49:02
0001 /* 0002 SPDX-FileCopyrightText: 2017 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr> 0003 0004 SPDX-License-Identifier: LGPL-3.0-or-later 0005 */ 0006 0007 #include "trackslistener.h" 0008 0009 #include "playListLogging.h" 0010 #include "filescanner.h" 0011 #include "filewriter.h" 0012 0013 #include <QSet> 0014 #include <QList> 0015 0016 #include <array> 0017 #include <algorithm> 0018 0019 class TracksListenerPrivate 0020 { 0021 public: 0022 0023 QSet<qulonglong> mTracksByIdSet; 0024 0025 QSet<qulonglong> mRadiosByIdSet; 0026 0027 QList<std::tuple<QString, QString, QString, int, int>> mTracksByNameSet; 0028 0029 QList<QUrl> mTracksByFileNameSet; 0030 0031 DatabaseInterface *mDatabase = nullptr; 0032 0033 FileScanner mFileScanner; 0034 0035 FileWriter mFileWriter; 0036 }; 0037 0038 TracksListener::TracksListener(DatabaseInterface *database, QObject *parent) : QObject(parent), d(std::make_unique<TracksListenerPrivate>()) 0039 { 0040 d->mDatabase = database; 0041 } 0042 0043 TracksListener::~TracksListener() 0044 = default; 0045 0046 void TracksListener::tracksAdded(const ListTrackDataType &allTracks) 0047 { 0048 for (const auto &oneTrack : allTracks) { 0049 if (d->mTracksByIdSet.contains(oneTrack.databaseId())) { 0050 Q_EMIT trackHasChanged(oneTrack); 0051 } 0052 0053 if (d->mTracksByNameSet.isEmpty()) { 0054 return; 0055 } 0056 0057 for (auto itTrack = d->mTracksByNameSet.cbegin(); itTrack != d->mTracksByNameSet.cend(); ) { 0058 if (!std::get<0>(*itTrack).isEmpty() && std::get<0>(*itTrack) != oneTrack.title()) { 0059 ++itTrack; 0060 continue; 0061 } 0062 0063 if (!std::get<1>(*itTrack).isEmpty() && std::get<1>(*itTrack) != oneTrack.artist()) { 0064 ++itTrack; 0065 continue; 0066 } 0067 0068 if (!std::get<2>(*itTrack).isEmpty() && std::get<2>(*itTrack) != oneTrack.album()) { 0069 ++itTrack; 0070 continue; 0071 } 0072 0073 if (std::get<3>(*itTrack) != oneTrack.trackNumber()) { 0074 ++itTrack; 0075 continue; 0076 } 0077 0078 if (std::get<4>(*itTrack) != oneTrack.discNumber()) { 0079 ++itTrack; 0080 continue; 0081 } 0082 0083 Q_EMIT trackHasChanged(TrackDataType(oneTrack)); 0084 0085 d->mTracksByIdSet.insert(oneTrack.databaseId()); 0086 itTrack = d->mTracksByNameSet.erase(itTrack); 0087 } 0088 } 0089 } 0090 0091 void TracksListener::trackRemoved(qulonglong id) 0092 { 0093 if (d->mTracksByIdSet.contains(id)) { 0094 Q_EMIT trackHasBeenRemoved(id); 0095 } 0096 } 0097 0098 void TracksListener::trackModified(const TrackDataType &modifiedTrack) 0099 { 0100 if (d->mTracksByIdSet.contains(modifiedTrack.databaseId())) { 0101 Q_EMIT trackHasChanged(modifiedTrack); 0102 } 0103 } 0104 0105 void TracksListener::trackByNameInList(const QVariant &title, const QVariant &artist, const QVariant &album, 0106 const QVariant &trackNumber, const QVariant &discNumber) 0107 { 0108 const auto realTitle = title.toString(); 0109 const auto realArtist = artist.toString(); 0110 const auto albumIsValid = !album.isNull() && album.isValid() && !album.toString().isEmpty(); 0111 auto realAlbum = std::optional<QString>{}; 0112 if (albumIsValid) { 0113 realAlbum = album.toString(); 0114 } 0115 auto trackNumberIsValid = bool{}; 0116 const auto trackNumberValue = trackNumber.toInt(&trackNumberIsValid); 0117 auto realTrackNumber = std::optional<int>{}; 0118 if (trackNumberIsValid) { 0119 realTrackNumber = trackNumberValue; 0120 } 0121 auto discNumberIsValid = bool{}; 0122 const auto discNumberValue = discNumber.toInt(&discNumberIsValid); 0123 auto realDiscNumber = std::optional<int>{}; 0124 if (discNumberIsValid) { 0125 realDiscNumber = discNumberValue; 0126 } 0127 0128 auto newTrackId = d->mDatabase->trackIdFromTitleAlbumTrackDiscNumber(realTitle, realArtist, realAlbum, 0129 realTrackNumber, realDiscNumber); 0130 if (newTrackId == 0) { 0131 auto newTrack = std::tuple<QString, QString, QString, int, int>(realTitle, realArtist, album.toString(), trackNumber.toInt(), discNumber.toInt()); 0132 d->mTracksByNameSet.push_back(newTrack); 0133 0134 return; 0135 } 0136 0137 d->mTracksByIdSet.insert(newTrackId); 0138 0139 auto newTrack = d->mDatabase->trackDataFromDatabaseId(newTrackId); 0140 0141 if (!newTrack.isEmpty()) { 0142 Q_EMIT trackHasChanged(newTrack); 0143 } 0144 } 0145 0146 void TracksListener::trackByFileNameInList(ElisaUtils::PlayListEntryType type, const QUrl &fileName) 0147 { 0148 Q_UNUSED(type) 0149 0150 if (fileName.isLocalFile() || fileName.scheme().isEmpty()) { 0151 auto newTrackId = d->mDatabase->trackIdFromFileName(fileName); 0152 if (newTrackId == 0) { 0153 auto newTrack = d->mFileScanner.scanOneFile(fileName); 0154 0155 if (newTrack.isValid()) { 0156 d->mTracksByFileNameSet.push_back(fileName); 0157 0158 Q_EMIT trackHasChanged(newTrack); 0159 return; 0160 } 0161 0162 d->mTracksByFileNameSet.push_back(fileName); 0163 0164 return; 0165 } 0166 } else { 0167 auto newRadioId = d->mDatabase->radioIdFromFileName(fileName); 0168 if (newRadioId) { 0169 auto newRadio = d->mDatabase->radioDataFromDatabaseId(newRadioId); 0170 0171 if (!newRadio.isEmpty()) { 0172 Q_EMIT trackHasChanged({newRadio}); 0173 } 0174 } 0175 } 0176 } 0177 0178 void TracksListener::newAlbumInList(qulonglong newDatabaseId, const QString &entryTitle) 0179 { 0180 qCDebug(orgKdeElisaPlayList()) << "TracksListener::newAlbumInList" << newDatabaseId << entryTitle << d->mDatabase->albumData(newDatabaseId); 0181 Q_EMIT tracksListAdded(newDatabaseId, entryTitle, ElisaUtils::Album, d->mDatabase->albumData(newDatabaseId)); 0182 } 0183 0184 void TracksListener::newEntryInList(qulonglong newDatabaseId, 0185 const QString &entryTitle, 0186 ElisaUtils::PlayListEntryType databaseIdType) 0187 { 0188 qCDebug(orgKdeElisaPlayList()) << "TracksListener::newEntryInList" << newDatabaseId << entryTitle << databaseIdType; 0189 switch (databaseIdType) 0190 { 0191 case ElisaUtils::Track: 0192 { 0193 d->mTracksByIdSet.insert(newDatabaseId); 0194 0195 auto newTrack = d->mDatabase->trackDataFromDatabaseId(newDatabaseId); 0196 if (!newTrack.isEmpty()) { 0197 Q_EMIT trackHasChanged(newTrack); 0198 } 0199 break; 0200 } 0201 case ElisaUtils::Radio: 0202 { 0203 d->mRadiosByIdSet.insert(newDatabaseId); 0204 0205 auto newRadio = d->mDatabase->radioDataFromDatabaseId(newDatabaseId); 0206 if (!newRadio.isEmpty()) { 0207 Q_EMIT trackHasChanged(newRadio); 0208 } 0209 break; 0210 } 0211 case ElisaUtils::Artist: 0212 newArtistInList(newDatabaseId, entryTitle); 0213 break; 0214 case ElisaUtils::FileName: 0215 newUrlInList(QUrl::fromLocalFile(entryTitle), ElisaUtils::FileName); 0216 break; 0217 case ElisaUtils::Album: 0218 newAlbumInList(newDatabaseId, entryTitle); 0219 break; 0220 case ElisaUtils::Genre: 0221 newGenreInList(newDatabaseId, entryTitle); 0222 break; 0223 case ElisaUtils::Lyricist: 0224 case ElisaUtils::Composer: 0225 case ElisaUtils::Unknown: 0226 case ElisaUtils::Container: 0227 case ElisaUtils::PlayList: 0228 break; 0229 } 0230 } 0231 0232 void TracksListener::newUrlInList(const QUrl &entryUrl, ElisaUtils::PlayListEntryType databaseIdType) 0233 { 0234 switch (databaseIdType) 0235 { 0236 case ElisaUtils::Track: 0237 case ElisaUtils::FileName: 0238 { 0239 auto newDatabaseId = d->mDatabase->trackIdFromFileName(entryUrl); 0240 0241 if (!newDatabaseId) 0242 { 0243 trackByFileNameInList(databaseIdType, entryUrl); 0244 return; 0245 } 0246 0247 d->mTracksByIdSet.insert(newDatabaseId); 0248 0249 auto newTrack = d->mDatabase->trackDataFromDatabaseIdAndUrl(newDatabaseId, entryUrl); 0250 if (!newTrack.isEmpty()) { 0251 Q_EMIT trackHasChanged(newTrack); 0252 } 0253 break; 0254 } 0255 case ElisaUtils::Radio: 0256 { 0257 auto newDatabaseId = d->mDatabase->radioIdFromFileName(entryUrl); 0258 0259 if (!newDatabaseId) 0260 { 0261 return; 0262 } 0263 0264 d->mRadiosByIdSet.insert(newDatabaseId); 0265 0266 auto newRadio = d->mDatabase->radioDataFromDatabaseId(newDatabaseId); 0267 if (!newRadio.isEmpty()) { 0268 Q_EMIT trackHasChanged(newRadio); 0269 } 0270 break; 0271 } 0272 case ElisaUtils::Artist: 0273 case ElisaUtils::Album: 0274 case ElisaUtils::Lyricist: 0275 case ElisaUtils::Composer: 0276 case ElisaUtils::Genre: 0277 case ElisaUtils::Unknown: 0278 case ElisaUtils::Container: 0279 case ElisaUtils::PlayList: 0280 break; 0281 } 0282 } 0283 0284 void TracksListener::newArtistInList(qulonglong newDatabaseId, const QString &artist) 0285 { 0286 auto newTracks = d->mDatabase->tracksDataFromAuthor(artist); 0287 if (newTracks.isEmpty()) { 0288 return; 0289 } 0290 0291 for (const auto &oneTrack : newTracks) { 0292 d->mTracksByIdSet.insert(oneTrack.databaseId()); 0293 } 0294 0295 Q_EMIT tracksListAdded(newDatabaseId, artist, ElisaUtils::Artist, newTracks); 0296 } 0297 0298 void TracksListener::newGenreInList(qulonglong newDatabaseId, const QString &entryTitle) 0299 { 0300 auto newTracks = d->mDatabase->tracksDataFromGenre(entryTitle); 0301 0302 if (newTracks.isEmpty()) { 0303 return; 0304 } 0305 0306 for (const auto &oneTrack : newTracks) { 0307 d->mTracksByIdSet.insert(oneTrack.databaseId()); 0308 } 0309 0310 Q_EMIT tracksListAdded(newDatabaseId, entryTitle, ElisaUtils::Genre, newTracks); 0311 } 0312 0313 void TracksListener::updateSingleFileMetaData(const QUrl &url, DataTypes::ColumnsRoles role, const QVariant &data) 0314 { 0315 d->mFileWriter.writeSingleMetaDataToFile(url, role, data); 0316 } 0317 0318 #include "moc_trackslistener.cpp"