mediaplaylist.cpp 22.8 KB
Newer Older
1
/*
Matthieu Gallien's avatar
Matthieu Gallien committed
2
3
4
   SPDX-FileCopyrightText: 2015 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr>

   SPDX-License-Identifier: LGPL-3.0-or-later
5
6
7
 */

#include "mediaplaylist.h"
8
9

#include "playListLogging.h"
10
#include "datatypes.h"
11

12
13
14
#include <QUrl>
#include <QPersistentModelIndex>
#include <QList>
15
#include <QMediaPlaylist>
16
#include <QFileInfo>
17
18
#include <QJsonArray>
#include <QJsonDocument>
19
#include <QDebug>
Alexander Stippich's avatar
Alexander Stippich committed
20
#include <QRandomGenerator>
21

22
23
#include <algorithm>

24
25
26
27
class MediaPlayListPrivate
{
public:

28
    QList<MediaPlayListEntry> mData;
29

30
    QList<DataTypes::TrackDataType> mTrackData;
31

32
33
};

34
MediaPlayList::MediaPlayList(QObject *parent) : QAbstractListModel(parent), d(new MediaPlayListPrivate)
35
36
37
38
{
}

MediaPlayList::~MediaPlayList()
39
= default;
40
41
42
43
44
45
46
47
48
49

int MediaPlayList::rowCount(const QModelIndex &parent) const
{
    if (parent.isValid()) {
        return 0;
    }

    return d->mData.size();
}

50
51
52
53
54
QHash<int, QByteArray> MediaPlayList::roleNames() const
{
    auto roles = QAbstractItemModel::roleNames();

    roles[static_cast<int>(ColumnsRoles::IsValidRole)] = "isValid";
55
    roles[static_cast<int>(ColumnsRoles::DatabaseIdRole)] = "databaseId";
56
    roles[static_cast<int>(ColumnsRoles::TitleRole)] = "title";
57
    roles[static_cast<int>(ColumnsRoles::StringDurationRole)] = "duration";
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
    roles[static_cast<int>(ColumnsRoles::ArtistRole)] = "artist";
    roles[static_cast<int>(ColumnsRoles::AlbumArtistRole)] = "albumArtist";
    roles[static_cast<int>(ColumnsRoles::AlbumRole)] = "album";
    roles[static_cast<int>(ColumnsRoles::TrackNumberRole)] = "trackNumber";
    roles[static_cast<int>(ColumnsRoles::DiscNumberRole)] = "discNumber";
    roles[static_cast<int>(ColumnsRoles::RatingRole)] = "rating";
    roles[static_cast<int>(ColumnsRoles::GenreRole)] = "genre";
    roles[static_cast<int>(ColumnsRoles::LyricistRole)] = "lyricist";
    roles[static_cast<int>(ColumnsRoles::ComposerRole)] = "composer";
    roles[static_cast<int>(ColumnsRoles::CommentRole)] = "comment";
    roles[static_cast<int>(ColumnsRoles::YearRole)] = "year";
    roles[static_cast<int>(ColumnsRoles::ChannelsRole)] = "channels";
    roles[static_cast<int>(ColumnsRoles::BitRateRole)] = "bitRate";
    roles[static_cast<int>(ColumnsRoles::SampleRateRole)] = "sampleRate";
    roles[static_cast<int>(ColumnsRoles::CountRole)] = "count";
    roles[static_cast<int>(ColumnsRoles::IsPlayingRole)] = "isPlaying";
74
    roles[static_cast<int>(ColumnsRoles::IsSingleDiscAlbumRole)] = "isSingleDiscAlbum";
75
76
77
78
    roles[static_cast<int>(ColumnsRoles::SecondaryTextRole)] = "secondaryText";
    roles[static_cast<int>(ColumnsRoles::ImageUrlRole)] = "imageUrl";
    roles[static_cast<int>(ColumnsRoles::ShadowForImageRole)] = "shadowForImage";
    roles[static_cast<int>(ColumnsRoles::ResourceRole)] = "trackResource";
79
    roles[static_cast<int>(ColumnsRoles::FullDataRole)] = "trackData";
80
    roles[static_cast<int>(ColumnsRoles::AlbumIdRole)] = "albumId";
81
    roles[static_cast<int>(ColumnsRoles::AlbumSectionRole)] = "albumSection";
82
    roles[static_cast<int>(ColumnsRoles::ElementTypeRole)] = "entryType";
83
84
85
86

    return roles;
}

