File indexing completed on 2024-04-14 04:44:01
0001 /* 0002 SPDX-FileCopyrightText: 2015 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr> 0003 0004 SPDX-License-Identifier: LGPL-3.0-or-later 0005 */ 0006 0007 #include "mediaplaylist.h" 0008 0009 #include "playListLogging.h" 0010 0011 #include <QUrl> 0012 #include <QList> 0013 #include <QFileInfo> 0014 #include <QJsonArray> 0015 #include <QJsonDocument> 0016 #include <QDebug> 0017 0018 #include <algorithm> 0019 0020 class MediaPlayListPrivate 0021 { 0022 public: 0023 0024 QList<MediaPlayListEntry> mData; 0025 0026 QList<DataTypes::TrackDataType> mTrackData; 0027 0028 }; 0029 0030 MediaPlayList::MediaPlayList(QObject *parent) : QAbstractListModel(parent), d(new MediaPlayListPrivate) 0031 { 0032 } 0033 0034 MediaPlayList::~MediaPlayList() 0035 = default; 0036 0037 int MediaPlayList::rowCount(const QModelIndex &parent) const 0038 { 0039 if (parent.isValid()) { 0040 return 0; 0041 } 0042 0043 return d->mData.size(); 0044 } 0045 0046 QHash<int, QByteArray> MediaPlayList::roleNames() const 0047 { 0048 auto roles = QAbstractItemModel::roleNames(); 0049 0050 roles[static_cast<int>(ColumnsRoles::IsValidRole)] = "isValid"; 0051 roles[static_cast<int>(ColumnsRoles::DatabaseIdRole)] = "databaseId"; 0052 roles[static_cast<int>(ColumnsRoles::TitleRole)] = "title"; 0053 roles[static_cast<int>(ColumnsRoles::StringDurationRole)] = "duration"; 0054 roles[static_cast<int>(ColumnsRoles::ArtistRole)] = "artist"; 0055 roles[static_cast<int>(ColumnsRoles::AlbumArtistRole)] = "albumArtist"; 0056 roles[static_cast<int>(ColumnsRoles::AlbumRole)] = "album"; 0057 roles[static_cast<int>(ColumnsRoles::TrackNumberRole)] = "trackNumber"; 0058 roles[static_cast<int>(ColumnsRoles::DiscNumberRole)] = "discNumber"; 0059 roles[static_cast<int>(ColumnsRoles::RatingRole)] = "rating"; 0060 roles[static_cast<int>(ColumnsRoles::GenreRole)] = "genre"; 0061 roles[static_cast<int>(ColumnsRoles::LyricistRole)] = "lyricist"; 0062 roles[static_cast<int>(ColumnsRoles::ComposerRole)] = "composer"; 0063 roles[static_cast<int>(ColumnsRoles::CommentRole)] = "comment"; 0064 roles[static_cast<int>(ColumnsRoles::YearRole)] = "year"; 0065 roles[static_cast<int>(ColumnsRoles::ChannelsRole)] = "channels"; 0066 roles[static_cast<int>(ColumnsRoles::BitRateRole)] = "bitRate"; 0067 roles[static_cast<int>(ColumnsRoles::SampleRateRole)] = "sampleRate"; 0068 roles[static_cast<int>(ColumnsRoles::CountRole)] = "count"; 0069 roles[static_cast<int>(ColumnsRoles::IsPlayingRole)] = "isPlaying"; 0070 roles[static_cast<int>(ColumnsRoles::IsSingleDiscAlbumRole)] = "isSingleDiscAlbum"; 0071 roles[static_cast<int>(ColumnsRoles::SecondaryTextRole)] = "secondaryText"; 0072 roles[static_cast<int>(ColumnsRoles::ImageUrlRole)] = "imageUrl"; 0073 roles[static_cast<int>(ColumnsRoles::ShadowForImageRole)] = "shadowForImage"; 0074 roles[static_cast<int>(ColumnsRoles::ResourceRole)] = "trackResource"; 0075 roles[static_cast<int>(ColumnsRoles::FullDataRole)] = "trackData"; 0076 roles[static_cast<int>(ColumnsRoles::AlbumIdRole)] = "albumId"; 0077 roles[static_cast<int>(ColumnsRoles::AlbumSectionRole)] = "albumSection"; 0078 roles[static_cast<int>(ColumnsRoles::ElementTypeRole)] = "entryType"; 0079 roles[static_cast<int>(ColumnsRoles::MetadataModifiableRole)] = "metadataModifiableRole"; 0080 0081 return roles; 0082 } 0083 0084 QVariant MediaPlayList::data(const QModelIndex &index, int role) const 0085 { 0086 auto result = QVariant(); 0087 0088 if (!index.isValid()) { 0089 return result; 0090 } 0091 0092 if (d->mData[index.row()].mIsValid) { 0093 switch(role) 0094 { 0095 case ColumnsRoles::IsValidRole: 0096 result = d->mData[index.row()].mIsValid; 0097 break; 0098 case ColumnsRoles::IsPlayingRole: 0099 result = d->mData[index.row()].mIsPlaying; 0100 break; 0101 case ColumnsRoles::ElementTypeRole: 0102 result = QVariant::fromValue(d->mData[index.row()].mEntryType); 0103 break; 0104 case ColumnsRoles::StringDurationRole: 0105 { 0106 QTime trackDuration = d->mTrackData[index.row()][TrackDataType::key_type::DurationRole].toTime(); 0107 if (trackDuration.hour() == 0) { 0108 result = trackDuration.toString(QStringLiteral("mm:ss")); 0109 } else { 0110 result = trackDuration.toString(); 0111 } 0112 break; 0113 } 0114 case ColumnsRoles::AlbumSectionRole: 0115 result = QJsonDocument{QJsonArray{d->mTrackData[index.row()][TrackDataType::key_type::AlbumRole].toString(), 0116 d->mTrackData[index.row()][TrackDataType::key_type::AlbumArtistRole].toString(), 0117 d->mTrackData[index.row()][TrackDataType::key_type::ImageUrlRole].toUrl().toString()}}.toJson(); 0118 break; 0119 case ColumnsRoles::TitleRole: 0120 { 0121 const auto &trackData = d->mTrackData[index.row()]; 0122 auto titleData = trackData[TrackDataType::key_type::TitleRole]; 0123 if (titleData.toString().isEmpty()) { 0124 result = trackData[TrackDataType::key_type::ResourceRole].toUrl().fileName(); 0125 } else { 0126 result = titleData; 0127 } 0128 break; 0129 } 0130 case ColumnsRoles::MetadataModifiableRole: 0131 switch (d->mData[index.row()].mEntryType) 0132 { 0133 case ElisaUtils::Album: 0134 case ElisaUtils::Artist: 0135 case ElisaUtils::Composer: 0136 case ElisaUtils::Genre: 0137 case ElisaUtils::Unknown: 0138 case ElisaUtils::Lyricist: 0139 case ElisaUtils::Container: 0140 case ElisaUtils::PlayList: 0141 result = false; 0142 break; 0143 case ElisaUtils::Radio: 0144 result = true; 0145 break; 0146 case ElisaUtils::FileName: 0147 case ElisaUtils::Track: 0148 result = d->mTrackData[index.row()].resourceURI().isLocalFile(); 0149 break; 0150 } 0151 break; 0152 default: 0153 const auto &trackData = d->mTrackData[index.row()]; 0154 auto roleEnum = static_cast<TrackDataType::key_type>(role); 0155 auto itData = trackData.find(roleEnum); 0156 if (itData != trackData.end()) { 0157 result = itData.value(); 0158 } else { 0159 result = {}; 0160 } 0161 } 0162 } else { 0163 switch(role) 0164 { 0165 case ColumnsRoles::IsValidRole: 0166 result = d->mData[index.row()].mIsValid; 0167 break; 0168 case ColumnsRoles::TitleRole: 0169 result = d->mData[index.row()].mTitle; 0170 break; 0171 case ColumnsRoles::IsPlayingRole: 0172 result = d->mData[index.row()].mIsPlaying; 0173 break; 0174 case ColumnsRoles::ArtistRole: 0175 result = d->mData[index.row()].mArtist; 0176 break; 0177 case ColumnsRoles::AlbumArtistRole: 0178 result = d->mData[index.row()].mArtist; 0179 break; 0180 case ColumnsRoles::AlbumRole: 0181 result = d->mData[index.row()].mAlbum; 0182 break; 0183 case ColumnsRoles::TrackNumberRole: 0184 result = -1; 0185 break; 0186 case ColumnsRoles::IsSingleDiscAlbumRole: 0187 result = false; 0188 break; 0189 case Qt::DisplayRole: 0190 result = d->mData[index.row()].mTitle; 0191 break; 0192 case ColumnsRoles::ImageUrlRole: 0193 result = QUrl(QStringLiteral("image://icon/error")); 0194 break; 0195 case ColumnsRoles::ShadowForImageRole: 0196 result = false; 0197 break; 0198 case ColumnsRoles::AlbumSectionRole: 0199 result = QJsonDocument{QJsonArray{d->mData[index.row()].mAlbum.toString(), 0200 d->mData[index.row()].mArtist.toString(), 0201 QUrl(QStringLiteral("image://icon/error")).toString()}}.toJson(); 0202 break; 0203 0204 default: 0205 result = {}; 0206 } 0207 } 0208 0209 return result; 0210 } 0211 0212 bool MediaPlayList::setData(const QModelIndex &index, const QVariant &value, int role) 0213 { 0214 bool modelModified = false; 0215 0216 if (!index.isValid()) { 0217 return modelModified; 0218 } 0219 0220 if (index.row() < 0 || index.row() >= d->mData.size()) { 0221 return modelModified; 0222 } 0223 0224 if (role < ColumnsRoles::IsValidRole || role > ColumnsRoles::IsPlayingRole) { 0225 return modelModified; 0226 } 0227 0228 auto convertedRole = static_cast<ColumnsRoles>(role); 0229 0230 switch(convertedRole) 0231 { 0232 case ColumnsRoles::IsPlayingRole: 0233 { 0234 modelModified = true; 0235 auto newState = static_cast<PlayState>(value.toInt()); 0236 d->mData[index.row()].mIsPlaying = newState; 0237 Q_EMIT dataChanged(index, index, {role}); 0238 0239 break; 0240 } 0241 case ColumnsRoles::TitleRole: 0242 { 0243 modelModified = true; 0244 d->mData[index.row()].mTitle = value; 0245 d->mTrackData[index.row()][static_cast<TrackDataType::key_type>(role)] = value; 0246 Q_EMIT dataChanged(index, index, {role}); 0247 0248 break; 0249 } 0250 case ColumnsRoles::ArtistRole: 0251 { 0252 modelModified = true; 0253 d->mData[index.row()].mArtist = value; 0254 d->mTrackData[index.row()][static_cast<TrackDataType::key_type>(role)] = value; 0255 Q_EMIT dataChanged(index, index, {role}); 0256 0257 break; 0258 } 0259 default: 0260 modelModified = false; 0261 } 0262 0263 return modelModified; 0264 } 0265 0266 bool MediaPlayList::removeRows(int row, int count, const QModelIndex &parent) 0267 { 0268 beginRemoveRows(parent, row, row + count - 1); 0269 0270 for (int i = row, cpt = 0; cpt < count; ++i, ++cpt) { 0271 d->mData.removeAt(i); 0272 d->mTrackData.removeAt(i); 0273 } 0274 endRemoveRows(); 0275 0276 return true; 0277 } 0278 0279 bool MediaPlayList::moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) 0280 { 0281 if (sourceParent != destinationParent) { 0282 return false; 0283 } 0284 0285 if (!beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1, destinationParent, destinationChild)) { 0286 return false; 0287 } 0288 0289 for (auto cptItem = 0; cptItem < count; ++cptItem) { 0290 if (sourceRow < destinationChild) { 0291 d->mData.move(sourceRow, destinationChild - 1); 0292 d->mTrackData.move(sourceRow, destinationChild - 1); 0293 } else { 0294 d->mData.move(sourceRow, destinationChild); 0295 d->mTrackData.move(sourceRow, destinationChild); 0296 } 0297 } 0298 0299 endMoveRows(); 0300 0301 return true; 0302 } 0303 0304 void MediaPlayList::enqueueRestoredEntries(const QVariantList &newEntries) 0305 { 0306 if (newEntries.isEmpty()) { 0307 return; 0308 } 0309 0310 beginInsertRows(QModelIndex(), d->mData.size(), d->mData.size() + newEntries.size() - 1); 0311 for (auto &oneData : newEntries) { 0312 auto trackData = oneData.toStringList(); 0313 if (trackData.size() != 7 && trackData.size() != 8) { 0314 continue; 0315 } 0316 0317 auto restoredId = trackData[0].toULongLong(); 0318 auto restoredTitle = trackData[1]; 0319 auto restoredArtist = trackData[2]; 0320 auto restoredAlbum = trackData[3]; 0321 auto restoredTrackNumber = trackData[4]; 0322 auto restoredDiscNumber = trackData[5]; 0323 auto restoredFileUrl = QVariant{}; 0324 if (trackData.size() == 8) { 0325 restoredFileUrl = QUrl{trackData[7]}; 0326 } 0327 0328 auto mEntryType = static_cast<ElisaUtils::PlayListEntryType>(trackData[6].toInt()); 0329 auto newEntry = MediaPlayListEntry({restoredId, restoredTitle, restoredArtist, restoredAlbum, restoredFileUrl, restoredTrackNumber, restoredDiscNumber, mEntryType}); 0330 0331 d->mData.push_back(newEntry); 0332 d->mTrackData.push_back({}); 0333 0334 if (newEntry.mEntryType == ElisaUtils::Radio) { 0335 Q_EMIT newEntryInList(newEntry.mId, {}, ElisaUtils::Radio); 0336 } else if (newEntry.mTrackUrl.isValid()) { 0337 auto entryURL = newEntry.mTrackUrl.toUrl(); 0338 if (entryURL.isLocalFile()) { 0339 auto entryString = entryURL.toLocalFile(); 0340 QFileInfo newTrackFile(entryString); 0341 if (newTrackFile.exists()) { 0342 d->mData.last().mIsValid = true; 0343 Q_EMIT newEntryInList(0, entryString, ElisaUtils::FileName); 0344 } else if (newEntry.mTitle.toString().isEmpty()) { 0345 Q_EMIT newEntryInList(0, entryString, ElisaUtils::FileName); 0346 } else { 0347 Q_EMIT newTrackByNameInList(newEntry.mTitle, 0348 newEntry.mArtist, 0349 newEntry.mAlbum, 0350 newEntry.mTrackNumber, 0351 newEntry.mDiscNumber); 0352 } 0353 } else { 0354 d->mData.last().mIsValid = true; 0355 } 0356 } else { 0357 Q_EMIT newTrackByNameInList(newEntry.mTitle, 0358 newEntry.mArtist, 0359 newEntry.mAlbum, 0360 newEntry.mTrackNumber, 0361 newEntry.mDiscNumber); 0362 } 0363 } 0364 endInsertRows(); 0365 } 0366 0367 void MediaPlayList::enqueueFilesList(const DataTypes::EntryDataList &newEntries) 0368 { 0369 qCDebug(orgKdeElisaPlayList()) << "MediaPlayList::enqueueFilesList"; 0370 0371 beginInsertRows(QModelIndex(), d->mData.size(), d->mData.size() + newEntries.size() - 1); 0372 for (const auto &oneTrackUrl : newEntries) { 0373 const auto &trackUrl = std::get<2>(oneTrackUrl); 0374 auto newEntry = MediaPlayListEntry(trackUrl); 0375 newEntry.mEntryType = ElisaUtils::FileName; 0376 d->mData.push_back(newEntry); 0377 if (trackUrl.isValid()) { 0378 if (trackUrl.isLocalFile()) { 0379 d->mTrackData.push_back({{DataTypes::ColumnsRoles::ResourceRole, trackUrl}}); 0380 auto entryString = trackUrl.toLocalFile(); 0381 QFileInfo newTrackFile(entryString); 0382 if (newTrackFile.exists()) { 0383 d->mData.last().mIsValid = true; 0384 } 0385 } else { 0386 d->mTrackData.push_back({{DataTypes::ColumnsRoles::ResourceRole, trackUrl}, 0387 {DataTypes::ColumnsRoles::TitleRole, trackUrl.fileName()}}); 0388 d->mData.last().mIsValid = true; 0389 } 0390 Q_EMIT newUrlInList(trackUrl, newEntry.mEntryType); 0391 } else { 0392 d->mTrackData.push_back({}); 0393 } 0394 } 0395 endInsertRows(); 0396 } 0397 0398 void MediaPlayList::enqueueOneEntry(const DataTypes::EntryData &entryData) 0399 { 0400 if (!std::get<0>(entryData).isEmpty() || !std::get<1>(entryData).isEmpty() || !std::get<2>(entryData).isEmpty()) { 0401 beginInsertRows(QModelIndex(), d->mData.size(), d->mData.size()); 0402 if (!std::get<0>(entryData).databaseId() && std::get<2>(entryData).isValid()) { 0403 auto newEntry = MediaPlayListEntry{std::get<2>(entryData)}; 0404 newEntry.mEntryType = ElisaUtils::FileName; 0405 d->mData.push_back(std::move(newEntry)); 0406 d->mTrackData.push_back({}); 0407 } else { 0408 qCDebug(orgKdeElisaPlayList()) << "MediaPlayList::enqueueOneEntry" << std::get<0>(entryData) << std::get<1>(entryData) << std::get<0>(entryData).elementType(); 0409 0410 d->mData.push_back(MediaPlayListEntry{std::get<0>(entryData).databaseId(), std::get<1>(entryData), std::get<0>(entryData).elementType()}); 0411 const auto &data = std::get<0>(entryData); 0412 switch (data.elementType()) 0413 { 0414 case ElisaUtils::Track: 0415 case ElisaUtils::Radio: 0416 d->mTrackData.push_back(static_cast<const DataTypes::TrackDataType&>(data)); 0417 break; 0418 default: 0419 d->mTrackData.push_back({}); 0420 } 0421 } 0422 if (std::get<2>(entryData).isValid()) { 0423 Q_EMIT newUrlInList(std::get<2>(entryData), std::get<0>(entryData).elementType()); 0424 } else { 0425 Q_EMIT newEntryInList(std::get<0>(entryData).databaseId(), std::get<1>(entryData), std::get<0>(entryData).elementType()); 0426 } 0427 endInsertRows(); 0428 } 0429 } 0430 0431 void MediaPlayList::enqueueMultipleEntries(const DataTypes::EntryDataList &entriesData) 0432 { 0433 qCDebug(orgKdeElisaPlayList()) << "MediaPlayList::enqueueMultipleEntries" << entriesData.size(); 0434 0435 beginInsertRows(QModelIndex(), d->mData.size(), d->mData.size() + entriesData.size() - 1); 0436 for (const auto &entryData : entriesData) { 0437 qCDebug(orgKdeElisaPlayList()) << "MediaPlayList::enqueueMultipleEntries" << std::get<0>(entryData); 0438 auto trackUrl = std::get<0>(entryData)[DataTypes::ResourceRole].toUrl(); 0439 if (!std::get<0>(entryData).databaseId() && trackUrl.isValid()) { 0440 auto newEntry = MediaPlayListEntry{trackUrl}; 0441 newEntry.mEntryType = ElisaUtils::FileName; 0442 d->mData.push_back(std::move(newEntry)); 0443 d->mTrackData.push_back({}); 0444 } else { 0445 d->mData.push_back(MediaPlayListEntry{std::get<0>(entryData).databaseId(), std::get<1>(entryData), std::get<0>(entryData).elementType()}); 0446 const auto &data = std::get<0>(entryData); 0447 switch (data.elementType()) 0448 { 0449 case ElisaUtils::Track: 0450 case ElisaUtils::Radio: 0451 case ElisaUtils::FileName: 0452 d->mTrackData.push_back(static_cast<const DataTypes::TrackDataType&>(data)); 0453 break; 0454 default: 0455 d->mTrackData.push_back({}); 0456 } 0457 } 0458 0459 if (trackUrl.isValid()) { 0460 qCDebug(orgKdeElisaPlayList()) << "MediaPlayList::enqueueMultipleEntries" << "new url" << trackUrl 0461 << std::get<0>(entryData).elementType(); 0462 Q_EMIT newUrlInList(trackUrl, std::get<0>(entryData).elementType()); 0463 } else { 0464 Q_EMIT newEntryInList(std::get<0>(entryData).databaseId(), std::get<1>(entryData), std::get<0>(entryData).elementType()); 0465 } 0466 } 0467 endInsertRows(); 0468 } 0469 0470 void MediaPlayList::clearPlayList() 0471 { 0472 if (d->mData.isEmpty()) { 0473 return; 0474 } 0475 0476 beginRemoveRows({}, 0, d->mData.count() - 1); 0477 d->mData.clear(); 0478 d->mTrackData.clear(); 0479 endRemoveRows(); 0480 } 0481 0482 QVariantList MediaPlayList::getEntriesForRestore() const 0483 { 0484 QVariantList result; 0485 0486 for (int trackIndex = 0; trackIndex < d->mData.size(); ++trackIndex) { 0487 QStringList oneData; 0488 const auto &oneEntry = d->mData[trackIndex]; 0489 if (oneEntry.mIsValid) { 0490 const auto &oneTrack = d->mTrackData[trackIndex]; 0491 0492 oneData.push_back(QString::number(oneTrack.databaseId())); 0493 oneData.push_back(oneTrack.title()); 0494 oneData.push_back(oneTrack.artist()); 0495 if (oneTrack.hasAlbum()) { 0496 oneData.push_back(oneTrack.album()); 0497 } else { 0498 oneData.push_back({}); 0499 } 0500 if (oneTrack.hasTrackNumber()) { 0501 oneData.push_back(QString::number(oneTrack.trackNumber())); 0502 } else { 0503 oneData.push_back({}); 0504 } 0505 if (oneTrack.hasDiscNumber()) { 0506 oneData.push_back(QString::number(oneTrack.discNumber())); 0507 } else { 0508 oneData.push_back({}); 0509 } 0510 oneData.push_back(QString::number(oneEntry.mEntryType)); 0511 oneData.push_back(oneTrack.resourceURI().toString()); 0512 0513 result.push_back(QVariant(oneData)); 0514 } 0515 } 0516 return result; 0517 } 0518 0519 void MediaPlayList::tracksListAdded(qulonglong newDatabaseId, 0520 const QString &entryTitle, 0521 ElisaUtils::PlayListEntryType databaseIdType, 0522 const ListTrackDataType &tracks) 0523 { 0524 if (tracks.isEmpty()) { 0525 qCDebug(orgKdeElisaPlayList()) << "MediaPlayList::tracksListAdded" << " empty tracks list"; 0526 return; 0527 } 0528 0529 for (int playListIndex = 0; playListIndex < d->mData.size(); ++playListIndex) { 0530 auto &oneEntry = d->mData[playListIndex]; 0531 if (oneEntry.mEntryType != databaseIdType) { 0532 continue; 0533 } 0534 0535 if (oneEntry.mTitle != entryTitle) { 0536 continue; 0537 } 0538 0539 if (newDatabaseId != 0 && oneEntry.mId != newDatabaseId) { 0540 continue; 0541 } 0542 0543 beginRemoveRows(QModelIndex(),playListIndex,playListIndex); 0544 d->mData.removeAt(playListIndex); 0545 d->mTrackData.removeAt(playListIndex); 0546 endRemoveRows(); 0547 0548 beginInsertRows(QModelIndex(), playListIndex, playListIndex - 1 + tracks.size()); 0549 for (int trackIndex = 0; trackIndex < tracks.size(); ++trackIndex) { 0550 auto newEntry = MediaPlayListEntry{tracks[trackIndex]}; 0551 newEntry.mEntryType = ElisaUtils::Track; 0552 d->mData.insert(playListIndex + trackIndex, newEntry); 0553 d->mTrackData.insert(playListIndex + trackIndex, tracks[trackIndex]); 0554 } 0555 endInsertRows(); 0556 } 0557 } 0558 0559 void MediaPlayList::trackChanged(const TrackDataType &track) 0560 { 0561 qCDebug(orgKdeElisaPlayList()) << "MediaPlayList::trackChanged" << track[DataTypes::TitleRole]; 0562 0563 for (int i = 0; i < d->mData.size(); ++i) { 0564 auto &oneEntry = d->mData[i]; 0565 0566 if (oneEntry.mEntryType != ElisaUtils::Artist && oneEntry.mIsValid) { 0567 if (oneEntry.mTrackUrl.toUrl().isValid() && track.resourceURI() != oneEntry.mTrackUrl.toUrl()) { 0568 continue; 0569 } 0570 0571 if (!oneEntry.mTrackUrl.toUrl().isValid() && (oneEntry.mId == 0 || track.databaseId() != oneEntry.mId)) { 0572 continue; 0573 } 0574 0575 const auto &trackData = d->mTrackData[i]; 0576 0577 if (!trackData.empty()) { 0578 bool sameData = true; 0579 for (auto oneKeyIterator = track.constKeyValueBegin(); oneKeyIterator != track.constKeyValueEnd(); ++oneKeyIterator) { 0580 if (trackData[(*oneKeyIterator).first] != (*oneKeyIterator).second) { 0581 sameData = false; 0582 break; 0583 } 0584 } 0585 if (sameData) { 0586 continue; 0587 } 0588 } 0589 0590 d->mTrackData[i] = track; 0591 0592 Q_EMIT dataChanged(index(i, 0), index(i, 0), {}); 0593 continue; 0594 } else if (oneEntry.mEntryType == ElisaUtils::Radio ) { 0595 if (track.databaseId() != oneEntry.mId) { 0596 continue; 0597 } 0598 0599 d->mTrackData[i] = track; 0600 oneEntry.mId = track.databaseId(); 0601 oneEntry.mIsValid = true; 0602 0603 Q_EMIT dataChanged(index(i, 0), index(i, 0), {}); 0604 0605 break; 0606 } else if (oneEntry.mEntryType != ElisaUtils::Artist && !oneEntry.mIsValid && !oneEntry.mTrackUrl.isValid()) { 0607 if (track.find(TrackDataType::key_type::TitleRole) != track.end() && 0608 track.title() != oneEntry.mTitle) { 0609 continue; 0610 } 0611 0612 if (track.find(TrackDataType::key_type::AlbumRole) != track.end() && 0613 track.album() != oneEntry.mAlbum) { 0614 continue; 0615 } 0616 0617 if (track.find(TrackDataType::key_type::TrackNumberRole) != track.end() && 0618 track.trackNumber() != oneEntry.mTrackNumber) { 0619 continue; 0620 } 0621 0622 if (track.find(TrackDataType::key_type::DiscNumberRole) != track.end() && 0623 track.discNumber() != oneEntry.mDiscNumber) { 0624 continue; 0625 } 0626 0627 d->mTrackData[i] = track; 0628 oneEntry.mId = track.databaseId(); 0629 oneEntry.mIsValid = true; 0630 0631 Q_EMIT dataChanged(index(i, 0), index(i, 0), {}); 0632 0633 break; 0634 } else if (oneEntry.mEntryType != ElisaUtils::Artist && !oneEntry.mIsValid && oneEntry.mTrackUrl.isValid()) { 0635 if (track.resourceURI() != oneEntry.mTrackUrl) { 0636 continue; 0637 } 0638 0639 d->mTrackData[i] = track; 0640 oneEntry.mId = track.databaseId(); 0641 oneEntry.mIsValid = true; 0642 0643 Q_EMIT dataChanged(index(i, 0), index(i, 0), {}); 0644 break; 0645 } 0646 } 0647 } 0648 0649 void MediaPlayList::trackRemoved(qulonglong trackId) 0650 { 0651 for (int i = 0; i < d->mData.size(); ++i) { 0652 auto &oneEntry = d->mData[i]; 0653 0654 if (oneEntry.mIsValid) { 0655 if (oneEntry.mId == trackId) { 0656 oneEntry.mIsValid = false; 0657 oneEntry.mTitle = d->mTrackData[i].title(); 0658 oneEntry.mArtist = d->mTrackData[i].artist(); 0659 oneEntry.mAlbum = d->mTrackData[i].album(); 0660 oneEntry.mTrackNumber = d->mTrackData[i].trackNumber(); 0661 oneEntry.mDiscNumber = d->mTrackData[i].discNumber(); 0662 0663 Q_EMIT dataChanged(index(i, 0), index(i, 0), {}); 0664 0665 } 0666 } 0667 } 0668 } 0669 0670 void MediaPlayList::trackInError(const QUrl &sourceInError, QMediaPlayer::Error playerError) 0671 { 0672 Q_UNUSED(playerError) 0673 0674 for (int i = 0; i < d->mData.size(); ++i) { 0675 auto &oneTrack = d->mData[i]; 0676 if (oneTrack.mIsValid) { 0677 const auto &oneTrackData = d->mTrackData.at(i); 0678 0679 if (oneTrackData.resourceURI() == sourceInError) { 0680 oneTrack.mIsValid = false; 0681 Q_EMIT dataChanged(index(i, 0), index(i, 0), {ColumnsRoles::IsValidRole}); 0682 } 0683 } 0684 } 0685 } 0686 0687 QDebug operator<<(const QDebug &stream, const MediaPlayListEntry &data) 0688 { 0689 stream << data.mTitle << data.mAlbum << data.mArtist << data.mTrackUrl << data.mTrackNumber << data.mDiscNumber << data.mId << data.mIsValid; 0690 return stream; 0691 } 0692 0693 #include "moc_mediaplaylist.cpp"