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"