87
88
QVariant MediaPlayList::data(const QModelIndex &index, int role) const
{
89
90
    auto result = QVariant();

91
92
93
94
    if (!index.isValid()) {
        return result;
    }

95
    if (d->mData[index.row()].mIsValid) {
96
        switch(role)
97
98
        {
        case ColumnsRoles::IsValidRole:
99
100
            result = d->mData[index.row()].mIsValid;
            break;
101
102
103
        case ColumnsRoles::IsPlayingRole:
            result = d->mData[index.row()].mIsPlaying;
            break;
104
105
106
        case ColumnsRoles::ElementTypeRole:
            result = d->mData[index.row()].mEntryType;
            break;
107
108
        case ColumnsRoles::StringDurationRole:
        {
109
            QTime trackDuration = d->mTrackData[index.row()][TrackDataType::key_type::DurationRole].toTime();
110
111
112
113
114
115
116
            if (trackDuration.hour() == 0) {
                result = trackDuration.toString(QStringLiteral("mm:ss"));
            } else {
                result = trackDuration.toString();
            }
            break;
        }
117
118
        case ColumnsRoles::AlbumSectionRole:
            result = QJsonDocument{QJsonArray{d->mTrackData[index.row()][TrackDataType::key_type::AlbumRole].toString(),
119
120
                    d->mTrackData[index.row()][TrackDataType::key_type::AlbumArtistRole].toString(),
                    d->mTrackData[index.row()][TrackDataType::key_type::ImageUrlRole].toUrl().toString()}}.toJson();
121
            break;
122
123
124
125
126
127
128
129
130
131
132
        case ColumnsRoles::TitleRole:
        {
            const auto &trackData = d->mTrackData[index.row()];
            auto titleData = trackData[TrackDataType::key_type::TitleRole];
            if (titleData.toString().isEmpty()) {
                result = trackData[TrackDataType::key_type::ResourceRole].toUrl().fileName();
            } else {
                result = titleData;
            }
            break;
        }
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
        default:
            const auto &trackData = d->mTrackData[index.row()];
            auto roleEnum = static_cast<TrackDataType::key_type>(role);
            auto itData = trackData.find(roleEnum);
            if (itData != trackData.end()) {
                result = itData.value();
            } else {
                result = {};
            }
        }
    } else {
        switch(role)
        {
        case ColumnsRoles::IsValidRole:
            result = d->mData[index.row()].mIsValid;
            break;
        case ColumnsRoles::TitleRole:
            result = d->mData[index.row()].mTitle;
            break;
        case ColumnsRoles::IsPlayingRole:
            result = d->mData[index.row()].mIsPlaying;
            break;
        case ColumnsRoles::ArtistRole:
            result = d->mData[index.row()].mArtist;
            break;
        case ColumnsRoles::AlbumArtistRole:
            result = d->mData[index.row()].mArtist;
            break;
        case ColumnsRoles::AlbumRole:
            result = d->mData[index.row()].mAlbum;
            break;
        case ColumnsRoles::TrackNumberRole:
            result = -1;
            break;
        case ColumnsRoles::IsSingleDiscAlbumRole:
            result = false;
            break;
        case Qt::DisplayRole:
            result = d->mData[index.row()].mTitle;
            break;
        case ColumnsRoles::ImageUrlRole:
            result = QUrl(QStringLiteral("image://icon/error"));
            break;
        case ColumnsRoles::ShadowForImageRole:
            result = false;
            break;
        case ColumnsRoles::AlbumSectionRole:
            result = QJsonDocument{QJsonArray{d->mData[index.row()].mAlbum.toString(),
                    d->mData[index.row()].mArtist.toString(),
                    QUrl(QStringLiteral("image://icon/error")).toString()}}.toJson();
            break;
184

185
        default:
Matthieu Gallien's avatar
Matthieu Gallien committed
186
            result = {};
187
        }
188
    }
189

190
    return result;
191
192
193
194
}

