Commit a3eb443d authored by Matthieu Gallien's avatar Matthieu Gallien 🎵
Browse files

fix restore of tracks with missing metadata in playlist

Summary:
fix storing of tracks without track, disc, ...

correctly store a null when track, disc, channels, bit rate, sample rate
are not existing in the track data

will need a complete reindexing to fix users database

let play list and audio player restore state when track has few metadata

when album, track number or disc number are missing, the state is not
correctly restored at startup

let those metadata be optional in the saved state such that tracks
missing those are still restored

Test Plan: new test is OK and a track without album, track and disc numbers will restore and playback will restore at correct position

Reviewers: #elisa, astippich

Reviewed By: astippich

Subscribers: astippich, #elisa

Tags: #elisa

Differential Revision: https://phabricator.kde.org/D21900
parent 69168dab
......@@ -4958,6 +4958,155 @@ private Q_SLOTS:
QCOMPARE(musicDbTrackModifiedSpy.count(), 0);
QCOMPARE(musicDbDatabaseErrorSpy.count(), 0);
}
void enqueueTracksWithMissingMetadata()
{
QTemporaryFile databaseFile;
databaseFile.open();
qDebug() << "enqueueTracksWithMissingMetadata" << databaseFile.fileName();
DatabaseInterface musicDb;
musicDb.init(QStringLiteral("enqueueTracksWithMissingMetadata"), databaseFile.fileName());
QSignalSpy musicDbArtistAddedSpy(&musicDb, &DatabaseInterface::artistsAdded);
QSignalSpy musicDbAlbumAddedSpy(&musicDb, &DatabaseInterface::albumsAdded);
QSignalSpy musicDbTrackAddedSpy(&musicDb, &DatabaseInterface::tracksAdded);
QSignalSpy musicDbArtistRemovedSpy(&musicDb, &DatabaseInterface::artistRemoved);
QSignalSpy musicDbAlbumRemovedSpy(&musicDb, &DatabaseInterface::albumRemoved);
QSignalSpy musicDbTrackRemovedSpy(&musicDb, &DatabaseInterface::trackRemoved);
QSignalSpy musicDbAlbumModifiedSpy(&musicDb, &DatabaseInterface::albumModified);
QSignalSpy musicDbTrackModifiedSpy(&musicDb, &DatabaseInterface::trackModified);
QSignalSpy musicDbDatabaseErrorSpy(&musicDb, &DatabaseInterface::databaseError);
QCOMPARE(musicDb.allAlbumsData().count(), 0);
QCOMPARE(musicDb.allArtistsData().count(), 0);
QCOMPARE(musicDb.allTracksData().count(), 0);
QCOMPARE(musicDbArtistAddedSpy.count(), 0);
QCOMPARE(musicDbAlbumAddedSpy.count(), 0);
QCOMPARE(musicDbTrackAddedSpy.count(), 0);
QCOMPARE(musicDbArtistRemovedSpy.count(), 0);
QCOMPARE(musicDbAlbumRemovedSpy.count(), 0);
QCOMPARE(musicDbTrackRemovedSpy.count(), 0);
QCOMPARE(musicDbAlbumModifiedSpy.count(), 0);
QCOMPARE(musicDbTrackModifiedSpy.count(), 0);
QCOMPARE(musicDbDatabaseErrorSpy.count(), 0);
auto fullTrack = MusicAudioTrack{true, QStringLiteral("$23"), QStringLiteral("0"), QStringLiteral("track6"),
QStringLiteral("artist2"), QStringLiteral("album3"), QStringLiteral("artist2"),
6, 1, QTime::fromMSecsSinceStartOfDay(23), {QUrl::fromLocalFile(QStringLiteral("/test/$23"))},
QDateTime::fromMSecsSinceEpoch(23),
QUrl::fromLocalFile(QStringLiteral("album3")), 5, true,
QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false};
fullTrack.setBitRate(154);
fullTrack.setChannels(2);
fullTrack.setSampleRate(48000);
auto newTrack = MusicAudioTrack{};
newTrack.setValid(true);
newTrack.setId(QStringLiteral("$29"));
newTrack.setParentId(QStringLiteral("0"));
newTrack.setTitle(QStringLiteral("track19"));
newTrack.setArtist(QStringLiteral("artist2"));
newTrack.setDuration(QTime::fromMSecsSinceStartOfDay(29));
newTrack.setResourceURI(QUrl::fromLocalFile(QStringLiteral("/$29")));
newTrack.setFileModificationTime(QDateTime::fromMSecsSinceEpoch(29));
newTrack.setAlbumCover(QUrl::fromLocalFile(QStringLiteral("/withoutAlbum")));
newTrack.setRating(9);
newTrack.setIsSingleDiscAlbum(true);
newTrack.setGenre(QStringLiteral("genre1"));
newTrack.setComposer(QStringLiteral("composer1"));
newTrack.setLyricist(QStringLiteral("lyricist1"));
newTrack.setHasEmbeddedCover(false);
musicDb.insertTracksList({fullTrack, newTrack}, mNewCovers);
QCOMPARE(musicDb.allAlbumsData().count(), 1);
QCOMPARE(musicDb.allArtistsData().count(), 1);
QCOMPARE(musicDb.allTracksData().count(), 2);
QCOMPARE(musicDbArtistAddedSpy.count(), 1);
QCOMPARE(musicDbAlbumAddedSpy.count(), 1);
QCOMPARE(musicDbTrackAddedSpy.count(), 1);
QCOMPARE(musicDbArtistRemovedSpy.count(), 0);
QCOMPARE(musicDbAlbumRemovedSpy.count(), 0);
QCOMPARE(musicDbTrackRemovedSpy.count(), 0);
QCOMPARE(musicDbAlbumModifiedSpy.count(), 0);
QCOMPARE(musicDbTrackModifiedSpy.count(), 0);
QCOMPARE(musicDbDatabaseErrorSpy.count(), 0);
auto firstTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track6"), QStringLiteral("artist2"),
QStringLiteral("album3"), 6, 1);
auto firstTrack = musicDb.trackDataFromDatabaseId(firstTrackId);
auto firstTrackTitle = firstTrack.title();
auto firstTrackArtist = firstTrack.artist();
auto firstTrackAlbumArtist = firstTrack.albumArtist();
auto firstTrackAlbum = firstTrack.album();
auto firstTrackImage = firstTrack.albumCover();
auto firstTrackDuration = firstTrack.duration();
auto firstTrackMilliSecondsDuration = firstTrack.duration().msecsSinceStartOfDay();
auto firstTrackTrackNumber = firstTrack.trackNumber();
auto firstTrackDiscNumber = firstTrack.discNumber();
const auto &firstTrackResource = firstTrack.resourceURI();
auto firstTrackRating = firstTrack.rating();
auto firstIsSingleDiscAlbum = firstTrack.isSingleDiscAlbum();
QCOMPARE(firstTrack.isValid(), true);
QCOMPARE(firstTrackTitle, QStringLiteral("track6"));
QCOMPARE(firstTrackArtist, QStringLiteral("artist2"));
QCOMPARE(firstTrackAlbumArtist, QStringLiteral("artist2"));
QCOMPARE(firstTrackAlbum, QStringLiteral("album3"));
QCOMPARE(firstTrackImage.isValid(), true);
QCOMPARE(firstTrackImage, QUrl::fromLocalFile(QStringLiteral("album3")));
QCOMPARE(firstTrackDuration, QTime::fromMSecsSinceStartOfDay(23));
QCOMPARE(firstTrackMilliSecondsDuration, 23);
QCOMPARE(firstTrackTrackNumber, 6);
QCOMPARE(firstTrackDiscNumber, 1);
QCOMPARE(firstTrackResource.isValid(), true);
QCOMPARE(firstTrackResource, QUrl::fromLocalFile(QStringLiteral("/test/$23")));
QCOMPARE(firstTrackRating, 5);
QCOMPARE(firstIsSingleDiscAlbum, true);
auto secondTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track19"), QStringLiteral("artist2"), {}, {}, {});
auto secondTrack = musicDb.trackDataFromDatabaseId(secondTrackId);
auto secondTrackTitle = secondTrack.title();
auto secondTrackArtist = secondTrack.artist();
auto secondTrackAlbumArtist = secondTrack.albumArtist();
auto secondTrackAlbum = secondTrack.album();
auto secondTrackImage = secondTrack.albumCover();
auto secondTrackDuration = secondTrack.duration();
auto secondTrackMilliSecondsDuration = secondTrack.duration().msecsSinceStartOfDay();
auto secondTrackTrackNumber = secondTrack.trackNumber();
auto secondTrackDiscNumber = secondTrack.discNumber();
auto secondTrackChannels = secondTrack.channels();
auto secondTrackBitRate = secondTrack.bitRate();
auto secondTrackSampleRate = secondTrack.sampleRate();
const auto &secondTrackResource = secondTrack.resourceURI();
auto secondTrackRating = secondTrack.rating();
auto secondIsSingleDiscAlbum = secondTrack.isSingleDiscAlbum();
QCOMPARE(secondTrack.isValid(), true);
QCOMPARE(secondTrackTitle, QStringLiteral("track19"));
QCOMPARE(secondTrackArtist, QStringLiteral("artist2"));
QCOMPARE(secondTrackAlbumArtist, QString());
QCOMPARE(secondTrackAlbum, QString());
QCOMPARE(secondTrackImage.isValid(), false);
QCOMPARE(secondTrackDuration, QTime::fromMSecsSinceStartOfDay(29));
QCOMPARE(secondTrackMilliSecondsDuration, 29);
QCOMPARE(secondTrackTrackNumber, 0);
QCOMPARE(secondTrackDiscNumber, 0);
QCOMPARE(secondTrackChannels, 0);
QCOMPARE(secondTrackBitRate, 0);
QCOMPARE(secondTrackSampleRate, 0);
QCOMPARE(secondTrackResource.isValid(), true);
QCOMPARE(secondTrackResource, QUrl::fromLocalFile(QStringLiteral("/$29")));
QCOMPARE(secondTrackRating, 9);
QCOMPARE(secondIsSingleDiscAlbum, true);
}
};
QTEST_GUILESS_MAIN(DatabaseInterfaceTests)
......
......@@ -2918,6 +2918,140 @@ void MediaPlayListTest::restoreMultipleIdenticalTracks()
QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 3);
}
void MediaPlayListTest::restoreTrackWithoutAlbum()
{
QTemporaryFile databaseFile;
databaseFile.open();
qDebug() << "restoreTrackWithoutAlbum" << databaseFile.fileName();
MediaPlayList myPlayList;
QAbstractItemModelTester testModel(&myPlayList);
DatabaseInterface myDatabaseContent;
TracksListener myListener(&myDatabaseContent);
QSignalSpy rowsAboutToBeMovedSpy(&myPlayList, &MediaPlayList::rowsAboutToBeMoved);
QSignalSpy rowsAboutToBeRemovedSpy(&myPlayList, &MediaPlayList::rowsAboutToBeRemoved);
QSignalSpy rowsAboutToBeInsertedSpy(&myPlayList, &MediaPlayList::rowsAboutToBeInserted);
QSignalSpy rowsMovedSpy(&myPlayList, &MediaPlayList::rowsMoved);
QSignalSpy rowsRemovedSpy(&myPlayList, &MediaPlayList::rowsRemoved);
QSignalSpy rowsInsertedSpy(&myPlayList, &MediaPlayList::rowsInserted);
QSignalSpy persistentStateChangedSpy(&myPlayList, &MediaPlayList::persistentStateChanged);
QSignalSpy dataChangedSpy(&myPlayList, &MediaPlayList::dataChanged);
QSignalSpy newTrackByNameInListSpy(&myPlayList, &MediaPlayList::newTrackByNameInList);
QSignalSpy newEntryInListSpy(&myPlayList, &MediaPlayList::newEntryInList);
QCOMPARE(rowsAboutToBeRemovedSpy.count(), 0);
QCOMPARE(rowsAboutToBeMovedSpy.count(), 0);
QCOMPARE(rowsAboutToBeInsertedSpy.count(), 0);
QCOMPARE(rowsRemovedSpy.count(), 0);
QCOMPARE(rowsMovedSpy.count(), 0);
QCOMPARE(rowsInsertedSpy.count(), 0);
QCOMPARE(persistentStateChangedSpy.count(), 0);
QCOMPARE(dataChangedSpy.count(), 0);
QCOMPARE(newTrackByNameInListSpy.count(), 0);
QCOMPARE(newEntryInListSpy.count(), 0);
myDatabaseContent.init(QStringLiteral("restoreTrackWithoutAlbum"), databaseFile.fileName());
connect(&myListener, &TracksListener::trackHasChanged,
&myPlayList, &MediaPlayList::trackChanged,
Qt::QueuedConnection);
connect(&myListener, &TracksListener::tracksListAdded,
&myPlayList, &MediaPlayList::tracksListAdded,
Qt::QueuedConnection);
connect(&myPlayList, &MediaPlayList::newTrackByNameInList,
&myListener, &TracksListener::trackByNameInList,
Qt::QueuedConnection);
connect(&myPlayList, &MediaPlayList::newEntryInList,
&myListener, &TracksListener::newEntryInList,
Qt::QueuedConnection);
connect(&myDatabaseContent, &DatabaseInterface::tracksAdded,
&myListener, &TracksListener::tracksAdded);
myDatabaseContent.insertTracksList(mNewTracks, mNewCovers);
QCOMPARE(rowsAboutToBeRemovedSpy.count(), 0);
QCOMPARE(rowsAboutToBeMovedSpy.count(), 0);
QCOMPARE(rowsAboutToBeInsertedSpy.count(), 0);
QCOMPARE(rowsRemovedSpy.count(), 0);
QCOMPARE(rowsMovedSpy.count(), 0);
QCOMPARE(rowsInsertedSpy.count(), 0);
QCOMPARE(persistentStateChangedSpy.count(), 0);
QCOMPARE(dataChangedSpy.count(), 0);
QCOMPARE(newTrackByNameInListSpy.count(), 0);
QCOMPARE(newEntryInListSpy.count(), 0);
auto newTrack = MusicAudioTrack{};
newTrack.setValid(true);
newTrack.setId(QStringLiteral("$29"));
newTrack.setParentId(QStringLiteral("0"));
newTrack.setTitle(QStringLiteral("track19"));
newTrack.setArtist(QStringLiteral("artist2"));
newTrack.setDuration(QTime::fromMSecsSinceStartOfDay(29));
newTrack.setResourceURI(QUrl::fromLocalFile(QStringLiteral("/$29")));
newTrack.setFileModificationTime(QDateTime::fromMSecsSinceEpoch(29));
newTrack.setAlbumCover(QUrl::fromLocalFile(QStringLiteral("withoutAlbum")));
newTrack.setRating(9);
newTrack.setIsSingleDiscAlbum(true);
newTrack.setGenre(QStringLiteral("genre1"));
newTrack.setComposer(QStringLiteral("composer1"));
newTrack.setLyricist(QStringLiteral("lyricist1"));
newTrack.setHasEmbeddedCover(false);
myDatabaseContent.insertTracksList({newTrack}, mNewCovers);
QCOMPARE(rowsAboutToBeRemovedSpy.count(), 0);
QCOMPARE(rowsAboutToBeMovedSpy.count(), 0);
QCOMPARE(rowsAboutToBeInsertedSpy.count(), 0);
QCOMPARE(rowsRemovedSpy.count(), 0);
QCOMPARE(rowsMovedSpy.count(), 0);
QCOMPARE(rowsInsertedSpy.count(), 0);
QCOMPARE(persistentStateChangedSpy.count(), 0);
QCOMPARE(dataChangedSpy.count(), 0);
QCOMPARE(newTrackByNameInListSpy.count(), 0);
QCOMPARE(newEntryInListSpy.count(), 0);
auto newEntry = MediaPlayListEntry{};
newEntry.mTitle = QStringLiteral("track19");
newEntry.mArtist = QStringLiteral("artist2");
myPlayList.enqueueRestoredEntry(newEntry);
QCOMPARE(rowsAboutToBeRemovedSpy.count(), 0);
QCOMPARE(rowsAboutToBeMovedSpy.count(), 0);
QCOMPARE(rowsAboutToBeInsertedSpy.count(), 1);
QCOMPARE(rowsRemovedSpy.count(), 0);
QCOMPARE(rowsMovedSpy.count(), 0);
QCOMPARE(rowsInsertedSpy.count(), 1);
QCOMPARE(persistentStateChangedSpy.count(), 1);
QCOMPARE(dataChangedSpy.count(), 1);
QCOMPARE(newTrackByNameInListSpy.count(), 1);
QCOMPARE(newEntryInListSpy.count(), 0);
QCOMPARE(dataChangedSpy.wait(), true);
QCOMPARE(rowsAboutToBeRemovedSpy.count(), 0);
QCOMPARE(rowsAboutToBeMovedSpy.count(), 0);
QCOMPARE(rowsAboutToBeInsertedSpy.count(), 1);
QCOMPARE(rowsRemovedSpy.count(), 0);
QCOMPARE(rowsMovedSpy.count(), 0);
QCOMPARE(rowsInsertedSpy.count(), 1);
QCOMPARE(persistentStateChangedSpy.count(), 1);
QCOMPARE(dataChangedSpy.count(), 2);
QCOMPARE(newTrackByNameInListSpy.count(), 1);
QCOMPARE(newEntryInListSpy.count(), 0);
QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::TitleRole).toString(), QStringLiteral("track19"));
QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::AlbumRole).toString(), {});
QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::ArtistRole).toString(), QStringLiteral("artist2"));
QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::TrackNumberRole).toInt(), 0);
QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::DiscNumberRole).toInt(), 0);
QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 29);
}
void MediaPlayListTest::testHasHeaderAlbumWithSameTitle()
{
MediaPlayList myPlayList;
......
......@@ -73,6 +73,8 @@ private Q_SLOTS:
void restoreMultipleIdenticalTracks();
void restoreTrackWithoutAlbum();
void testHasHeaderAlbumWithSameTitle();
void testSavePersistentState();
......
......@@ -702,8 +702,8 @@ DatabaseInterface::TrackDataType DatabaseInterface::trackDataFromDatabaseId(qulo
return result;
}
qulonglong DatabaseInterface::trackIdFromTitleAlbumTrackDiscNumber(const QString &title, const QString &artist, const QString &album,
int trackNumber, int discNumber)
qulonglong DatabaseInterface::trackIdFromTitleAlbumTrackDiscNumber(const QString &title, const QString &artist, const std::optional<QString> &album,
std::optional<int> trackNumber, std::optional<int> discNumber)
{
auto result = qulonglong(0);
......@@ -4770,9 +4770,9 @@ void DatabaseInterface::initRequest()
"`Tracks` tracks "
"WHERE "
"tracks.`Title` = :title AND "
"tracks.`AlbumTitle` = :album AND "
"tracks.`TrackNumber` = :trackNumber AND "
"tracks.`DiscNumber` = :discNumber AND "
"(tracks.`AlbumTitle` = :album OR (:album IS NULL AND tracks.`AlbumTitle` IS NULL)) AND "
"(tracks.`TrackNumber` = :trackNumber OR (:trackNumber IS NULL AND tracks.`TrackNumber` IS NULL)) AND "
"(tracks.`DiscNumber` = :discNumber OR (:discNumber IS NULL AND tracks.`DiscNumber` IS NULL)) AND "
"tracks.`ArtistName` = :artist");
auto result = prepareQuery(d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery, selectTrackQueryText);
......@@ -5632,9 +5632,13 @@ qulonglong DatabaseInterface::internalInsertTrack(const MusicAudioTrack &oneTrac
d->mInsertTrackQuery.bindValue(QStringLiteral(":albumPath"), trackPath);
if (oneTrack.trackNumberIsValid()) {
d->mInsertTrackQuery.bindValue(QStringLiteral(":trackNumber"), oneTrack.trackNumber());
} else {
d->mInsertTrackQuery.bindValue(QStringLiteral(":trackNumber"), {});
}
if (oneTrack.discNumberIsValid()) {
d->mInsertTrackQuery.bindValue(QStringLiteral(":discNumber"), oneTrack.discNumber());
} else {
d->mInsertTrackQuery.bindValue(QStringLiteral(":discNumber"), {});
}
d->mInsertTrackQuery.bindValue(QStringLiteral(":trackDuration"), QVariant::fromValue<qlonglong>(oneTrack.duration().msecsSinceStartOfDay()));
d->mInsertTrackQuery.bindValue(QStringLiteral(":trackRating"), oneTrack.rating());
......@@ -5657,12 +5661,18 @@ qulonglong DatabaseInterface::internalInsertTrack(const MusicAudioTrack &oneTrac
d->mInsertTrackQuery.bindValue(QStringLiteral(":year"), oneTrack.year());
if (oneTrack.channelsIsValid()) {
d->mInsertTrackQuery.bindValue(QStringLiteral(":channels"), oneTrack.channels());
} else {
d->mInsertTrackQuery.bindValue(QStringLiteral(":channels"), {});
}
if (oneTrack.bitRateIsValid()) {
d->mInsertTrackQuery.bindValue(QStringLiteral(":bitRate"), oneTrack.bitRate());
} else {
d->mInsertTrackQuery.bindValue(QStringLiteral(":bitRate"), {});
}
if (oneTrack.sampleRateIsValid()) {
d->mInsertTrackQuery.bindValue(QStringLiteral(":sampleRate"), oneTrack.sampleRate());
} else {
d->mInsertTrackQuery.bindValue(QStringLiteral(":sampleRate"), {});
}
d->mInsertTrackQuery.bindValue(QStringLiteral(":hasEmbeddedCover"), oneTrack.hasEmbeddedCover());
......@@ -6455,8 +6465,8 @@ MusicAudioTrack DatabaseInterface::internalTrackFromDatabaseId(qulonglong id)
return result;
}
qulonglong DatabaseInterface::internalTrackIdFromTitleAlbumTracDiscNumber(const QString &title, const QString &artist, const QString &album,
int trackNumber, int discNumber)
qulonglong DatabaseInterface::internalTrackIdFromTitleAlbumTracDiscNumber(const QString &title, const QString &artist, const std::optional<QString> &album,
std::optional<int> trackNumber, std::optional<int> discNumber)
{
auto result = qulonglong(0);
......@@ -6466,9 +6476,21 @@ qulonglong DatabaseInterface::internalTrackIdFromTitleAlbumTracDiscNumber(const
d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery.bindValue(QStringLiteral(":title"), title);
d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery.bindValue(QStringLiteral(":artist"), artist);
d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery.bindValue(QStringLiteral(":album"), album);
d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery.bindValue(QStringLiteral(":trackNumber"), trackNumber);
d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery.bindValue(QStringLiteral(":discNumber"), discNumber);
if (album.has_value()) {
d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery.bindValue(QStringLiteral(":album"), album.value());
} else {
d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery.bindValue(QStringLiteral(":album"), {});
}
if (trackNumber.has_value()) {
d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery.bindValue(QStringLiteral(":trackNumber"), trackNumber.value());
} else {
d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery.bindValue(QStringLiteral(":trackNumber"), {});
}
if (discNumber.has_value()) {
d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery.bindValue(QStringLiteral(":discNumber"), discNumber.value());
} else {
d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery.bindValue(QStringLiteral(":discNumber"), {});
}
auto queryResult = execQuery(d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery);
......
......@@ -33,6 +33,7 @@
#include <QPair>
#include <memory>
#include <optional>
class DatabaseInterfacePrivate;
class QMutex;
......@@ -127,6 +128,11 @@ public:
return operator[](key_type::AlbumIdRole).toULongLong();
}
bool hasAlbum() const
{
return find(key_type::AlbumRole) != end();
}
QString album() const
{
return operator[](key_type::AlbumRole).toString();
......@@ -137,11 +143,21 @@ public:
return operator[](key_type::AlbumArtistRole).toString();
}
bool hasTrackNumber() const
{
return find(key_type::TrackNumberRole) != end();
}
int trackNumber() const
{
return operator[](key_type::TrackNumberRole).toInt();
}
bool hasDiscNumber() const
{
return find(key_type::DiscNumberRole) != end();
}
int discNumber() const
{
return operator[](key_type::DiscNumberRole).toInt();
......@@ -367,8 +383,8 @@ public:
TrackDataType trackDataFromDatabaseId(qulonglong id);
qulonglong trackIdFromTitleAlbumTrackDiscNumber(const QString &title, const QString &artist, const QString &album,
int trackNumber, int discNumber);
qulonglong trackIdFromTitleAlbumTrackDiscNumber(const QString &title, const QString &artist, const std::optional<QString> &album,
std::optional<int> trackNumber, std::optional<int> discNumber);
qulonglong trackIdFromFileName(const QUrl &fileName);
......@@ -447,8 +463,8 @@ private:
MusicAudioTrack internalTrackFromDatabaseId(qulonglong id);
qulonglong internalTrackIdFromTitleAlbumTracDiscNumber(const QString &title, const QString &artist, const QString &album,
int trackNumber, int discNumber);
qulonglong internalTrackIdFromTitleAlbumTracDiscNumber(const QString &title, const QString &artist, const std::optional<QString> &album,
std::optional<int> trackNumber, std::optional<int> discNumber);
qulonglong getDuplicateTrackIdFromTitleAlbumTrackDiscNumber(const QString &title, const QString &trackArtist, const QString &album,
const QString &albumArtist, const QString &trackPath, int trackNumber,
......
......@@ -557,8 +557,9 @@ void ManageAudioPlayer::restorePreviousState()
return;
}
if (*itTitle != mCurrentTrack.data(mTitleRole) || *itArtistName != mCurrentTrack.data(mArtistNameRole) ||
*itAlbumName != mCurrentTrack.data(mAlbumNameRole)) {
if (*itTitle != mCurrentTrack.data(mTitleRole) ||
(itArtistName->isValid() && *itArtistName != mCurrentTrack.data(mArtistNameRole)) ||
(itAlbumName->isValid() && *itAlbumName != mCurrentTrack.data(mAlbumNameRole))) {
if (mCurrentTrack.isValid() && mCurrentTrack.data(mTitleRole).isValid() && mCurrentTrack.data(mArtistNameRole).isValid() &&
mCurrentTrack.data(mAlbumNameRole).isValid()) {
mPersistentState.clear();
......
......@@ -146,7 +146,14 @@ QVariant MediaPlayList::data(const QModelIndex &index, int role) const
d->mTrackData[index.row()][TrackDataType::key_type::ImageUrlRole].toUrl().toString()}}.toJson();
break;
default:
result = d->mTrackData[index.row()][static_cast<TrackDataType::key_type>(role)];
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)
......@@ -338,11 +345,11 @@ void MediaPlayList::enqueueRestoredEntry(const MediaPlayListEntry &newEntry)
Q_EMIT newEntryInList(0, entryString, ElisaUtils::FileName);
}
} else {
Q_EMIT newTrackByNameInList(newEntry.mTitle.toString(),
newEntry.mArtist.toString(),
newEntry.mAlbum.toString(),
newEntry.mTrackNumber.toInt(),
newEntry.mDiscNumber.toInt());
Q_EMIT newTrackByNameInList(newEntry.mTitle,
newEntry.mArtist,
newEntry.mAlbum,
newEntry.mTrackNumber,
newEntry.mDiscNumber);
}
} else {
Q_EMIT newEntryInList(newEntry.mId, {}, ElisaUtils::Track);
......@@ -710,9 +717,21 @@ QVariantMap MediaPlayList::persistentState() const
oneData.push_back(oneTrack.title());
oneData.push_back(oneTrack.artist());
oneData.push_back(oneTrack.album());
oneData.push_back(QString::number(oneTrack.trackNumber()));
oneData.push_back(QString::number(oneTrack.discNumber()));
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({});
}
oneData.push_back(QString::number(oneEntry.mEntryType));
result.push_back(QVariant(oneData));
......@@ -778,10 +797,10 @@ void MediaPlayList::setPersistentState(const QVariantMap &persistentStateValue)
auto restoredTitle = trackData[0];
auto restoredArtist = trackData[1];
auto restoredAlbum = trackData[2];
auto restoredTrackNumber = trackData[3].toInt();
auto restoredDiscNumber = trackData[4].toInt();
auto restoredTrackNumber = trackData[3];
auto restoredDiscNumber = trackData[4];
ElisaUtils::PlayListEntryType mEntryType = static_cast<ElisaUtils::PlayListEntryType>(trackData[5].toInt());
auto mEntryType = static_cast<ElisaUtils::PlayListEntryType>(trackData[5].toInt());
enqueueRestoredEntry({restoredTitle, restoredArtist, restoredAlbum, restoredTrackNumber, restoredDiscNumber, mEntryType});
}
......@@ -893,19 +912,23 @@ void MediaPlayList::trackChanged(const TrackDataType &track)
}
continue;
} else if (oneEntry.mEntryType != ElisaUtils::Artist && !oneEntry.mIsValid && !oneEntry.mTrackUrl.isValid()) {
if (track.title() != oneEntry.mTitle) {
if (track.find(TrackDataType::key_type::TitleRole) != track.end() &&
track.title() != oneEntry.mTitle) {
continue;
}
if (track.album() != oneEntry.mAlbum) {
if (track.find(TrackDataType::key_type::AlbumRole) != track.end() &&
track.album() != oneEntry.mAlbum) {
continue;
}
if (track.trackNumber() != oneEntry.mTrackNumber) {
if (track.find(TrackDataType::key_type::TrackNumberRole) != track.end() &&
track.trackNumber() != oneEntry.mTrackNumber) {
continue;
}
if (track.discNumber() != oneEntry.mDiscNumber) {
if (track.find(TrackDataType::key_type::DiscNumberRole) != track.end() &&
track.discNumber() != oneEntry.mDiscNumber) {
continue;
}
......
......@@ -175,7 +175,7 @@ Q_SIGNALS:
void hideUndoInline();
void newTrackByNameInList(const QString &title, const QString &artist, const QString &album, int trackNumber, int discNumber);
void newTrackByNameInList(const QVariant &title, const QVariant &artist, const QVariant &album, const QVariant &trackNumber, const QVariant &discNumber);
void newEntryInList(qulonglong newDatabaseId,
const QString &entryTitle,
......@@ -319,6 +319,12 @@ public:
mTrackNumber(trackNumber), mDiscNumber(discNumber), mEntryType(entryType) {
}
MediaPlayListEntry(QVariant title, QVariant artist, QVariant album, QVariant trackNumber,
QVariant discNumber, ElisaUtils::PlayListEntryType entryType = ElisaUtils::Unknown)
: mTitle(std::move(title)), mAlbum(std::move(album)), mArtist(std::move(artist)),
mTrackNumber(std::move(trackNumber)), mDiscNumber(std::move(discNumber)), mEntryType(entryType) {
}
explicit MediaPlayListEntry(const MusicAudioTrack &track)
: mTitle(track.title()), mAlbum(track.albumName()), mTrackNumber(track.trackNumber()),
mDiscNumber(track.discNumber()), mId(track.databaseId