bool MediaPlayList::setData(const QModelIndex &index, const QVariant &value, int role)
{
195
196
    bool modelModified = false;

197
    if (!index.isValid()) {
198
        return modelModified;
199
200
    }

201
    if (index.row() < 0 || index.row() >= d->mData.size()) {
202
        return modelModified;
203
204
    }

205
    if (role < ColumnsRoles::IsValidRole || role > ColumnsRoles::IsPlayingRole) {
206
        return modelModified;
207
208
    }

209
    auto convertedRole = static_cast<ColumnsRoles>(role);
210
211
212
213

    switch(convertedRole)
    {
    case ColumnsRoles::IsPlayingRole:
214
    {
215
        modelModified = true;
216
        auto newState = static_cast<PlayState>(value.toInt());
217
        d->mData[index.row()].mIsPlaying = newState;
218
        Q_EMIT dataChanged(index, index, {role});
219

220
        break;
221
    }
Jerome Guidon's avatar
Jerome Guidon committed
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
    case ColumnsRoles::TitleRole:
    {
        modelModified = true;
        d->mData[index.row()].mTitle = value;
        d->mTrackData[index.row()][static_cast<TrackDataType::key_type>(role)] = value;
        Q_EMIT dataChanged(index, index, {role});

        break;
    }
    case ColumnsRoles::ArtistRole:
    {
        modelModified = true;
        d->mData[index.row()].mArtist = value;
        d->mTrackData[index.row()][static_cast<TrackDataType::key_type>(role)] = value;
        Q_EMIT dataChanged(index, index, {role});

        break;
    }
240
241
242
243
244
245
246
247
248
249
    default:
        modelModified = false;
    }

    return modelModified;
}

bool MediaPlayList::removeRows(int row, int count, const QModelIndex &parent)
{
    beginRemoveRows(parent, row, row + count - 1);
250

251
252
    for (int i = row, cpt = 0; cpt < count; ++i, ++cpt) {
        d->mData.removeAt(i);
253
        d->mTrackData.removeAt(i);
254
255
256
    }
    endRemoveRows();

257
    return true;
258
259
}

260
bool MediaPlayList::moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild)
261
{
262
263
    if (sourceParent != destinationParent) {
        return false;
264
    }
265

266
267
268
269
270
271
272
    if (!beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1, destinationParent, destinationChild)) {
        return false;
    }

    for (auto cptItem = 0; cptItem < count; ++cptItem) {
        if (sourceRow < destinationChild) {
            d->mData.move(sourceRow, destinationChild - 1);
273
            d->mTrackData.move(sourceRow, destinationChild - 1);
274
275
        } else {
            d->mData.move(sourceRow, destinationChild);
276
            d->mTrackData.move(sourceRow, destinationChild);
277
278
        }
    }
279

280
281
282
283
284
    endMoveRows();

    return true;
}

285
void MediaPlayList::enqueueRestoredEntries(const QVariantList &newEntries)
286
{
Alexander Stippich's avatar
Alexander Stippich committed
287
288
289
290
    if (newEntries.isEmpty()) {
        return;
    }

291
292
293
294
295
296
    beginInsertRows(QModelIndex(), d->mData.size(), d->mData.size() + newEntries.size() - 1);
    for (auto &oneData : newEntries) {
        auto trackData = oneData.toStringList();
        if (trackData.size() != 7) {
            continue;
        }
297

298
299
300
301
302
303
        auto restoredId = trackData[0].toULongLong();
        auto restoredTitle = trackData[1];
        auto restoredArtist = trackData[2];
        auto restoredAlbum = trackData[3];
        auto restoredTrackNumber = trackData[4];
        auto restoredDiscNumber = trackData[5];
304

305
306
        auto mEntryType = static_cast<ElisaUtils::PlayListEntryType>(trackData[6].toInt());
        auto newEntry = MediaPlayListEntry({restoredId, restoredTitle, restoredArtist, restoredAlbum, restoredTrackNumber, restoredDiscNumber, mEntryType});
307

308
309
        d->mData.push_back(newEntry);
        d->mTrackData.push_back({});
310

311
312
313
314
315
316
317
318
319
320
321
322
        if (!newEntry.mIsValid) {
            if (newEntry.mEntryType == ElisaUtils::Radio) {
                Q_EMIT newEntryInList(newEntry.mId, {}, ElisaUtils::Radio);
            } else if (newEntry.mTrackUrl.isValid()) {
                auto entryURL = newEntry.mTrackUrl.toUrl();
                if (entryURL.isLocalFile()) {
                    auto entryString =  entryURL.toLocalFile();
                    QFileInfo newTrackFile(entryString);
                    if (newTrackFile.exists()) {
                        d->mData.last().mIsValid = true;
                    }
                    Q_EMIT newEntryInList(0, entryString, ElisaUtils::FileName);
323
                }
324
325
326
327
328
329
            } else {
                Q_EMIT newTrackByNameInList(newEntry.mTitle,
                                            newEntry.mArtist,
                                            newEntry.mAlbum,
                                            newEntry.mTrackNumber,
                                            newEntry.mDiscNumber);
330
331
            }
        } else {
332
            Q_EMIT newEntryInList(newEntry.mId, {}, ElisaUtils::Track);
333
334
        }
    }
335
    endInsertRows();
336
337
}

338
void MediaPlayList::enqueueFilesList(const DataTypes::EntryDataList &newEntries, ElisaUtils::PlayListEntryType databaseIdType)
339
{
340
    qCDebug(orgKdeElisaPlayList()) << "MediaPlayList::enqueueFilesList";
341

342
343
    beginInsertRows(QModelIndex(), d->mData.size(), d->mData.size() + newEntries.size() - 1);
    for (const auto &oneTrackUrl : newEntries) {
344
345
346
347
348
349
350
351
352
353
        switch (databaseIdType)
        {
        case ElisaUtils::Radio:
        case ElisaUtils::Track:
        case ElisaUtils::FileName:
        {
            const auto &trackUrl = std::get<2>(oneTrackUrl);
            auto newEntry = MediaPlayListEntry(trackUrl);
            newEntry.mEntryType = databaseIdType;
            d->mData.push_back(newEntry);
354
355
            if (trackUrl.isValid()) {
                if (trackUrl.isLocalFile()) {
356
                    d->mTrackData.push_back({{DataTypes::ColumnsRoles::ResourceRole, trackUrl}});
357
                    auto entryString =  trackUrl.toLocalFile();
358
359
360
361
362
363
364
                    QFileInfo newTrackFile(entryString);
                    if (newTrackFile.exists()) {
                        d->mData.last().mIsValid = true;
                    }
                } else {
                    d->mTrackData.push_back({{DataTypes::ColumnsRoles::ResourceRole, trackUrl},
                                             {DataTypes::ColumnsRoles::TitleRole, trackUrl.fileName()}});
365
366
                    d->mData.last().mIsValid = true;
                }
367
                Q_EMIT newUrlInList(trackUrl, newEntry.mEntryType);
368
369
            } else {
                d->mTrackData.push_back({});
370
            }
371
372
373
374
375
376
377
378
379
            break;
        }
        case ElisaUtils::Album:
        case ElisaUtils::Artist:
        case ElisaUtils::Genre:
        case ElisaUtils::Lyricist:
        case ElisaUtils::Composer:
        case ElisaUtils::Unknown:
            break;
380
381
382
        }
    }
    endInsertRows();
383
384
}

385
void MediaPlayList::enqueueOneEntry(const DataTypes::EntryData &entryData, ElisaUtils::PlayListEntryType type)
Alexander Stippich's avatar
Alexander Stippich committed
386
{
387
    qCDebug(orgKdeElisaPlayList()) << "MediaPlayList::enqueueOneEntry" << std::get<0>(entryData) << std::get<1>(entryData) << type;
388

389
390
391
    if (!std::get<0>(entryData).isEmpty() || !std::get<1>(entryData).isEmpty()) {
        beginInsertRows(QModelIndex(), d->mData.size(), d->mData.size());
        d->mData.push_back(MediaPlayListEntry{std::get<0>(entryData).databaseId(), std::get<1>(entryData), type});
392
393
394
395
396
397
398
399
400
401
        const auto &data = std::get<0>(entryData);
        switch (data.elementType())
        {
        case ElisaUtils::Track:
        case ElisaUtils::Radio:
            d->mTrackData.push_back(static_cast<const DataTypes::TrackDataType&>(data));
            break;
        default:
            d->mTrackData.push_back({});
        }
402
403
404
        Q_EMIT newEntryInList(std::get<0>(entryData).databaseId(), std::get<1>(entryData), type);
        endInsertRows();
    }
405
406
}

407
void MediaPlayList::enqueueMultipleEntries(const DataTypes::EntryDataList &entriesData, ElisaUtils::PlayListEntryType type)
408
{
409
    qCDebug(orgKdeElisaPlayList()) << "MediaPlayList::enqueueMultipleEntries" << entriesData.size() << type;
410

411
412
    beginInsertRows(QModelIndex(), d->mData.size(), d->mData.size() + entriesData.size() - 1);
    for (const auto &entryData : entriesData) {
413
        if (!std::get<0>(entryData).databaseId() && std::get<2>(entryData).isValid()) {
414
            d->mData.push_back(MediaPlayListEntry{std::get<2>(entryData)});
415
            d->mTrackData.push_back({});
416
        } else {
417
            d->mData.push_back(MediaPlayListEntry{std::get<0>(entryData).databaseId(), std::get<1>(entryData), type});
418
419
420
421
422
423
424
425
426
427
428
429
430
431
            const auto &data = std::get<0>(entryData);
            switch (data.elementType())
            {
            case ElisaUtils::Track:
            case ElisaUtils::Radio:
                d->mTrackData.push_back(static_cast<const DataTypes::TrackDataType&>(data));
                break;
            default:
                d->mTrackData.push_back({});
            }
        }
        if (std::get<2>(entryData).isValid()) {
            Q_EMIT newUrlInList(std::get<2>(entryData), type);
        } else {
432
            Q_EMIT newEntryInList(std::get<0>(entryData).databaseId(), std::get<1>(entryData), type);
433
        }
Alexander Stippich's avatar
Alexander Stippich committed
434
    }
435
    endInsertRows();
Alexander Stippich's avatar
Alexander Stippich committed
436
437
}

438
void MediaPlayList::clearPlayList()
439
{
440
441
442
443
    if (d->mData.isEmpty()) {
        return;
    }

444
    beginRemoveRows({}, 0, d->mData.count() - 1);
445
    d->mData.clear();
446
    d->mTrackData.clear();
447
    endRemoveRows();
448
449
}

450
QVariantList MediaPlayList::getEntriesForRestore() const
451
{
452
    QVariantList result;
453

454
    for (int trackIndex = 0; trackIndex < d->mData.size(); ++trackIndex) {
455
        QStringList oneData;
456
457
458
        const auto &oneEntry = d->mData[trackIndex];
        if (oneEntry.mIsValid) {
            const auto &oneTrack = d->mTrackData[trackIndex];
459

Jerome Guidon's avatar
Jerome Guidon committed
460
            oneData.push_back(QString::number(oneTrack.databaseId()));
461
            oneData.push_back(oneTrack.title());
462
            oneData.push_back(oneTrack.artist());
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
            if (oneTrack.hasAlbum()) {
                oneData.push_back(oneTrack.album());
            } else {
                oneData.push_back({});
            }
            if (oneTrack.hasTrackNumber()) {
                oneData.push_back(QString::number(oneTrack.trackNumber()));
            } else {
                oneData.push_back({});
            }
            if (oneTrack.hasDiscNumber()) {
                oneData.push_back(QString::number(oneTrack.discNumber()));
            } else {
                oneData.push_back({});
            }
478
            oneData.push_back(QString::number(oneEntry.mEntryType));
479

480
481
            result.push_back(QVariant(oneData));
        }
482
    }
483
    return result;
484
485
}

486
487
488
489
void MediaPlayList::tracksListAdded(qulonglong newDatabaseId,
                                    const QString &entryTitle,
                                    ElisaUtils::PlayListEntryType databaseIdType,
                                    const ListTrackDataType &tracks)
490
{
491
    if (tracks.isEmpty()) {
492
        qCDebug(orgKdeElisaPlayList()) << "MediaPlayList::tracksListAdded" << " empty tracks list";
493
494
495
        return;
    }

496
497
    for (int playListIndex = 0; playListIndex < d->mData.size(); ++playListIndex) {
        auto &oneEntry = d->mData[playListIndex];
498
499
500
501
502
        if (oneEntry.mEntryType != databaseIdType) {
            continue;
        }

        if (oneEntry.mTitle != entryTitle) {
503
504
            continue;
        }
505

506
        if (newDatabaseId != 0 && oneEntry.mId != newDatabaseId) {
507
            continue;
508
509
        }

510
511
512
513
        beginRemoveRows(QModelIndex(),playListIndex,playListIndex);
        d->mData.removeAt(playListIndex);
        d->mTrackData.removeAt(playListIndex);
        endRemoveRows();
514

515
516
517
518
519
520
        beginInsertRows(QModelIndex(), playListIndex, playListIndex - 1 + tracks.size());
        for (int trackIndex = 0; trackIndex < tracks.size(); ++trackIndex) {
            auto newEntry = MediaPlayListEntry{tracks[trackIndex]};
            newEntry.mEntryType = ElisaUtils::Track;
            d->mData.insert(playListIndex + trackIndex, newEntry);
            d->mTrackData.insert(playListIndex + trackIndex, tracks[trackIndex]);
521
        }
522
        endInsertRows();
523
524
525
    }
}

526
void MediaPlayList::trackChanged(const TrackDataType &track)
527
{
Matthieu Gallien's avatar
Matthieu Gallien committed
528
529
    qCDebug(orgKdeElisaPlayList()) << "MediaPlayList::trackChanged" << track[DataTypes::TitleRole];

530
531
532
    for (int i = 0; i < d->mData.size(); ++i) {
        auto &oneEntry = d->mData[i];

533
        if (oneEntry.mEntryType != ElisaUtils::Artist && oneEntry.mIsValid) {
534
            if (oneEntry.mTrackUrl.toUrl().isValid() && track.resourceURI() != oneEntry.mTrackUrl.toUrl()) {
535
536
537
                continue;
            }

538
            if (!oneEntry.mTrackUrl.toUrl().isValid() && (oneEntry.mId == 0 || track.databaseId() != oneEntry.mId)) {
539
540
541
                continue;
            }

542
            const auto &trackData = d->mTrackData[i];
543

544
545
            if (!trackData.empty()) {
                bool sameData = true;
546
547
                for (auto oneKeyIterator = track.constKeyValueBegin(); oneKeyIterator != track.constKeyValueEnd(); ++oneKeyIterator) {
                    if (trackData[(*oneKeyIterator).first] != (*oneKeyIterator).second) {
548
549
550
551
552
553
                        sameData = false;
                        break;
                    }
                }
                if (sameData) {
                    continue;
554
                }
555
            }
556
557
558
559

            d->mTrackData[i] = track;

            Q_EMIT dataChanged(index(i, 0), index(i, 0), {});
560
            continue;
Jerome Guidon's avatar
Jerome Guidon committed
561
562
563
564
565
566
567
568
569
570
571
572
        } else if (oneEntry.mEntryType == ElisaUtils::Radio ) {
            if (track.databaseId() != oneEntry.mId) {
                continue;
            }

            d->mTrackData[i] = track;
            oneEntry.mId = track.databaseId();
            oneEntry.mIsValid = true;

            Q_EMIT dataChanged(index(i, 0), index(i, 0), {});

            break;
573
        } else if (oneEntry.mEntryType != ElisaUtils::Artist && !oneEntry.mIsValid && !oneEntry.mTrackUrl.isValid()) {
574
575
            if (track.find(TrackDataType::key_type::TitleRole) != track.end() &&
                    track.title() != oneEntry.mTitle) {
576
577
578
                continue;
            }

579
580
            if (track.find(TrackDataType::key_type::AlbumRole) != track.end() &&
                    track.album() != oneEntry.mAlbum) {
581
582
583
                continue;
            }

584
585
            if (track.find(TrackDataType::key_type::TrackNumberRole) != track.end() &&
                    track.trackNumber() != oneEntry.mTrackNumber) {
586
587
588
                continue;
            }

589
590
            if (track.find(TrackDataType::key_type::DiscNumberRole) != track.end() &&
                    track.discNumber() != oneEntry.mDiscNumber) {
591
592
593
594
595
                continue;
            }

            d->mTrackData[i] = track;
            oneEntry.mId = track.databaseId();
596
            oneEntry.mIsValid = true;
597

598
            Q_EMIT dataChanged(index(i, 0), index(i, 0), {});
599

600
            break;
601
        } else if (oneEntry.mEntryType != ElisaUtils::Artist && !oneEntry.mIsValid && oneEntry.mTrackUrl.isValid()) {
602
603
604
605
606
607
608
609
610
            if (track.resourceURI() != oneEntry.mTrackUrl) {
                continue;
            }

            d->mTrackData[i] = track;
            oneEntry.mId = track.databaseId();
            oneEntry.mIsValid = true;

            Q_EMIT dataChanged(index(i, 0), index(i, 0), {});
611
            break;
612
        }
613
614
615
    }
}

616
void MediaPlayList::trackRemoved(qulonglong trackId)
617
618
619
620
621
{
    for (int i = 0; i < d->mData.size(); ++i) {
        auto &oneEntry = d->mData[i];

        if (oneEntry.mIsValid) {
622
            if (oneEntry.mId == trackId) {
623
                oneEntry.mIsValid = false;
624
                oneEntry.mTitle = d->mTrackData[i].title();
625
                oneEntry.mArtist = d->mTrackData[i].artist();
626
                oneEntry.mAlbum = d->mTrackData[i].album();
627
                oneEntry.mTrackNumber = d->mTrackData[i].trackNumber();
628
                oneEntry.mDiscNumber = d->mTrackData[i].discNumber();
629
630

                Q_EMIT dataChanged(index(i, 0), index(i, 0), {});
631
632
633
634
635
636

            }
        }
    }
}

637
void MediaPlayList::trackInError(const QUrl &sourceInError, QMediaPlayer::Error playerError)
638
639
640
641
642
643
644
645
{
    Q_UNUSED(playerError)

    for (int i = 0; i < d->mData.size(); ++i) {
        auto &oneTrack = d->mData[i];
        if (oneTrack.mIsValid) {
            const auto &oneTrackData = d->mTrackData.at(i);

646
            if (oneTrackData.resourceURI() == sourceInError) {
647
648
                oneTrack.mIsValid = false;
                Q_EMIT dataChanged(index(i, 0), index(i, 0), {ColumnsRoles::IsValidRole});
649
            }
650
651
652
653
        }
    }
}

654
QDebug operator<<(const QDebug &stream, const MediaPlayListEntry &data)
655
656
657
658
{
    stream << data.mTitle << data.mAlbum << data.mArtist << data.mTrackUrl << data.mTrackNumber << data.mDiscNumber << data.mId << data.mIsValid;
    return stream;
}
659

660
#include "moc_mediaplaylist.cpp"