diff --git a/autotests/databaseinterfacetest.cpp b/autotests/databaseinterfacetest.cpp index ed14f5f0..d1114ddf 100644 --- a/autotests/databaseinterfacetest.cpp +++ b/autotests/databaseinterfacetest.cpp @@ -1,4815 +1,4828 @@ /* * Copyright 2015-2017 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "databasetestdata.h" #include "databaseinterface.h" #include "musicaudiotrack.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include class DatabaseInterfaceTests: public QObject, public DatabaseTestData { Q_OBJECT private: private Q_SLOTS: void initTestCase() { qRegisterMetaType>("QHash"); qRegisterMetaType>("QHash"); qRegisterMetaType>("QList"); qRegisterMetaType>("QVector"); qRegisterMetaType>("QHash"); qRegisterMetaType>("QHash"); qRegisterMetaType("ListTrackDataType"); qRegisterMetaType("ListAlbumDataType"); qRegisterMetaType("ListArtistDataType"); qRegisterMetaType("ListGenreDataType"); qRegisterMetaType("TrackDataType"); qRegisterMetaType("AlbumDataType"); qRegisterMetaType("ArtistDataType"); qRegisterMetaType("GenreDataType"); } void avoidCrashInTrackIdFromTitleAlbumArtist() { DatabaseInterface musicDb; musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track1"), QStringLiteral("artist1"), QStringLiteral("album3"), 1, 1); } void avoidCrashInAllArtists() { DatabaseInterface musicDb; musicDb.allArtistsData(); } void avoidCrashInallAlbumsData() { DatabaseInterface musicDb; musicDb.allAlbumsData(); } void addOneTrackWithoutAlbumArtist() { QTemporaryFile databaseFile; databaseFile.open(); qDebug() << "addOneTrackWithoutAlbumArtist" << databaseFile.fileName(); DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb"), 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 newTrack = MusicAudioTrack{true, QStringLiteral("$23"), QStringLiteral("0"), QStringLiteral("track6"), QStringLiteral("artist2"), QStringLiteral("album3"), {}, 6, 1, QTime::fromMSecsSinceStartOfDay(23), {QUrl::fromLocalFile(QStringLiteral("/$23"))}, QDateTime::fromMSecsSinceEpoch(23), {QUrl::fromLocalFile(QStringLiteral("album3"))}, 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}; auto newTracks = QList(); newTracks.push_back(newTrack); auto newCovers = mNewCovers; newCovers[QStringLiteral("file:///$23")] = QUrl::fromLocalFile(QStringLiteral("album3")); musicDb.insertTracksList(newTracks, newCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 1); QCOMPARE(musicDb.allArtistsData().count(), 1); QCOMPARE(musicDb.allTracksData().count(), 1); 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 track = musicDb.trackDataFromDatabaseId(musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track6"), QStringLiteral("artist2"), QStringLiteral("album3"), 6, 1)); QCOMPARE(track.isValid(), true); QCOMPARE(track.title(), QStringLiteral("track6")); QCOMPARE(track.artist(), QStringLiteral("artist2")); QCOMPARE(track.album(), QStringLiteral("album3")); QVERIFY(track.albumArtist().isEmpty()); QCOMPARE(track.albumCover(), QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(track.trackNumber(), 6); QCOMPARE(track.discNumber(), 1); QCOMPARE(track.duration(), QTime::fromMSecsSinceStartOfDay(23)); QCOMPARE(track.resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$23"))); QCOMPARE(track.rating(), 5); QCOMPARE(track.genre(), QStringLiteral("genre1")); QCOMPARE(track.composer(), QStringLiteral("composer1")); QCOMPARE(track.lyricist(), QStringLiteral("lyricist1")); auto albumId = musicDb.albumIdFromTitleAndArtist(QStringLiteral("album3"), QStringLiteral("artist2")); QVERIFY(albumId != 0); auto album = musicDb.albumDataFromDatabaseId(albumId); auto albumData = musicDb.albumData(albumId); QCOMPARE(album.isValid(), true); QCOMPARE(albumData.count(), 1); QCOMPARE(album.title(), QStringLiteral("album3")); QCOMPARE(album.artist(), {}); QCOMPARE(album.isValidArtist(), false); QCOMPARE(album.albumArtURI(), QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(album.isSingleDiscAlbum(), true); } void addAndRemoveOneTrackWithoutAlbum() { QTemporaryFile databaseFile; databaseFile.open(); qDebug() << "addAndRemoveOneTrackWithoutAlbum" << databaseFile.fileName(); DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb"), 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 newTrack = MusicAudioTrack {true, QStringLiteral("$24"), QStringLiteral("0"), QStringLiteral("track10"), QStringLiteral("artist8"), {}, QStringLiteral("artist8"), 9, 1, QTime::fromMSecsSinceStartOfDay(24), {QUrl::fromLocalFile(QStringLiteral("/$24"))}, QDateTime::fromMSecsSinceEpoch(24), {}, 9, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}; auto newTracks = QList(); newTracks.push_back(newTrack); auto newCovers = mNewCovers; newCovers[QStringLiteral("file:///$24")] = QUrl::fromLocalFile(QStringLiteral("album4")); musicDb.insertTracksList(newTracks, newCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 0); QCOMPARE(musicDb.allArtistsData().count(), 1); QCOMPARE(musicDb.allTracksData().count(), 1); QCOMPARE(musicDbArtistAddedSpy.count(), 1); QCOMPARE(musicDbAlbumAddedSpy.count(), 0); 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 trackId = musicDb.trackIdFromFileName(QUrl::fromLocalFile(QStringLiteral("/$24"))); QVERIFY(trackId != 0); auto track = musicDb.trackDataFromDatabaseId(trackId); QCOMPARE(track.isValid(), true); QCOMPARE(track.title(), QStringLiteral("track10")); QCOMPARE(track.artist(), QStringLiteral("artist8")); QCOMPARE(track.album(), QString()); QEXPECT_FAIL("","Album artist is currently associated with the album in the database. if the album is missing, we lose this information", Continue); QVERIFY(!track.albumArtist().isEmpty()); QCOMPARE(track.albumCover(), QUrl()); QCOMPARE(track.trackNumber(), 9); QCOMPARE(track.discNumber(), 1); QCOMPARE(track.duration(), QTime::fromMSecsSinceStartOfDay(24)); QCOMPARE(track.resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$24"))); QCOMPARE(track.rating(), 9); QCOMPARE(track.genre(), QStringLiteral("genre1")); QCOMPARE(track.composer(), QStringLiteral("composer1")); QCOMPARE(track.lyricist(), QStringLiteral("lyricist1")); musicDb.removeTracksList({track.resourceURI()}); QCOMPARE(musicDb.allAlbumsData().count(), 0); QCOMPARE(musicDb.allArtistsData().count(), 0); QCOMPARE(musicDb.allTracksData().count(), 0); QCOMPARE(musicDbArtistAddedSpy.count(), 1); QCOMPARE(musicDbAlbumAddedSpy.count(), 0); QCOMPARE(musicDbTrackAddedSpy.count(), 1); QCOMPARE(musicDbArtistRemovedSpy.count(), 1); QCOMPARE(musicDbAlbumRemovedSpy.count(), 0); QCOMPARE(musicDbTrackRemovedSpy.count(), 1); QCOMPARE(musicDbAlbumModifiedSpy.count(), 0); QCOMPARE(musicDbTrackModifiedSpy.count(), 0); QCOMPARE(musicDbDatabaseErrorSpy.count(), 0); } void addAndRemoveOneTrackWithoutTrackNumber() { DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb")); 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 newTrack = MusicAudioTrack {true, QStringLiteral("$26"), QStringLiteral("0"), QStringLiteral("track12"), QStringLiteral("artist8"), QStringLiteral("album4"), QStringLiteral("artist8"), -1, 1, QTime::fromMSecsSinceStartOfDay(26), {QUrl::fromLocalFile(QStringLiteral("/$26"))}, QDateTime::fromMSecsSinceEpoch(26), QUrl::fromLocalFile(QStringLiteral("file://image$26")), 9, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}; auto newTracks = QList(); newTracks.push_back(newTrack); auto newCovers = mNewCovers; newCovers[QStringLiteral("file:///$26")] = QUrl::fromLocalFile(QStringLiteral("album4")); musicDb.insertTracksList(newTracks, newCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 1); QCOMPARE(musicDb.allArtistsData().count(), 1); QCOMPARE(musicDb.allTracksData().count(), 1); 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 track = musicDb.trackDataFromDatabaseId(musicDb.trackIdFromFileName(QUrl::fromLocalFile(QStringLiteral("/$26")))); QCOMPARE(track.isValid(), true); QCOMPARE(track.title(), QStringLiteral("track12")); QCOMPARE(track.artist(), QStringLiteral("artist8")); QCOMPARE(track.album(), QStringLiteral("album4")); QCOMPARE(track.albumArtist(), QStringLiteral("artist8")); QCOMPARE(track.albumCover(), QUrl::fromLocalFile(QStringLiteral("album4"))); QCOMPARE(track.trackNumber(), -1); QCOMPARE(track.discNumber(), 1); QCOMPARE(track.duration(), QTime::fromMSecsSinceStartOfDay(26)); QCOMPARE(track.resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$26"))); QCOMPARE(track.rating(), 9); QCOMPARE(track.genre(), QStringLiteral("genre1")); QCOMPARE(track.composer(), QStringLiteral("composer1")); QCOMPARE(track.lyricist(), QStringLiteral("lyricist1")); musicDb.removeTracksList({track.resourceURI()}); QCOMPARE(musicDb.allAlbumsData().count(), 0); QCOMPARE(musicDb.allArtistsData().count(), 0); QCOMPARE(musicDb.allTracksData().count(), 0); QCOMPARE(musicDbArtistAddedSpy.count(), 1); QCOMPARE(musicDbAlbumAddedSpy.count(), 1); QCOMPARE(musicDbTrackAddedSpy.count(), 1); QCOMPARE(musicDbArtistRemovedSpy.count(), 1); QCOMPARE(musicDbAlbumRemovedSpy.count(), 1); QCOMPARE(musicDbTrackRemovedSpy.count(), 1); QCOMPARE(musicDbAlbumModifiedSpy.count(), 0); QCOMPARE(musicDbTrackModifiedSpy.count(), 0); QCOMPARE(musicDbDatabaseErrorSpy.count(), 0); } void addAndRemoveOneTrackWithoutArtist() { DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb")); 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 newTrack = MusicAudioTrack {true, QStringLiteral("$26"), QStringLiteral("0"), QStringLiteral("track11"), {}, QStringLiteral("album4"), {}, 9, 1, QTime::fromMSecsSinceStartOfDay(26), {QUrl::fromLocalFile(QStringLiteral("/$26"))}, QDateTime::fromMSecsSinceEpoch(26), QUrl::fromLocalFile(QStringLiteral("file://image$26")), 9, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}; auto newTracks = QList(); newTracks.push_back(newTrack); auto newCovers = mNewCovers; newCovers[QStringLiteral("file:///$26")] = QUrl::fromLocalFile(QStringLiteral("album4")); musicDb.insertTracksList(newTracks, newCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 1); QCOMPARE(musicDb.allArtistsData().count(), 0); QCOMPARE(musicDb.allTracksData().count(), 1); QCOMPARE(musicDbArtistAddedSpy.count(), 0); 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 track = musicDb.trackDataFromDatabaseId(musicDb.trackIdFromFileName(QUrl::fromLocalFile(QStringLiteral("/$26")))); QCOMPARE(track.isValid(), true); QCOMPARE(track.title(), QStringLiteral("track11")); QCOMPARE(track.artist(), QString()); QCOMPARE(track.album(), QStringLiteral("album4")); QVERIFY(track.albumArtist().isEmpty()); QCOMPARE(track.albumCover(), QUrl::fromLocalFile(QStringLiteral("album4"))); QCOMPARE(track.trackNumber(), 9); QCOMPARE(track.discNumber(), 1); QCOMPARE(track.duration(), QTime::fromMSecsSinceStartOfDay(26)); QCOMPARE(track.resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$26"))); QCOMPARE(track.rating(), 9); QCOMPARE(track.genre(), QStringLiteral("genre1")); QCOMPARE(track.composer(), QStringLiteral("composer1")); QCOMPARE(track.lyricist(), QStringLiteral("lyricist1")); musicDb.removeTracksList({track.resourceURI()}); QCOMPARE(musicDb.allAlbumsData().count(), 0); QCOMPARE(musicDb.allArtistsData().count(), 0); QCOMPARE(musicDb.allTracksData().count(), 0); QCOMPARE(musicDbArtistAddedSpy.count(), 0); QCOMPARE(musicDbAlbumAddedSpy.count(), 1); QCOMPARE(musicDbTrackAddedSpy.count(), 1); QCOMPARE(musicDbArtistRemovedSpy.count(), 0); QCOMPARE(musicDbAlbumRemovedSpy.count(), 1); QCOMPARE(musicDbTrackRemovedSpy.count(), 1); QCOMPARE(musicDbAlbumModifiedSpy.count(), 0); QCOMPARE(musicDbTrackModifiedSpy.count(), 0); QCOMPARE(musicDbDatabaseErrorSpy.count(), 0); } void addOneTrackWithoutAlbumArtistAndAnotherTrackWith() { DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb")); 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 newTrack = MusicAudioTrack {true, QStringLiteral("$26"), QStringLiteral("0"), QStringLiteral("track11"), {}, QStringLiteral("album4"), {}, 9, 1, QTime::fromMSecsSinceStartOfDay(26), {QUrl::fromLocalFile(QStringLiteral("/$26"))}, QDateTime::fromMSecsSinceEpoch(26), QUrl::fromLocalFile(QStringLiteral("file://image$26")), 9, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}; auto newTracks = QList(); newTracks.push_back(newTrack); auto newCovers = mNewCovers; newCovers[QStringLiteral("file:///$26")] = QUrl::fromLocalFile(QStringLiteral("album4")); musicDb.insertTracksList(newTracks, newCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 1); QCOMPARE(musicDb.allArtistsData().count(), 0); QCOMPARE(musicDb.allTracksData().count(), 1); QCOMPARE(musicDbArtistAddedSpy.count(), 0); 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 track = musicDb.trackDataFromDatabaseId(musicDb.trackIdFromFileName(QUrl::fromLocalFile(QStringLiteral("/$26")))); QCOMPARE(track.isValid(), true); QCOMPARE(track.title(), QStringLiteral("track11")); QCOMPARE(track.artist(), QString()); QCOMPARE(track.album(), QStringLiteral("album4")); QCOMPARE(track.albumArtist(), QString()); QVERIFY(track.albumArtist().isEmpty()); QCOMPARE(track.albumCover(), QUrl::fromLocalFile(QStringLiteral("album4"))); QCOMPARE(track.trackNumber(), 9); QCOMPARE(track.discNumber(), 1); QCOMPARE(track.duration(), QTime::fromMSecsSinceStartOfDay(26)); QCOMPARE(track.resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$26"))); QCOMPARE(track.rating(), 9); QCOMPARE(track.genre(), QStringLiteral("genre1")); QCOMPARE(track.composer(), QStringLiteral("composer1")); QCOMPARE(track.lyricist(), QStringLiteral("lyricist1")); newTrack = MusicAudioTrack {true, QStringLiteral("$27"), QStringLiteral("0"), QStringLiteral("track12"), QStringLiteral("artist1"), QStringLiteral("album4"), QStringLiteral("artist2"), 10, 1, QTime::fromMSecsSinceStartOfDay(27), {QUrl::fromLocalFile(QStringLiteral("/autre/$27"))}, QDateTime::fromMSecsSinceEpoch(27), QUrl::fromLocalFile(QStringLiteral("file://image$27")), 10, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}; newTracks = QList(); newTracks.push_back(newTrack); newCovers = mNewCovers; newCovers[QStringLiteral("file:///autre/$27")] = QUrl::fromLocalFile(QStringLiteral("album4")); musicDb.insertTracksList(newTracks, newCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 2); QCOMPARE(musicDb.allArtistsData().count(), 2); QCOMPARE(musicDb.allTracksData().count(), 2); QCOMPARE(musicDbArtistAddedSpy.count(), 1); QCOMPARE(musicDbAlbumAddedSpy.count(), 2); QCOMPARE(musicDbTrackAddedSpy.count(), 2); QCOMPARE(musicDbArtistRemovedSpy.count(), 0); QCOMPARE(musicDbAlbumRemovedSpy.count(), 0); QCOMPARE(musicDbTrackRemovedSpy.count(), 0); QCOMPARE(musicDbAlbumModifiedSpy.count(), 0); QCOMPARE(musicDbTrackModifiedSpy.count(), 0); QCOMPARE(musicDbDatabaseErrorSpy.count(), 0); } void addTwoTracksWithoutAlbumArtist() { QTemporaryFile databaseFile; databaseFile.open(); qDebug() << "addTwoTracksWithoutAlbumArtist" << databaseFile.fileName(); DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb"), 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 newTracks = QList(); newTracks = {{true, QStringLiteral("$19"), QStringLiteral("0"), QStringLiteral("track6"), QStringLiteral("artist2"), QStringLiteral("album3"), {}, 6, 1, QTime::fromMSecsSinceStartOfDay(19), {QUrl::fromLocalFile(QStringLiteral("/$19"))}, QDateTime::fromMSecsSinceEpoch(23), {QUrl::fromLocalFile(QStringLiteral("album3"))}, 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), true}, {true, QStringLiteral("$20"), QStringLiteral("0"), QStringLiteral("track7"), QStringLiteral("artist3"), QStringLiteral("album3"), {}, 7, 1, QTime::fromMSecsSinceStartOfDay(20), {QUrl::fromLocalFile(QStringLiteral("/$20"))}, QDateTime::fromMSecsSinceEpoch(23), {QUrl::fromLocalFile(QStringLiteral("album3"))}, 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}}; auto newCovers = mNewCovers; newCovers[QStringLiteral("file:///$23")] = QUrl::fromLocalFile(QStringLiteral("album3")); newCovers[QStringLiteral("file:///$20")] = QUrl::fromLocalFile(QStringLiteral("album3")); musicDb.insertTracksList(newTracks, newCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 1); QCOMPARE(musicDb.allArtistsData().count(), 2); 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 firstTrack = musicDb.trackDataFromDatabaseId(musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track6"), QStringLiteral("artist2"), QStringLiteral("album3"), 6, 1)); QCOMPARE(firstTrack.isValid(), true); QCOMPARE(firstTrack.title(), QStringLiteral("track6")); QCOMPARE(firstTrack.artist(), QStringLiteral("artist2")); QCOMPARE(firstTrack.album(), QStringLiteral("album3")); QVERIFY(firstTrack.albumArtist().isEmpty()); QCOMPARE(firstTrack.albumCover(), QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(firstTrack.trackNumber(), 6); QCOMPARE(firstTrack.discNumber(), 1); QCOMPARE(firstTrack.duration(), QTime::fromMSecsSinceStartOfDay(19)); QCOMPARE(firstTrack.resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$19"))); QCOMPARE(firstTrack.rating(), 5); QCOMPARE(firstTrack.genre(), QStringLiteral("genre1")); QCOMPARE(firstTrack.composer(), QStringLiteral("composer1")); QCOMPARE(firstTrack.lyricist(), QStringLiteral("lyricist1")); QCOMPARE(firstTrack.hasEmbeddedCover(), true); auto secondTrack = musicDb.trackDataFromDatabaseId(musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track7"), QStringLiteral("artist3"), QStringLiteral("album3"), 7, 1)); QCOMPARE(secondTrack.isValid(), true); QCOMPARE(secondTrack.title(), QStringLiteral("track7")); QCOMPARE(secondTrack.artist(), QStringLiteral("artist3")); QCOMPARE(secondTrack.album(), QStringLiteral("album3")); QVERIFY(secondTrack.albumArtist().isEmpty()); QCOMPARE(secondTrack.albumCover(), QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(secondTrack.trackNumber(), 7); QCOMPARE(secondTrack.discNumber(), 1); QCOMPARE(secondTrack.duration(), QTime::fromMSecsSinceStartOfDay(20)); QCOMPARE(secondTrack.resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$20"))); QCOMPARE(secondTrack.rating(), 5); QCOMPARE(secondTrack.genre(), QStringLiteral("genre1")); QCOMPARE(secondTrack.composer(), QStringLiteral("composer1")); QCOMPARE(secondTrack.lyricist(), QStringLiteral("lyricist1")); QCOMPARE(secondTrack.hasEmbeddedCover(), false); auto albumId = musicDb.albumIdFromTitleAndArtist(QStringLiteral("album3"), QStringLiteral("artist2")); auto album = musicDb.albumDataFromDatabaseId(albumId); auto albumData = musicDb.albumData(albumId); QCOMPARE(album.isValid(), true); QCOMPARE(albumData.count(), 2); QCOMPARE(album.title(), QStringLiteral("album3")); QCOMPARE(album.isValidArtist(), false); QCOMPARE(album.albumArtURI(), QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(album.isSingleDiscAlbum(), true); } void addThreeTracksWithoutAlbumArtistButSameArtist() { DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb")); 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 newTracks = QList(); newTracks = {{true, QStringLiteral("$19"), QStringLiteral("0"), QStringLiteral("track6"), QStringLiteral("artist2"), QStringLiteral("album3"), {}, 6, 1, QTime::fromMSecsSinceStartOfDay(19), {QUrl::fromLocalFile(QStringLiteral("/$19"))}, QDateTime::fromMSecsSinceEpoch(19), {QUrl::fromLocalFile(QStringLiteral("album3"))}, 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}, {true, QStringLiteral("$20"), QStringLiteral("0"), QStringLiteral("track7"), QStringLiteral("artist2"), QStringLiteral("album3"), {}, 7, 1, QTime::fromMSecsSinceStartOfDay(20), {QUrl::fromLocalFile(QStringLiteral("/$20"))}, QDateTime::fromMSecsSinceEpoch(20), {QUrl::fromLocalFile(QStringLiteral("album3"))}, 4, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}, {true, QStringLiteral("$21"), QStringLiteral("0"), QStringLiteral("track8"), QStringLiteral("artist2"), QStringLiteral("album3"), {}, 8, 1, QTime::fromMSecsSinceStartOfDay(21), {QUrl::fromLocalFile(QStringLiteral("/$21"))}, QDateTime::fromMSecsSinceEpoch(21), {QUrl::fromLocalFile(QStringLiteral("album3"))}, 3, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}}; auto newCovers = mNewCovers; newCovers[QStringLiteral("file:///$19")] = QUrl::fromLocalFile(QStringLiteral("album3")); newCovers[QStringLiteral("file:///$20")] = QUrl::fromLocalFile(QStringLiteral("album3")); newCovers[QStringLiteral("file:///$21")] = QUrl::fromLocalFile(QStringLiteral("album3")); musicDb.insertTracksList(newTracks, newCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 1); QCOMPARE(musicDb.allArtistsData().count(), 1); QCOMPARE(musicDb.allTracksData().count(), 3); 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 firstTrack = musicDb.trackDataFromDatabaseId(musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track6"), QStringLiteral("artist2"), QStringLiteral("album3"), 6, 1)); QCOMPARE(firstTrack.isValid(), true); QCOMPARE(firstTrack.title(), QStringLiteral("track6")); QCOMPARE(firstTrack.artist(), QStringLiteral("artist2")); QCOMPARE(firstTrack.album(), QStringLiteral("album3")); QVERIFY(firstTrack.albumArtist().isEmpty()); QCOMPARE(firstTrack.albumCover(), QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(firstTrack.trackNumber(), 6); QCOMPARE(firstTrack.discNumber(), 1); QCOMPARE(firstTrack.duration(), QTime::fromMSecsSinceStartOfDay(19)); QCOMPARE(firstTrack.resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$19"))); QCOMPARE(firstTrack.rating(), 5); QCOMPARE(firstTrack.genre(), QStringLiteral("genre1")); QCOMPARE(firstTrack.composer(), QStringLiteral("composer1")); QCOMPARE(firstTrack.lyricist(), QStringLiteral("lyricist1")); QCOMPARE(firstTrack.isSingleDiscAlbum(), true); auto secondTrack = musicDb.trackDataFromDatabaseId(musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track7"), QStringLiteral("artist2"), QStringLiteral("album3"), 7, 1)); QCOMPARE(secondTrack.isValid(), true); QCOMPARE(secondTrack.title(), QStringLiteral("track7")); QCOMPARE(secondTrack.artist(), QStringLiteral("artist2")); QCOMPARE(secondTrack.album(), QStringLiteral("album3")); QVERIFY(secondTrack.albumArtist().isEmpty()); QCOMPARE(secondTrack.albumCover(), QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(secondTrack.trackNumber(), 7); QCOMPARE(secondTrack.discNumber(), 1); QCOMPARE(secondTrack.duration(), QTime::fromMSecsSinceStartOfDay(20)); QCOMPARE(secondTrack.resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$20"))); QCOMPARE(secondTrack.rating(), 4); QCOMPARE(secondTrack.genre(), QStringLiteral("genre1")); QCOMPARE(secondTrack.composer(), QStringLiteral("composer1")); QCOMPARE(secondTrack.lyricist(), QStringLiteral("lyricist1")); QCOMPARE(secondTrack.isSingleDiscAlbum(), true); QCOMPARE(secondTrack.hasEmbeddedCover(), false); auto thirdTrack = musicDb.trackDataFromDatabaseId(musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track8"), QStringLiteral("artist2"), QStringLiteral("album3"), 8, 1)); QCOMPARE(thirdTrack.isValid(), true); QCOMPARE(thirdTrack.title(), QStringLiteral("track8")); QCOMPARE(thirdTrack.artist(), QStringLiteral("artist2")); QCOMPARE(thirdTrack.album(), QStringLiteral("album3")); QVERIFY(thirdTrack.albumArtist().isEmpty()); QCOMPARE(thirdTrack.albumCover(), QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(thirdTrack.trackNumber(), 8); QCOMPARE(thirdTrack.discNumber(), 1); QCOMPARE(thirdTrack.duration(), QTime::fromMSecsSinceStartOfDay(21)); QCOMPARE(thirdTrack.resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$21"))); QCOMPARE(thirdTrack.rating(), 3); QCOMPARE(thirdTrack.genre(), QStringLiteral("genre1")); QCOMPARE(thirdTrack.composer(), QStringLiteral("composer1")); QCOMPARE(thirdTrack.lyricist(), QStringLiteral("lyricist1")); QCOMPARE(thirdTrack.isSingleDiscAlbum(), true); auto albumId = musicDb.albumIdFromTitleAndArtist(QStringLiteral("album3"), QStringLiteral("artist2")); auto album = musicDb.albumDataFromDatabaseId(albumId); auto albumData = musicDb.albumData(albumId); QCOMPARE(album.isValid(), true); QCOMPARE(albumData.count(), 3); QCOMPARE(album.title(), QStringLiteral("album3")); QCOMPARE(album.isValidArtist(), false); QCOMPARE(album.albumArtURI(), QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(album.isSingleDiscAlbum(), true); } void addTwoTracksWithPartialAlbumArtist() { QTemporaryFile databaseFile; databaseFile.open(); qDebug() << "addTwoTracksWithPartialAlbumArtist" << databaseFile.fileName(); DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb"), 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 newTracks = QList(); newTracks = {{true, QStringLiteral("$19"), QStringLiteral("0"), QStringLiteral("track6"), QStringLiteral("artist2"), QStringLiteral("album3"), {}, 6, 1, QTime::fromMSecsSinceStartOfDay(19), {QUrl::fromLocalFile(QStringLiteral("/$19"))}, QDateTime::fromMSecsSinceEpoch(19), {QUrl::fromLocalFile(QStringLiteral("album3"))}, 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), true}, {true, QStringLiteral("$20"), QStringLiteral("0"), QStringLiteral("track7"), QStringLiteral("artist3"), QStringLiteral("album3"), {QStringLiteral("artist4")}, 7, 1, QTime::fromMSecsSinceStartOfDay(20), {QUrl::fromLocalFile(QStringLiteral("/$20"))}, QDateTime::fromMSecsSinceEpoch(20), {QUrl::fromLocalFile(QStringLiteral("album3"))}, 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}}; auto newCovers = mNewCovers; newCovers[QStringLiteral("file:///$19")] = QUrl::fromLocalFile(QStringLiteral("album3")); newCovers[QStringLiteral("file:///$20")] = QUrl::fromLocalFile(QStringLiteral("album3")); musicDb.insertTracksList(newTracks, newCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 1); QCOMPARE(musicDb.allArtistsData().count(), 3); 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 firstTrack = musicDb.trackDataFromDatabaseId(musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track6"), QStringLiteral("artist2"), QStringLiteral("album3"), 6, 1)); QCOMPARE(firstTrack.isValid(), true); QCOMPARE(firstTrack.title(), QStringLiteral("track6")); QCOMPARE(firstTrack.artist(), QStringLiteral("artist2")); QCOMPARE(firstTrack.album(), QStringLiteral("album3")); QCOMPARE(firstTrack.albumArtist(), QStringLiteral("artist4")); QCOMPARE(firstTrack.albumCover(), QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(firstTrack.trackNumber(), 6); QCOMPARE(firstTrack.discNumber(), 1); QCOMPARE(firstTrack.duration(), QTime::fromMSecsSinceStartOfDay(19)); QCOMPARE(firstTrack.resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$19"))); QCOMPARE(firstTrack.rating(), 5); QCOMPARE(firstTrack.genre(), QStringLiteral("genre1")); QCOMPARE(firstTrack.composer(), QStringLiteral("composer1")); QCOMPARE(firstTrack.lyricist(), QStringLiteral("lyricist1")); QCOMPARE(firstTrack.isSingleDiscAlbum(), true); QCOMPARE(firstTrack.hasEmbeddedCover(), true); auto secondTrack = musicDb.trackDataFromDatabaseId(musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track7"), QStringLiteral("artist3"), QStringLiteral("album3"), 7, 1)); QCOMPARE(secondTrack.isValid(), true); QCOMPARE(secondTrack.title(), QStringLiteral("track7")); QCOMPARE(secondTrack.artist(), QStringLiteral("artist3")); QCOMPARE(secondTrack.album(), QStringLiteral("album3")); QCOMPARE(secondTrack.albumArtist(), QStringLiteral("artist4")); QCOMPARE(secondTrack.albumCover(), QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(secondTrack.trackNumber(), 7); QCOMPARE(secondTrack.discNumber(), 1); QCOMPARE(secondTrack.duration(), QTime::fromMSecsSinceStartOfDay(20)); QCOMPARE(secondTrack.resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$20"))); QCOMPARE(secondTrack.rating(), 5); QCOMPARE(secondTrack.genre(), QStringLiteral("genre1")); QCOMPARE(secondTrack.composer(), QStringLiteral("composer1")); QCOMPARE(secondTrack.lyricist(), QStringLiteral("lyricist1")); QCOMPARE(secondTrack.isSingleDiscAlbum(), true); QCOMPARE(secondTrack.hasEmbeddedCover(), false); auto albumId = musicDb.albumIdFromTitleAndArtist(QStringLiteral("album3"), QStringLiteral("artist4")); auto album = musicDb.albumDataFromDatabaseId(albumId); auto albumData = musicDb.albumData(albumId); QCOMPARE(album.isValid(), true); QCOMPARE(albumData.count(), 2); QCOMPARE(album.title(), QStringLiteral("album3")); QCOMPARE(album.artist(), QStringLiteral("artist4")); QCOMPARE(album.isValidArtist(), true); QCOMPARE(album.albumArtURI(), QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(album.isSingleDiscAlbum(), true); } void addMultipleTimeSameTracks() { QTemporaryFile databaseFile; databaseFile.open(); qDebug() << "addMultipleTimeSameTracks" << databaseFile.fileName(); DatabaseInterface musicDb; QSignalSpy musicDbTrackAddedSpy(&musicDb, &DatabaseInterface::tracksAdded); QSignalSpy musicDbErrorSpy(&musicDb, &DatabaseInterface::databaseError); musicDb.init(QStringLiteral("testDb"), databaseFile.fileName()); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDbErrorSpy.count(), 0); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDbErrorSpy.count(), 0); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDbErrorSpy.count(), 0); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDbErrorSpy.count(), 0); auto firstAlbum = musicDb.albumDataFromDatabaseId(musicDb.albumIdFromTitleAndArtist(QStringLiteral("album1"), QStringLiteral("Various Artists"))); QCOMPARE(firstAlbum.isValid(), true); QCOMPARE(firstAlbum.title(), QStringLiteral("album1")); QCOMPARE(musicDbErrorSpy.count(), 0); auto firstAlbumInvalid = musicDb.albumDataFromDatabaseId(musicDb.albumIdFromTitleAndArtist(QStringLiteral("album1Invalid"), QStringLiteral("Invalid Artist"))); QCOMPARE(firstAlbumInvalid.isValid(), false); QCOMPARE(musicDbErrorSpy.count(), 0); } void addTwiceSameTracksWithDatabaseFile() { QTemporaryFile myTempDatabase; myTempDatabase.open(); { DatabaseInterface musicDb; QSignalSpy musicDbTrackAddedSpy(&musicDb, &DatabaseInterface::tracksAdded); musicDb.init(QStringLiteral("testDb1"), myTempDatabase.fileName()); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); auto firstAlbum = musicDb.albumDataFromDatabaseId(musicDb.albumIdFromTitleAndArtist(QStringLiteral("album1"), QStringLiteral("Various Artists"))); QCOMPARE(firstAlbum.isValid(), true); QCOMPARE(firstAlbum.title(), QStringLiteral("album1")); auto firstAlbumInvalid = musicDb.albumDataFromDatabaseId(musicDb.albumIdFromTitleAndArtist(QStringLiteral("album1Invalid"), QStringLiteral("Invalid Artist"))); QCOMPARE(firstAlbumInvalid.isValid(), false); } { DatabaseInterface musicDb; QSignalSpy musicDbTrackAddedSpy(&musicDb, &DatabaseInterface::tracksAdded); musicDb.init(QStringLiteral("testDb2"), myTempDatabase.fileName()); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); auto firstAlbum = musicDb.albumDataFromDatabaseId(musicDb.albumIdFromTitleAndArtist(QStringLiteral("album1"), QStringLiteral("Various Artists"))); QCOMPARE(firstAlbum.isValid(), true); QCOMPARE(firstAlbum.title(), QStringLiteral("album1")); auto firstAlbumInvalid = musicDb.albumDataFromDatabaseId(musicDb.albumIdFromTitleAndArtist(QStringLiteral("album1Invalid"), QStringLiteral("Invalid Artist"))); QCOMPARE(firstAlbumInvalid.isValid(), false); } } void restoreModifiedTracksWidthDatabaseFile() { QTemporaryFile myTempDatabase; myTempDatabase.open(); { DatabaseInterface musicDb; 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 allNewTracks = mNewTracks; allNewTracks.push_back({true, QStringLiteral("$23"), QStringLiteral("0"), QStringLiteral("track6"), QStringLiteral("artist2"), QStringLiteral("album3"), QStringLiteral("artist2"), 6, 1, QTime::fromMSecsSinceStartOfDay(23), {QUrl::fromLocalFile(QStringLiteral("/$23"))}, QDateTime::fromMSecsSinceEpoch(23), {QUrl::fromLocalFile(QStringLiteral("album3"))}, 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}); musicDb.init(QStringLiteral("testDb1"), myTempDatabase.fileName()); 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); qDebug() << "restoreModifiedTracksWidthDatabaseFile" << myTempDatabase.fileName(); auto newCovers = mNewCovers; newCovers[QStringLiteral("file:///$23")] = QUrl::fromLocalFile(QStringLiteral("album3")); musicDb.insertTracksList(allNewTracks, newCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 23); 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 firstAlbum = musicDb.albumDataFromDatabaseId(musicDb.albumIdFromTitleAndArtist(QStringLiteral("album1"), QStringLiteral("Various Artists"))); QCOMPARE(firstAlbum.isValid(), true); QCOMPARE(firstAlbum.title(), QStringLiteral("album1")); auto firstAlbumInvalid = musicDb.albumDataFromDatabaseId(musicDb.albumIdFromTitleAndArtist(QStringLiteral("album1Invalid"), QStringLiteral("Invalid Artist"))); QCOMPARE(firstAlbumInvalid.isValid(), false); auto fourthAlbumId = musicDb.albumIdFromTitleAndArtist(QStringLiteral("album3"), QStringLiteral("artist2")); auto fourthAlbum = musicDb.albumDataFromDatabaseId(fourthAlbumId); auto fourthAlbumData = musicDb.albumData(fourthAlbumId); QCOMPARE(fourthAlbum.isValid(), true); QCOMPARE(fourthAlbum.title(), QStringLiteral("album3")); QCOMPARE(fourthAlbumData.count(), 4); const auto &oneTrack = fourthAlbumData.at(3); QCOMPARE(oneTrack.isValid(), true); QCOMPARE(oneTrack.rating(), 5); } { DatabaseInterface musicDb; 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 allNewTracks = mNewTracks; allNewTracks.push_back({true, QStringLiteral("$23"), QStringLiteral("0"), QStringLiteral("track6"), QStringLiteral("artist2"), QStringLiteral("album3"), QStringLiteral("artist2"), 6, 1, QTime::fromMSecsSinceStartOfDay(23), {QUrl::fromLocalFile(QStringLiteral("/$23"))}, QDateTime::fromMSecsSinceEpoch(23), {QUrl::fromLocalFile(QStringLiteral("album3"))}, 3, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}); musicDb.init(QStringLiteral("testDb2"), myTempDatabase.fileName()); qDebug() << "restoreModifiedTracksWidthDatabaseFile" << myTempDatabase.fileName(); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 23); 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 newCovers = mNewCovers; newCovers[QStringLiteral("file:///$23")] = QUrl::fromLocalFile(QStringLiteral("album3")); musicDb.insertTracksList(allNewTracks, newCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 23); 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(), 2); QCOMPARE(musicDbTrackModifiedSpy.count(), 2); QCOMPARE(musicDbDatabaseErrorSpy.count(), 0); QCOMPARE(musicDb.allAlbumsData().count(), 5); auto firstAlbum = musicDb.albumDataFromDatabaseId(musicDb.albumIdFromTitleAndArtist(QStringLiteral("album1"), QStringLiteral("Various Artists"))); QCOMPARE(firstAlbum.isValid(), true); QCOMPARE(firstAlbum.title(), QStringLiteral("album1")); auto firstAlbumInvalid = musicDb.albumDataFromDatabaseId(musicDb.albumIdFromTitleAndArtist(QStringLiteral("album1Invalid"), QStringLiteral("Invalid Artist"))); QCOMPARE(firstAlbumInvalid.isValid(), false); auto fourthAlbumId = musicDb.albumIdFromTitleAndArtist(QStringLiteral("album3"), QStringLiteral("artist2")); auto fourthAlbum = musicDb.albumDataFromDatabaseId(fourthAlbumId); auto fourthAlbumData = musicDb.albumData(fourthAlbumId); QCOMPARE(fourthAlbum.isValid(), true); QCOMPARE(fourthAlbum.title(), QStringLiteral("album3")); QCOMPARE(fourthAlbumData.count(), 4); const auto &oneTrack = fourthAlbumData.at(3); QCOMPARE(oneTrack.isValid(), true); QCOMPARE(oneTrack.title(), QStringLiteral("track6")); QCOMPARE(oneTrack.rating(), 3); } } void simpleAccessor() { DatabaseInterface musicDb; QSignalSpy musicDbTrackAddedSpy(&musicDb, &DatabaseInterface::tracksAdded); musicDb.init(QStringLiteral("testDb")); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); auto allAlbums = musicDb.allAlbumsData(); auto firstAlbumData = musicDb.albumData(allAlbums[0].databaseId()); auto firstAlbumTitle = allAlbums[0].title(); auto firstAlbumArtist = allAlbums[0].artist(); auto firstAlbumImage = allAlbums[0].albumArtURI(); auto firstAlbumTracksCount = firstAlbumData.count(); auto firstAlbumIsSingleDiscAlbum = allAlbums[0].isSingleDiscAlbum(); QCOMPARE(firstAlbumTitle, QStringLiteral("album1")); QCOMPARE(firstAlbumArtist, QStringLiteral("Various Artists")); QCOMPARE(firstAlbumImage.isValid(), true); QCOMPARE(firstAlbumImage, QUrl::fromLocalFile(QStringLiteral("album1"))); QCOMPARE(firstAlbumTracksCount, 4); QCOMPARE(firstAlbumIsSingleDiscAlbum, false); auto invalidTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track1"), QStringLiteral("artist1"), QStringLiteral("album1"), 2, 1); QCOMPARE(invalidTrackId, decltype(invalidTrackId)(0)); auto trackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track1"), QStringLiteral("artist1"), QStringLiteral("album1"), 1, 1); auto firstTrack = musicDb.trackDataFromDatabaseId(trackId); 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("track1")); QCOMPARE(firstTrackArtist, QStringLiteral("artist1")); QCOMPARE(firstTrackAlbumArtist, QStringLiteral("Various Artists")); QCOMPARE(firstTrackAlbum, QStringLiteral("album1")); QCOMPARE(firstTrackImage.isValid(), true); QCOMPARE(firstTrackImage, QUrl::fromLocalFile(QStringLiteral("album1"))); QCOMPARE(firstTrackDuration, QTime::fromMSecsSinceStartOfDay(1)); QCOMPARE(firstTrackMilliSecondsDuration, 1); QCOMPARE(firstTrackTrackNumber, 1); QCOMPARE(firstTrackDiscNumber, 1); QCOMPARE(firstTrackResource.isValid(), true); QCOMPARE(firstTrackResource, QUrl::fromLocalFile(QStringLiteral("/$1"))); QCOMPARE(firstTrackRating, 1); QCOMPARE(firstIsSingleDiscAlbum, false); auto secondAlbumData = musicDb.albumData(allAlbums[1].databaseId()); auto secondAlbumTitle = allAlbums[1].title(); auto secondAlbumArtist = allAlbums[1].artist(); auto secondAlbumImage = allAlbums[1].albumArtURI(); auto secondAlbumTracksCount = secondAlbumData.count(); auto secondAlbumIsSingleDiscAlbum = allAlbums[1].isSingleDiscAlbum(); QCOMPARE(secondAlbumTitle, QStringLiteral("album2")); QCOMPARE(secondAlbumArtist, QStringLiteral("artist1")); QCOMPARE(secondAlbumImage.isValid(), true); QCOMPARE(secondAlbumImage, QUrl::fromLocalFile(QStringLiteral("album2"))); QCOMPARE(secondAlbumTracksCount, 6); QCOMPARE(secondAlbumIsSingleDiscAlbum, true); } void simpleAccessorAndVariousArtistAlbum() { DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDbVariousArtistAlbum")); QSignalSpy musicDbArtistAddedSpy(&musicDb, &DatabaseInterface::artistsAdded); QSignalSpy musicDbAlbumAddedSpy(&musicDb, &DatabaseInterface::albumsAdded); QSignalSpy musicDbTrackAddedSpy(&musicDb, &DatabaseInterface::tracksAdded); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 22); QCOMPARE(musicDbArtistAddedSpy.count(), 1); QCOMPARE(musicDbAlbumAddedSpy.count(), 1); QCOMPARE(musicDbTrackAddedSpy.count(), 1); auto allAlbums = musicDb.allAlbumsData(); auto firstAlbumData = musicDb.albumData(allAlbums[0].databaseId()); auto firstAlbumTitle = allAlbums[0].title(); auto firstAlbumArtist = allAlbums[0].artist(); auto firstAlbumImage = allAlbums[0].albumArtURI(); auto firstAlbumTracksCount = firstAlbumData.count(); auto firstAlbumIsSingleDiscAlbum = allAlbums[0].isSingleDiscAlbum(); QCOMPARE(firstAlbumTitle, QStringLiteral("album1")); QCOMPARE(firstAlbumArtist, QStringLiteral("Various Artists")); QCOMPARE(firstAlbumImage.isValid(), true); QCOMPARE(firstAlbumImage, QUrl::fromLocalFile(QStringLiteral("album1"))); QCOMPARE(firstAlbumTracksCount, 4); QCOMPARE(firstAlbumIsSingleDiscAlbum, false); auto invalidTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track1"), QStringLiteral("artist1"), QStringLiteral("album1"), 2, 1); QCOMPARE(invalidTrackId, decltype(invalidTrackId)(0)); auto firstTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track1"), QStringLiteral("artist1"), QStringLiteral("album1"), 1, 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("track1")); QCOMPARE(firstTrackArtist, QStringLiteral("artist1")); QCOMPARE(firstTrackAlbumArtist, QStringLiteral("Various Artists")); QCOMPARE(firstTrackAlbum, QStringLiteral("album1")); QCOMPARE(firstTrackImage.isValid(), true); QCOMPARE(firstTrackImage, QUrl::fromLocalFile(QStringLiteral("album1"))); QCOMPARE(firstTrackDuration, QTime::fromMSecsSinceStartOfDay(1)); QCOMPARE(firstTrackMilliSecondsDuration, 1); QCOMPARE(firstTrackTrackNumber, 1); QCOMPARE(firstTrackDiscNumber, 1); QCOMPARE(firstTrackResource.isValid(), true); QCOMPARE(firstTrackResource, QUrl::fromLocalFile(QStringLiteral("/$1"))); QCOMPARE(firstTrackRating, 1); QCOMPARE(firstIsSingleDiscAlbum, false); auto secondTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track2"), QStringLiteral("artist2"), QStringLiteral("album1"), 2, 2); auto secondTrack = musicDb.trackDataFromDatabaseId(secondTrackId); auto secondTrackTitle = secondTrack.title(); auto secondTrackArtist = secondTrack.artist(); auto secondTrackAlbumArtist = secondTrack.albumArtist(); auto secondTrackAlbum = secondTrack.album(); auto seconfTrackImage = secondTrack.albumCover(); auto secondTrackDuration = secondTrack.duration(); auto secondTrackMilliSecondsDuration = secondTrack.duration().msecsSinceStartOfDay(); auto secondTrackTrackNumber = secondTrack.trackNumber(); auto secondTrackDiscNumber = secondTrack.discNumber(); const auto &secondTrackResource = secondTrack.resourceURI(); auto secondTrackRating = secondTrack.rating(); auto secondIsSingleDiscAlbum = secondTrack.isSingleDiscAlbum(); QCOMPARE(secondTrack.isValid(), true); QCOMPARE(secondTrackTitle, QStringLiteral("track2")); QCOMPARE(secondTrackArtist, QStringLiteral("artist2")); QCOMPARE(secondTrackAlbumArtist, QStringLiteral("Various Artists")); QCOMPARE(secondTrackAlbum, QStringLiteral("album1")); QCOMPARE(seconfTrackImage.isValid(), true); QCOMPARE(seconfTrackImage, QUrl::fromLocalFile(QStringLiteral("album1"))); QCOMPARE(secondTrackDuration, QTime::fromMSecsSinceStartOfDay(2)); QCOMPARE(secondTrackMilliSecondsDuration, 2); QCOMPARE(secondTrackTrackNumber, 2); QCOMPARE(secondTrackDiscNumber, 2); QCOMPARE(secondTrackResource.isValid(), true); QCOMPARE(secondTrackResource, QUrl::fromLocalFile(QStringLiteral("/$2"))); QCOMPARE(secondTrackRating, 2); QCOMPARE(secondIsSingleDiscAlbum, false); auto thirdTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track3"), QStringLiteral("artist3"), QStringLiteral("album1"), 3, 3); auto thirdTrack = musicDb.trackDataFromDatabaseId(thirdTrackId); auto thirdTrackTitle = thirdTrack.title(); auto thirdTrackArtist = thirdTrack.artist(); auto thirdTrackAlbumArtist = thirdTrack.albumArtist(); auto thirdTrackAlbum = thirdTrack.album(); auto thirdTrackImage = thirdTrack.albumCover(); auto thirdTrackDuration = thirdTrack.duration(); auto thirdTrackMilliSecondsDuration = thirdTrack.duration().msecsSinceStartOfDay(); auto thirdTrackTrackNumber = thirdTrack.trackNumber(); auto thirdTrackDiscNumber = thirdTrack.discNumber(); const auto &thirdTrackResource = thirdTrack.resourceURI(); auto thirdTrackRating = thirdTrack.rating(); auto thirdIsSingleDiscAlbum = thirdTrack.isSingleDiscAlbum(); QCOMPARE(thirdTrack.isValid(), true); QCOMPARE(thirdTrackTitle, QStringLiteral("track3")); QCOMPARE(thirdTrackArtist, QStringLiteral("artist3")); QCOMPARE(thirdTrackAlbumArtist, QStringLiteral("Various Artists")); QCOMPARE(thirdTrackAlbum, QStringLiteral("album1")); QCOMPARE(thirdTrackImage.isValid(), true); QCOMPARE(thirdTrackImage, QUrl::fromLocalFile(QStringLiteral("album1"))); QCOMPARE(thirdTrackDuration, QTime::fromMSecsSinceStartOfDay(3)); QCOMPARE(thirdTrackMilliSecondsDuration, 3); QCOMPARE(thirdTrackTrackNumber, 3); QCOMPARE(thirdTrackDiscNumber, 3); QCOMPARE(thirdTrackResource.isValid(), true); QCOMPARE(thirdTrackResource, QUrl::fromLocalFile(QStringLiteral("/$3"))); QCOMPARE(thirdTrackRating, 3); QCOMPARE(thirdIsSingleDiscAlbum, false); auto fourthTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track4"), QStringLiteral("artist4"), QStringLiteral("album1"), 4, 4); auto fourthTrack = musicDb.trackDataFromDatabaseId(fourthTrackId); auto fourthTrackTitle = fourthTrack.title(); auto fourthTrackArtist = fourthTrack.artist(); auto fourthTrackAlbumArtist = fourthTrack.albumArtist(); auto fourthTrackAlbum = fourthTrack.album(); auto fourthTrackImage = fourthTrack.albumCover(); auto fourthTrackDuration = fourthTrack.duration(); auto fourthTrackMilliSecondsDuration = fourthTrack.duration().msecsSinceStartOfDay(); auto fourthTrackTrackNumber = fourthTrack.trackNumber(); auto fourthTrackDiscNumber = fourthTrack.discNumber(); const auto &fourthTrackResource = fourthTrack.resourceURI(); auto fourthTrackRating = thirdTrack.rating(); auto fourthIsSingleDiscAlbum = fourthTrack.isSingleDiscAlbum(); QCOMPARE(fourthTrack.isValid(), true); QCOMPARE(fourthTrackTitle, QStringLiteral("track4")); QCOMPARE(fourthTrackArtist, QStringLiteral("artist4")); QCOMPARE(fourthTrackAlbumArtist, QStringLiteral("Various Artists")); QCOMPARE(fourthTrackAlbum, QStringLiteral("album1")); QCOMPARE(fourthTrackImage.isValid(), true); QCOMPARE(fourthTrackImage, QUrl::fromLocalFile(QStringLiteral("album1"))); QCOMPARE(fourthTrackDuration, QTime::fromMSecsSinceStartOfDay(4)); QCOMPARE(fourthTrackMilliSecondsDuration, 4); QCOMPARE(fourthTrackTrackNumber, 4); QCOMPARE(fourthTrackDiscNumber, 4); QCOMPARE(fourthTrackResource.isValid(), true); QCOMPARE(fourthTrackResource, QUrl::fromLocalFile(QStringLiteral("/$4"))); QCOMPARE(fourthTrackRating, 3); QCOMPARE(fourthIsSingleDiscAlbum, false); auto secondAlbumData = musicDb.albumData(allAlbums[1].databaseId()); auto secondAlbumTitle = allAlbums[1].title(); auto secondAlbumArtist = allAlbums[1].artist(); auto secondAlbumImage = allAlbums[1].albumArtURI(); auto secondAlbumTracksCount = secondAlbumData.count(); auto secondAlbumIsSingleDiscAlbum = allAlbums[1].isSingleDiscAlbum(); QCOMPARE(secondAlbumTitle, QStringLiteral("album2")); QCOMPARE(secondAlbumArtist, QStringLiteral("artist1")); QCOMPARE(secondAlbumImage.isValid(), true); QCOMPARE(secondAlbumImage, QUrl::fromLocalFile(QStringLiteral("album2"))); QCOMPARE(secondAlbumTracksCount, 6); QCOMPARE(secondAlbumIsSingleDiscAlbum, true); } void simpleAccessorAndVariousArtistAlbumWithFile() { QTemporaryFile myDatabaseFile; myDatabaseFile.open(); { DatabaseInterface musicDb; QSignalSpy musicDbArtistAddedSpy(&musicDb, &DatabaseInterface::artistsAdded); QSignalSpy musicDbAlbumAddedSpy(&musicDb, &DatabaseInterface::albumsAdded); QSignalSpy musicDbTrackAddedSpy(&musicDb, &DatabaseInterface::tracksAdded); QCOMPARE(musicDb.allAlbumsData().count(), 0); QCOMPARE(musicDbArtistAddedSpy.count(), 0); QCOMPARE(musicDbAlbumAddedSpy.count(), 0); QCOMPARE(musicDbTrackAddedSpy.count(), 0); musicDb.init(QStringLiteral("testDbVariousArtistAlbum1"), myDatabaseFile.fileName()); QCOMPARE(musicDb.allAlbumsData().count(), 0); QCOMPARE(musicDbArtistAddedSpy.count(), 0); QCOMPARE(musicDbAlbumAddedSpy.count(), 0); QCOMPARE(musicDbTrackAddedSpy.count(), 0); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 22); QCOMPARE(musicDbArtistAddedSpy.count(), 1); QCOMPARE(musicDbAlbumAddedSpy.count(), 1); QCOMPARE(musicDbTrackAddedSpy.count(), 1); auto allAlbums = musicDb.allAlbumsData(); auto firstAlbumData = musicDb.albumData(allAlbums[0].databaseId()); auto firstAlbumTitle = allAlbums[0].title(); auto firstAlbumArtist = allAlbums[0].artist(); auto firstAlbumImage = allAlbums[0].albumArtURI(); auto firstAlbumTracksCount = firstAlbumData.count(); auto firstAlbumIsSingleDiscAlbum = allAlbums[0].isSingleDiscAlbum(); QCOMPARE(firstAlbumTitle, QStringLiteral("album1")); QCOMPARE(firstAlbumArtist, QStringLiteral("Various Artists")); QCOMPARE(firstAlbumImage.isValid(), true); QCOMPARE(firstAlbumImage, QUrl::fromLocalFile(QStringLiteral("album1"))); QCOMPARE(firstAlbumTracksCount, 4); QCOMPARE(firstAlbumIsSingleDiscAlbum, false); auto invalidTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track1"), QStringLiteral("artist1"), QStringLiteral("album1"), 2, 1); QCOMPARE(invalidTrackId, decltype(invalidTrackId)(0)); auto firstTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track1"), QStringLiteral("artist1"), QStringLiteral("album1"), 1, 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("track1")); QCOMPARE(firstTrackArtist, QStringLiteral("artist1")); QCOMPARE(firstTrackAlbumArtist, QStringLiteral("Various Artists")); QCOMPARE(firstTrackAlbum, QStringLiteral("album1")); QCOMPARE(firstTrackImage.isValid(), true); QCOMPARE(firstTrackImage, QUrl::fromLocalFile(QStringLiteral("album1"))); QCOMPARE(firstTrackDuration, QTime::fromMSecsSinceStartOfDay(1)); QCOMPARE(firstTrackMilliSecondsDuration, 1); QCOMPARE(firstTrackTrackNumber, 1); QCOMPARE(firstTrackDiscNumber, 1); QCOMPARE(firstTrackResource.isValid(), true); QCOMPARE(firstTrackResource, QUrl::fromLocalFile(QStringLiteral("/$1"))); QCOMPARE(firstTrackRating, 1); QCOMPARE(firstIsSingleDiscAlbum, false); auto secondTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track2"), QStringLiteral("artist2"), QStringLiteral("album1"), 2, 2); auto secondTrack = musicDb.trackDataFromDatabaseId(secondTrackId); auto secondTrackTitle = secondTrack.title(); auto secondTrackArtist = secondTrack.artist(); auto secondTrackAlbumArtist = secondTrack.albumArtist(); auto secondTrackAlbum = secondTrack.album(); auto seconfTrackImage = secondTrack.albumCover(); auto secondTrackDuration = secondTrack.duration(); auto secondTrackMilliSecondsDuration = secondTrack.duration().msecsSinceStartOfDay(); auto secondTrackTrackNumber = secondTrack.trackNumber(); auto secondTrackDiscNumber = secondTrack.discNumber(); const auto &secondTrackResource = secondTrack.resourceURI(); auto secondTrackRating = secondTrack.rating(); auto secondIsSingleDiscAlbum = secondTrack.isSingleDiscAlbum(); QCOMPARE(secondTrack.isValid(), true); QCOMPARE(secondTrackTitle, QStringLiteral("track2")); QCOMPARE(secondTrackArtist, QStringLiteral("artist2")); QCOMPARE(secondTrackAlbumArtist, QStringLiteral("Various Artists")); QCOMPARE(secondTrackAlbum, QStringLiteral("album1")); QCOMPARE(seconfTrackImage.isValid(), true); QCOMPARE(seconfTrackImage, QUrl::fromLocalFile(QStringLiteral("album1"))); QCOMPARE(secondTrackDuration, QTime::fromMSecsSinceStartOfDay(2)); QCOMPARE(secondTrackMilliSecondsDuration, 2); QCOMPARE(secondTrackTrackNumber, 2); QCOMPARE(secondTrackDiscNumber, 2); QCOMPARE(secondTrackResource.isValid(), true); QCOMPARE(secondTrackResource, QUrl::fromLocalFile(QStringLiteral("/$2"))); QCOMPARE(secondTrackRating, 2); QCOMPARE(secondIsSingleDiscAlbum, false); auto thirdTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track3"), QStringLiteral("artist3"), QStringLiteral("album1"), 3, 3); auto thirdTrack = musicDb.trackDataFromDatabaseId(thirdTrackId); auto thirdTrackTitle = thirdTrack.title(); auto thirdTrackArtist = thirdTrack.artist(); auto thirdTrackAlbumArtist = thirdTrack.albumArtist(); auto thirdTrackAlbum = thirdTrack.album(); auto thirdTrackImage = thirdTrack.albumCover(); auto thirdTrackDuration = thirdTrack.duration(); auto thirdTrackMilliSecondsDuration = thirdTrack.duration().msecsSinceStartOfDay(); auto thirdTrackTrackNumber = thirdTrack.trackNumber(); auto thirdTrackDiscNumber = thirdTrack.discNumber(); const auto &thirdTrackResource = thirdTrack.resourceURI(); auto thirdTrackRating = thirdTrack.rating(); auto thirdIsSingleDiscAlbum = thirdTrack.isSingleDiscAlbum(); QCOMPARE(thirdTrack.isValid(), true); QCOMPARE(thirdTrackTitle, QStringLiteral("track3")); QCOMPARE(thirdTrackArtist, QStringLiteral("artist3")); QCOMPARE(thirdTrackAlbumArtist, QStringLiteral("Various Artists")); QCOMPARE(thirdTrackAlbum, QStringLiteral("album1")); QCOMPARE(thirdTrackImage.isValid(), true); QCOMPARE(thirdTrackImage, QUrl::fromLocalFile(QStringLiteral("album1"))); QCOMPARE(thirdTrackDuration, QTime::fromMSecsSinceStartOfDay(3)); QCOMPARE(thirdTrackMilliSecondsDuration, 3); QCOMPARE(thirdTrackTrackNumber, 3); QCOMPARE(thirdTrackDiscNumber, 3); QCOMPARE(thirdTrackResource.isValid(), true); QCOMPARE(thirdTrackResource, QUrl::fromLocalFile(QStringLiteral("/$3"))); QCOMPARE(thirdTrackRating, 3); QCOMPARE(thirdIsSingleDiscAlbum, false); auto fourthTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track4"), QStringLiteral("artist4"), QStringLiteral("album1"), 4, 4); auto fourthTrack = musicDb.trackDataFromDatabaseId(fourthTrackId); auto fourthTrackTitle = fourthTrack.title(); auto fourthTrackArtist = fourthTrack.artist(); auto fourthTrackAlbumArtist = fourthTrack.albumArtist(); auto fourthTrackAlbum = fourthTrack.album(); auto fourthTrackImage = fourthTrack.albumCover(); auto fourthTrackDuration = fourthTrack.duration(); auto fourthTrackMilliSecondsDuration = fourthTrack.duration().msecsSinceStartOfDay(); auto fourthTrackTrackNumber = fourthTrack.trackNumber(); auto fourthTrackDiscNumber = fourthTrack.discNumber(); const auto &fourthTrackResource = fourthTrack.resourceURI(); auto fourthTrackRating = thirdTrack.rating(); auto fourthIsSingleDiscAlbum = fourthTrack.isSingleDiscAlbum(); QCOMPARE(fourthTrack.isValid(), true); QCOMPARE(fourthTrackTitle, QStringLiteral("track4")); QCOMPARE(fourthTrackArtist, QStringLiteral("artist4")); QCOMPARE(fourthTrackAlbumArtist, QStringLiteral("Various Artists")); QCOMPARE(fourthTrackAlbum, QStringLiteral("album1")); QCOMPARE(fourthTrackImage.isValid(), true); QCOMPARE(fourthTrackImage, QUrl::fromLocalFile(QStringLiteral("album1"))); QCOMPARE(fourthTrackDuration, QTime::fromMSecsSinceStartOfDay(4)); QCOMPARE(fourthTrackMilliSecondsDuration, 4); QCOMPARE(fourthTrackTrackNumber, 4); QCOMPARE(fourthTrackDiscNumber, 4); QCOMPARE(fourthTrackResource.isValid(), true); QCOMPARE(fourthTrackResource, QUrl::fromLocalFile(QStringLiteral("/$4"))); QCOMPARE(fourthTrackRating, 3); QCOMPARE(fourthIsSingleDiscAlbum, false); auto secondAlbumData = musicDb.albumData(allAlbums[1].databaseId()); auto secondAlbumTitle = allAlbums[1].title(); auto secondAlbumArtist = allAlbums[1].artist(); auto secondAlbumImage = allAlbums[1].albumArtURI(); auto secondAlbumTracksCount = secondAlbumData.count(); auto secondAlbumIsSingleDiscAlbum = allAlbums[1].isSingleDiscAlbum(); QCOMPARE(secondAlbumTitle, QStringLiteral("album2")); QCOMPARE(secondAlbumArtist, QStringLiteral("artist1")); QCOMPARE(secondAlbumImage.isValid(), true); QCOMPARE(secondAlbumImage, QUrl::fromLocalFile(QStringLiteral("album2"))); QCOMPARE(secondAlbumTracksCount, 6); QCOMPARE(secondAlbumIsSingleDiscAlbum, true); } { DatabaseInterface musicDb; QSignalSpy musicDbArtistAddedSpy(&musicDb, &DatabaseInterface::artistsAdded); QSignalSpy musicDbAlbumAddedSpy(&musicDb, &DatabaseInterface::albumsAdded); QSignalSpy musicDbTrackAddedSpy(&musicDb, &DatabaseInterface::tracksAdded); QCOMPARE(musicDb.allAlbumsData().count(), 0); QCOMPARE(musicDbArtistAddedSpy.count(), 0); QCOMPARE(musicDbAlbumAddedSpy.count(), 0); QCOMPARE(musicDbTrackAddedSpy.count(), 0); musicDb.init(QStringLiteral("testDbVariousArtistAlbum2"), myDatabaseFile.fileName()); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 22); QCOMPARE(musicDbArtistAddedSpy.count(), 0); QCOMPARE(musicDbAlbumAddedSpy.count(), 0); QCOMPARE(musicDbTrackAddedSpy.count(), 0); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 22); QCOMPARE(musicDbArtistAddedSpy.count(), 0); QCOMPARE(musicDbAlbumAddedSpy.count(), 0); QCOMPARE(musicDbTrackAddedSpy.count(), 0); auto allAlbums = musicDb.allAlbumsData(); auto firstAlbumData = musicDb.albumData(allAlbums[0].databaseId()); auto firstAlbumTitle = allAlbums[0].title(); auto firstAlbumArtist = allAlbums[0].artist(); auto firstAlbumImage = allAlbums[0].albumArtURI(); auto firstAlbumTracksCount = firstAlbumData.count(); auto firstAlbumIsSingleDiscAlbum = allAlbums[0].isSingleDiscAlbum(); QCOMPARE(firstAlbumTitle, QStringLiteral("album1")); QCOMPARE(firstAlbumArtist, QStringLiteral("Various Artists")); QCOMPARE(firstAlbumImage.isValid(), true); QCOMPARE(firstAlbumImage, QUrl::fromLocalFile(QStringLiteral("album1"))); QCOMPARE(firstAlbumTracksCount, 4); QCOMPARE(firstAlbumIsSingleDiscAlbum, false); auto invalidTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track1"), QStringLiteral("artist1"), QStringLiteral("album1"), 2, 1); QCOMPARE(invalidTrackId, decltype(invalidTrackId)(0)); auto firstTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track1"), QStringLiteral("artist1"), QStringLiteral("album1"), 1, 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("track1")); QCOMPARE(firstTrackArtist, QStringLiteral("artist1")); QCOMPARE(firstTrackAlbumArtist, QStringLiteral("Various Artists")); QCOMPARE(firstTrackAlbum, QStringLiteral("album1")); QCOMPARE(firstTrackImage.isValid(), true); QCOMPARE(firstTrackImage, QUrl::fromLocalFile(QStringLiteral("album1"))); QCOMPARE(firstTrackDuration, QTime::fromMSecsSinceStartOfDay(1)); QCOMPARE(firstTrackMilliSecondsDuration, 1); QCOMPARE(firstTrackTrackNumber, 1); QCOMPARE(firstTrackDiscNumber, 1); QCOMPARE(firstTrackResource.isValid(), true); QCOMPARE(firstTrackResource, QUrl::fromLocalFile(QStringLiteral("/$1"))); QCOMPARE(firstTrackRating, 1); QCOMPARE(firstIsSingleDiscAlbum, false); auto secondTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track2"), QStringLiteral("artist2"), QStringLiteral("album1"), 2, 2); auto secondTrack = musicDb.trackDataFromDatabaseId(secondTrackId); auto secondTrackTitle = secondTrack.title(); auto secondTrackArtist = secondTrack.artist(); auto secondTrackAlbumArtist = secondTrack.albumArtist(); auto secondTrackAlbum = secondTrack.album(); auto seconfTrackImage = secondTrack.albumCover(); auto secondTrackDuration = secondTrack.duration(); auto secondTrackMilliSecondsDuration = secondTrack.duration().msecsSinceStartOfDay(); auto secondTrackTrackNumber = secondTrack.trackNumber(); auto secondTrackDiscNumber = secondTrack.discNumber(); const auto &secondTrackResource = secondTrack.resourceURI(); auto secondTrackRating = secondTrack.rating(); auto secondIsSingleDiscAlbum = secondTrack.isSingleDiscAlbum(); QCOMPARE(secondTrack.isValid(), true); QCOMPARE(secondTrackTitle, QStringLiteral("track2")); QCOMPARE(secondTrackArtist, QStringLiteral("artist2")); QCOMPARE(secondTrackAlbumArtist, QStringLiteral("Various Artists")); QCOMPARE(secondTrackAlbum, QStringLiteral("album1")); QCOMPARE(seconfTrackImage.isValid(), true); QCOMPARE(seconfTrackImage, QUrl::fromLocalFile(QStringLiteral("album1"))); QCOMPARE(secondTrackDuration, QTime::fromMSecsSinceStartOfDay(2)); QCOMPARE(secondTrackMilliSecondsDuration, 2); QCOMPARE(secondTrackTrackNumber, 2); QCOMPARE(secondTrackDiscNumber, 2); QCOMPARE(secondTrackResource.isValid(), true); QCOMPARE(secondTrackResource, QUrl::fromLocalFile(QStringLiteral("/$2"))); QCOMPARE(secondTrackRating, 2); QCOMPARE(secondIsSingleDiscAlbum, false); auto thirdTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track3"), QStringLiteral("artist3"), QStringLiteral("album1"), 3, 3); auto thirdTrack = musicDb.trackDataFromDatabaseId(thirdTrackId); auto thirdTrackTitle = thirdTrack.title(); auto thirdTrackArtist = thirdTrack.artist(); auto thirdTrackAlbumArtist = thirdTrack.albumArtist(); auto thirdTrackAlbum = thirdTrack.album(); auto thirdTrackImage = thirdTrack.albumCover(); auto thirdTrackDuration = thirdTrack.duration(); auto thirdTrackMilliSecondsDuration = thirdTrack.duration().msecsSinceStartOfDay(); auto thirdTrackTrackNumber = thirdTrack.trackNumber(); auto thirdTrackDiscNumber = thirdTrack.discNumber(); const auto &thirdTrackResource = thirdTrack.resourceURI(); auto thirdTrackRating = thirdTrack.rating(); auto thirdIsSingleDiscAlbum = thirdTrack.isSingleDiscAlbum(); QCOMPARE(thirdTrack.isValid(), true); QCOMPARE(thirdTrackTitle, QStringLiteral("track3")); QCOMPARE(thirdTrackArtist, QStringLiteral("artist3")); QCOMPARE(thirdTrackAlbumArtist, QStringLiteral("Various Artists")); QCOMPARE(thirdTrackAlbum, QStringLiteral("album1")); QCOMPARE(thirdTrackImage.isValid(), true); QCOMPARE(thirdTrackImage, QUrl::fromLocalFile(QStringLiteral("album1"))); QCOMPARE(thirdTrackDuration, QTime::fromMSecsSinceStartOfDay(3)); QCOMPARE(thirdTrackMilliSecondsDuration, 3); QCOMPARE(thirdTrackTrackNumber, 3); QCOMPARE(thirdTrackDiscNumber, 3); QCOMPARE(thirdTrackResource.isValid(), true); QCOMPARE(thirdTrackResource, QUrl::fromLocalFile(QStringLiteral("/$3"))); QCOMPARE(thirdTrackRating, 3); QCOMPARE(thirdIsSingleDiscAlbum, false); auto fourthTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track4"), QStringLiteral("artist4"), QStringLiteral("album1"), 4, 4); auto fourthTrack = musicDb.trackDataFromDatabaseId(fourthTrackId); auto fourthTrackTitle = fourthTrack.title(); auto fourthTrackArtist = fourthTrack.artist(); auto fourthTrackAlbumArtist = fourthTrack.albumArtist(); auto fourthTrackAlbum = fourthTrack.album(); auto fourthTrackImage = fourthTrack.albumCover(); auto fourthTrackDuration = fourthTrack.duration(); auto fourthTrackMilliSecondsDuration = fourthTrack.duration().msecsSinceStartOfDay(); auto fourthTrackTrackNumber = fourthTrack.trackNumber(); auto fourthTrackDiscNumber = fourthTrack.discNumber(); const auto &fourthTrackResource = fourthTrack.resourceURI(); auto fourthTrackRating = thirdTrack.rating(); auto fourthIsSingleDiscAlbum = fourthTrack.isSingleDiscAlbum(); QCOMPARE(fourthTrack.isValid(), true); QCOMPARE(fourthTrackTitle, QStringLiteral("track4")); QCOMPARE(fourthTrackArtist, QStringLiteral("artist4")); QCOMPARE(fourthTrackAlbumArtist, QStringLiteral("Various Artists")); QCOMPARE(fourthTrackAlbum, QStringLiteral("album1")); QCOMPARE(fourthTrackImage.isValid(), true); QCOMPARE(fourthTrackImage, QUrl::fromLocalFile(QStringLiteral("album1"))); QCOMPARE(fourthTrackDuration, QTime::fromMSecsSinceStartOfDay(4)); QCOMPARE(fourthTrackMilliSecondsDuration, 4); QCOMPARE(fourthTrackTrackNumber, 4); QCOMPARE(fourthTrackDiscNumber, 4); QCOMPARE(fourthTrackResource.isValid(), true); QCOMPARE(fourthTrackResource, QUrl::fromLocalFile(QStringLiteral("/$4"))); QCOMPARE(fourthTrackRating, 3); QCOMPARE(fourthIsSingleDiscAlbum, false); auto secondAlbumData = musicDb.albumData(allAlbums[1].databaseId()); auto secondAlbumTitle = allAlbums[1].title(); auto secondAlbumArtist = allAlbums[1].artist(); auto secondAlbumImage = allAlbums[1].albumArtURI(); auto secondAlbumTracksCount = secondAlbumData.count(); auto secondAlbumIsSingleDiscAlbum = allAlbums[1].isSingleDiscAlbum(); QCOMPARE(secondAlbumTitle, QStringLiteral("album2")); QCOMPARE(secondAlbumArtist, QStringLiteral("artist1")); QCOMPARE(secondAlbumImage.isValid(), true); QCOMPARE(secondAlbumImage, QUrl::fromLocalFile(QStringLiteral("album2"))); QCOMPARE(secondAlbumTracksCount, 6); QCOMPARE(secondAlbumIsSingleDiscAlbum, true); auto newTrack = MusicAudioTrack{true, QStringLiteral("$23"), QStringLiteral("0"), QStringLiteral("track6"), QStringLiteral("artist8"), QStringLiteral("album3"), QStringLiteral("artist2"), 6, 1, QTime::fromMSecsSinceStartOfDay(23), {QUrl::fromLocalFile(QStringLiteral("/$23"))}, QDateTime::fromMSecsSinceEpoch(23), {QUrl::fromLocalFile(QStringLiteral("album3"))}, 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}; auto newTracks = QList(); newTracks.push_back(newTrack); auto newFiles2 = QList(); for (const auto &oneTrack : newTracks) { newFiles2.push_back(oneTrack.resourceURI()); } auto newCovers = mNewCovers; newCovers[QStringLiteral("file:///$23")] = QUrl::fromLocalFile(QStringLiteral("image$19")); musicDb.insertTracksList(newTracks, newCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 8); QCOMPARE(musicDb.allTracksData().count(), 23); QCOMPARE(musicDbArtistAddedSpy.count(), 1); QCOMPARE(musicDbAlbumAddedSpy.count(), 0); QCOMPARE(musicDbTrackAddedSpy.count(), 1); } } void testTracksFromAuthor() { DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDbVariousArtistAlbum")); QSignalSpy musicDbArtistAddedSpy(&musicDb, &DatabaseInterface::artistsAdded); QSignalSpy musicDbAlbumAddedSpy(&musicDb, &DatabaseInterface::albumsAdded); QSignalSpy musicDbTrackAddedSpy(&musicDb, &DatabaseInterface::tracksAdded); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 22); QCOMPARE(musicDbArtistAddedSpy.count(), 1); QCOMPARE(musicDbAlbumAddedSpy.count(), 1); QCOMPARE(musicDbTrackAddedSpy.count(), 1); auto allTracks = musicDb.tracksDataFromAuthor(QStringLiteral("artist1")); QCOMPARE(allTracks.size(), 6); QCOMPARE(allTracks[0].albumArtist(), QStringLiteral("Various Artists")); QCOMPARE(allTracks[1].albumArtist(), QStringLiteral("artist1")); QCOMPARE(allTracks[2].albumArtist(), QStringLiteral("artist1")); QCOMPARE(allTracks[3].albumArtist(), QStringLiteral("artist1")); QCOMPARE(allTracks[4].albumArtist(), QStringLiteral("artist1")); QCOMPARE(allTracks[5].albumArtist(), QStringLiteral("artist1")); } void removeOneTrack() { QTemporaryFile databaseFile; databaseFile.open(); qDebug() << "removeOneTrack" << databaseFile.fileName(); DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb"), 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); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 22); 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 allAlbums = musicDb.allAlbumsData(); auto firstAlbumData = musicDb.albumData(allAlbums[0].databaseId()); auto firstAlbumTitle = allAlbums[0].title(); auto firstAlbumArtist = allAlbums[0].artist(); auto firstAlbumImage = allAlbums[0].albumArtURI(); auto firstAlbumTracksCount = firstAlbumData.count(); auto firstAlbumIsSingleDiscAlbum = allAlbums[0].isSingleDiscAlbum(); QCOMPARE(firstAlbumTitle, QStringLiteral("album1")); QCOMPARE(firstAlbumArtist, QStringLiteral("Various Artists")); QCOMPARE(firstAlbumImage.isValid(), true); QCOMPARE(firstAlbumImage, QUrl::fromLocalFile(QStringLiteral("album1"))); QCOMPARE(firstAlbumTracksCount, 4); QCOMPARE(firstAlbumIsSingleDiscAlbum, false); auto trackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track1"), QStringLiteral("artist1"), QStringLiteral("album1"), 1, 1); QVERIFY2(trackId != 0, "trackId should be different from 0"); auto firstTrack = musicDb.trackDataFromDatabaseId(trackId); QCOMPARE(firstTrack.isValid(), true); musicDb.removeTracksList({firstTrack.resourceURI()}); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 21); QCOMPARE(musicDbArtistAddedSpy.count(), 1); QCOMPARE(musicDbAlbumAddedSpy.count(), 1); QCOMPARE(musicDbTrackAddedSpy.count(), 1); QCOMPARE(musicDbArtistRemovedSpy.count(), 0); QCOMPARE(musicDbAlbumRemovedSpy.count(), 0); QCOMPARE(musicDbTrackRemovedSpy.count(), 1); QCOMPARE(musicDbAlbumModifiedSpy.count(), 1); QCOMPARE(musicDbTrackModifiedSpy.count(), 0); QCOMPARE(musicDbDatabaseErrorSpy.count(), 0); auto allAlbumsV2 = musicDb.allAlbumsData(); const auto &firstAlbum = allAlbumsV2[0]; QCOMPARE(musicDb.allAlbumsData().isEmpty(), false); QCOMPARE(firstAlbum.isValid(), true); auto firstAlbumDataV2 = musicDb.albumData(firstAlbum.databaseId()); auto firstAlbumTitleV2 = firstAlbum.title(); auto firstAlbumArtistV2 = firstAlbum.artist(); auto firstAlbumImageV2 = firstAlbum.albumArtURI(); auto firstAlbumTracksCountV2 = firstAlbumDataV2.count(); auto firstAlbumIsSingleDiscAlbumV2 = firstAlbum.isSingleDiscAlbum(); QCOMPARE(firstAlbumTitleV2, QStringLiteral("album1")); QCOMPARE(firstAlbumArtistV2, QStringLiteral("Various Artists")); QCOMPARE(firstAlbumImageV2.isValid(), true); QCOMPARE(firstAlbumImageV2, QUrl::fromLocalFile(QStringLiteral("album1"))); QCOMPARE(firstAlbumTracksCountV2, 3); QCOMPARE(firstAlbumIsSingleDiscAlbumV2, false); auto removedTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track1"), QStringLiteral("artist1"), QStringLiteral("album1"), 1, 1); QCOMPARE(removedTrackId, qulonglong(0)); } void removeOneTrackAndModifyIt() { QTemporaryFile databaseFile; databaseFile.open(); qDebug() << "removeOneTrackAndModifyIt" << databaseFile.fileName(); DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb"), 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); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 22); 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 allAlbums = musicDb.allAlbumsData(); auto firstAlbumData = musicDb.albumData(allAlbums[0].databaseId()); auto firstAlbumTitle = allAlbums[0].title(); auto firstAlbumArtist = allAlbums[0].artist(); auto firstAlbumImage = allAlbums[0].albumArtURI(); auto firstAlbumTracksCount = firstAlbumData.count(); auto firstAlbumIsSingleDiscAlbum = allAlbums[0].isSingleDiscAlbum(); QCOMPARE(firstAlbumTitle, QStringLiteral("album1")); QCOMPARE(firstAlbumArtist, QStringLiteral("Various Artists")); QCOMPARE(firstAlbumImage.isValid(), true); QCOMPARE(firstAlbumImage, QUrl::fromLocalFile(QStringLiteral("album1"))); QCOMPARE(firstAlbumTracksCount, 4); QCOMPARE(firstAlbumIsSingleDiscAlbum, false); auto trackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track1"), QStringLiteral("artist1"), QStringLiteral("album1"), 1, 1); QCOMPARE(trackId != 0, true); auto firstTrack = musicDb.trackDataFromDatabaseId(trackId); QCOMPARE(firstTrack.isValid(), true); musicDb.removeTracksList({firstTrack.resourceURI()}); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 21); QCOMPARE(musicDbArtistAddedSpy.count(), 1); QCOMPARE(musicDbAlbumAddedSpy.count(), 1); QCOMPARE(musicDbTrackAddedSpy.count(), 1); QCOMPARE(musicDbArtistRemovedSpy.count(), 0); QCOMPARE(musicDbAlbumRemovedSpy.count(), 0); QCOMPARE(musicDbTrackRemovedSpy.count(), 1); QCOMPARE(musicDbAlbumModifiedSpy.count(), 1); QCOMPARE(musicDbTrackModifiedSpy.count(), 0); QCOMPARE(musicDbDatabaseErrorSpy.count(), 0); auto allAlbumsV2 = musicDb.allAlbumsData(); const auto &firstAlbum = allAlbumsV2[0]; QCOMPARE(musicDb.allAlbumsData().isEmpty(), false); QCOMPARE(firstAlbum.isValid(), true); auto firstAlbumDataV2 = musicDb.albumData(firstAlbum.databaseId()); auto firstAlbumTitleV2 = firstAlbum.title(); auto firstAlbumArtistV2 = firstAlbum.artist(); auto firstAlbumImageV2 = firstAlbum.albumArtURI(); auto firstAlbumTracksCountV2 = firstAlbumDataV2.count(); auto firstAlbumIsSingleDiscAlbumV2 = firstAlbum.isSingleDiscAlbum(); QCOMPARE(firstAlbumTitleV2, QStringLiteral("album1")); QCOMPARE(firstAlbumArtistV2, QStringLiteral("Various Artists")); QCOMPARE(firstAlbumImageV2.isValid(), true); QCOMPARE(firstAlbumImageV2, QUrl::fromLocalFile(QStringLiteral("album1"))); QCOMPARE(firstAlbumTracksCountV2, 3); QCOMPARE(firstAlbumIsSingleDiscAlbumV2, false); auto removedTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track1"), QStringLiteral("artist1"), QStringLiteral("album1"), 1, 1); QCOMPARE(removedTrackId, qulonglong(0)); firstTrack[DatabaseInterface::DatabaseIdRole] = 0; musicDb.insertTracksList({MusicAudioTrack::trackFromData(firstTrack)}, mNewCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 22); QCOMPARE(musicDbArtistAddedSpy.count(), 1); QCOMPARE(musicDbAlbumAddedSpy.count(), 1); QCOMPARE(musicDbTrackAddedSpy.count(), 2); QCOMPARE(musicDbArtistRemovedSpy.count(), 0); QCOMPARE(musicDbAlbumRemovedSpy.count(), 0); QCOMPARE(musicDbTrackRemovedSpy.count(), 1); QCOMPARE(musicDbAlbumModifiedSpy.count(), 2); QCOMPARE(musicDbTrackModifiedSpy.count(), 3); QCOMPARE(musicDbDatabaseErrorSpy.count(), 0); auto allAlbums3 = musicDb.allAlbumsData(); auto firstAlbumData3 = musicDb.albumData(allAlbums3[0].databaseId()); auto firstAlbumTitle3 = allAlbums3[0].title(); auto firstAlbumArtist3 = allAlbums3[0].artist(); auto firstAlbumImage3 = allAlbums3[0].albumArtURI(); auto firstAlbumTracksCount3 = firstAlbumData3.count(); auto firstAlbumIsSingleDiscAlbum3 = allAlbums3[0].isSingleDiscAlbum(); QCOMPARE(firstAlbumTitle3, QStringLiteral("album1")); QCOMPARE(firstAlbumArtist3, QStringLiteral("Various Artists")); QCOMPARE(firstAlbumImage3.isValid(), true); QCOMPARE(firstAlbumImage3, QUrl::fromLocalFile(QStringLiteral("album1"))); QCOMPARE(firstAlbumTracksCount3, 4); QCOMPARE(firstAlbumIsSingleDiscAlbum3, false); auto trackId3 = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track1"), QStringLiteral("artist1"), QStringLiteral("album1"), 1, 1); QCOMPARE(trackId3 != 0, true); } void removeOneAlbum() { QTemporaryFile databaseFile; databaseFile.open(); qDebug() << "removeOneAlbum" << databaseFile.fileName(); DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb"), 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); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 22); 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 allAlbums = musicDb.allAlbumsData(); auto firstAlbumData = musicDb.albumData(allAlbums[0].databaseId()); auto firstAlbumTitle = allAlbums[0].title(); auto firstAlbumArtist = allAlbums[0].artist(); auto firstAlbumImage = allAlbums[0].albumArtURI(); auto firstAlbumTracksCount = firstAlbumData.count(); auto firstAlbumIsSingleDiscAlbum = allAlbums[0].isSingleDiscAlbum(); QCOMPARE(firstAlbumTitle, QStringLiteral("album1")); QCOMPARE(firstAlbumArtist, QStringLiteral("Various Artists")); QCOMPARE(firstAlbumImage.isValid(), true); QCOMPARE(firstAlbumImage, QUrl::fromLocalFile(QStringLiteral("album1"))); QCOMPARE(firstAlbumTracksCount, 4); QCOMPARE(firstAlbumIsSingleDiscAlbum, false); auto firstTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track1"), QStringLiteral("artist1"), QStringLiteral("album2"), 1, 1); auto firstTrack = musicDb.trackDataFromDatabaseId(firstTrackId); auto secondTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track2"), QStringLiteral("artist1"), QStringLiteral("album2"), 2, 1); auto secondTrack = musicDb.trackDataFromDatabaseId(secondTrackId); auto thirdTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track3"), QStringLiteral("artist1"), QStringLiteral("album2"), 3, 1); auto thirdTrack = musicDb.trackDataFromDatabaseId(thirdTrackId); auto fourthTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track4"), QStringLiteral("artist1"), QStringLiteral("album2"), 4, 1); auto fourthTrack = musicDb.trackDataFromDatabaseId(fourthTrackId); auto fithTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track5"), QStringLiteral("artist1"), QStringLiteral("album2"), 5, 1); auto fithTrack = musicDb.trackDataFromDatabaseId(fithTrackId); auto sixthTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track6"), QStringLiteral("artist1 and artist2"), QStringLiteral("album2"), 6, 1); auto sixthTrack = musicDb.trackDataFromDatabaseId(sixthTrackId); musicDb.removeTracksList({firstTrack.resourceURI(), secondTrack.resourceURI(), thirdTrack.resourceURI(), fourthTrack.resourceURI(), fithTrack.resourceURI(), sixthTrack.resourceURI()}); QCOMPARE(musicDb.allAlbumsData().count(), 4); QCOMPARE(musicDb.allArtistsData().count(), 6); QCOMPARE(musicDb.allTracksData().count(), 16); QCOMPARE(musicDbArtistAddedSpy.count(), 1); QCOMPARE(musicDbAlbumAddedSpy.count(), 1); QCOMPARE(musicDbTrackAddedSpy.count(), 1); QCOMPARE(musicDbArtistRemovedSpy.count(), 1); QCOMPARE(musicDbAlbumRemovedSpy.count(), 1); QCOMPARE(musicDbTrackRemovedSpy.count(), 6); QCOMPARE(musicDbAlbumModifiedSpy.count(), 0); QCOMPARE(musicDbTrackModifiedSpy.count(), 0); QCOMPARE(musicDbDatabaseErrorSpy.count(), 0); auto removedAlbum = musicDb.albumDataFromDatabaseId(musicDb.albumIdFromTitleAndArtist(QStringLiteral("album2"), QStringLiteral("artist1"))); QCOMPARE(removedAlbum.isValid(), false); } void removeOneArtist() { DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb")); 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); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 22); 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 allAlbums = musicDb.allAlbumsData(); auto firstAlbumData = musicDb.albumData(allAlbums[0].databaseId()); auto firstAlbumTitle = allAlbums[0].title(); auto firstAlbumArtist = allAlbums[0].artist(); auto firstAlbumImage = allAlbums[0].albumArtURI(); auto firstAlbumTracksCount = firstAlbumData.count(); auto firstAlbumIsSingleDiscAlbum = allAlbums[0].isSingleDiscAlbum(); QCOMPARE(firstAlbumTitle, QStringLiteral("album1")); QCOMPARE(firstAlbumArtist, QStringLiteral("Various Artists")); QCOMPARE(firstAlbumImage.isValid(), true); QCOMPARE(firstAlbumImage, QUrl::fromLocalFile(QStringLiteral("album1"))); QCOMPARE(firstAlbumTracksCount, 4); QCOMPARE(firstAlbumIsSingleDiscAlbum, false); auto trackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track3"), QStringLiteral("artist3"), QStringLiteral("album1"), 3, 3); auto track = musicDb.trackDataFromDatabaseId(trackId); musicDb.removeTracksList({track.resourceURI()}); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 6); QCOMPARE(musicDb.allTracksData().count(), 21); QCOMPARE(musicDbArtistAddedSpy.count(), 1); QCOMPARE(musicDbAlbumAddedSpy.count(), 1); QCOMPARE(musicDbTrackAddedSpy.count(), 1); QCOMPARE(musicDbArtistRemovedSpy.count(), 1); QCOMPARE(musicDbAlbumRemovedSpy.count(), 0); QCOMPARE(musicDbTrackRemovedSpy.count(), 1); QCOMPARE(musicDbAlbumModifiedSpy.count(), 1); QCOMPARE(musicDbTrackModifiedSpy.count(), 0); QCOMPARE(musicDbDatabaseErrorSpy.count(), 0); } void addOneTrack() { DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb")); 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); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 22); 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 newTrack = MusicAudioTrack{true, QStringLiteral("$23"), QStringLiteral("0"), QStringLiteral("track6"), QStringLiteral("artist2"), QStringLiteral("album3"), QStringLiteral("artist2"), 6, 1, QTime::fromMSecsSinceStartOfDay(23), {QUrl::fromLocalFile(QStringLiteral("/$23"))}, QDateTime::fromMSecsSinceEpoch(23), QUrl::fromLocalFile(QStringLiteral("album3")), 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}; auto newTracks = QList(); newTracks.push_back(newTrack); auto newCovers = mNewCovers; newCovers[QStringLiteral("file:///$23")] = QUrl::fromLocalFile(QStringLiteral("album3")); musicDb.insertTracksList(newTracks, newCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 23); QCOMPARE(musicDbArtistAddedSpy.count(), 1); QCOMPARE(musicDbAlbumAddedSpy.count(), 1); QCOMPARE(musicDbTrackAddedSpy.count(), 2); QCOMPARE(musicDbArtistRemovedSpy.count(), 0); QCOMPARE(musicDbAlbumRemovedSpy.count(), 0); QCOMPARE(musicDbTrackRemovedSpy.count(), 0); QCOMPARE(musicDbAlbumModifiedSpy.count(), 1); QCOMPARE(musicDbTrackModifiedSpy.count(), 3); QCOMPARE(musicDbDatabaseErrorSpy.count(), 0); } void addTwoTracksSameAlbumSameTitle() { QTemporaryFile databaseFile; databaseFile.open(); qDebug() << "addTwoTracksSameAlbumSameTitle" << databaseFile.fileName(); DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb"), 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 newTrack = MusicAudioTrack{true, QStringLiteral("$23"), QStringLiteral("0"), QStringLiteral("track6"), QStringLiteral("artist2"), QStringLiteral("album3"), QStringLiteral("artist2"), 6, 1, QTime::fromMSecsSinceStartOfDay(23), {QUrl::fromLocalFile(QStringLiteral("/$23"))}, QDateTime::fromMSecsSinceEpoch(23), {QUrl::fromLocalFile(QStringLiteral("album3"))}, 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}; auto newTracks = QList(); newTracks.push_back(newTrack); auto newCovers = mNewCovers; newCovers[QStringLiteral("file:///$23")] = QUrl::fromLocalFile(QStringLiteral("album3")); musicDb.insertTracksList(newTracks, newCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 1); QCOMPARE(musicDb.allArtistsData().count(), 1); QCOMPARE(musicDb.allTracksData().count(), 1); 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("/$23"))); QCOMPARE(firstTrackRating, 5); QCOMPARE(firstIsSingleDiscAlbum, true); auto allAlbums = musicDb.allAlbumsData(); auto firstAlbumData = musicDb.albumData(allAlbums[0].databaseId()); auto firstAlbumTitle = allAlbums[0].title(); auto firstAlbumArtist = allAlbums[0].artist(); auto firstAlbumImage = allAlbums[0].albumArtURI(); auto firstAlbumTracksCount = firstAlbumData.count(); auto firstAlbumIsSingleDiscAlbum = allAlbums[0].isSingleDiscAlbum(); QCOMPARE(firstAlbumTitle, QStringLiteral("album3")); QCOMPARE(firstAlbumArtist, QStringLiteral("artist2")); QCOMPARE(firstAlbumImage.isValid(), true); QCOMPARE(firstAlbumImage, QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(firstAlbumTracksCount, 1); QCOMPARE(firstAlbumIsSingleDiscAlbum, true); auto newTrack2 = MusicAudioTrack{true, QStringLiteral("$23"), QStringLiteral("0"), QStringLiteral("track6"), QStringLiteral("artist9"), QStringLiteral("album3"), QStringLiteral("artist2"), 6, 1, QTime::fromMSecsSinceStartOfDay(23), {QUrl::fromLocalFile(QStringLiteral("/$23"))}, QDateTime::fromMSecsSinceEpoch(23), QUrl::fromLocalFile(QStringLiteral("album3")), 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}; auto newTracks2 = QList(); newTracks2.push_back(newTrack2); auto newCovers2 = mNewCovers; newCovers2[QStringLiteral("file:///$23")] = QUrl::fromLocalFile(QStringLiteral("image$19")); musicDb.insertTracksList(newTracks2, newCovers2); musicDbTrackAddedSpy.wait(50); QCOMPARE(musicDb.allAlbumsData().count(), 1); QCOMPARE(musicDb.allArtistsData().count(), 2); QCOMPARE(musicDb.allTracksData().count(), 1); QCOMPARE(musicDbArtistAddedSpy.count(), 2); QCOMPARE(musicDbAlbumAddedSpy.count(), 1); QCOMPARE(musicDbTrackAddedSpy.count(), 1); QCOMPARE(musicDbArtistRemovedSpy.count(), 0); QCOMPARE(musicDbAlbumRemovedSpy.count(), 0); QCOMPARE(musicDbTrackRemovedSpy.count(), 0); QCOMPARE(musicDbAlbumModifiedSpy.count(), 1); QCOMPARE(musicDbTrackModifiedSpy.count(), 1); QCOMPARE(musicDbDatabaseErrorSpy.count(), 0); auto secondTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track6"), QStringLiteral("artist9"), QStringLiteral("album3"), 6, 1); 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(); const auto &secondTrackResource = secondTrack.resourceURI(); auto secondTrackRating = secondTrack.rating(); auto secondIsSingleDiscAlbum = secondTrack.isSingleDiscAlbum(); QCOMPARE(secondTrack.isValid(), true); QCOMPARE(secondTrackTitle, QStringLiteral("track6")); QCOMPARE(secondTrackArtist, QStringLiteral("artist9")); QCOMPARE(secondTrackAlbumArtist, QStringLiteral("artist2")); QCOMPARE(secondTrackAlbum, QStringLiteral("album3")); QCOMPARE(secondTrackImage.isValid(), true); QCOMPARE(secondTrackImage, QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(secondTrackDuration, QTime::fromMSecsSinceStartOfDay(23)); QCOMPARE(secondTrackMilliSecondsDuration, 23); QCOMPARE(secondTrackTrackNumber, 6); QCOMPARE(secondTrackDiscNumber, 1); QCOMPARE(secondTrackResource.isValid(), true); QCOMPARE(secondTrackResource, QUrl::fromLocalFile(QStringLiteral("/$23"))); QCOMPARE(secondTrackRating, 5); QCOMPARE(secondIsSingleDiscAlbum, true); auto allAlbums2 = musicDb.allAlbumsData(); auto firstAlbumData2 = musicDb.albumData(allAlbums2[0].databaseId()); auto firstAlbumTitle2 = allAlbums2[0].title(); auto firstAlbumArtist2 = allAlbums2[0].artist(); auto firstAlbumImage2 = allAlbums2[0].albumArtURI(); auto firstAlbumTracksCount2 = firstAlbumData2.count(); auto firstAlbumIsSingleDiscAlbum2 = allAlbums2[0].isSingleDiscAlbum(); QCOMPARE(firstAlbumTitle2, QStringLiteral("album3")); QCOMPARE(firstAlbumArtist2, QStringLiteral("artist2")); QCOMPARE(firstAlbumImage2.isValid(), true); QCOMPARE(firstAlbumImage2, QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(firstAlbumTracksCount2, 1); QCOMPARE(firstAlbumIsSingleDiscAlbum2, true); } void addTwoTracksSameFileWithAlbumSameName() { QTemporaryFile databaseFile; databaseFile.open(); qDebug() << "addTwoTracksSameFileWithAlbumSameName" << databaseFile.fileName(); DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb"), 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 newTrack = MusicAudioTrack{true, QStringLiteral("$23"), QStringLiteral("0"), QStringLiteral("track6"), QStringLiteral("artist2"), QStringLiteral("album3"), QStringLiteral("artist2"), 6, 1, QTime::fromMSecsSinceStartOfDay(23), {QUrl::fromLocalFile(QStringLiteral("/$23"))}, QDateTime::fromMSecsSinceEpoch(23), {QUrl::fromLocalFile(QStringLiteral("album3"))}, 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}; auto newTracks = QList(); newTracks.push_back(newTrack); auto newCovers = mNewCovers; newCovers[QStringLiteral("file:///$23")] = QUrl::fromLocalFile(QStringLiteral("album3")); musicDb.insertTracksList(newTracks, newCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 1); QCOMPARE(musicDb.allArtistsData().count(), 1); QCOMPARE(musicDb.allTracksData().count(), 1); 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("/$23"))); QCOMPARE(firstTrackRating, 5); QCOMPARE(firstIsSingleDiscAlbum, true); auto allAlbums = musicDb.allAlbumsData(); QCOMPARE(allAlbums.size(), 1); auto firstAlbumTitle = allAlbums[0].title(); auto firstAlbumArtist = allAlbums[0].artist(); auto firstAlbumImage = allAlbums[0].albumArtURI(); auto firstAlbumTracksCount = musicDb.albumData(allAlbums[0].databaseId()).count(); auto firstAlbumIsSingleDiscAlbum = allAlbums[0].isSingleDiscAlbum(); QCOMPARE(firstAlbumTitle, QStringLiteral("album3")); QCOMPARE(firstAlbumArtist, QStringLiteral("artist2")); QCOMPARE(firstAlbumImage.isValid(), true); QCOMPARE(firstAlbumImage, QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(firstAlbumTracksCount, 1); QCOMPARE(firstAlbumIsSingleDiscAlbum, true); auto newTrack2 = MusicAudioTrack{true, QStringLiteral("$23"), QStringLiteral("0"), QStringLiteral("track6"), QStringLiteral("artist9"), QStringLiteral("album3"), QStringLiteral("artist9"), 6, 1, QTime::fromMSecsSinceStartOfDay(23), {QUrl::fromLocalFile(QStringLiteral("/$23"))}, QDateTime::fromMSecsSinceEpoch(23), QUrl::fromLocalFile(QStringLiteral("album3")), 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}; auto newTracks2 = QList(); newTracks2.push_back(newTrack2); auto newCovers2 = mNewCovers; newCovers2[QStringLiteral("file:///$23")] = QUrl::fromLocalFile(QStringLiteral("album3")); musicDb.insertTracksList(newTracks2, newCovers2); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 1); QCOMPARE(musicDb.allArtistsData().count(), 2); QCOMPARE(musicDb.allTracksData().count(), 1); QCOMPARE(musicDbArtistAddedSpy.count(), 2); QCOMPARE(musicDbAlbumAddedSpy.count(), 2); QCOMPARE(musicDbTrackAddedSpy.count(), 1); QCOMPARE(musicDbArtistRemovedSpy.count(), 0); QCOMPARE(musicDbAlbumRemovedSpy.count(), 1); QCOMPARE(musicDbTrackRemovedSpy.count(), 0); QCOMPARE(musicDbAlbumModifiedSpy.count(), 0); QCOMPARE(musicDbTrackModifiedSpy.count(), 1); QCOMPARE(musicDbDatabaseErrorSpy.count(), 0); auto secondTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track6"), QStringLiteral("artist9"), QStringLiteral("album3"), 6, 1); 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(); const auto &secondTrackResource = secondTrack.resourceURI(); auto secondTrackRating = secondTrack.rating(); auto secondIsSingleDiscAlbum = secondTrack.isSingleDiscAlbum(); QCOMPARE(secondTrack.isValid(), true); QCOMPARE(secondTrackTitle, QStringLiteral("track6")); QCOMPARE(secondTrackArtist, QStringLiteral("artist9")); QCOMPARE(secondTrackAlbumArtist, QStringLiteral("artist9")); QCOMPARE(secondTrackAlbum, QStringLiteral("album3")); QCOMPARE(secondTrackImage.isValid(), true); QCOMPARE(secondTrackImage, QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(secondTrackDuration, QTime::fromMSecsSinceStartOfDay(23)); QCOMPARE(secondTrackMilliSecondsDuration, 23); QCOMPARE(secondTrackTrackNumber, 6); QCOMPARE(secondTrackDiscNumber, 1); QCOMPARE(secondTrackResource.isValid(), true); QCOMPARE(secondTrackResource, QUrl::fromLocalFile(QStringLiteral("/$23"))); QCOMPARE(secondTrackRating, 5); QCOMPARE(secondIsSingleDiscAlbum, true); auto allAlbums2 = musicDb.allAlbumsData(); auto secondAlbumTitle = allAlbums2[0].title(); auto secondAlbumArtist = allAlbums2[0].artist(); auto secondAlbumImage = allAlbums2[0].albumArtURI(); auto secondAlbumTracksCount = musicDb.albumData(allAlbums2[0].databaseId()).count(); auto secondAlbumIsSingleDiscAlbum = allAlbums2[0].isSingleDiscAlbum(); QCOMPARE(secondAlbumTitle, QStringLiteral("album3")); QCOMPARE(secondAlbumArtist, QStringLiteral("artist9")); QCOMPARE(secondAlbumImage.isValid(), true); QCOMPARE(secondAlbumImage, QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(secondAlbumTracksCount, 1); QCOMPARE(secondAlbumIsSingleDiscAlbum, true); } void addTwoTracksWithAlbumSameName() { QTemporaryFile databaseFile; databaseFile.open(); qDebug() << "addTwoTracksWithAlbumSameName" << databaseFile.fileName(); DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb"), 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 newTrack = MusicAudioTrack{true, QStringLiteral("$23"), QStringLiteral("0"), QStringLiteral("track6"), QStringLiteral("artist2"), QStringLiteral("album3"), QStringLiteral("artist2"), 6, 1, QTime::fromMSecsSinceStartOfDay(23), {QUrl::fromLocalFile(QStringLiteral("/$23"))}, QDateTime::fromMSecsSinceEpoch(23), {QUrl::fromLocalFile(QStringLiteral("album3"))}, 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}; auto newTracks = QList(); newTracks.push_back(newTrack); auto newCovers = mNewCovers; newCovers[QStringLiteral("file:///$23")] = QUrl::fromLocalFile(QStringLiteral("album3")); musicDb.insertTracksList(newTracks, newCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 1); QCOMPARE(musicDb.allArtistsData().count(), 1); QCOMPARE(musicDb.allTracksData().count(), 1); 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("/$23"))); QCOMPARE(firstTrackRating, 5); QCOMPARE(firstIsSingleDiscAlbum, true); auto allAlbums = musicDb.allAlbumsData(); QCOMPARE(allAlbums.size(), 1); auto firstAlbumData = musicDb.albumData(allAlbums[0].databaseId()); auto firstAlbumTitle = allAlbums[0].title(); auto firstAlbumArtist = allAlbums[0].artist(); auto firstAlbumImage = allAlbums[0].albumArtURI(); auto firstAlbumTracksCount = firstAlbumData.count(); auto firstAlbumIsSingleDiscAlbum = allAlbums[0].isSingleDiscAlbum(); QCOMPARE(firstAlbumTitle, QStringLiteral("album3")); QCOMPARE(firstAlbumArtist, QStringLiteral("artist2")); QCOMPARE(firstAlbumImage.isValid(), true); QCOMPARE(firstAlbumImage, QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(firstAlbumTracksCount, 1); QCOMPARE(firstAlbumIsSingleDiscAlbum, true); auto newTrack2 = MusicAudioTrack{true, QStringLiteral("$20"), QStringLiteral("0"), QStringLiteral("track6"), QStringLiteral("artist9"), QStringLiteral("album3"), QStringLiteral("artist9"), 6, 1, QTime::fromMSecsSinceStartOfDay(20), {QUrl::fromLocalFile(QStringLiteral("/$20"))}, QDateTime::fromMSecsSinceEpoch(20), {QUrl::fromLocalFile(QStringLiteral("file://image$20"))}, 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}; auto newTracks2 = QList(); newTracks2.push_back(newTrack2); auto newCovers2 = mNewCovers; newCovers2[QStringLiteral("file:///$20")] = QUrl::fromLocalFile(QStringLiteral("album3")); musicDb.insertTracksList(newTracks2, newCovers2); musicDbTrackAddedSpy.wait(50); QCOMPARE(musicDb.allAlbumsData().count(), 2); QCOMPARE(musicDb.allArtistsData().count(), 2); QCOMPARE(musicDb.allTracksData().count(), 2); QCOMPARE(musicDbArtistAddedSpy.count(), 2); QCOMPARE(musicDbAlbumAddedSpy.count(), 2); QCOMPARE(musicDbTrackAddedSpy.count(), 2); 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 secondTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track6"), QStringLiteral("artist9"), QStringLiteral("album3"), 6, 1); 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(); const auto &secondTrackResource = secondTrack.resourceURI(); auto secondTrackRating = secondTrack.rating(); auto secondIsSingleDiscAlbum = secondTrack.isSingleDiscAlbum(); QCOMPARE(secondTrack.isValid(), true); QCOMPARE(secondTrackTitle, QStringLiteral("track6")); QCOMPARE(secondTrackArtist, QStringLiteral("artist9")); QCOMPARE(secondTrackAlbumArtist, QStringLiteral("artist9")); QCOMPARE(secondTrackAlbum, QStringLiteral("album3")); QCOMPARE(secondTrackImage.isValid(), true); QCOMPARE(secondTrackImage, QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(secondTrackDuration, QTime::fromMSecsSinceStartOfDay(20)); QCOMPARE(secondTrackMilliSecondsDuration, 20); QCOMPARE(secondTrackTrackNumber, 6); QCOMPARE(secondTrackDiscNumber, 1); QCOMPARE(secondTrackResource.isValid(), true); QCOMPARE(secondTrackResource, QUrl::fromLocalFile(QStringLiteral("/$20"))); QCOMPARE(secondTrackRating, 5); QCOMPARE(secondIsSingleDiscAlbum, true); auto allAlbums2 = musicDb.allAlbumsData(); auto firstAlbumData2 = musicDb.albumData(allAlbums2[0].databaseId()); auto firstAlbumTitle2 = allAlbums2[0].title(); auto firstAlbumArtist2 = allAlbums2[0].artist(); auto firstAlbumImage2 = allAlbums2[0].albumArtURI(); auto firstAlbumTracksCount2 = firstAlbumData2.count(); auto firstAlbumIsSingleDiscAlbum2 = allAlbums2[0].isSingleDiscAlbum(); QCOMPARE(firstAlbumTitle2, QStringLiteral("album3")); QCOMPARE(firstAlbumArtist2, QStringLiteral("artist2")); QCOMPARE(firstAlbumImage2.isValid(), true); QCOMPARE(firstAlbumImage2, QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(firstAlbumTracksCount2, 1); QCOMPARE(firstAlbumIsSingleDiscAlbum2, true); auto secondAlbumData = musicDb.albumData(allAlbums2[1].databaseId()); auto secondAlbumTitle = allAlbums2[1].title(); auto secondAlbumArtist = allAlbums2[1].artist(); auto secondAlbumImage = allAlbums2[1].albumArtURI(); auto secondAlbumTracksCount = secondAlbumData.count(); auto secondAlbumIsSingleDiscAlbum = allAlbums2[1].isSingleDiscAlbum(); QCOMPARE(secondAlbumTitle, QStringLiteral("album3")); QCOMPARE(secondAlbumArtist, QStringLiteral("artist9")); QCOMPARE(secondAlbumImage.isValid(), true); QCOMPARE(secondAlbumImage, QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(secondAlbumTracksCount, 1); QCOMPARE(secondAlbumIsSingleDiscAlbum, true); } void addTwoTracksInAlbumWithoutCover() { DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb")); 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); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 22); 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 newTrack = MusicAudioTrack{true, QStringLiteral("$23"), QStringLiteral("0"), QStringLiteral("track6"), QStringLiteral("artist2"), QStringLiteral("album7"), QStringLiteral("artist2"), 6, 1, QTime::fromMSecsSinceStartOfDay(23), {QUrl::fromLocalFile(QStringLiteral("/$23"))}, QDateTime::fromMSecsSinceEpoch(23), QUrl::fromLocalFile(QStringLiteral("album3")), 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}; auto newTracks = QList(); newTracks.push_back(newTrack); auto newCovers = mNewCovers; newCovers[QStringLiteral("file:///$23")] = QUrl(); musicDb.insertTracksList(newTracks, newCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 6); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 23); QCOMPARE(musicDbArtistAddedSpy.count(), 1); QCOMPARE(musicDbAlbumAddedSpy.count(), 2); QCOMPARE(musicDbTrackAddedSpy.count(), 2); 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 trackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track6"), QStringLiteral("artist2"), QStringLiteral("album7"), 6, 1); const auto &firstTrack = musicDb.trackDataFromDatabaseId(trackId); QCOMPARE(firstTrack.isValid(), true); QCOMPARE(firstTrack.albumCover(), QUrl()); auto newTrack2 = MusicAudioTrack{true, QStringLiteral("$23"), QStringLiteral("0"), QStringLiteral("track7"), QStringLiteral("artist2"), QStringLiteral("album7"), QStringLiteral("artist2"), 7, 1, QTime::fromMSecsSinceStartOfDay(23), {QUrl::fromLocalFile(QStringLiteral("/$23"))}, QDateTime::fromMSecsSinceEpoch(23), {QUrl::fromLocalFile(QStringLiteral("album7"))}, 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}; auto newTracks2 = QList(); newTracks2.push_back(newTrack2); auto newCovers2 = mNewCovers; newCovers2[QStringLiteral("file:///$23")] = QUrl::fromLocalFile(QStringLiteral("album7")); musicDb.insertTracksList(newTracks2, newCovers2); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 6); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 23); QCOMPARE(musicDbArtistAddedSpy.count(), 1); QCOMPARE(musicDbAlbumAddedSpy.count(), 2); QCOMPARE(musicDbTrackAddedSpy.count(), 2); QCOMPARE(musicDbArtistRemovedSpy.count(), 0); QCOMPARE(musicDbAlbumRemovedSpy.count(), 0); QCOMPARE(musicDbTrackRemovedSpy.count(), 0); QCOMPARE(musicDbAlbumModifiedSpy.count(), 1); QCOMPARE(musicDbTrackModifiedSpy.count(), 1); QCOMPARE(musicDbDatabaseErrorSpy.count(), 0); auto secondTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track7"), QStringLiteral("artist2"), QStringLiteral("album7"), 7, 1); const auto &secondTrack = musicDb.trackDataFromDatabaseId(secondTrackId); QCOMPARE(secondTrack.isValid(), true); QCOMPARE(secondTrack.albumCover(), QUrl::fromLocalFile(QStringLiteral("album7"))); } void modifyOneTrack() { QTemporaryFile databaseFile; databaseFile.open(); qDebug() << "modifyOneTrack" << databaseFile.fileName(); DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb"), 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); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 22); 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 modifiedTrack = MusicAudioTrack{true, QStringLiteral("$3"), QStringLiteral("0"), QStringLiteral("track3"), QStringLiteral("artist3"), QStringLiteral("album1"), QStringLiteral("Various Artists"), 5, 3, QTime::fromMSecsSinceStartOfDay(3), {QUrl::fromLocalFile(QStringLiteral("/$3"))}, QDateTime::fromMSecsSinceEpoch(23), {QUrl::fromLocalFile(QStringLiteral("file://image$3"))}, 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}; musicDb.insertTracksList({modifiedTrack}, mNewCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 22); 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(), 1); QCOMPARE(musicDbTrackModifiedSpy.count(), 1); QCOMPARE(musicDbDatabaseErrorSpy.count(), 0); auto trackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track3"), QStringLiteral("artist3"), QStringLiteral("album1"), 5, 3); QCOMPARE(trackId != 0, true); auto track = musicDb.trackDataFromDatabaseId(trackId); QCOMPARE(track.isValid(), true); QCOMPARE(track.trackNumber(), 5); } void addOneAlbum() { DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb")); 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); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 22); 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 newTrack = MusicAudioTrack{true, QStringLiteral("$23"), QStringLiteral("0"), QStringLiteral("track6"), QStringLiteral("artist2"), QStringLiteral("album7"), QStringLiteral("artist2"), 6, 1, QTime::fromMSecsSinceStartOfDay(23), {QUrl::fromLocalFile(QStringLiteral("/$23"))}, QDateTime::fromMSecsSinceEpoch(23), {QUrl::fromLocalFile(QStringLiteral("album7"))}, 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}; auto newTracks = QList(); newTracks.push_back(newTrack); auto newCover = QUrl::fromLocalFile(QStringLiteral("file://image$19")); auto newCovers = mNewCovers; newCovers[QStringLiteral("file:///$23")] = newCover; musicDb.insertTracksList(newTracks, newCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 6); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 23); QCOMPARE(musicDbArtistAddedSpy.count(), 1); QCOMPARE(musicDbAlbumAddedSpy.count(), 2); QCOMPARE(musicDbTrackAddedSpy.count(), 2); QCOMPARE(musicDbArtistRemovedSpy.count(), 0); QCOMPARE(musicDbAlbumRemovedSpy.count(), 0); QCOMPARE(musicDbTrackRemovedSpy.count(), 0); QCOMPARE(musicDbAlbumModifiedSpy.count(), 0); QCOMPARE(musicDbTrackModifiedSpy.count(), 0); QCOMPARE(musicDbDatabaseErrorSpy.count(), 0); const auto &newAlbum = musicDb.albumDataFromDatabaseId(musicDb.albumIdFromTitleAndArtist(QStringLiteral("album7"), QStringLiteral("artist2"))); QCOMPARE(newAlbum.albumArtURI(), QUrl::fromLocalFile(QStringLiteral("file://image$19"))); } void addOneArtist() { DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb")); 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); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 22); 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 newTrack = MusicAudioTrack{true, QStringLiteral("$23"), QStringLiteral("0"), QStringLiteral("track6"), QStringLiteral("artist6"), QStringLiteral("album1"), QStringLiteral("Various Artists"), 6, 1, QTime::fromMSecsSinceStartOfDay(23), {QUrl::fromLocalFile(QStringLiteral("/$23"))}, QDateTime::fromMSecsSinceEpoch(23), QUrl::fromLocalFile(QStringLiteral("album1")), 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}; auto newTracks = QList(); newTracks.push_back(newTrack); auto newFiles2 = QList(); for (const auto &oneTrack : newTracks) { newFiles2.push_back(oneTrack.resourceURI()); } auto newCovers = mNewCovers; newCovers[QStringLiteral("file:///$23")] = QUrl::fromLocalFile(QStringLiteral("album1")); musicDb.insertTracksList(newTracks, newCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 8); QCOMPARE(musicDb.allTracksData().count(), 23); QCOMPARE(musicDbArtistAddedSpy.count(), 2); QCOMPARE(musicDbAlbumAddedSpy.count(), 1); QCOMPARE(musicDbTrackAddedSpy.count(), 2); QCOMPARE(musicDbArtistRemovedSpy.count(), 0); QCOMPARE(musicDbAlbumRemovedSpy.count(), 0); QCOMPARE(musicDbTrackRemovedSpy.count(), 0); QCOMPARE(musicDbAlbumModifiedSpy.count(), 1); QCOMPARE(musicDbTrackModifiedSpy.count(), 4); QCOMPARE(musicDbDatabaseErrorSpy.count(), 0); } void reloadDatabaseWithAllTracks() { QTemporaryFile databaseFile; databaseFile.open(); qDebug() << "reloadDatabaseWithAllTracks" << databaseFile.fileName(); { DatabaseInterface musicDb; QSignalSpy musicDbTrackAddedSpy(&musicDb, &DatabaseInterface::tracksAdded); QSignalSpy musicDbDatabaseErrorSpy(&musicDb, &DatabaseInterface::databaseError); musicDb.init(QStringLiteral("testDb"), databaseFile.fileName()); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDbDatabaseErrorSpy.count(), 0); } DatabaseInterface musicDb2; QSignalSpy musicDbArtistAddedSpy2(&musicDb2, &DatabaseInterface::artistsAdded); QSignalSpy musicDbAlbumAddedSpy2(&musicDb2, &DatabaseInterface::albumsAdded); QSignalSpy musicDbTrackAddedSpy2(&musicDb2, &DatabaseInterface::tracksAdded); QSignalSpy musicDbArtistRemovedSpy2(&musicDb2, &DatabaseInterface::artistRemoved); QSignalSpy musicDbAlbumRemovedSpy2(&musicDb2, &DatabaseInterface::albumRemoved); QSignalSpy musicDbTrackRemovedSpy2(&musicDb2, &DatabaseInterface::trackRemoved); QSignalSpy musicDbAlbumModifiedSpy2(&musicDb2, &DatabaseInterface::albumModified); QSignalSpy musicDbTrackModifiedSpy2(&musicDb2, &DatabaseInterface::trackModified); QSignalSpy musicDbDatabaseErrorSpy2(&musicDb2, &DatabaseInterface::databaseError); QCOMPARE(musicDb2.allAlbumsData().count(), 0); QCOMPARE(musicDb2.allArtistsData().count(), 0); QCOMPARE(musicDb2.allTracksData().count(), 0); QCOMPARE(musicDbArtistAddedSpy2.count(), 0); QCOMPARE(musicDbAlbumAddedSpy2.count(), 0); QCOMPARE(musicDbTrackAddedSpy2.count(), 0); QCOMPARE(musicDbArtistRemovedSpy2.count(), 0); QCOMPARE(musicDbAlbumRemovedSpy2.count(), 0); QCOMPARE(musicDbTrackRemovedSpy2.count(), 0); QCOMPARE(musicDbAlbumModifiedSpy2.count(), 0); QCOMPARE(musicDbTrackModifiedSpy2.count(), 0); QCOMPARE(musicDbDatabaseErrorSpy2.count(), 0); musicDb2.init(QStringLiteral("testDb2"), databaseFile.fileName()); musicDbTrackAddedSpy2.wait(300); QCOMPARE(musicDb2.allAlbumsData().count(), 5); QCOMPARE(musicDb2.allArtistsData().count(), 7); QCOMPARE(musicDb2.allTracksData().count(), 22); QCOMPARE(musicDbArtistAddedSpy2.count(), 0); QCOMPARE(musicDbAlbumAddedSpy2.count(), 0); QCOMPARE(musicDbTrackAddedSpy2.count(), 0); QCOMPARE(musicDbArtistRemovedSpy2.count(), 0); QCOMPARE(musicDbAlbumRemovedSpy2.count(), 0); QCOMPARE(musicDbTrackRemovedSpy2.count(), 0); QCOMPARE(musicDbAlbumModifiedSpy2.count(), 0); QCOMPARE(musicDbTrackModifiedSpy2.count(), 0); QCOMPARE(musicDbDatabaseErrorSpy2.count(), 0); musicDb2.insertTracksList(mNewTracks, mNewCovers); musicDbTrackAddedSpy2.wait(300); QCOMPARE(musicDb2.allAlbumsData().count(), 5); QCOMPARE(musicDb2.allArtistsData().count(), 7); QCOMPARE(musicDb2.allTracksData().count(), 22); QCOMPARE(musicDbArtistAddedSpy2.count(), 0); QCOMPARE(musicDbAlbumAddedSpy2.count(), 0); QCOMPARE(musicDbTrackAddedSpy2.count(), 0); QCOMPARE(musicDbArtistRemovedSpy2.count(), 0); QCOMPARE(musicDbAlbumRemovedSpy2.count(), 0); QCOMPARE(musicDbTrackRemovedSpy2.count(), 0); QCOMPARE(musicDbAlbumModifiedSpy2.count(), 1); QCOMPARE(musicDbTrackModifiedSpy2.count(), 1); QCOMPARE(musicDbDatabaseErrorSpy2.count(), 0); } void testAddAlbumsSameName() { QTemporaryFile databaseFile; databaseFile.open(); qDebug() << "testAddAlbumsSameName" << databaseFile.fileName(); DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb"), 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); QList newTracks = { {true, QStringLiteral("$20"), QStringLiteral("0"), QStringLiteral("track1"), QStringLiteral("artist6"), QStringLiteral("album1"), QStringLiteral("artist6"), 1, 1, QTime::fromMSecsSinceStartOfDay(1), {QUrl::fromLocalFile(QStringLiteral("/$20"))}, QDateTime::fromMSecsSinceEpoch(20), {QUrl::fromLocalFile(QStringLiteral("file://image$6"))}, 1, false, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}, {true, QStringLiteral("$21"), QStringLiteral("0"), QStringLiteral("track2"), QStringLiteral("artist6"), QStringLiteral("album1"), QStringLiteral("artist6"), 2, 1, QTime::fromMSecsSinceStartOfDay(2), {QUrl::fromLocalFile(QStringLiteral("/$21"))}, QDateTime::fromMSecsSinceEpoch(21), {QUrl::fromLocalFile(QStringLiteral("file://image$6"))}, 2, false, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}, {true, QStringLiteral("$22"), QStringLiteral("0"), QStringLiteral("track3"), QStringLiteral("artist6"), QStringLiteral("album1"), QStringLiteral("artist6"), 3, 1, QTime::fromMSecsSinceStartOfDay(3), {QUrl::fromLocalFile(QStringLiteral("/$22"))}, QDateTime::fromMSecsSinceEpoch(22), {QUrl::fromLocalFile(QStringLiteral("file://image$6"))}, 3, false, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}, {true, QStringLiteral("$23"), QStringLiteral("0"), QStringLiteral("track4"), QStringLiteral("artist6"), QStringLiteral("album1"), QStringLiteral("artist6"), 4, 1, QTime::fromMSecsSinceStartOfDay(4), {QUrl::fromLocalFile(QStringLiteral("/$23"))}, QDateTime::fromMSecsSinceEpoch(23), {QUrl::fromLocalFile(QStringLiteral("file://image$6"))}, 4, false, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}, {true, QStringLiteral("$24"), QStringLiteral("0"), QStringLiteral("track5"), QStringLiteral("artist6"), QStringLiteral("album1"), QStringLiteral("artist6"), 5, 1, QTime::fromMSecsSinceStartOfDay(4), {QUrl::fromLocalFile(QStringLiteral("/$24"))}, QDateTime::fromMSecsSinceEpoch(24), {QUrl::fromLocalFile(QStringLiteral("file://image$6"))}, 5, false, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}, {true, QStringLiteral("$25"), QStringLiteral("0"), QStringLiteral("track6"), QStringLiteral("artist6"), QStringLiteral("album1"), QStringLiteral("artist6"), 6, 1, QTime::fromMSecsSinceStartOfDay(5), {QUrl::fromLocalFile(QStringLiteral("/$25"))}, QDateTime::fromMSecsSinceEpoch(25), {QUrl::fromLocalFile(QStringLiteral("file://image$6"))}, 6, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}, {true, QStringLiteral("$2"), QStringLiteral("0"), QStringLiteral("track2"), QStringLiteral("artist2"), QStringLiteral("album1"), QStringLiteral("Various Artists"), 2, 2, QTime::fromMSecsSinceStartOfDay(2), {QUrl::fromLocalFile(QStringLiteral("/$26"))}, QDateTime::fromMSecsSinceEpoch(26), {QUrl::fromLocalFile(QStringLiteral("file://image$2"))}, 2, false, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}, }; musicDb.insertTracksList(newTracks, mNewCovers); musicDbTrackAddedSpy.wait(100); QCOMPARE(musicDb.allAlbumsData().count(), 2); QCOMPARE(musicDb.allArtistsData().count(), 3); QCOMPARE(musicDb.allTracksData().count(), 7); 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 firstAlbum = musicDb.albumDataFromDatabaseId(musicDb.albumIdFromTitleAndArtist(QStringLiteral("album1"), QStringLiteral("Invalid Artist"))); } void addTwoIdenticalTracksWithPartialAlbumArtist() { QTemporaryFile databaseFile; databaseFile.open(); qDebug() << "addTwoTracksWithoutAlbumArtist" << databaseFile.fileName(); DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb"), 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 newTracks = QList(); newTracks = {{true, QStringLiteral("$23"), QStringLiteral("0"), QStringLiteral("track6"), QStringLiteral("artist2"), QStringLiteral("album3"), {}, 6, 1, QTime::fromMSecsSinceStartOfDay(23), {QUrl::fromLocalFile(QStringLiteral("/$23"))}, QDateTime::fromMSecsSinceEpoch(23), {QUrl::fromLocalFile(QStringLiteral("album3"))}, 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), true},}; auto newCovers = mNewCovers; newCovers[QStringLiteral("file:///$23")] = QUrl::fromLocalFile(QStringLiteral("album3")); musicDb.insertTracksList(newTracks, newCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 1); QCOMPARE(musicDb.allArtistsData().count(), 1); QCOMPARE(musicDb.allTracksData().count(), 1); 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 firstTrack = musicDb.trackDataFromDatabaseId(musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track6"), QStringLiteral("artist2"), QStringLiteral("album3"), 6, 1)); QCOMPARE(firstTrack.isValid(), true); QCOMPARE(firstTrack.title(), QStringLiteral("track6")); QCOMPARE(firstTrack.artist(), QStringLiteral("artist2")); QCOMPARE(firstTrack.album(), QStringLiteral("album3")); QVERIFY(firstTrack.albumArtist().isEmpty()); QCOMPARE(firstTrack.albumCover(), QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(firstTrack.trackNumber(), 6); QCOMPARE(firstTrack.discNumber(), 1); QCOMPARE(firstTrack.duration(), QTime::fromMSecsSinceStartOfDay(23)); QCOMPARE(firstTrack.resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$23"))); QCOMPARE(firstTrack.rating(), 5); QCOMPARE(firstTrack.genre(), QStringLiteral("genre1")); QCOMPARE(firstTrack.composer(), QStringLiteral("composer1")); QCOMPARE(firstTrack.lyricist(), QStringLiteral("lyricist1")); QCOMPARE(firstTrack.hasEmbeddedCover(), true); auto newTracks2 = QList(); newTracks2 = {{true, QStringLiteral("$23"), QStringLiteral("0"), QStringLiteral("track6"), QStringLiteral("artist2"), QStringLiteral("album3"), QStringLiteral("artist2"), 6, 1, QTime::fromMSecsSinceStartOfDay(23), {QUrl::fromLocalFile(QStringLiteral("/$23"))}, QDateTime::fromMSecsSinceEpoch(23), {QUrl::fromLocalFile(QStringLiteral("album3"))}, 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false},}; auto newCovers2 = mNewCovers; newCovers2[QStringLiteral("file:///$23")] = QUrl::fromLocalFile(QStringLiteral("album3")); musicDb.insertTracksList(newTracks2, newCovers2); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 1); QCOMPARE(musicDb.allArtistsData().count(), 1); QCOMPARE(musicDb.allTracksData().count(), 1); 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); } void addTwoTracksWithPartialAlbumArtist2() { QTemporaryFile databaseFile; databaseFile.open(); qDebug() << "addTwoTracksWithPartialAlbumArtist" << databaseFile.fileName(); DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb"), 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 newTracks = QList(); newTracks = {{true, QStringLiteral("$20"), QStringLiteral("0"), QStringLiteral("track7"), QStringLiteral("artist3"), QStringLiteral("album3"), {QStringLiteral("artist4")}, 7, 1, QTime::fromMSecsSinceStartOfDay(20), {QUrl::fromLocalFile(QStringLiteral("/$20"))}, QDateTime::fromMSecsSinceEpoch(20), {QUrl::fromLocalFile(QStringLiteral("album3"))}, 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}}; auto newCovers = mNewCovers; newCovers[QStringLiteral("file:///$23")] = QUrl::fromLocalFile(QStringLiteral("album3")); newCovers[QStringLiteral("file:///$20")] = QUrl::fromLocalFile(QStringLiteral("album3")); musicDb.insertTracksList(newTracks, newCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 1); QCOMPARE(musicDb.allArtistsData().count(), 2); QCOMPARE(musicDb.allTracksData().count(), 1); 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 newTracks2 = QList(); newTracks2 = {{true, QStringLiteral("$19"), QStringLiteral("0"), QStringLiteral("track6"), QStringLiteral("artist4"), QStringLiteral("album3"), {}, 6, 1, QTime::fromMSecsSinceStartOfDay(19), {QUrl::fromLocalFile(QStringLiteral("/$19"))}, QDateTime::fromMSecsSinceEpoch(19), {QUrl::fromLocalFile(QStringLiteral("album3"))}, 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), true}}; musicDb.insertTracksList(newTracks2, newCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 1); QCOMPARE(musicDb.allArtistsData().count(), 2); QCOMPARE(musicDb.allTracksData().count(), 2); QCOMPARE(musicDbArtistAddedSpy.count(), 1); QCOMPARE(musicDbAlbumAddedSpy.count(), 1); QCOMPARE(musicDbTrackAddedSpy.count(), 2); QCOMPARE(musicDbArtistRemovedSpy.count(), 0); QCOMPARE(musicDbAlbumRemovedSpy.count(), 0); QCOMPARE(musicDbTrackRemovedSpy.count(), 0); QCOMPARE(musicDbAlbumModifiedSpy.count(), 1); QCOMPARE(musicDbTrackModifiedSpy.count(), 1); QCOMPARE(musicDbDatabaseErrorSpy.count(), 0); auto firstTrack = musicDb.trackDataFromDatabaseId(musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track6"), QStringLiteral("artist4"), QStringLiteral("album3"), 6, 1)); QCOMPARE(firstTrack.isValid(), true); QCOMPARE(firstTrack.title(), QStringLiteral("track6")); QCOMPARE(firstTrack.artist(), QStringLiteral("artist4")); QCOMPARE(firstTrack.album(), QStringLiteral("album3")); QCOMPARE(firstTrack.albumArtist(), QStringLiteral("artist4")); QCOMPARE(firstTrack.albumCover(), QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(firstTrack.trackNumber(), 6); QCOMPARE(firstTrack.discNumber(), 1); QCOMPARE(firstTrack.duration(), QTime::fromMSecsSinceStartOfDay(19)); QCOMPARE(firstTrack.resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$19"))); QCOMPARE(firstTrack.rating(), 5); QCOMPARE(firstTrack.genre(), QStringLiteral("genre1")); QCOMPARE(firstTrack.composer(), QStringLiteral("composer1")); QCOMPARE(firstTrack.lyricist(), QStringLiteral("lyricist1")); QCOMPARE(firstTrack.hasEmbeddedCover(), true); auto secondTrack = musicDb.trackDataFromDatabaseId(musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track7"), QStringLiteral("artist3"), QStringLiteral("album3"), 7, 1)); QCOMPARE(secondTrack.isValid(), true); QCOMPARE(secondTrack.title(), QStringLiteral("track7")); QCOMPARE(secondTrack.artist(), QStringLiteral("artist3")); QCOMPARE(secondTrack.album(), QStringLiteral("album3")); QCOMPARE(secondTrack.albumArtist(), QStringLiteral("artist4")); QCOMPARE(secondTrack.albumCover(), QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(secondTrack.trackNumber(), 7); QCOMPARE(secondTrack.discNumber(), 1); QCOMPARE(secondTrack.duration(), QTime::fromMSecsSinceStartOfDay(20)); QCOMPARE(secondTrack.resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$20"))); QCOMPARE(secondTrack.rating(), 5); QCOMPARE(secondTrack.genre(), QStringLiteral("genre1")); QCOMPARE(secondTrack.composer(), QStringLiteral("composer1")); QCOMPARE(secondTrack.lyricist(), QStringLiteral("lyricist1")); QCOMPARE(secondTrack.hasEmbeddedCover(), false); auto albumId = musicDb.albumIdFromTitleAndArtist(QStringLiteral("album3"), QStringLiteral("artist4")); auto album = musicDb.albumDataFromDatabaseId(albumId); auto albumData = musicDb.albumData(albumId); QCOMPARE(album.isValid(), true); QCOMPARE(albumData.count(), 2); QCOMPARE(album.title(), QStringLiteral("album3")); QCOMPARE(album.artist(), QStringLiteral("artist4")); QCOMPARE(album.isValidArtist(), true); QCOMPARE(album.albumArtURI(), QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(album.isSingleDiscAlbum(), true); } void addTowAlbumsWithDifferentPathsAndSameName() { QTemporaryFile databaseFile; databaseFile.open(); qDebug() << "addTowAlbumsWithDifferentPathsAndSameName" << databaseFile.fileName(); DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb"), 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 newTracks = QList(); newTracks = {{true, QStringLiteral("$20"), QStringLiteral("0"), QStringLiteral("track7"), QStringLiteral("artist1"), QStringLiteral("album7"), {}, 7, 1, QTime::fromMSecsSinceStartOfDay(20), {QUrl::fromLocalFile(QStringLiteral("/album7/$20"))}, QDateTime::fromMSecsSinceEpoch(20), {QUrl::fromLocalFile(QStringLiteral("album7"))}, 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}, {true, QStringLiteral("$21"), QStringLiteral("0"), QStringLiteral("track8"), QStringLiteral("artist2"), QStringLiteral("album7"), {}, 8, 1, QTime::fromMSecsSinceStartOfDay(21), {QUrl::fromLocalFile(QStringLiteral("/album7/$21"))}, QDateTime::fromMSecsSinceEpoch(21), {QUrl::fromLocalFile(QStringLiteral("album7"))}, 5, true, QStringLiteral("genre2"), QStringLiteral("composer2"), QStringLiteral("lyricist2"), false}, {true, QStringLiteral("$22"), QStringLiteral("0"), QStringLiteral("track9"), QStringLiteral("artist3"), QStringLiteral("album7"), {}, 9, 1, QTime::fromMSecsSinceStartOfDay(22), {QUrl::fromLocalFile(QStringLiteral("/album8/$22"))}, QDateTime::fromMSecsSinceEpoch(22), {QUrl::fromLocalFile(QStringLiteral("album7"))}, 5, true, QStringLiteral("genre3"), QStringLiteral("composer3"), QStringLiteral("lyricist3"), false}, {true, QStringLiteral("$23"), QStringLiteral("0"), QStringLiteral("track10"), QStringLiteral("artist4"), QStringLiteral("album7"), {}, 10, 1, QTime::fromMSecsSinceStartOfDay(23), {QUrl::fromLocalFile(QStringLiteral("/album8/$23"))}, QDateTime::fromMSecsSinceEpoch(23), {QUrl::fromLocalFile(QStringLiteral("album7"))}, 5, true, QStringLiteral("genre4"), QStringLiteral("composer4"), QStringLiteral("lyricist4"), false},}; auto newCovers = mNewCovers; newCovers[QStringLiteral("file:///album7/$20")] = QUrl::fromLocalFile(QStringLiteral("album7")); newCovers[QStringLiteral("file:///album7/$21")] = QUrl::fromLocalFile(QStringLiteral("album7")); newCovers[QStringLiteral("file:///album8/$22")] = QUrl::fromLocalFile(QStringLiteral("album8")); newCovers[QStringLiteral("file:///album8/$23")] = QUrl::fromLocalFile(QStringLiteral("album8")); musicDb.insertTracksList(newTracks, newCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 2); QCOMPARE(musicDb.allArtistsData().count(), 4); QCOMPARE(musicDb.allTracksData().count(), 4); 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); QCOMPARE(musicDb.allAlbumsData().size(), 2); QCOMPARE(musicDb.allArtistsData().size(), 4); QCOMPARE(musicDb.allTracksData().size(), 4); auto allAlbums = musicDb.allAlbumsData(); auto firstAlbum = allAlbums[0]; auto firstAlbumData = musicDb.albumData(firstAlbum.databaseId()); QCOMPARE(firstAlbumData.count(), 2); auto secondAlbum = allAlbums[1]; auto secondAlbumData = musicDb.albumData(secondAlbum.databaseId()); QCOMPARE(secondAlbumData.count(), 2); } void addTowAlbumsWithDifferentPathsAndSameTracks() { QTemporaryFile databaseFile; databaseFile.open(); qDebug() << "addTowAlbumsWithDifferentPathsAndSameName" << databaseFile.fileName(); DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb"), 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 newTracks = QList(); newTracks = {{true, QStringLiteral("$20"), QStringLiteral("0"), QStringLiteral("track7"), QStringLiteral("artist1"), QStringLiteral("album7"), {}, 7, 1, QTime::fromMSecsSinceStartOfDay(20), {QUrl::fromLocalFile(QStringLiteral("/album7/$20"))}, QDateTime::fromMSecsSinceEpoch(20), {QUrl::fromLocalFile(QStringLiteral("album7"))}, 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}, {true, QStringLiteral("$21"), QStringLiteral("0"), QStringLiteral("track8"), QStringLiteral("artist2"), QStringLiteral("album7"), {}, 8, 1, QTime::fromMSecsSinceStartOfDay(21), {QUrl::fromLocalFile(QStringLiteral("/album7/$21"))}, QDateTime::fromMSecsSinceEpoch(21), {QUrl::fromLocalFile(QStringLiteral("album7"))}, 5, true, QStringLiteral("genre2"), QStringLiteral("composer2"), QStringLiteral("lyricist2"), false}, {true, QStringLiteral("$22"), QStringLiteral("0"), QStringLiteral("track9"), QStringLiteral("artist3"), QStringLiteral("album7"), {}, 9, 1, QTime::fromMSecsSinceStartOfDay(22), {QUrl::fromLocalFile(QStringLiteral("/album7/$22"))}, QDateTime::fromMSecsSinceEpoch(22), {QUrl::fromLocalFile(QStringLiteral("album7"))}, 5, true, QStringLiteral("genre3"), QStringLiteral("composer3"), QStringLiteral("lyricist3"), false}, {true, QStringLiteral("$20"), QStringLiteral("0"), QStringLiteral("track7"), QStringLiteral("artist1"), QStringLiteral("album7"), {}, 7, 1, QTime::fromMSecsSinceStartOfDay(20), {QUrl::fromLocalFile(QStringLiteral("/album8/$20"))}, QDateTime::fromMSecsSinceEpoch(20), {QUrl::fromLocalFile(QStringLiteral("album7"))}, 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}, {true, QStringLiteral("$21"), QStringLiteral("0"), QStringLiteral("track8"), QStringLiteral("artist2"), QStringLiteral("album7"), {}, 8, 1, QTime::fromMSecsSinceStartOfDay(21), {QUrl::fromLocalFile(QStringLiteral("/album8/$21"))}, QDateTime::fromMSecsSinceEpoch(21), {QUrl::fromLocalFile(QStringLiteral("album7"))}, 5, true, QStringLiteral("genre2"), QStringLiteral("composer2"), QStringLiteral("lyricist2"), false}, {true, QStringLiteral("$22"), QStringLiteral("0"), QStringLiteral("track9"), QStringLiteral("artist3"), QStringLiteral("album7"), {}, 9, 1, QTime::fromMSecsSinceStartOfDay(22), {QUrl::fromLocalFile(QStringLiteral("/album8/$22"))}, QDateTime::fromMSecsSinceEpoch(22), {QUrl::fromLocalFile(QStringLiteral("album7"))}, 5, true, QStringLiteral("genre3"), QStringLiteral("composer3"), QStringLiteral("lyricist3"), false},}; auto newCovers = mNewCovers; newCovers[QStringLiteral("file:///album7/$20")] = QUrl::fromLocalFile(QStringLiteral("album7")); newCovers[QStringLiteral("file:///album7/$21")] = QUrl::fromLocalFile(QStringLiteral("album7")); newCovers[QStringLiteral("file:///album7/$22")] = QUrl::fromLocalFile(QStringLiteral("album7")); newCovers[QStringLiteral("file:///album8/$20")] = QUrl::fromLocalFile(QStringLiteral("album8")); newCovers[QStringLiteral("file:///album8/$21")] = QUrl::fromLocalFile(QStringLiteral("album8")); newCovers[QStringLiteral("file:///album8/$22")] = QUrl::fromLocalFile(QStringLiteral("album8")); musicDb.insertTracksList(newTracks, newCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 2); QCOMPARE(musicDb.allArtistsData().count(), 3); QCOMPARE(musicDb.allTracksData().count(), 6); 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 allAlbums = musicDb.allAlbumsData(); auto firstAlbum = allAlbums[0]; auto firstAlbumData = musicDb.albumData(firstAlbum.databaseId()); QCOMPARE(firstAlbumData.count(), 3); auto secondAlbum = allAlbums[1]; auto secondAlbumData = musicDb.albumData(secondAlbum.databaseId()); QCOMPARE(secondAlbumData.count(), 3); } void addTwoTracksFromSameAlbumButDifferentDiscs() { QTemporaryFile databaseFile; databaseFile.open(); qDebug() << "addTwoTracksFromSameAlbumButDifferentDiscs" << databaseFile.fileName(); DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb"), 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 newTrack = MusicAudioTrack{true, QStringLiteral("$23"), QStringLiteral("0"), QStringLiteral("track6"), QStringLiteral("artist2"), QStringLiteral("album3"), QStringLiteral("artist2"), 6, 1, QTime::fromMSecsSinceStartOfDay(23), {QUrl::fromLocalFile(QStringLiteral("/$23"))}, QDateTime::fromMSecsSinceEpoch(23), {QUrl::fromLocalFile(QStringLiteral("album3"))}, 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}; auto newTracks = QList(); newTracks.push_back(newTrack); auto newCovers = mNewCovers; newCovers[QStringLiteral("file:///$23")] = QUrl::fromLocalFile(QStringLiteral("album3")); musicDb.insertTracksList(newTracks, newCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 1); QCOMPARE(musicDb.allArtistsData().count(), 1); QCOMPARE(musicDb.allTracksData().count(), 1); 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("/$23"))); QCOMPARE(firstTrackRating, 5); QCOMPARE(firstIsSingleDiscAlbum, true); auto allAlbums = musicDb.allAlbumsData(); QCOMPARE(allAlbums.size(), 1); auto firstAlbumData = musicDb.albumData(allAlbums[0].databaseId()); auto firstAlbumTitle = allAlbums[0].title(); auto firstAlbumArtist = allAlbums[0].artist(); auto firstAlbumImage = allAlbums[0].albumArtURI(); auto firstAlbumTracksCount = firstAlbumData.count(); auto firstAlbumIsSingleDiscAlbum = allAlbums[0].isSingleDiscAlbum(); QCOMPARE(firstAlbumTitle, QStringLiteral("album3")); QCOMPARE(firstAlbumArtist, QStringLiteral("artist2")); QCOMPARE(firstAlbumImage.isValid(), true); QCOMPARE(firstAlbumImage, QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(firstAlbumTracksCount, 1); QCOMPARE(firstAlbumIsSingleDiscAlbum, true); auto newTrack2 = MusicAudioTrack{true, QStringLiteral("$25"), QStringLiteral("0"), QStringLiteral("track8"), QStringLiteral("artist9"), QStringLiteral("album3"), QStringLiteral("artist2"), 8, 2, QTime::fromMSecsSinceStartOfDay(25), {QUrl::fromLocalFile(QStringLiteral("/$25"))}, QDateTime::fromMSecsSinceEpoch(25), {QUrl::fromLocalFile(QStringLiteral("file://image$25"))}, 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}; auto newTracks2 = QList(); newTracks2.push_back(newTrack2); auto newCovers2 = mNewCovers; newCovers2[QStringLiteral("file:///$25")] = QUrl::fromLocalFile(QStringLiteral("album3")); musicDb.insertTracksList(newTracks2, newCovers2); musicDbTrackAddedSpy.wait(50); QCOMPARE(musicDb.allAlbumsData().count(), 1); QCOMPARE(musicDb.allArtistsData().count(), 2); QCOMPARE(musicDb.allTracksData().count(), 2); QCOMPARE(musicDbArtistAddedSpy.count(), 2); QCOMPARE(musicDbAlbumAddedSpy.count(), 1); QCOMPARE(musicDbTrackAddedSpy.count(), 2); QCOMPARE(musicDbArtistRemovedSpy.count(), 0); QCOMPARE(musicDbAlbumRemovedSpy.count(), 0); QCOMPARE(musicDbTrackRemovedSpy.count(), 0); QCOMPARE(musicDbAlbumModifiedSpy.count(), 1); QCOMPARE(musicDbTrackModifiedSpy.count(), 1); QCOMPARE(musicDbDatabaseErrorSpy.count(), 0); auto secondTrackId = musicDb.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track8"), QStringLiteral("artist9"), QStringLiteral("album3"), 8, 2); 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(); const auto &secondTrackResource = secondTrack.resourceURI(); auto secondTrackRating = secondTrack.rating(); auto secondIsSingleDiscAlbum = secondTrack.isSingleDiscAlbum(); QCOMPARE(secondTrack.isValid(), true); QCOMPARE(secondTrackTitle, QStringLiteral("track8")); QCOMPARE(secondTrackArtist, QStringLiteral("artist9")); QCOMPARE(secondTrackAlbumArtist, QStringLiteral("artist2")); QCOMPARE(secondTrackAlbum, QStringLiteral("album3")); QCOMPARE(secondTrackImage.isValid(), true); QCOMPARE(secondTrackImage, QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(secondTrackDuration, QTime::fromMSecsSinceStartOfDay(25)); QCOMPARE(secondTrackMilliSecondsDuration, 25); QCOMPARE(secondTrackTrackNumber, 8); QCOMPARE(secondTrackDiscNumber, 2); QCOMPARE(secondTrackResource.isValid(), true); QCOMPARE(secondTrackResource, QUrl::fromLocalFile(QStringLiteral("/$25"))); QCOMPARE(secondTrackRating, 5); QCOMPARE(secondIsSingleDiscAlbum, false); const auto &modifiedTrackSignal = musicDbTrackModifiedSpy.at(0); QCOMPARE(modifiedTrackSignal.count(), 1); const auto &modifiedTrack = modifiedTrackSignal.at(0).value(); auto modifiedTrackTitle = modifiedTrack.title(); auto modifiedTrackArtist = modifiedTrack.artist(); auto modifiedTrackAlbumArtist = modifiedTrack.albumArtist(); auto modifiedTrackAlbum = modifiedTrack.album(); auto modifiedTrackImage = modifiedTrack.albumCover(); auto modifiedTrackDuration = modifiedTrack.duration(); auto modifiedTrackMilliSecondsDuration = modifiedTrack.duration().msecsSinceStartOfDay(); auto modifiedTrackTrackNumber = modifiedTrack.trackNumber(); auto modifiedTrackDiscNumber = modifiedTrack.discNumber(); const auto &modifiedTrackResource = modifiedTrack.resourceURI(); auto modifiedTrackRating = modifiedTrack.rating(); auto modifiedTrackIsSingleDiscAlbum = modifiedTrack.isSingleDiscAlbum(); QCOMPARE(modifiedTrack.isValid(), true); QCOMPARE(modifiedTrackTitle, QStringLiteral("track6")); QCOMPARE(modifiedTrackArtist, QStringLiteral("artist2")); QCOMPARE(modifiedTrackAlbumArtist, QStringLiteral("artist2")); QCOMPARE(modifiedTrackAlbum, QStringLiteral("album3")); QCOMPARE(modifiedTrackImage.isValid(), true); QCOMPARE(modifiedTrackImage, QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(modifiedTrackDuration, QTime::fromMSecsSinceStartOfDay(23)); QCOMPARE(modifiedTrackMilliSecondsDuration, 23); QCOMPARE(modifiedTrackTrackNumber, 6); QCOMPARE(modifiedTrackDiscNumber, 1); QCOMPARE(modifiedTrackResource.isValid(), true); QCOMPARE(modifiedTrackResource, QUrl::fromLocalFile(QStringLiteral("/$23"))); QCOMPARE(modifiedTrackRating, 5); QCOMPARE(modifiedTrackIsSingleDiscAlbum, false); auto allAlbums2 = musicDb.allAlbumsData(); auto firstAlbumData2 = musicDb.albumData(allAlbums2[0].databaseId()); auto firstAlbumTitle2 = allAlbums2[0].title(); auto firstAlbumArtist2 = allAlbums2[0].artist(); auto firstAlbumImage2 = allAlbums2[0].albumArtURI(); auto firstAlbumTracksCount2 = firstAlbumData2.count(); auto firstAlbumIsSingleDiscAlbum2 = allAlbums2[0].isSingleDiscAlbum(); QCOMPARE(firstAlbumTitle2, QStringLiteral("album3")); QCOMPARE(firstAlbumArtist2, QStringLiteral("artist2")); QCOMPARE(firstAlbumImage2.isValid(), true); QCOMPARE(firstAlbumImage2, QUrl::fromLocalFile(QStringLiteral("album3"))); QCOMPARE(firstAlbumTracksCount2, 2); QCOMPARE(firstAlbumIsSingleDiscAlbum2, false); } void addTwoIdenticalInvalidTracks() { DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb")); 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); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 22); 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 newTrack = MusicAudioTrack{true, QStringLiteral("$23"), QStringLiteral("0"), {}, {}, {}, {}, {}, {}, {}, {QUrl::fromLocalFile(QStringLiteral("file:///$23"))}, QDateTime::fromMSecsSinceEpoch(23), {}, {}, {}, {}, {}, {}, false}; auto newTracks = QList(); newTracks.push_back(newTrack); newTracks.push_back(newTrack); auto newCovers = mNewCovers; newCovers[QStringLiteral("file:///$23")] = QUrl::fromLocalFile(QStringLiteral("album3")); musicDb.insertTracksList(newTracks, newCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 22); 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); } void checkRestoredTracks() { DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb")); 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); QSignalSpy musicDbRestoredTracksSpy(&musicDb, &DatabaseInterface::restoredTracks); 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); QCOMPARE(musicDbRestoredTracksSpy.count(), 0); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 22); 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); QCOMPARE(musicDbRestoredTracksSpy.count(), 0); musicDb.askRestoredTracks(); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 22); 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); QCOMPARE(musicDbRestoredTracksSpy.count(), 1); const auto &firstSignal = musicDbRestoredTracksSpy.at(0); QCOMPARE(firstSignal.count(), 1); const auto &restoredTracks = firstSignal.at(0).value>(); QCOMPARE(restoredTracks.count(), 23); } void addOneTrackWithParticularPath() { DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb")); 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 newTrack = MusicAudioTrack{true, QStringLiteral("$23"), QStringLiteral("0"), QStringLiteral("track6"), QStringLiteral("artist2"), QStringLiteral("album3"), QStringLiteral("artist2"), 6, 1, QTime::fromMSecsSinceStartOfDay(23), {QUrl::fromLocalFile(QStringLiteral("/test{{test}}/$23"))}, QDateTime::fromMSecsSinceEpoch(23), QUrl::fromLocalFile(QStringLiteral("album3")), 5, true, QStringLiteral("genre1"), QStringLiteral("composer1"), QStringLiteral("lyricist1"), false}; auto newTracks = QList(); newTracks.push_back(newTrack); auto newCovers = mNewCovers; newCovers[QStringLiteral("/test{{test}}/$23")] = QUrl::fromLocalFile(QStringLiteral("album3")); musicDb.insertTracksList(newTracks, newCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 1); QCOMPARE(musicDb.allArtistsData().count(), 1); QCOMPARE(musicDb.allTracksData().count(), 1); 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); } void readRecentlyPlayedTracksData() { DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb")); 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); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 22); 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); musicDb.trackHasStartedPlaying(QUrl::fromLocalFile(QStringLiteral("/$9")), QDateTime::fromSecsSinceEpoch(1534689)); musicDb.trackHasStartedPlaying(QUrl::fromLocalFile(QStringLiteral("/$17")), QDateTime::fromSecsSinceEpoch(1534692)); musicDb.trackHasStartedPlaying(QUrl::fromLocalFile(QStringLiteral("/$16")), QDateTime::fromSecsSinceEpoch(1534759)); musicDb.trackHasStartedPlaying(QUrl::fromLocalFile(QStringLiteral("/$8")), QDateTime::fromSecsSinceEpoch(1534869)); musicDb.trackHasStartedPlaying(QUrl::fromLocalFile(QStringLiteral("/$2")), QDateTime::fromSecsSinceEpoch(1535189)); musicDb.trackHasStartedPlaying(QUrl::fromLocalFile(QStringLiteral("/$11")), QDateTime::fromSecsSinceEpoch(1535389)); musicDb.trackHasStartedPlaying(QUrl::fromLocalFile(QStringLiteral("/$18")), QDateTime::fromSecsSinceEpoch(1535689)); musicDb.trackHasStartedPlaying(QUrl::fromLocalFile(QStringLiteral("/$7")), QDateTime::fromSecsSinceEpoch(1536189)); musicDb.trackHasStartedPlaying(QUrl::fromLocalFile(QStringLiteral("/$5")), QDateTime::fromSecsSinceEpoch(1536689)); musicDb.trackHasStartedPlaying(QUrl::fromLocalFile(QStringLiteral("/$13")), QDateTime::fromSecsSinceEpoch(1537689)); + QCOMPARE(musicDb.allAlbumsData().count(), 5); + QCOMPARE(musicDb.allArtistsData().count(), 7); + QCOMPARE(musicDb.allTracksData().count(), 22); + 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(), 10); + QCOMPARE(musicDbDatabaseErrorSpy.count(), 0); + auto recentlyPlayedTracksData = musicDb.recentlyPlayedTracksData(10); QCOMPARE(recentlyPlayedTracksData.count(), 10); QCOMPARE(recentlyPlayedTracksData[0].resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$13"))); QCOMPARE(recentlyPlayedTracksData[1].resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$5"))); QCOMPARE(recentlyPlayedTracksData[2].resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$7"))); QCOMPARE(recentlyPlayedTracksData[3].resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$18"))); QCOMPARE(recentlyPlayedTracksData[4].resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$11"))); QCOMPARE(recentlyPlayedTracksData[5].resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$2"))); QCOMPARE(recentlyPlayedTracksData[6].resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$8"))); QCOMPARE(recentlyPlayedTracksData[7].resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$16"))); QCOMPARE(recentlyPlayedTracksData[8].resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$17"))); QCOMPARE(recentlyPlayedTracksData[9].resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$9"))); } void readFrequentlyPlayedTracksData() { DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb")); 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); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 22); 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); musicDb.trackHasStartedPlaying(QUrl::fromLocalFile(QStringLiteral("/$9")), QDateTime::fromSecsSinceEpoch(1553279650)); musicDb.trackHasStartedPlaying(QUrl::fromLocalFile(QStringLiteral("/$17")), QDateTime::fromSecsSinceEpoch(1553288650)); musicDb.trackHasStartedPlaying(QUrl::fromLocalFile(QStringLiteral("/$16")), QDateTime::fromSecsSinceEpoch(1553287650)); musicDb.trackHasStartedPlaying(QUrl::fromLocalFile(QStringLiteral("/$8")), QDateTime::fromSecsSinceEpoch(1553286650)); musicDb.trackHasStartedPlaying(QUrl::fromLocalFile(QStringLiteral("/$2")), QDateTime::fromSecsSinceEpoch(1553285650)); musicDb.trackHasStartedPlaying(QUrl::fromLocalFile(QStringLiteral("/$11")), QDateTime::fromSecsSinceEpoch(1553284650)); musicDb.trackHasStartedPlaying(QUrl::fromLocalFile(QStringLiteral("/$18")), QDateTime::fromSecsSinceEpoch(1553283650)); musicDb.trackHasStartedPlaying(QUrl::fromLocalFile(QStringLiteral("/$7")), QDateTime::fromSecsSinceEpoch(1553282650)); musicDb.trackHasStartedPlaying(QUrl::fromLocalFile(QStringLiteral("/$5")), QDateTime::fromSecsSinceEpoch(1553281650)); musicDb.trackHasStartedPlaying(QUrl::fromLocalFile(QStringLiteral("/$13")), QDateTime::fromSecsSinceEpoch(1553280650)); musicDb.trackHasStartedPlaying(QUrl::fromLocalFile(QStringLiteral("/$9")), QDateTime::fromSecsSinceEpoch(1553289660)); musicDb.trackHasStartedPlaying(QUrl::fromLocalFile(QStringLiteral("/$2")), QDateTime::fromSecsSinceEpoch(1553289680)); musicDb.trackHasStartedPlaying(QUrl::fromLocalFile(QStringLiteral("/$18")), QDateTime::fromSecsSinceEpoch(1553289700)); musicDb.trackHasStartedPlaying(QUrl::fromLocalFile(QStringLiteral("/$17")), QDateTime::fromSecsSinceEpoch(1553289720)); musicDb.trackHasStartedPlaying(QUrl::fromLocalFile(QStringLiteral("/$7")), QDateTime::fromSecsSinceEpoch(1553289740)); auto frequentlyPlayedTracksData = musicDb.frequentlyPlayedTracksData(5); QCOMPARE(frequentlyPlayedTracksData.count(), 5); QCOMPARE(frequentlyPlayedTracksData[0].resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$17"))); QCOMPARE(frequentlyPlayedTracksData[1].resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$2"))); QCOMPARE(frequentlyPlayedTracksData[2].resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$18"))); QCOMPARE(frequentlyPlayedTracksData[3].resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$7"))); QCOMPARE(frequentlyPlayedTracksData[4].resourceURI(), QUrl::fromLocalFile(QStringLiteral("/$9"))); } void readAllGenresData() { DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb")); 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); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 22); 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 allGenresData = musicDb.allGenresData(); QCOMPARE(allGenresData.count(), 4); QCOMPARE(allGenresData[0].title(), QStringLiteral("genre1")); QCOMPARE(allGenresData[1].title(), QStringLiteral("genre2")); QCOMPARE(allGenresData[2].title(), QStringLiteral("genre3")); QCOMPARE(allGenresData[3].title(), QStringLiteral("genre4")); } void clearDataTest() { DatabaseInterface musicDb; musicDb.init(QStringLiteral("testDb")); 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); QSignalSpy musicDbCleanedDatabaseSpy(&musicDb, &DatabaseInterface::cleanedDatabase); 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); QCOMPARE(musicDbCleanedDatabaseSpy.count(), 0); musicDb.insertTracksList(mNewTracks, mNewCovers); musicDbTrackAddedSpy.wait(300); QCOMPARE(musicDb.allAlbumsData().count(), 5); QCOMPARE(musicDb.allArtistsData().count(), 7); QCOMPARE(musicDb.allTracksData().count(), 22); 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); QCOMPARE(musicDbCleanedDatabaseSpy.count(), 0); musicDb.clearData(); QCOMPARE(musicDb.allAlbumsData().count(), 0); QCOMPARE(musicDb.allArtistsData().count(), 0); QCOMPARE(musicDb.allTracksData().count(), 0); 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); QCOMPARE(musicDbCleanedDatabaseSpy.count(), 1); } }; QTEST_GUILESS_MAIN(DatabaseInterfaceTests) #include "databaseinterfacetest.moc" diff --git a/autotests/trackmetadatamodeltest.cpp b/autotests/trackmetadatamodeltest.cpp index edf14f68..3e3d27ed 100644 --- a/autotests/trackmetadatamodeltest.cpp +++ b/autotests/trackmetadatamodeltest.cpp @@ -1,75 +1,148 @@ /* * Copyright 2018 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "models/trackmetadatamodel.h" + #include "qabstractitemmodeltester.h" +#include "databasetestdata.h" #include #include -class TrackMetadataModelTests: public QObject +class TrackMetadataModelTests: public QObject, public DatabaseTestData { Q_OBJECT private Q_SLOTS: void initTestCase() { } void loadOneTrackData() { TrackMetadataModel myModel; QAbstractItemModelTester testModel(&myModel); QSignalSpy beginResetSpy(&myModel, &TrackMetadataModel::modelAboutToBeReset); QSignalSpy endResetSpy(&myModel, &TrackMetadataModel::modelReset); QSignalSpy beginInsertRowsSpy(&myModel, &TrackMetadataModel::rowsAboutToBeInserted); QSignalSpy endInsertRowsSpy(&myModel, &TrackMetadataModel::rowsInserted); QSignalSpy dataChangedSpy(&myModel, &TrackMetadataModel::dataChanged); QSignalSpy beginRemovedRowsSpy(&myModel, &TrackMetadataModel::rowsAboutToBeRemoved); QSignalSpy endRemovedRowsSpy(&myModel, &TrackMetadataModel::rowsRemoved); QCOMPARE(beginResetSpy.count(), 0); QCOMPARE(endResetSpy.count(), 0); QCOMPARE(beginInsertRowsSpy.count(), 0); QCOMPARE(endInsertRowsSpy.count(), 0); QCOMPARE(dataChangedSpy.count(), 0); QCOMPARE(beginRemovedRowsSpy.count(), 0); QCOMPARE(endRemovedRowsSpy.count(), 0); QCOMPARE(myModel.rowCount(), 0); auto trackData = TrackMetadataModel::TrackDataType{{DatabaseInterface::DatabaseIdRole, 1}, {DatabaseInterface::TitleRole, QStringLiteral("title")}}; myModel.trackData(trackData); QCOMPARE(beginResetSpy.count(), 1); QCOMPARE(endResetSpy.count(), 1); QCOMPARE(beginInsertRowsSpy.count(), 0); QCOMPARE(endInsertRowsSpy.count(), 0); QCOMPARE(dataChangedSpy.count(), 0); QCOMPARE(beginRemovedRowsSpy.count(), 0); QCOMPARE(endRemovedRowsSpy.count(), 0); QCOMPARE(myModel.rowCount(), 1); } + + void modifyTrackInDatabase() + { + QTemporaryFile databaseFile; + databaseFile.open(); + + qDebug() << "addOneTrackWithoutAlbumArtist" << databaseFile.fileName(); + + DatabaseInterface musicDb; + + musicDb.init(QStringLiteral("testDb"), databaseFile.fileName()); + + musicDb.insertTracksList(mNewTracks, mNewCovers); + + TrackMetadataModel myModel; + QAbstractItemModelTester testModel(&myModel); + + QSignalSpy beginResetSpy(&myModel, &TrackMetadataModel::modelAboutToBeReset); + QSignalSpy endResetSpy(&myModel, &TrackMetadataModel::modelReset); + QSignalSpy beginInsertRowsSpy(&myModel, &TrackMetadataModel::rowsAboutToBeInserted); + QSignalSpy endInsertRowsSpy(&myModel, &TrackMetadataModel::rowsInserted); + QSignalSpy dataChangedSpy(&myModel, &TrackMetadataModel::dataChanged); + QSignalSpy beginRemovedRowsSpy(&myModel, &TrackMetadataModel::rowsAboutToBeRemoved); + QSignalSpy endRemovedRowsSpy(&myModel, &TrackMetadataModel::rowsRemoved); + + QCOMPARE(beginResetSpy.count(), 0); + QCOMPARE(endResetSpy.count(), 0); + QCOMPARE(beginInsertRowsSpy.count(), 0); + QCOMPARE(endInsertRowsSpy.count(), 0); + QCOMPARE(dataChangedSpy.count(), 0); + QCOMPARE(beginRemovedRowsSpy.count(), 0); + QCOMPARE(endRemovedRowsSpy.count(), 0); + QCOMPARE(myModel.rowCount(), 0); + + myModel.setDatabase(&musicDb); + + auto trackId = musicDb.trackIdFromFileName(QUrl::fromLocalFile(QStringLiteral("/$1"))); + + myModel.initializeByTrackId(trackId); + + QCOMPARE(beginResetSpy.count(), 1); + QCOMPARE(endResetSpy.count(), 1); + QCOMPARE(beginInsertRowsSpy.count(), 0); + QCOMPARE(endInsertRowsSpy.count(), 0); + QCOMPARE(dataChangedSpy.count(), 0); + QCOMPARE(beginRemovedRowsSpy.count(), 0); + QCOMPARE(endRemovedRowsSpy.count(), 0); + QCOMPARE(myModel.rowCount(), 11); + + musicDb.trackHasStartedPlaying(QUrl::fromLocalFile(QStringLiteral("/$2")), QDateTime::currentDateTime()); + + QCOMPARE(beginResetSpy.count(), 1); + QCOMPARE(endResetSpy.count(), 1); + QCOMPARE(beginInsertRowsSpy.count(), 0); + QCOMPARE(endInsertRowsSpy.count(), 0); + QCOMPARE(dataChangedSpy.count(), 0); + QCOMPARE(beginRemovedRowsSpy.count(), 0); + QCOMPARE(endRemovedRowsSpy.count(), 0); + QCOMPARE(myModel.rowCount(), 11); + + musicDb.trackHasStartedPlaying(QUrl::fromLocalFile(QStringLiteral("/$1")), QDateTime::currentDateTime()); + + QCOMPARE(beginResetSpy.count(), 2); + QCOMPARE(endResetSpy.count(), 2); + QCOMPARE(beginInsertRowsSpy.count(), 0); + QCOMPARE(endInsertRowsSpy.count(), 0); + QCOMPARE(dataChangedSpy.count(), 0); + QCOMPARE(beginRemovedRowsSpy.count(), 0); + QCOMPARE(endRemovedRowsSpy.count(), 0); + QCOMPARE(myModel.rowCount(), 12); + } }; QTEST_GUILESS_MAIN(TrackMetadataModelTests) #include "trackmetadatamodeltest.moc" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f94590ca..888f818f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,481 +1,484 @@ include_directories(${elisa_BINARY_DIR}) set(elisaLib_SOURCES mediaplaylist.cpp musicaudiotrack.cpp progressindicator.cpp databaseinterface.cpp musiclistenersmanager.cpp managemediaplayercontrol.cpp manageheaderbar.cpp manageaudioplayer.cpp trackslistener.cpp elisaapplication.cpp modeldataloader.cpp notificationitem.cpp topnotificationmanager.cpp elisautils.cpp datatype.cpp abstractfile/abstractfilelistener.cpp abstractfile/abstractfilelisting.cpp filescanner.cpp viewmanager.cpp file/filelistener.cpp file/localfilelisting.cpp models/datamodel.cpp models/abstractmediaproxymodel.cpp models/gridviewproxymodel.cpp models/alltracksproxymodel.cpp models/singlealbumproxymodel.cpp models/trackmetadatamodel.cpp + models/trackcontextmetadatamodel.cpp models/viewsmodel.cpp ) ecm_qt_declare_logging_category(elisaLib_SOURCES HEADER "indexersManager.h" IDENTIFIER "orgKdeElisaIndexersManager" CATEGORY_NAME "org.kde.elisa.indexers.manager" DEFAULT_SEVERITY Info ) ecm_qt_declare_logging_category(elisaLib_SOURCES HEADER "databaseLogging.h" IDENTIFIER "orgKdeElisaDatabase" CATEGORY_NAME "org.kde.elisa.database" DEFAULT_SEVERITY Info ) ecm_qt_declare_logging_category(elisaLib_SOURCES HEADER "abstractfile/indexercommon.h" IDENTIFIER "orgKdeElisaIndexer" CATEGORY_NAME "org.kde.elisa.indexer" DEFAULT_SEVERITY Info ) if (LIBVLC_FOUND) ecm_qt_declare_logging_category(elisaLib_SOURCES HEADER "vlcLogging.h" IDENTIFIER "orgKdeElisaPlayerVlc" CATEGORY_NAME "org.kde.elisa.player.vlc" DEFAULT_SEVERITY Info ) set(elisaLib_SOURCES ${elisaLib_SOURCES} audiowrapper_libvlc.cpp ) else() set(elisaLib_SOURCES ${elisaLib_SOURCES} audiowrapper_qtmultimedia.cpp ) endif() if (ANDROID) set(elisaLib_SOURCES ${elisaLib_SOURCES} android/androidmusiclistener.cpp ) endif() if (KF5KIO_FOUND) set(elisaLib_SOURCES ${elisaLib_SOURCES} models/filebrowsermodel.cpp models/filebrowserproxymodel.cpp ) endif() if (KF5Baloo_FOUND) if (Qt5DBus_FOUND) ecm_qt_declare_logging_category(elisaLib_SOURCES HEADER "baloo/baloocommon.h" IDENTIFIER "orgKdeElisaBaloo" CATEGORY_NAME "org.kde.elisa.baloo" DEFAULT_SEVERITY Info ) set(elisaLib_SOURCES ${elisaLib_SOURCES} baloo/localbaloofilelisting.cpp baloo/baloolistener.cpp baloo/baloodetector.cpp ) qt5_add_dbus_interface(elisaLib_SOURCES ${BALOO_DBUS_INTERFACES_DIR}/org.kde.baloo.main.xml baloo/main) qt5_add_dbus_interface(elisaLib_SOURCES ${BALOO_DBUS_INTERFACES_DIR}/org.kde.baloo.fileindexer.xml baloo/fileindexer) qt5_add_dbus_interface(elisaLib_SOURCES ${BALOO_DBUS_INTERFACES_DIR}/org.kde.baloo.scheduler.xml baloo/scheduler) qt5_add_dbus_adaptor(elisaLib_SOURCES ${BALOO_DBUS_INTERFACES_DIR}/org.kde.BalooWatcherApplication.xml baloo/localbaloofilelisting.h LocalBalooFileListing) endif() endif() if (Qt5DBus_FOUND) set(elisaLib_SOURCES ${elisaLib_SOURCES} mpris2/mpris2.cpp mpris2/mediaplayer2.cpp mpris2/mediaplayer2player.cpp ) endif() if (UPNPQT_FOUND) set(elisaLib_SOURCES ${elisaLib_SOURCES} upnp/upnpcontrolcontentdirectory.cpp upnp/upnpcontentdirectorymodel.cpp upnp/upnpcontrolconnectionmanager.cpp upnp/upnpcontrolmediaserver.cpp upnp/didlparser.cpp upnp/upnplistener.cpp upnp/upnpdiscoverallmusic.cpp ) endif() if (KF5Baloo_FOUND) if (Qt5DBus_FOUND) qt5_add_dbus_interface(elisaLib_SOURCES ${BALOO_DBUS_INTERFACES_DIR}/org.kde.baloo.fileindexer.xml baloo/fileindexer) qt5_add_dbus_interface(elisaLib_SOURCES ${BALOO_DBUS_INTERFACES_DIR}/org.kde.baloo.scheduler.xml baloo/scheduler) set(elisaLib_SOURCES ${elisaLib_SOURCES} ../src/baloo/baloolistener.cpp ../src/baloo/localbaloofilelisting.cpp ) endif() endif() kconfig_add_kcfg_files(elisaLib_SOURCES ../src/elisa_settings.kcfgc ) set(elisaLib_SOURCES ${elisaLib_SOURCES} ../src/elisa_core.kcfg ) add_library(elisaLib ${elisaLib_SOURCES}) target_link_libraries(elisaLib LINK_PUBLIC Qt5::Multimedia LINK_PRIVATE Qt5::Core Qt5::Sql Qt5::Widgets Qt5::Concurrent Qt5::Qml KF5::I18n KF5::CoreAddons KF5::ConfigCore KF5::ConfigGui) if (KF5FileMetaData_FOUND) target_link_libraries(elisaLib LINK_PRIVATE KF5::FileMetaData ) endif() if (KF5KIO_FOUND) target_link_libraries(elisaLib LINK_PUBLIC KF5::KIOCore KF5::KIOFileWidgets KF5::KIOWidgets ) endif() if (KF5XmlGui_FOUND) target_link_libraries(elisaLib LINK_PUBLIC KF5::XmlGui ) endif() if (KF5ConfigWidgets_FOUND) target_link_libraries(elisaLib LINK_PUBLIC KF5::ConfigWidgets ) endif() if (KF5KCMUtils_FOUND) target_link_libraries(elisaLib LINK_PUBLIC KF5::KCMUtils ) endif() if (KF5Baloo_FOUND) if (Qt5DBus_FOUND) target_link_libraries(elisaLib LINK_PUBLIC KF5::Baloo ) endif() endif() if (Qt5DBus_FOUND) target_link_libraries(elisaLib LINK_PUBLIC Qt5::DBus ) if (KF5DBusAddons_FOUND) target_link_libraries(elisaLib LINK_PUBLIC KF5::DBusAddons ) endif() endif() if (LIBVLC_FOUND) target_include_directories(elisaLib PRIVATE ${LIBVLC_INCLUDE_DIR} ) target_link_libraries(elisaLib LINK_PRIVATE ${LIBVLC_LIBRARY} ) endif() if (ANDROID) target_link_libraries(elisaLib LINK_PUBLIC Qt5::AndroidExtras ) endif() generate_export_header(elisaLib BASE_NAME ElisaLib EXPORT_FILE_NAME elisaLib_export.h) set_target_properties(elisaLib PROPERTIES VERSION 0.1 SOVERSION 0 EXPORT_NAME ElisaLib ) if (NOT APPLE AND NOT WIN32) install(TARGETS elisaLib LIBRARY DESTINATION ${KDE_INSTALL_FULL_LIBDIR}/elisa NAMELINK_SKIP RUNTIME DESTINATION ${KDE_INSTALL_FULL_LIBDIR}/elisa BUNDLE DESTINATION ${KDE_INSTALL_FULL_LIBDIR}/elisa ) else() install(TARGETS elisaLib ${INSTALL_TARGETS_DEFAULT_ARGS}) endif() set(elisaqmlplugin_SOURCES elisaqmlplugin.cpp datatype.cpp elisautils.cpp ) if (KF5FileMetaData_FOUND) set(elisaqmlplugin_SOURCES ${elisaqmlplugin_SOURCES} embeddedcoverageimageprovider.cpp ) endif() add_library(elisaqmlplugin SHARED ${elisaqmlplugin_SOURCES}) target_link_libraries(elisaqmlplugin LINK_PRIVATE Qt5::Quick Qt5::Widgets KF5::ConfigCore KF5::ConfigGui elisaLib ) if (KF5FileMetaData_FOUND) target_link_libraries(elisaqmlplugin LINK_PRIVATE KF5::FileMetaData ) endif() set_target_properties(elisaqmlplugin PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/org/kde/elisa ) if (NOT APPLE AND NOT WIN32) set_target_properties(elisaqmlplugin PROPERTIES INSTALL_RPATH "${KDE_INSTALL_FULL_LIBDIR}/elisa;${CMAKE_INSTALL_RPATH}" ) endif() install(TARGETS elisaqmlplugin DESTINATION ${QML_INSTALL_DIR}/org/kde/elisa/) install(FILES qmldir DESTINATION ${QML_INSTALL_DIR}/org/kde/elisa) add_custom_target(copy) add_custom_target(copy2) file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/bin/org/kde/elisa) add_custom_command(TARGET copy PRE_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/qmldir ${CMAKE_BINARY_DIR}/bin/org/kde/elisa/) add_custom_command(TARGET copy2 PRE_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/plugins.qmltypes ${CMAKE_BINARY_DIR}/bin/org/kde/elisa/) add_dependencies(elisaqmlplugin copy copy2) if (Qt5Quick_FOUND AND Qt5Widgets_FOUND) set(elisa_SOURCES main.cpp windows/WindowsTheme.qml windows/PlatformIntegration.qml android/ElisaMainWindow.qml android/AndroidTheme.qml android/PlatformIntegration.qml android/AlbumsView.qml android/ArtistsView.qml android/TracksView.qml android/GenresView.qml qml/ElisaMainWindow.qml qml/ApplicationMenu.qml qml/BaseTheme.qml qml/Theme.qml qml/PlatformIntegration.qml qml/LabelWithToolTip.qml qml/RatingStar.qml qml/DraggableItem.qml qml/PassiveNotification.qml qml/TopNotification.qml qml/TopNotificationItem.qml qml/TrackImportNotification.qml qml/HeaderBar.qml qml/NavigationActionBar.qml qml/MediaPlayerControl.qml qml/ContextView.qml + qml/ContextViewLyrics.qml qml/ContentView.qml qml/ViewSelector.qml qml/DataGridView.qml qml/TracksView.qml qml/AlbumView.qml qml/RecentlyPlayedTracks.qml qml/FrequentlyPlayedTracks.qml qml/MediaPlayListView.qml qml/PlayListBasicView.qml qml/PlayListEntry.qml qml/SimplePlayListView.qml qml/SimplePlayListEntry.qml qml/PlayListAlbumHeader.qml qml/BasicPlayListAlbumHeader.qml + qml/MetaDataDelegate.qml qml/MediaTrackDelegate.qml qml/MediaAlbumTrackDelegate.qml qml/MediaTrackMetadataView.qml qml/GridBrowserView.qml qml/GridBrowserDelegate.qml qml/ListBrowserView.qml qml/FileBrowserDelegate.qml qml/FileBrowserView.qml qml/ScrollHelper.qml qml/FlatButtonWithToolTip.qml ) qt5_add_resources(elisa_SOURCES resources.qrc) set_property(SOURCE qrc_resources.cpp PROPERTY SKIP_AUTOMOC ON) set(elisa_ICONS_PNG ../icons/128-apps-elisa.png ../icons/64-apps-elisa.png ../icons/48-apps-elisa.png ../icons/32-apps-elisa.png ../icons/22-apps-elisa.png ../icons/16-apps-elisa.png ) # add icons to application sources, to have them bundled ecm_add_app_icon(elisa_SOURCES ICONS ${elisa_ICONS_PNG}) add_executable(elisa ${elisa_SOURCES}) target_include_directories(elisa PRIVATE ${KDSoap_INCLUDE_DIRS}) target_link_libraries(elisa LINK_PRIVATE elisaLib Qt5::Widgets Qt5::QuickControls2 KF5::I18n KF5::CoreAddons KF5::ConfigCore KF5::ConfigGui ) if (ANDROID) target_link_libraries(elisa LINK_PRIVATE Qt5::AndroidExtras Qt5::Svg Qt5::Sql Qt5::Concurrent KF5::Kirigami2 ) endif() if (KF5Crash_FOUND) target_link_libraries(elisa LINK_PRIVATE KF5::Crash ) endif() if (KF5Declarative_FOUND) target_link_libraries(elisa LINK_PRIVATE KF5::Declarative ) endif() if (NOT APPLE AND NOT WIN32) set_target_properties(elisa PROPERTIES INSTALL_RPATH "${KDE_INSTALL_FULL_LIBDIR}/elisa;${CMAKE_INSTALL_RPATH}" ) endif() install(TARGETS elisa ${INSTALL_TARGETS_DEFAULT_ARGS}) endif() if (KF5ConfigWidgets_FOUND AND KF5Declarative_FOUND) add_subdirectory(localFileConfiguration) endif() set(elisaImport_SOURCES elisaimport.cpp elisaimportapplication.cpp ) kconfig_add_kcfg_files(elisaImport_SOURCES ../src/elisa_settings.kcfgc ) set(elisaImport_SOURCES ${elisaImport_SOURCES} ../src/elisa_core.kcfg ) add_executable(elisaImport ${elisaImport_SOURCES}) target_link_libraries(elisaImport LINK_PRIVATE KF5::ConfigCore KF5::ConfigGui elisaLib ) if (KF5FileMetaData_FOUND) target_link_libraries(elisaImport LINK_PRIVATE KF5::FileMetaData ) endif() set(QML_IMPORT_PATH ${CMAKE_BINARY_DIR}/bin CACHE INTERNAL "qml import path" FORCE) if (ANDROID) kirigami_package_breeze_icons(ICONS elisa) endif() diff --git a/src/databaseinterface.cpp b/src/databaseinterface.cpp index 5108f7d1..dde505fa 100644 --- a/src/databaseinterface.cpp +++ b/src/databaseinterface.cpp @@ -1,6552 +1,6556 @@ /* * Copyright 2016-2017 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "databaseinterface.h" #include "databaseLogging.h" #include "musicaudiotrack.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include class DatabaseInterfacePrivate { public: DatabaseInterfacePrivate(const QSqlDatabase &tracksDatabase) : mTracksDatabase(tracksDatabase), mSelectAlbumQuery(mTracksDatabase), mSelectTrackQuery(mTracksDatabase), mSelectAlbumIdFromTitleQuery(mTracksDatabase), mInsertAlbumQuery(mTracksDatabase), mSelectTrackIdFromTitleAlbumIdArtistQuery(mTracksDatabase), mInsertTrackQuery(mTracksDatabase), mSelectTracksFromArtist(mTracksDatabase), mSelectTrackFromIdQuery(mTracksDatabase), mSelectCountAlbumsForArtistQuery(mTracksDatabase), mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery(mTracksDatabase), mSelectAllAlbumsFromArtistQuery(mTracksDatabase), mSelectAllArtistsQuery(mTracksDatabase), mInsertArtistsQuery(mTracksDatabase), mSelectArtistByNameQuery(mTracksDatabase), mSelectArtistQuery(mTracksDatabase), mUpdateTrackStatistics(mTracksDatabase), mRemoveTrackQuery(mTracksDatabase), mRemoveAlbumQuery(mTracksDatabase), mRemoveArtistQuery(mTracksDatabase), mSelectAllTracksQuery(mTracksDatabase), mInsertTrackMapping(mTracksDatabase), mUpdateTrackFirstPlayStatistics(mTracksDatabase), mInsertMusicSource(mTracksDatabase), mSelectMusicSource(mTracksDatabase), mUpdateTrackPriority(mTracksDatabase), mUpdateTrackFileModifiedTime(mTracksDatabase), mSelectTracksMapping(mTracksDatabase), mSelectTracksMappingPriority(mTracksDatabase), mUpdateAlbumArtUriFromAlbumIdQuery(mTracksDatabase), mSelectTracksMappingPriorityByTrackId(mTracksDatabase), mSelectAlbumIdsFromArtist(mTracksDatabase), mSelectAllTrackFilesQuery(mTracksDatabase), mRemoveTracksMappingFromSource(mTracksDatabase), mRemoveTracksMapping(mTracksDatabase), mSelectTracksWithoutMappingQuery(mTracksDatabase), mSelectAlbumIdFromTitleAndArtistQuery(mTracksDatabase), mSelectAlbumIdFromTitleWithoutArtistQuery(mTracksDatabase), mSelectTrackIdFromTitleAlbumTrackDiscNumberQuery(mTracksDatabase), mSelectAlbumArtUriFromAlbumIdQuery(mTracksDatabase), mInsertComposerQuery(mTracksDatabase), mSelectComposerByNameQuery(mTracksDatabase), mSelectComposerQuery(mTracksDatabase), mInsertLyricistQuery(mTracksDatabase), mSelectLyricistByNameQuery(mTracksDatabase), mSelectLyricistQuery(mTracksDatabase), mInsertGenreQuery(mTracksDatabase), mSelectGenreByNameQuery(mTracksDatabase), mSelectGenreQuery(mTracksDatabase), mSelectAllTracksShortQuery(mTracksDatabase), mSelectAllAlbumsShortQuery(mTracksDatabase), mSelectAllComposersQuery(mTracksDatabase), mSelectAllLyricistsQuery(mTracksDatabase), mSelectCountAlbumsForComposerQuery(mTracksDatabase), mSelectCountAlbumsForLyricistQuery(mTracksDatabase), mSelectAllGenresQuery(mTracksDatabase), mSelectGenreForArtistQuery(mTracksDatabase), mSelectGenreForAlbumQuery(mTracksDatabase), mUpdateTrackQuery(mTracksDatabase), mUpdateAlbumArtistQuery(mTracksDatabase), mUpdateAlbumArtistInTracksQuery(mTracksDatabase), mQueryMaximumTrackIdQuery(mTracksDatabase), mQueryMaximumAlbumIdQuery(mTracksDatabase), mQueryMaximumArtistIdQuery(mTracksDatabase), mQueryMaximumLyricistIdQuery(mTracksDatabase), mQueryMaximumComposerIdQuery(mTracksDatabase), mQueryMaximumGenreIdQuery(mTracksDatabase), mSelectAllArtistsWithGenreFilterQuery(mTracksDatabase), mSelectAllAlbumsShortWithGenreArtistFilterQuery(mTracksDatabase), mSelectAllAlbumsShortWithArtistFilterQuery(mTracksDatabase), mSelectAllRecentlyPlayedTracksQuery(mTracksDatabase), mSelectAllFrequentlyPlayedTracksQuery(mTracksDatabase), mClearTracksTable(mTracksDatabase), mClearAlbumsTable(mTracksDatabase), mClearArtistsTable(mTracksDatabase), mClearComposerTable(mTracksDatabase), mClearGenreTable(mTracksDatabase), mClearLyricistTable(mTracksDatabase), mArtistMatchGenreQuery(mTracksDatabase), mSelectTrackIdQuery(mTracksDatabase) { } QSqlDatabase mTracksDatabase; QSqlQuery mSelectAlbumQuery; QSqlQuery mSelectTrackQuery; QSqlQuery mSelectAlbumIdFromTitleQuery; QSqlQuery mInsertAlbumQuery; QSqlQuery mSelectTrackIdFromTitleAlbumIdArtistQuery; QSqlQuery mInsertTrackQuery; QSqlQuery mSelectTracksFromArtist; QSqlQuery mSelectTrackFromIdQuery; QSqlQuery mSelectCountAlbumsForArtistQuery; QSqlQuery mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery; QSqlQuery mSelectAllAlbumsFromArtistQuery; QSqlQuery mSelectAllArtistsQuery; QSqlQuery mInsertArtistsQuery; QSqlQuery mSelectArtistByNameQuery; QSqlQuery mSelectArtistQuery; QSqlQuery mUpdateTrackStatistics; QSqlQuery mRemoveTrackQuery; QSqlQuery mRemoveAlbumQuery; QSqlQuery mRemoveArtistQuery; QSqlQuery mSelectAllTracksQuery; QSqlQuery mInsertTrackMapping; QSqlQuery mUpdateTrackFirstPlayStatistics; QSqlQuery mInsertMusicSource; QSqlQuery mSelectMusicSource; QSqlQuery mUpdateTrackPriority; QSqlQuery mUpdateTrackFileModifiedTime; QSqlQuery mSelectTracksMapping; QSqlQuery mSelectTracksMappingPriority; QSqlQuery mUpdateAlbumArtUriFromAlbumIdQuery; QSqlQuery mSelectTracksMappingPriorityByTrackId; QSqlQuery mSelectAlbumIdsFromArtist; QSqlQuery mSelectAllTrackFilesQuery; QSqlQuery mRemoveTracksMappingFromSource; QSqlQuery mRemoveTracksMapping; QSqlQuery mSelectTracksWithoutMappingQuery; QSqlQuery mSelectAlbumIdFromTitleAndArtistQuery; QSqlQuery mSelectAlbumIdFromTitleWithoutArtistQuery; QSqlQuery mSelectTrackIdFromTitleAlbumTrackDiscNumberQuery; QSqlQuery mSelectAlbumArtUriFromAlbumIdQuery; QSqlQuery mInsertComposerQuery; QSqlQuery mSelectComposerByNameQuery; QSqlQuery mSelectComposerQuery; QSqlQuery mInsertLyricistQuery; QSqlQuery mSelectLyricistByNameQuery; QSqlQuery mSelectLyricistQuery; QSqlQuery mInsertGenreQuery; QSqlQuery mSelectGenreByNameQuery; QSqlQuery mSelectGenreQuery; QSqlQuery mSelectAllTracksShortQuery; QSqlQuery mSelectAllAlbumsShortQuery; QSqlQuery mSelectAllComposersQuery; QSqlQuery mSelectAllLyricistsQuery; QSqlQuery mSelectCountAlbumsForComposerQuery; QSqlQuery mSelectCountAlbumsForLyricistQuery; QSqlQuery mSelectAllGenresQuery; QSqlQuery mSelectGenreForArtistQuery; QSqlQuery mSelectGenreForAlbumQuery; QSqlQuery mUpdateTrackQuery; QSqlQuery mUpdateAlbumArtistQuery; QSqlQuery mUpdateAlbumArtistInTracksQuery; QSqlQuery mQueryMaximumTrackIdQuery; QSqlQuery mQueryMaximumAlbumIdQuery; QSqlQuery mQueryMaximumArtistIdQuery; QSqlQuery mQueryMaximumLyricistIdQuery; QSqlQuery mQueryMaximumComposerIdQuery; QSqlQuery mQueryMaximumGenreIdQuery; QSqlQuery mSelectAllArtistsWithGenreFilterQuery; QSqlQuery mSelectAllAlbumsShortWithGenreArtistFilterQuery; QSqlQuery mSelectAllAlbumsShortWithArtistFilterQuery; QSqlQuery mSelectAllRecentlyPlayedTracksQuery; QSqlQuery mSelectAllFrequentlyPlayedTracksQuery; QSqlQuery mClearTracksTable; QSqlQuery mClearAlbumsTable; QSqlQuery mClearArtistsTable; QSqlQuery mClearComposerTable; QSqlQuery mClearGenreTable; QSqlQuery mClearLyricistTable; QSqlQuery mArtistMatchGenreQuery; QSqlQuery mSelectTrackIdQuery; QSet mModifiedTrackIds; QSet mModifiedAlbumIds; QSet mModifiedArtistIds; QSet mInsertedTracks; QSet mInsertedAlbums; QSet mInsertedArtists; qulonglong mAlbumId = 1; qulonglong mArtistId = 1; qulonglong mComposerId = 1; qulonglong mLyricistId = 1; qulonglong mGenreId = 1; qulonglong mTrackId = 1; QAtomicInt mStopRequest = 0; bool mInitFinished = false; bool mIsInBadState = false; }; DatabaseInterface::DatabaseInterface(QObject *parent) : QObject(parent), d(nullptr) { } DatabaseInterface::~DatabaseInterface() { if (d) { d->mTracksDatabase.close(); } } void DatabaseInterface::init(const QString &dbName, const QString &databaseFileName) { QSqlDatabase tracksDatabase = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), dbName); if (!databaseFileName.isEmpty()) { tracksDatabase.setDatabaseName(QStringLiteral("file:") + databaseFileName); } else { tracksDatabase.setDatabaseName(QStringLiteral("file:memdb1?mode=memory")); } tracksDatabase.setConnectOptions(QStringLiteral("foreign_keys = ON;locking_mode = EXCLUSIVE;QSQLITE_OPEN_URI;QSQLITE_BUSY_TIMEOUT=500000")); auto result = tracksDatabase.open(); if (result) { qCDebug(orgKdeElisaDatabase) << "database open"; } else { qCDebug(orgKdeElisaDatabase) << "database not open"; } qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::init" << (tracksDatabase.driver()->hasFeature(QSqlDriver::Transactions) ? "yes" : "no"); tracksDatabase.exec(QStringLiteral("PRAGMA foreign_keys = ON;")); d = std::make_unique(tracksDatabase); initDatabase(); initRequest(); if (!databaseFileName.isEmpty()) { reloadExistingDatabase(); } } qulonglong DatabaseInterface::albumIdFromTitleAndArtist(const QString &title, const QString &artist) { auto result = qulonglong{0}; auto transactionResult = startTransaction(); if (!transactionResult) { return result; } result = internalAlbumIdFromTitleAndArtist(title, artist); transactionResult = finishTransaction(); if (!transactionResult) { return result; } return result; } DatabaseInterface::ListTrackDataType DatabaseInterface::allTracksData() { auto result = ListTrackDataType{}; if (!d) { return result; } auto transactionResult = startTransaction(); if (!transactionResult) { return result; } result = internalAllTracksPartialData(); transactionResult = finishTransaction(); if (!transactionResult) { return result; } return result; } DatabaseInterface::ListTrackDataType DatabaseInterface::recentlyPlayedTracksData(int count) { auto result = ListTrackDataType{}; if (!d) { return result; } auto transactionResult = startTransaction(); if (!transactionResult) { return result; } result = internalRecentlyPlayedTracksData(count); transactionResult = finishTransaction(); if (!transactionResult) { return result; } return result; } DatabaseInterface::ListTrackDataType DatabaseInterface::frequentlyPlayedTracksData(int count) { auto result = ListTrackDataType{}; if (!d) { return result; } auto transactionResult = startTransaction(); if (!transactionResult) { return result; } result = internalFrequentlyPlayedTracksData(count); transactionResult = finishTransaction(); if (!transactionResult) { return result; } return result; } DatabaseInterface::ListAlbumDataType DatabaseInterface::allAlbumsData() { auto result = ListAlbumDataType{}; if (!d) { return result; } auto transactionResult = startTransaction(); if (!transactionResult) { return result; } result = internalAllAlbumsPartialData(d->mSelectAllAlbumsShortQuery); transactionResult = finishTransaction(); if (!transactionResult) { return result; } return result; } DatabaseInterface::ListAlbumDataType DatabaseInterface::allAlbumsDataByGenreAndArtist(const QString &genre, const QString &artist) { auto result = ListAlbumDataType{}; if (!d) { return result; } auto transactionResult = startTransaction(); if (!transactionResult) { return result; } d->mSelectAllAlbumsShortWithGenreArtistFilterQuery.bindValue(QStringLiteral(":artistFilter"), artist); d->mSelectAllAlbumsShortWithGenreArtistFilterQuery.bindValue(QStringLiteral(":genreFilter"), genre); result = internalAllAlbumsPartialData(d->mSelectAllAlbumsShortWithGenreArtistFilterQuery); transactionResult = finishTransaction(); if (!transactionResult) { return result; } return result; } DatabaseInterface::ListAlbumDataType DatabaseInterface::allAlbumsDataByArtist(const QString &artist) { auto result = ListAlbumDataType{}; if (!d) { return result; } auto transactionResult = startTransaction(); if (!transactionResult) { return result; } d->mSelectAllAlbumsShortWithArtistFilterQuery.bindValue(QStringLiteral(":artistFilter"), artist); result = internalAllAlbumsPartialData(d->mSelectAllAlbumsShortWithArtistFilterQuery); transactionResult = finishTransaction(); if (!transactionResult) { return result; } return result; } DatabaseInterface::AlbumDataType DatabaseInterface::albumDataFromDatabaseId(qulonglong id) { auto result = DatabaseInterface::AlbumDataType{}; if (!d) { return result; } auto transactionResult = startTransaction(); if (!transactionResult) { return result; } result = internalOneAlbumPartialData(id); transactionResult = finishTransaction(); if (!transactionResult) { return result; } return result; } DatabaseInterface::ListTrackDataType DatabaseInterface::albumData(qulonglong databaseId) { auto result = ListTrackDataType{}; if (!d) { return result; } auto transactionResult = startTransaction(); if (!transactionResult) { return result; } d->mSelectTrackQuery.bindValue(QStringLiteral(":albumId"), databaseId); auto queryResult = execQuery(d->mSelectTrackQuery); if (!queryResult || !d->mSelectTrackQuery.isSelect() || !d->mSelectTrackQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::albumData" << d->mSelectTrackQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::albumData" << d->mSelectTrackQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::albumData" << d->mSelectTrackQuery.lastError(); } while (d->mSelectTrackQuery.next()) { const auto ¤tRecord = d->mSelectTrackQuery.record(); result.push_back(buildTrackDataFromDatabaseRecord(currentRecord)); } d->mSelectTrackQuery.finish(); transactionResult = finishTransaction(); if (!transactionResult) { return result; } return result; } DatabaseInterface::ListArtistDataType DatabaseInterface::allArtistsData() { auto result = ListArtistDataType{}; if (!d) { return result; } auto transactionResult = startTransaction(); if (!transactionResult) { return result; } result = internalAllArtistsPartialData(d->mSelectAllArtistsQuery); transactionResult = finishTransaction(); if (!transactionResult) { return result; } return result; } DatabaseInterface::ListArtistDataType DatabaseInterface::allArtistsDataByGenre(const QString &genre) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::allArtistsDataByGenre" << genre; auto result = ListArtistDataType{}; if (!d) { return result; } auto transactionResult = startTransaction(); if (!transactionResult) { return result; } d->mSelectAllArtistsWithGenreFilterQuery.bindValue(QStringLiteral(":genreFilter"), genre); result = internalAllArtistsPartialData(d->mSelectAllArtistsWithGenreFilterQuery); transactionResult = finishTransaction(); if (!transactionResult) { return result; } return result; } DatabaseInterface::ListGenreDataType DatabaseInterface::allGenresData() { auto result = ListGenreDataType{}; if (!d) { return result; } auto transactionResult = startTransaction(); if (!transactionResult) { return result; } result = internalAllGenresPartialData(); transactionResult = finishTransaction(); if (!transactionResult) { return result; } return result; } bool DatabaseInterface::internalArtistMatchGenre(qulonglong databaseId, const QString &genre) { auto result = true; if (!d) { return result; } d->mArtistMatchGenreQuery.bindValue(QStringLiteral(":databaseId"), databaseId); d->mArtistMatchGenreQuery.bindValue(QStringLiteral(":genreFilter"), genre); auto queryResult = execQuery(d->mArtistMatchGenreQuery); if (!queryResult || !d->mArtistMatchGenreQuery.isSelect() || !d->mArtistMatchGenreQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::artistMatchGenre" << d->mArtistMatchGenreQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::artistMatchGenre" << d->mArtistMatchGenreQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::artistMatchGenre" << d->mArtistMatchGenreQuery.lastError(); d->mArtistMatchGenreQuery.finish(); auto transactionResult = finishTransaction(); if (!transactionResult) { return result; } return result; } result = d->mArtistMatchGenreQuery.next(); d->mArtistMatchGenreQuery.finish(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::internalArtistMatchGenre" << databaseId << (result ? "match" : "does not match"); return result; } DatabaseInterface::ListTrackDataType DatabaseInterface::tracksDataFromAuthor(const QString &ArtistName) { auto allTracks = ListTrackDataType{}; auto transactionResult = startTransaction(); if (!transactionResult) { return allTracks; } allTracks = internalTracksFromAuthor(ArtistName); transactionResult = finishTransaction(); if (!transactionResult) { return allTracks; } return allTracks; } DatabaseInterface::TrackDataType DatabaseInterface::trackDataFromDatabaseId(qulonglong id) { auto result = TrackDataType(); if (!d) { return result; } auto transactionResult = startTransaction(); if (!transactionResult) { return result; } result = internalOneTrackPartialData(id); transactionResult = finishTransaction(); if (!transactionResult) { return result; } return result; } qulonglong DatabaseInterface::trackIdFromTitleAlbumTrackDiscNumber(const QString &title, const QString &artist, const QString &album, int trackNumber, int discNumber) { auto result = qulonglong(0); if (!d) { return result; } auto transactionResult = startTransaction(); if (!transactionResult) { return result; } result = internalTrackIdFromTitleAlbumTracDiscNumber(title, artist, album, trackNumber, discNumber); transactionResult = finishTransaction(); if (!transactionResult) { return result; } return result; } qulonglong DatabaseInterface::trackIdFromFileName(const QUrl &fileName) { auto result = qulonglong(0); if (!d) { return result; } auto transactionResult = startTransaction(); if (!transactionResult) { return result; } result = internalTrackIdFromFileName(fileName); transactionResult = finishTransaction(); if (!transactionResult) { return result; } return result; } void DatabaseInterface::applicationAboutToQuit() { d->mStopRequest = 1; } void DatabaseInterface::askRestoredTracks() { auto transactionResult = startTransaction(); if (!transactionResult) { return; } auto result = internalAllFileName(); Q_EMIT restoredTracks(result); transactionResult = finishTransaction(); if (!transactionResult) { return; } } void DatabaseInterface::trackHasStartedPlaying(const QUrl &fileName, const QDateTime &time) { auto transactionResult = startTransaction(); if (!transactionResult) { return; } updateTrackStatistics(fileName, time); + auto trackId = internalTrackIdFromFileName(fileName); + if (trackId != 0) { + Q_EMIT trackModified(internalOneTrackPartialData(trackId)); + } transactionResult = finishTransaction(); if (!transactionResult) { return; } } void DatabaseInterface::clearData() { auto transactionResult = startTransaction(); if (!transactionResult) { return; } auto queryResult = execQuery(d->mClearTracksTable); if (!queryResult || !d->mClearTracksTable.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::clearData" << d->mClearTracksTable.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::clearData" << d->mClearTracksTable.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::clearData" << d->mClearTracksTable.lastError(); } d->mClearTracksTable.finish(); queryResult = execQuery(d->mClearAlbumsTable); if (!queryResult || !d->mClearAlbumsTable.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::clearData" << d->mClearAlbumsTable.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::clearData" << d->mClearAlbumsTable.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::clearData" << d->mClearAlbumsTable.lastError(); } d->mClearAlbumsTable.finish(); queryResult = execQuery(d->mClearComposerTable); if (!queryResult || !d->mClearComposerTable.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::clearData" << d->mClearComposerTable.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::clearData" << d->mClearComposerTable.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::clearData" << d->mClearComposerTable.lastError(); } d->mClearComposerTable.finish(); queryResult = execQuery(d->mClearLyricistTable); if (!queryResult || !d->mClearLyricistTable.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::clearData" << d->mClearLyricistTable.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::clearData" << d->mClearLyricistTable.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::clearData" << d->mClearLyricistTable.lastError(); } d->mClearLyricistTable.finish(); queryResult = execQuery(d->mClearGenreTable); if (!queryResult || !d->mClearGenreTable.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::clearData" << d->mClearGenreTable.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::clearData" << d->mClearGenreTable.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::clearData" << d->mClearGenreTable.lastError(); } d->mClearGenreTable.finish(); queryResult = execQuery(d->mClearArtistsTable); if (!queryResult || !d->mClearArtistsTable.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::clearData" << d->mClearArtistsTable.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::clearData" << d->mClearArtistsTable.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::clearData" << d->mClearArtistsTable.lastError(); } d->mClearArtistsTable.finish(); transactionResult = finishTransaction(); if (!transactionResult) { return; } Q_EMIT cleanedDatabase(); } void DatabaseInterface::initChangesTrackers() { d->mModifiedTrackIds.clear(); d->mModifiedAlbumIds.clear(); d->mModifiedArtistIds.clear(); d->mInsertedTracks.clear(); d->mInsertedAlbums.clear(); d->mInsertedArtists.clear(); } void DatabaseInterface::recordModifiedTrack(qulonglong trackId) { d->mModifiedTrackIds.insert(trackId); } void DatabaseInterface::recordModifiedAlbum(qulonglong albumId) { d->mModifiedAlbumIds.insert(albumId); } void DatabaseInterface::insertTracksList(const QList &tracks, const QHash &covers) { qCDebug(orgKdeElisaDatabase()) << "DatabaseInterface::insertTracksList" << tracks.count(); if (d->mStopRequest == 1) { Q_EMIT finishInsertingTracksList(); return; } auto transactionResult = startTransaction(); if (!transactionResult) { Q_EMIT finishInsertingTracksList(); return; } initChangesTrackers(); for(const auto &oneTrack : tracks) { d->mSelectTracksMapping.bindValue(QStringLiteral(":fileName"), oneTrack.resourceURI()); auto result = execQuery(d->mSelectTracksMapping); if (!result || !d->mSelectTracksMapping.isSelect() || !d->mSelectTracksMapping.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertTracksList" << d->mSelectTracksMapping.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertTracksList" << d->mSelectTracksMapping.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertTracksList" << d->mSelectTracksMapping.lastError(); d->mSelectTracksMapping.finish(); rollBackTransaction(); Q_EMIT finishInsertingTracksList(); return; } bool isNewTrack = !d->mSelectTracksMapping.next(); if (isNewTrack) { insertTrackOrigin(oneTrack.resourceURI(), oneTrack.fileModificationTime(), QDateTime::currentDateTime()); } else if (!d->mSelectTracksMapping.record().value(0).isNull() && d->mSelectTracksMapping.record().value(0).toULongLong() != 0) { updateTrackOrigin(oneTrack.resourceURI(), oneTrack.fileModificationTime()); } d->mSelectTracksMapping.finish(); bool isInserted = false; const auto insertedTrackId = internalInsertTrack(oneTrack, covers, isInserted); if (isInserted && insertedTrackId != 0) { d->mInsertedTracks.insert(insertedTrackId); } if (d->mStopRequest == 1) { transactionResult = finishTransaction(); if (!transactionResult) { Q_EMIT finishInsertingTracksList(); return; } Q_EMIT finishInsertingTracksList(); return; } } if (!d->mInsertedArtists.isEmpty()) { ListArtistDataType newArtists; for (auto artistId : qAsConst(d->mInsertedArtists)) { newArtists.push_back({{DatabaseIdRole, artistId}}); } qCInfo(orgKdeElisaDatabase) << "artistsAdded" << newArtists.size(); Q_EMIT artistsAdded(newArtists); } if (!d->mInsertedAlbums.isEmpty()) { ListAlbumDataType newAlbums; for (auto albumId : qAsConst(d->mInsertedAlbums)) { d->mModifiedAlbumIds.remove(albumId); newAlbums.push_back(internalOneAlbumPartialData(albumId)); } qCInfo(orgKdeElisaDatabase) << "albumsAdded" << newAlbums.size(); Q_EMIT albumsAdded(newAlbums); } for (auto albumId : qAsConst(d->mModifiedAlbumIds)) { Q_EMIT albumModified({{DatabaseIdRole, albumId}}, albumId); } if (!d->mInsertedTracks.isEmpty()) { ListTrackDataType newTracks; for (auto trackId : qAsConst(d->mInsertedTracks)) { newTracks.push_back(internalOneTrackPartialData(trackId)); d->mModifiedTrackIds.remove(trackId); } qCInfo(orgKdeElisaDatabase) << "tracksAdded" << newTracks.size(); Q_EMIT tracksAdded(newTracks); } for (auto trackId : qAsConst(d->mModifiedTrackIds)) { Q_EMIT trackModified(internalOneTrackPartialData(trackId)); } transactionResult = finishTransaction(); if (!transactionResult) { Q_EMIT finishInsertingTracksList(); return; } Q_EMIT finishInsertingTracksList(); } void DatabaseInterface::removeTracksList(const QList &removedTracks) { auto transactionResult = startTransaction(); if (!transactionResult) { Q_EMIT finishRemovingTracksList(); return; } initChangesTrackers(); internalRemoveTracksList(removedTracks); if (!d->mInsertedArtists.isEmpty()) { ListArtistDataType newArtists; for (auto artistId : qAsConst(d->mInsertedArtists)) { newArtists.push_back({{DatabaseIdRole, artistId}}); } Q_EMIT artistsAdded(newArtists); } transactionResult = finishTransaction(); if (!transactionResult) { Q_EMIT finishRemovingTracksList(); return; } Q_EMIT finishRemovingTracksList(); } bool DatabaseInterface::startTransaction() const { auto result = false; auto transactionResult = d->mTracksDatabase.transaction(); if (!transactionResult) { qCDebug(orgKdeElisaDatabase) << "transaction failed" << d->mTracksDatabase.lastError() << d->mTracksDatabase.lastError().driverText(); return result; } result = true; return result; } bool DatabaseInterface::finishTransaction() const { auto result = false; auto transactionResult = d->mTracksDatabase.commit(); if (!transactionResult) { qCDebug(orgKdeElisaDatabase) << "commit failed" << d->mTracksDatabase.lastError() << d->mTracksDatabase.lastError().nativeErrorCode(); return result; } result = true; return result; } bool DatabaseInterface::rollBackTransaction() const { auto result = false; auto transactionResult = d->mTracksDatabase.rollback(); if (!transactionResult) { qCDebug(orgKdeElisaDatabase) << "commit failed" << d->mTracksDatabase.lastError() << d->mTracksDatabase.lastError().nativeErrorCode(); return result; } result = true; return result; } void DatabaseInterface::initDatabase() { auto listTables = d->mTracksDatabase.tables(); if (listTables.contains(QStringLiteral("DatabaseVersionV2")) || listTables.contains(QStringLiteral("DatabaseVersionV3")) || listTables.contains(QStringLiteral("DatabaseVersionV4")) || listTables.contains(QStringLiteral("DatabaseVersionV6")) || listTables.contains(QStringLiteral("DatabaseVersionV7")) || listTables.contains(QStringLiteral("DatabaseVersionV8")) || listTables.contains(QStringLiteral("DatabaseVersionV10"))) { qCDebug(orgKdeElisaDatabase()) << "Old database schema unsupported: delete and start from scratch"; qCDebug(orgKdeElisaDatabase()) << "list of old tables" << d->mTracksDatabase.tables(); auto oldTables = QStringList{ QStringLiteral("DatabaseVersionV2"), QStringLiteral("DatabaseVersionV3"), QStringLiteral("DatabaseVersionV4"), QStringLiteral("DatabaseVersionV5"), QStringLiteral("DatabaseVersionV6"), QStringLiteral("DatabaseVersionV7"), QStringLiteral("DatabaseVersionV8"), QStringLiteral("DatabaseVersionV10"), QStringLiteral("AlbumsArtists"), QStringLiteral("TracksArtists"), QStringLiteral("TracksMapping"), QStringLiteral("Tracks"), QStringLiteral("Composer"), QStringLiteral("Genre"), QStringLiteral("Lyricist"), QStringLiteral("Albums"), QStringLiteral("DiscoverSource"), QStringLiteral("Artists"),}; for (const auto &oneTable : oldTables) { if (listTables.indexOf(oneTable) == -1) { continue; } QSqlQuery createSchemaQuery(d->mTracksDatabase); auto result = createSchemaQuery.exec(QStringLiteral("DROP TABLE ") + oneTable); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initDatabase" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initDatabase" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } listTables = d->mTracksDatabase.tables(); } checkDatabaseSchema(); listTables = d->mTracksDatabase.tables(); if (listTables.contains(QStringLiteral("DatabaseVersionV5")) && !listTables.contains(QStringLiteral("DatabaseVersionV9"))) { upgradeDatabaseV9(); upgradeDatabaseV11(); upgradeDatabaseV12(); } else if (listTables.contains(QStringLiteral("DatabaseVersionV9"))) { if (!listTables.contains(QStringLiteral("DatabaseVersionV11"))) { upgradeDatabaseV11(); } if (!listTables.contains(QStringLiteral("DatabaseVersionV12"))) { upgradeDatabaseV12(); } } else { createDatabaseV9(); upgradeDatabaseV11(); upgradeDatabaseV12(); } } void DatabaseInterface::createDatabaseV9() { qCInfo(orgKdeElisaDatabase) << "begin creation of v9 database schema"; { QSqlQuery createSchemaQuery(d->mTracksDatabase); const auto &result = createSchemaQuery.exec(QStringLiteral("CREATE TABLE `DatabaseVersionV9` (`Version` INTEGER PRIMARY KEY NOT NULL)")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createSchemaQuery(d->mTracksDatabase); const auto &result = createSchemaQuery.exec(QStringLiteral("CREATE TABLE `DiscoverSource` (`ID` INTEGER PRIMARY KEY NOT NULL, " "`Name` VARCHAR(55) NOT NULL, " "UNIQUE (`Name`))")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createSchemaQuery(d->mTracksDatabase); const auto &result = createSchemaQuery.exec(QStringLiteral("CREATE TABLE `Artists` (`ID` INTEGER PRIMARY KEY NOT NULL, " "`Name` VARCHAR(55) NOT NULL, " "UNIQUE (`Name`))")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createSchemaQuery(d->mTracksDatabase); const auto &result = createSchemaQuery.exec(QStringLiteral("CREATE TABLE `Composer` (`ID` INTEGER PRIMARY KEY NOT NULL, " "`Name` VARCHAR(55) NOT NULL, " "UNIQUE (`Name`))")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createSchemaQuery(d->mTracksDatabase); const auto &result = createSchemaQuery.exec(QStringLiteral("CREATE TABLE `Genre` (`ID` INTEGER PRIMARY KEY NOT NULL, " "`Name` VARCHAR(85) NOT NULL, " "UNIQUE (`Name`))")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createSchemaQuery(d->mTracksDatabase); const auto &result = createSchemaQuery.exec(QStringLiteral("CREATE TABLE `Lyricist` (`ID` INTEGER PRIMARY KEY NOT NULL, " "`Name` VARCHAR(55) NOT NULL, " "UNIQUE (`Name`))")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createSchemaQuery(d->mTracksDatabase); const auto &result = createSchemaQuery.exec(QStringLiteral("CREATE TABLE `Albums` (" "`ID` INTEGER PRIMARY KEY NOT NULL, " "`Title` VARCHAR(55) NOT NULL, " "`ArtistName` VARCHAR(55), " "`AlbumPath` VARCHAR(255) NOT NULL, " "`CoverFileName` VARCHAR(255) NOT NULL, " "UNIQUE (`Title`, `ArtistName`, `AlbumPath`), " "CONSTRAINT fk_artists FOREIGN KEY (`ArtistName`) REFERENCES `Artists`(`Name`) " "ON DELETE CASCADE)")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createSchemaQuery.lastError(); } } { QSqlQuery createSchemaQuery(d->mTracksDatabase); const auto &result = createSchemaQuery.exec(QStringLiteral("CREATE TABLE `Tracks` (" "`ID` INTEGER PRIMARY KEY NOT NULL, " "`Title` VARCHAR(85) NOT NULL, " "`ArtistName` VARCHAR(55), " "`AlbumTitle` VARCHAR(55), " "`AlbumArtistName` VARCHAR(55), " "`AlbumPath` VARCHAR(255), " "`TrackNumber` INTEGER DEFAULT -1, " "`DiscNumber` INTEGER DEFAULT -1, " "`Duration` INTEGER NOT NULL, " "`Rating` INTEGER NOT NULL DEFAULT 0, " "`Genre` VARCHAR(55), " "`Composer` VARCHAR(55), " "`Lyricist` VARCHAR(55), " "`Comment` VARCHAR(255) DEFAULT '', " "`Year` INTEGER DEFAULT 0, " "`Channels` INTEGER DEFAULT -1, " "`BitRate` INTEGER DEFAULT -1, " "`SampleRate` INTEGER DEFAULT -1, " "`HasEmbeddedCover` BOOLEAN NOT NULL, " "`ImportDate` INTEGER NOT NULL, " "`FirstPlayDate` INTEGER, " "`LastPlayDate` INTEGER, " "`PlayCounter` INTEGER NOT NULL, " "UNIQUE (" "`Title`, `AlbumTitle`, `AlbumArtistName`, " "`AlbumPath`, `TrackNumber`, `DiscNumber`" "), " "CONSTRAINT fk_artist FOREIGN KEY (`ArtistName`) REFERENCES `Artists`(`Name`), " "CONSTRAINT fk_tracks_composer FOREIGN KEY (`Composer`) REFERENCES `Composer`(`Name`), " "CONSTRAINT fk_tracks_lyricist FOREIGN KEY (`Lyricist`) REFERENCES `Lyricist`(`Name`), " "CONSTRAINT fk_tracks_genre FOREIGN KEY (`Genre`) REFERENCES `Genre`(`Name`), " "CONSTRAINT fk_tracks_album FOREIGN KEY (" "`AlbumTitle`, `AlbumArtistName`, `AlbumPath`)" "REFERENCES `Albums`(`Title`, `ArtistName`, `AlbumPath`))")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createSchemaQuery(d->mTracksDatabase); const auto &result = createSchemaQuery.exec(QStringLiteral("CREATE TABLE `TracksMapping` (" "`TrackID` INTEGER NULL, " "`DiscoverID` INTEGER NOT NULL, " "`FileName` VARCHAR(255) NOT NULL, " "`Priority` INTEGER NOT NULL, " "`FileModifiedTime` DATETIME NOT NULL, " "PRIMARY KEY (`FileName`), " "CONSTRAINT TracksUnique UNIQUE (`TrackID`, `Priority`), " "CONSTRAINT fk_tracksmapping_trackID FOREIGN KEY (`TrackID`) REFERENCES `Tracks`(`ID`) ON DELETE CASCADE, " "CONSTRAINT fk_tracksmapping_discoverID FOREIGN KEY (`DiscoverID`) REFERENCES `DiscoverSource`(`ID`))")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createSchemaQuery.lastError(); } } { QSqlQuery createTrackIndex(d->mTracksDatabase); const auto &result = createTrackIndex.exec(QStringLiteral("CREATE INDEX " "IF NOT EXISTS " "`TitleAlbumsIndex` ON `Albums` " "(`Title`)")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createTrackIndex.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createTrackIndex.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createTrackIndex(d->mTracksDatabase); const auto &result = createTrackIndex.exec(QStringLiteral("CREATE INDEX " "IF NOT EXISTS " "`ArtistNameAlbumsIndex` ON `Albums` " "(`ArtistName`)")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createTrackIndex.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createTrackIndex.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createTrackIndex(d->mTracksDatabase); const auto &result = createTrackIndex.exec(QStringLiteral("CREATE INDEX " "IF NOT EXISTS " "`TracksAlbumIndex` ON `Tracks` " "(`AlbumTitle`, `AlbumArtistName`, `AlbumPath`)")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createTrackIndex.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createTrackIndex.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createTrackIndex(d->mTracksDatabase); const auto &result = createTrackIndex.exec(QStringLiteral("CREATE INDEX " "IF NOT EXISTS " "`ArtistNameIndex` ON `Tracks` " "(`ArtistName`)")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createTrackIndex.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createTrackIndex.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createTrackIndex(d->mTracksDatabase); const auto &result = createTrackIndex.exec(QStringLiteral("CREATE INDEX " "IF NOT EXISTS " "`AlbumArtistNameIndex` ON `Tracks` " "(`AlbumArtistName`)")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createTrackIndex.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createTrackIndex.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createTrackIndex(d->mTracksDatabase); const auto &result = createTrackIndex.exec(QStringLiteral("CREATE INDEX " "IF NOT EXISTS " "`TracksFileNameIndex` ON `TracksMapping` " "(`FileName`)")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createTrackIndex.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::createDatabaseV9" << createTrackIndex.lastError(); Q_EMIT databaseError(); } } qCInfo(orgKdeElisaDatabase) << "end creation of v9 database schema"; } void DatabaseInterface::upgradeDatabaseV9() { qCInfo(orgKdeElisaDatabase) << "begin update to v9 of database schema"; { QSqlQuery createSchemaQuery(d->mTracksDatabase); const auto &result = createSchemaQuery.exec(QStringLiteral("CREATE TABLE `DatabaseVersionV9` (`Version` INTEGER PRIMARY KEY NOT NULL)")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV9" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV9" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery disableForeignKeys(d->mTracksDatabase); auto result = disableForeignKeys.exec(QStringLiteral(" PRAGMA foreign_keys=OFF")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV9" << disableForeignKeys.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV9" << disableForeignKeys.lastError(); Q_EMIT databaseError(); } } d->mTracksDatabase.transaction(); { QSqlQuery createSchemaQuery(d->mTracksDatabase); const auto &result = createSchemaQuery.exec(QStringLiteral("CREATE TABLE `NewAlbums` (" "`ID` INTEGER PRIMARY KEY NOT NULL, " "`Title` VARCHAR(55) NOT NULL, " "`ArtistName` VARCHAR(55), " "`AlbumPath` VARCHAR(255) NOT NULL, " "`CoverFileName` VARCHAR(255) NOT NULL, " "`AlbumInternalID` VARCHAR(55), " "UNIQUE (`Title`, `ArtistName`, `AlbumPath`), " "CONSTRAINT fk_artists FOREIGN KEY (`ArtistName`) REFERENCES `Artists`(`Name`) " "ON DELETE CASCADE)")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV9" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV9" << createSchemaQuery.lastError(); } } { QSqlQuery copyDataQuery(d->mTracksDatabase); auto result = copyDataQuery.exec(QStringLiteral("INSERT INTO `NewAlbums` " "SELECT " "album.`ID`, " "album.`Title`, " "artist.`Name`, " "album.`AlbumPath`, " "album.`CoverFileName`, " "album.`AlbumInternalID` " "FROM " "`Albums` album, " "`AlbumsArtists` albumArtistMapping, " "`Artists` artist " "WHERE " "album.`ID` = albumArtistMapping.`AlbumID` AND " "albumArtistMapping.`ArtistID` = artist.`ID`")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV9" << copyDataQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV9" << copyDataQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createSchemaQuery(d->mTracksDatabase); auto result = createSchemaQuery.exec(QStringLiteral("DROP TABLE `Albums`")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV9" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV9" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createSchemaQuery(d->mTracksDatabase); auto result = createSchemaQuery.exec(QStringLiteral("DROP TABLE `AlbumsArtists`")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV9" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV9" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createSchemaQuery(d->mTracksDatabase); auto result = createSchemaQuery.exec(QStringLiteral("ALTER TABLE `NewAlbums` RENAME TO `Albums`")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV9" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV9" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createSchemaQuery(d->mTracksDatabase); const auto &result = createSchemaQuery.exec(QStringLiteral("CREATE TABLE `NewTracks` (" "`ID` INTEGER PRIMARY KEY NOT NULL, " "`Title` VARCHAR(85) NOT NULL, " "`ArtistName` VARCHAR(55), " "`AlbumTitle` VARCHAR(55), " "`AlbumArtistName` VARCHAR(55), " "`AlbumPath` VARCHAR(255), " "`TrackNumber` INTEGER DEFAULT -1, " "`DiscNumber` INTEGER DEFAULT -1, " "`Duration` INTEGER NOT NULL, " "`Rating` INTEGER NOT NULL DEFAULT 0, " "`Genre` VARCHAR(55), " "`Composer` VARCHAR(55), " "`Lyricist` VARCHAR(55), " "`Comment` VARCHAR(255) DEFAULT '', " "`Year` INTEGER DEFAULT 0, " "`Channels` INTEGER DEFAULT -1, " "`BitRate` INTEGER DEFAULT -1, " "`SampleRate` INTEGER DEFAULT -1, " "`HasEmbeddedCover` BOOLEAN NOT NULL, " "`ImportDate` INTEGER NOT NULL, " "`FirstPlayDate` INTEGER, " "`LastPlayDate` INTEGER, " "`PlayCounter` INTEGER NOT NULL, " "UNIQUE (" "`Title`, `AlbumTitle`, `AlbumArtistName`, " "`AlbumPath`, `TrackNumber`, `DiscNumber`" "), " "CONSTRAINT fk_artist FOREIGN KEY (`ArtistName`) REFERENCES `Artists`(`Name`), " "CONSTRAINT fk_tracks_composer FOREIGN KEY (`Composer`) REFERENCES `Composer`(`Name`), " "CONSTRAINT fk_tracks_lyricist FOREIGN KEY (`Lyricist`) REFERENCES `Lyricist`(`Name`), " "CONSTRAINT fk_tracks_genre FOREIGN KEY (`Genre`) REFERENCES `Genre`(`Name`), " "CONSTRAINT fk_tracks_album FOREIGN KEY (" "`AlbumTitle`, `AlbumArtistName`, `AlbumPath`)" "REFERENCES `Albums`(`Title`, `ArtistName`, `AlbumPath`))")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV9" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV9" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery copyDataQuery(d->mTracksDatabase); auto result = copyDataQuery.exec(QStringLiteral("INSERT INTO `NewTracks` " "(`ID`, `Title`, `ArtistName`, " "`AlbumTitle`, `AlbumArtistName`, `AlbumPath`, " "`TrackNumber`, `DiscNumber`, `Duration`, " "`Rating`, `Genre`, `Composer`, " "`Lyricist`, `Comment`, `Year`, " "`Channels`, `BitRate`, `SampleRate`, " "`HasEmbeddedCover`, `ImportDate`, `PlayCounter`) " "SELECT " "track.`ID`, " "track.`Title`, " "artist.`Name`, " "album.`Title`, " "album.`ArtistName`, " "album.`AlbumPath`, " "track.`TrackNumber`, " "track.`DiscNumber`, " "track.`Duration`, " "track.`Rating`, " "genre.`Name`, " "composer.`Name`, " "lyricist.`Name`, " "track.`Comment`, " "track.`Year`, " "track.`Channels`, " "track.`BitRate`, " "track.`SampleRate`, " "FALSE, " "strftime('%s', 'now'), " "0 " "FROM " "`Tracks` track, " "`TracksArtists` trackArtistMapping, " "`Artists` artist, " "`Albums` album " "left join " "`Genre` genre " "on track.`GenreID` = genre.`ID` " "left join " "`Composer` composer " "on track.`ComposerID` = composer.`ID` " "left join " "`Lyricist` lyricist " "on track.`LyricistID` = lyricist.`ID` " "WHERE " "track.`ID` = trackArtistMapping.`TrackID` AND " "trackArtistMapping.`ArtistID` = artist.`ID` AND " "track.`AlbumID` = album.`ID`")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV9" << copyDataQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV9" << copyDataQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createSchemaQuery(d->mTracksDatabase); auto result = createSchemaQuery.exec(QStringLiteral("DROP TABLE `Tracks`")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV9" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV9" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createSchemaQuery(d->mTracksDatabase); auto result = createSchemaQuery.exec(QStringLiteral("DROP TABLE `TracksArtists`")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV9" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV9" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createSchemaQuery(d->mTracksDatabase); auto result = createSchemaQuery.exec(QStringLiteral("ALTER TABLE `NewTracks` RENAME TO `Tracks`")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV9" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV9" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } d->mTracksDatabase.commit(); { QSqlQuery enableForeignKeys(d->mTracksDatabase); auto result = enableForeignKeys.exec(QStringLiteral(" PRAGMA foreign_keys=ON")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV9" << enableForeignKeys.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV9" << enableForeignKeys.lastError(); Q_EMIT databaseError(); } } qCInfo(orgKdeElisaDatabase) << "finished update to v9 of database schema"; } void DatabaseInterface::upgradeDatabaseV11() { qCInfo(orgKdeElisaDatabase) << "begin update to v11 of database schema"; { QSqlQuery createSchemaQuery(d->mTracksDatabase); const auto &result = createSchemaQuery.exec(QStringLiteral("CREATE TABLE `DatabaseVersionV11` (`Version` INTEGER PRIMARY KEY NOT NULL)")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery disableForeignKeys(d->mTracksDatabase); auto result = disableForeignKeys.exec(QStringLiteral(" PRAGMA foreign_keys=OFF")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << disableForeignKeys.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << disableForeignKeys.lastError(); Q_EMIT databaseError(); } } d->mTracksDatabase.transaction(); { QSqlQuery createSchemaQuery(d->mTracksDatabase); const auto &result = createSchemaQuery.exec(QStringLiteral("CREATE TABLE `TracksData` (" "`DiscoverID` INTEGER NOT NULL, " "`FileName` VARCHAR(255) NOT NULL, " "`FileModifiedTime` DATETIME NOT NULL, " "`ImportDate` INTEGER NOT NULL, " "`FirstPlayDate` INTEGER, " "`LastPlayDate` INTEGER, " "`PlayCounter` INTEGER NOT NULL, " "PRIMARY KEY (`FileName`, `DiscoverID`), " "CONSTRAINT fk_tracksmapping_discoverID FOREIGN KEY (`DiscoverID`) REFERENCES `DiscoverSource`(`ID`))")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << createSchemaQuery.lastError(); } } { QSqlQuery copyDataQuery(d->mTracksDatabase); auto result = copyDataQuery.exec(QStringLiteral("INSERT INTO `TracksData` " "SELECT " "m.`DiscoverID`, " "m.`FileName`, " "m.`FileModifiedTime`, " "t.`ImportDate`, " "t.`FirstPlayDate`, " "t.`LastPlayDate`, " "t.`PlayCounter` " "FROM " "`Tracks` t, " "`TracksMapping` m " "WHERE " "t.`ID` = m.`TrackID`")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << copyDataQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << copyDataQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createSchemaQuery(d->mTracksDatabase); auto result = createSchemaQuery.exec(QStringLiteral("CREATE TABLE `NewTracks` (" "`ID` INTEGER PRIMARY KEY AUTOINCREMENT, " "`DiscoverID` INTEGER NOT NULL, " "`FileName` VARCHAR(255) NOT NULL, " "`Priority` INTEGER NOT NULL, " "`Title` VARCHAR(85) NOT NULL, " "`ArtistName` VARCHAR(55), " "`AlbumTitle` VARCHAR(55), " "`AlbumArtistName` VARCHAR(55), " "`AlbumPath` VARCHAR(255), " "`TrackNumber` INTEGER, " "`DiscNumber` INTEGER, " "`Duration` INTEGER NOT NULL, " "`Rating` INTEGER NOT NULL DEFAULT 0, " "`Genre` VARCHAR(55), " "`Composer` VARCHAR(55), " "`Lyricist` VARCHAR(55), " "`Comment` VARCHAR(255), " "`Year` INTEGER, " "`Channels` INTEGER, " "`BitRate` INTEGER, " "`SampleRate` INTEGER, " "`HasEmbeddedCover` BOOLEAN NOT NULL, " "UNIQUE (" "`FileName`" "), " "UNIQUE (" "`Priority`, `Title`, `ArtistName`, " "`AlbumTitle`, `AlbumArtistName`, `AlbumPath`" "), " "CONSTRAINT fk_fileName FOREIGN KEY (`FileName`, `DiscoverID`) " "REFERENCES `TracksData`(`FileName`, `DiscoverID`) ON DELETE CASCADE, " "CONSTRAINT fk_artist FOREIGN KEY (`ArtistName`) REFERENCES `Artists`(`Name`), " "CONSTRAINT fk_tracks_composer FOREIGN KEY (`Composer`) REFERENCES `Composer`(`Name`), " "CONSTRAINT fk_tracks_lyricist FOREIGN KEY (`Lyricist`) REFERENCES `Lyricist`(`Name`), " "CONSTRAINT fk_tracks_genre FOREIGN KEY (`Genre`) REFERENCES `Genre`(`Name`), " "CONSTRAINT fk_tracks_discoverID FOREIGN KEY (`DiscoverID`) REFERENCES `DiscoverSource`(`ID`)" "CONSTRAINT fk_tracks_album FOREIGN KEY (" "`AlbumTitle`, `AlbumArtistName`, `AlbumPath`)" "REFERENCES `Albums`(`Title`, `ArtistName`, `AlbumPath`))")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery copyDataQuery(d->mTracksDatabase); auto result = copyDataQuery.exec(QStringLiteral("INSERT OR IGNORE INTO `NewTracks` " "(" "`DiscoverID`, " "`FileName`, " "`Priority`, " "`Title`, " "`ArtistName`, " "`AlbumTitle`, " "`AlbumArtistName`, " "`AlbumPath`, " "`TrackNumber`, " "`DiscNumber`, " "`Duration`, " "`Rating`, " "`Genre`, " "`Composer`, " "`Lyricist`, " "`Comment`, " "`Year`, " "`Channels`, " "`BitRate`, " "`SampleRate`, " "`HasEmbeddedCover`" ") " "SELECT " "m.`DiscoverID`, " "m.`FileName`, " "m.`Priority`, " "t.`Title`, " "t.`ArtistName`, " "t.`AlbumTitle`, " "t.`AlbumArtistName`, " "t.`AlbumPath`, " "t.`TrackNumber`, " "t.`DiscNumber`, " "t.`Duration`, " "t.`Rating`, " "t.`Genre`, " "t.`Composer`, " "t.`Lyricist`, " "t.`Comment`, " "t.`Year`, " "t.`Channels`, " "t.`BitRate`, " "t.`SampleRate`, " "t.`HasEmbeddedCover` " "FROM " "`Tracks` t, " "`TracksMapping` m " "WHERE " "t.`ID` = m.`TrackID`")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << copyDataQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << copyDataQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery updateDataQuery(d->mTracksDatabase); auto result = updateDataQuery.exec(QStringLiteral("UPDATE `NewTracks` " "SET " "`TrackNumber` = NULL " "WHERE " "`TrackNumber` = -1")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << updateDataQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << updateDataQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery updateDataQuery(d->mTracksDatabase); auto result = updateDataQuery.exec(QStringLiteral("UPDATE `NewTracks` " "SET " "`Channels` = NULL " "WHERE " "`Channels` = -1")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << updateDataQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << updateDataQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery updateDataQuery(d->mTracksDatabase); auto result = updateDataQuery.exec(QStringLiteral("UPDATE `NewTracks` " "SET " "`BitRate` = NULL " "WHERE " "`BitRate` = -1")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << updateDataQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << updateDataQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery updateDataQuery(d->mTracksDatabase); auto result = updateDataQuery.exec(QStringLiteral("UPDATE `NewTracks` " "SET " "`SampleRate` = NULL " "WHERE " "`SampleRate` = -1")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << updateDataQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << updateDataQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createSchemaQuery(d->mTracksDatabase); auto result = createSchemaQuery.exec(QStringLiteral("DROP TABLE `Tracks`")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createSchemaQuery(d->mTracksDatabase); auto result = createSchemaQuery.exec(QStringLiteral("DROP TABLE `TracksMapping`")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createSchemaQuery(d->mTracksDatabase); auto result = createSchemaQuery.exec(QStringLiteral("ALTER TABLE `NewTracks` RENAME TO `Tracks`")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } d->mTracksDatabase.commit(); { QSqlQuery enableForeignKeys(d->mTracksDatabase); auto result = enableForeignKeys.exec(QStringLiteral(" PRAGMA foreign_keys=ON")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << enableForeignKeys.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << enableForeignKeys.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createTrackIndex(d->mTracksDatabase); const auto &result = createTrackIndex.exec(QStringLiteral("CREATE INDEX " "IF NOT EXISTS " "`TracksAlbumIndex` ON `Tracks` " "(`AlbumTitle`, `AlbumArtistName`, `AlbumPath`)")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << createTrackIndex.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << createTrackIndex.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createTrackIndex(d->mTracksDatabase); const auto &result = createTrackIndex.exec(QStringLiteral("CREATE INDEX " "IF NOT EXISTS " "`ArtistNameIndex` ON `Tracks` " "(`ArtistName`)")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << createTrackIndex.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << createTrackIndex.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createTrackIndex(d->mTracksDatabase); const auto &result = createTrackIndex.exec(QStringLiteral("CREATE INDEX " "IF NOT EXISTS " "`AlbumArtistNameIndex` ON `Tracks` " "(`AlbumArtistName`)")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << createTrackIndex.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << createTrackIndex.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createTrackIndex(d->mTracksDatabase); const auto &result = createTrackIndex.exec(QStringLiteral("CREATE INDEX " "IF NOT EXISTS " "`TracksUniqueData` ON `Tracks` " "(`Title`, `ArtistName`, " "`AlbumTitle`, `AlbumArtistName`, `AlbumPath`)")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << createTrackIndex.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << createTrackIndex.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createTrackIndex(d->mTracksDatabase); const auto &result = createTrackIndex.exec(QStringLiteral("CREATE INDEX " "IF NOT EXISTS " "`TracksUniqueDataPriority` ON `Tracks` " "(`Priority`, `Title`, `ArtistName`, " "`AlbumTitle`, `AlbumArtistName`, `AlbumPath`)")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << createTrackIndex.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << createTrackIndex.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createTrackIndex(d->mTracksDatabase); const auto &result = createTrackIndex.exec(QStringLiteral("CREATE INDEX " "IF NOT EXISTS " "`TracksFileNameIndex` ON `Tracks` " "(`FileName`)")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << createTrackIndex.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV11" << createTrackIndex.lastError(); Q_EMIT databaseError(); } } qCInfo(orgKdeElisaDatabase) << "finished update to v11 of database schema"; } void DatabaseInterface::upgradeDatabaseV12() { qCInfo(orgKdeElisaDatabase) << "begin update to v12 of database schema"; { QSqlQuery createSchemaQuery(d->mTracksDatabase); const auto &result = createSchemaQuery.exec(QStringLiteral("CREATE TABLE `DatabaseVersionV12` (`Version` INTEGER PRIMARY KEY NOT NULL)")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery disableForeignKeys(d->mTracksDatabase); auto result = disableForeignKeys.exec(QStringLiteral(" PRAGMA foreign_keys=OFF")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << disableForeignKeys.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << disableForeignKeys.lastError(); Q_EMIT databaseError(); } } d->mTracksDatabase.transaction(); { QSqlQuery createSchemaQuery(d->mTracksDatabase); const auto &result = createSchemaQuery.exec(QStringLiteral("CREATE TABLE `NewTracks` (" "`ID` INTEGER PRIMARY KEY AUTOINCREMENT, " "`FileName` VARCHAR(255) NOT NULL, " "`Priority` INTEGER NOT NULL, " "`Title` VARCHAR(85) NOT NULL, " "`ArtistName` VARCHAR(55), " "`AlbumTitle` VARCHAR(55), " "`AlbumArtistName` VARCHAR(55), " "`AlbumPath` VARCHAR(255), " "`TrackNumber` INTEGER, " "`DiscNumber` INTEGER, " "`Duration` INTEGER NOT NULL, " "`Rating` INTEGER NOT NULL DEFAULT 0, " "`Genre` VARCHAR(55), " "`Composer` VARCHAR(55), " "`Lyricist` VARCHAR(55), " "`Comment` VARCHAR(255), " "`Year` INTEGER, " "`Channels` INTEGER, " "`BitRate` INTEGER, " "`SampleRate` INTEGER, " "`HasEmbeddedCover` BOOLEAN NOT NULL, " "UNIQUE (" "`FileName`" "), " "UNIQUE (" "`Priority`, `Title`, `ArtistName`, " "`AlbumTitle`, `AlbumArtistName`, `AlbumPath`" "), " "CONSTRAINT fk_fileName FOREIGN KEY (`FileName`) " "REFERENCES `TracksData`(`FileName`) ON DELETE CASCADE, " "CONSTRAINT fk_artist FOREIGN KEY (`ArtistName`) REFERENCES `Artists`(`Name`), " "CONSTRAINT fk_tracks_composer FOREIGN KEY (`Composer`) REFERENCES `Composer`(`Name`), " "CONSTRAINT fk_tracks_lyricist FOREIGN KEY (`Lyricist`) REFERENCES `Lyricist`(`Name`), " "CONSTRAINT fk_tracks_genre FOREIGN KEY (`Genre`) REFERENCES `Genre`(`Name`), " "CONSTRAINT fk_tracks_album FOREIGN KEY (" "`AlbumTitle`, `AlbumArtistName`, `AlbumPath`)" "REFERENCES `Albums`(`Title`, `ArtistName`, `AlbumPath`))")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << createSchemaQuery.lastError(); } } { QSqlQuery createSchemaQuery(d->mTracksDatabase); const auto &result = createSchemaQuery.exec(QStringLiteral("CREATE TABLE `NewTracksData` (" "`FileName` VARCHAR(255) NOT NULL, " "`FileModifiedTime` DATETIME NOT NULL, " "`ImportDate` INTEGER NOT NULL, " "`FirstPlayDate` INTEGER, " "`LastPlayDate` INTEGER, " "`PlayCounter` INTEGER NOT NULL, " "PRIMARY KEY (`FileName`))")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << createSchemaQuery.lastError(); } } { QSqlQuery copyDataQuery(d->mTracksDatabase); auto result = copyDataQuery.exec(QStringLiteral("INSERT INTO `NewTracksData` " "SELECT " "td.`FileName`, " "td.`FileModifiedTime`, " "td.`ImportDate`, " "td.`FirstPlayDate`, " "td.`LastPlayDate`, " "td.`PlayCounter` " "FROM " "`TracksData` td")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << copyDataQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << copyDataQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery copyDataQuery(d->mTracksDatabase); auto result = copyDataQuery.exec(QStringLiteral("INSERT INTO `NewTracks` " "SELECT " "t.`ID`, " "t.`FileName`, " "t.`Priority`, " "t.`Title`, " "t.`ArtistName`, " "t.`AlbumTitle`, " "t.`AlbumArtistName`, " "t.`AlbumPath`, " "t.`TrackNumber`, " "t.`DiscNumber`, " "t.`Duration`, " "t.`Rating`, " "t.`Genre`, " "t.`Composer`, " "t.`Lyricist`, " "t.`Comment`, " "t.`Year`, " "t.`Channels`, " "t.`BitRate`, " "t.`SampleRate`, " "t.`HasEmbeddedCover` " "FROM " "`Tracks` t")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << copyDataQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << copyDataQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createSchemaQuery(d->mTracksDatabase); auto result = createSchemaQuery.exec(QStringLiteral("DROP TABLE `TracksData`")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createSchemaQuery(d->mTracksDatabase); auto result = createSchemaQuery.exec(QStringLiteral("DROP TABLE `Tracks`")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createSchemaQuery(d->mTracksDatabase); auto result = createSchemaQuery.exec(QStringLiteral("ALTER TABLE `NewTracksData` RENAME TO `TracksData`")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createSchemaQuery(d->mTracksDatabase); auto result = createSchemaQuery.exec(QStringLiteral("ALTER TABLE `NewTracks` RENAME TO `Tracks`")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << createSchemaQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } d->mTracksDatabase.commit(); { QSqlQuery enableForeignKeys(d->mTracksDatabase); auto result = enableForeignKeys.exec(QStringLiteral(" PRAGMA foreign_keys=ON")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << enableForeignKeys.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << enableForeignKeys.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createTrackIndex(d->mTracksDatabase); const auto &result = createTrackIndex.exec(QStringLiteral("CREATE INDEX " "IF NOT EXISTS " "`TracksAlbumIndex` ON `Tracks` " "(`AlbumTitle`, `AlbumArtistName`, `AlbumPath`)")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << createTrackIndex.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << createTrackIndex.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createTrackIndex(d->mTracksDatabase); const auto &result = createTrackIndex.exec(QStringLiteral("CREATE INDEX " "IF NOT EXISTS " "`ArtistNameIndex` ON `Tracks` " "(`ArtistName`)")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << createTrackIndex.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << createTrackIndex.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createTrackIndex(d->mTracksDatabase); const auto &result = createTrackIndex.exec(QStringLiteral("CREATE INDEX " "IF NOT EXISTS " "`AlbumArtistNameIndex` ON `Tracks` " "(`AlbumArtistName`)")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << createTrackIndex.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << createTrackIndex.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createTrackIndex(d->mTracksDatabase); const auto &result = createTrackIndex.exec(QStringLiteral("CREATE INDEX " "IF NOT EXISTS " "`TracksUniqueData` ON `Tracks` " "(`Title`, `ArtistName`, " "`AlbumTitle`, `AlbumArtistName`, `AlbumPath`)")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << createTrackIndex.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << createTrackIndex.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createTrackIndex(d->mTracksDatabase); const auto &result = createTrackIndex.exec(QStringLiteral("CREATE INDEX " "IF NOT EXISTS " "`TracksUniqueDataPriority` ON `Tracks` " "(`Priority`, `Title`, `ArtistName`, " "`AlbumTitle`, `AlbumArtistName`, `AlbumPath`)")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << createTrackIndex.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << createTrackIndex.lastError(); Q_EMIT databaseError(); } } { QSqlQuery createTrackIndex(d->mTracksDatabase); const auto &result = createTrackIndex.exec(QStringLiteral("CREATE INDEX " "IF NOT EXISTS " "`TracksFileNameIndex` ON `Tracks` " "(`FileName`)")); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << createTrackIndex.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV12" << createTrackIndex.lastError(); Q_EMIT databaseError(); } } qCInfo(orgKdeElisaDatabase) << "finished update to v12 of database schema"; } void DatabaseInterface::checkDatabaseSchema() { checkAlbumsTableSchema(); if (d->mIsInBadState) { resetDatabase(); return; } checkArtistsTableSchema(); if (d->mIsInBadState) { resetDatabase(); return; } checkComposerTableSchema(); if (d->mIsInBadState) { resetDatabase(); return; } checkGenreTableSchema(); if (d->mIsInBadState) { resetDatabase(); return; } checkLyricistTableSchema(); if (d->mIsInBadState) { resetDatabase(); return; } checkTracksTableSchema(); if (d->mIsInBadState) { resetDatabase(); return; } checkTracksDataTableSchema(); if (d->mIsInBadState) { resetDatabase(); return; } } void DatabaseInterface::checkAlbumsTableSchema() { auto fieldsList = QStringList{QStringLiteral("ID"), QStringLiteral("Title"), QStringLiteral("ArtistName"), QStringLiteral("AlbumPath"), QStringLiteral("CoverFileName")}; genericCheckTable(QStringLiteral("Albums"), fieldsList); } void DatabaseInterface::checkArtistsTableSchema() { auto fieldsList = QStringList{QStringLiteral("ID"), QStringLiteral("Name")}; genericCheckTable(QStringLiteral("Artists"), fieldsList); } void DatabaseInterface::checkComposerTableSchema() { auto fieldsList = QStringList{QStringLiteral("ID"), QStringLiteral("Name")}; genericCheckTable(QStringLiteral("Composer"), fieldsList); } void DatabaseInterface::checkGenreTableSchema() { auto fieldsList = QStringList{QStringLiteral("ID"), QStringLiteral("Name")}; genericCheckTable(QStringLiteral("Genre"), fieldsList); } void DatabaseInterface::checkLyricistTableSchema() { auto fieldsList = QStringList{QStringLiteral("ID"), QStringLiteral("Name")}; genericCheckTable(QStringLiteral("Lyricist"), fieldsList); } void DatabaseInterface::checkTracksTableSchema() { auto fieldsList = QStringList{QStringLiteral("ID"), QStringLiteral("FileName"), QStringLiteral("Priority"), QStringLiteral("Title"), QStringLiteral("ArtistName"), QStringLiteral("AlbumTitle"), QStringLiteral("AlbumArtistName"), QStringLiteral("AlbumPath"), QStringLiteral("TrackNumber"), QStringLiteral("DiscNumber"), QStringLiteral("Duration"), QStringLiteral("Rating"), QStringLiteral("Genre"), QStringLiteral("Composer"), QStringLiteral("Lyricist"), QStringLiteral("Comment"), QStringLiteral("Year"), QStringLiteral("Channels"), QStringLiteral("BitRate"), QStringLiteral("SampleRate"), QStringLiteral("HasEmbeddedCover")}; genericCheckTable(QStringLiteral("Tracks"), fieldsList); } void DatabaseInterface::checkTracksDataTableSchema() { auto fieldsList = QStringList{QStringLiteral("FileName"), QStringLiteral("FileModifiedTime"), QStringLiteral("ImportDate"), QStringLiteral("FirstPlayDate"), QStringLiteral("LastPlayDate"), QStringLiteral("PlayCounter")}; genericCheckTable(QStringLiteral("TracksData"), fieldsList); } void DatabaseInterface::genericCheckTable(const QString &tableName, const QStringList &expectedColumns) { auto columnsList = d->mTracksDatabase.record(tableName); if (columnsList.count() != expectedColumns.count()) { qCInfo(orgKdeElisaDatabase()) << tableName << "table has wrong number of columns" << columnsList.count() << "expected" << expectedColumns.count(); d->mIsInBadState = true; return; } for (const auto &oneField : expectedColumns) { if (!columnsList.contains(oneField)) { qCInfo(orgKdeElisaDatabase()) << tableName << "table has missing column" << oneField; d->mIsInBadState = true; return; } } } void DatabaseInterface::resetDatabase() { qCInfo(orgKdeElisaDatabase()) << "Full reset of database due to corrupted database"; auto listTables = d->mTracksDatabase.tables(); while(!listTables.isEmpty()) { for (const auto &oneTable : listTables) { QSqlQuery createSchemaQuery(d->mTracksDatabase); qCDebug(orgKdeElisaDatabase()) << "dropping table" << oneTable; createSchemaQuery.exec(QStringLiteral("DROP TABLE ") + oneTable); } listTables = d->mTracksDatabase.tables(); if (listTables == QStringList{QStringLiteral("sqlite_sequence")}) { break; } } d->mIsInBadState = false; } void DatabaseInterface::initRequest() { auto transactionResult = startTransaction(); if (!transactionResult) { return; } { auto selectAlbumQueryText = QStringLiteral("SELECT " "album.`ID`, " "album.`Title`, " "album.`ArtistName`, " "album.`AlbumPath`, " "album.`CoverFileName`, " "(" "SELECT " "COUNT(*) " "FROM " "`Tracks` tracks3 " "WHERE " "tracks3.`AlbumTitle` = album.`Title` AND " "(tracks3.`AlbumArtistName` = album.`ArtistName` OR " "(tracks3.`AlbumArtistName` IS NULL AND " "album.`ArtistName` IS NULL" ")" ") AND " "tracks3.`AlbumPath` = album.`AlbumPath` " ") as `TracksCount`, " "(" "SELECT " "COUNT(DISTINCT tracks2.DiscNumber) <= 1 " "FROM " "`Tracks` tracks2 " "WHERE " "tracks2.`AlbumTitle` = album.`Title` AND " "(tracks2.`AlbumArtistName` = album.`ArtistName` OR " "(tracks2.`AlbumArtistName` IS NULL AND " "album.`ArtistName` IS NULL" ")" ") AND " "tracks2.`AlbumPath` = album.`AlbumPath` " ") as `IsSingleDiscAlbum`, " "GROUP_CONCAT(tracks.`ArtistName`, ', ') as AllArtists, " "MAX(tracks.`Rating`) as HighestRating, " "GROUP_CONCAT(genres.`Name`, ', ') as AllGenres " "FROM " "`Albums` album LEFT JOIN " "`Tracks` tracks ON " "tracks.`AlbumTitle` = album.`Title` AND " "(" "tracks.`AlbumArtistName` = album.`ArtistName` OR " "(" "tracks.`AlbumArtistName` IS NULL AND " "album.`ArtistName` IS NULL" ")" ") AND " "tracks.`AlbumPath` = album.`AlbumPath`" "LEFT JOIN " "`Genre` genres ON tracks.`Genre` = genres.`Name` " "WHERE " "album.`ID` = :albumId " "GROUP BY album.`ID`"); auto result = prepareQuery(d->mSelectAlbumQuery, selectAlbumQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAlbumQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAlbumQuery.lastError(); Q_EMIT databaseError(); } } { auto selectAllGenresText = QStringLiteral("SELECT " "genre.`ID`, " "genre.`Name` " "FROM `Genre` genre " "ORDER BY genre.`Name` COLLATE NOCASE"); auto result = prepareQuery(d->mSelectAllGenresQuery, selectAllGenresText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAllGenresQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAllGenresQuery.lastError(); Q_EMIT databaseError(); } } { auto selectAllAlbumsText = QStringLiteral("SELECT " "album.`ID`, " "album.`Title`, " "album.`ArtistName` as SecondaryText, " "album.`CoverFileName`, " "album.`ArtistName`, " "GROUP_CONCAT(tracks.`ArtistName`, ', ') as AllArtists, " "MAX(tracks.`Rating`) as HighestRating, " "GROUP_CONCAT(genres.`Name`, ', ') as AllGenres, " "(" "SELECT " "COUNT(DISTINCT tracks2.DiscNumber) <= 1 " "FROM " "`Tracks` tracks2 " "WHERE " "tracks2.`AlbumTitle` = album.`Title` AND " "(tracks2.`AlbumArtistName` = album.`ArtistName` OR " "(tracks2.`AlbumArtistName` IS NULL AND " "album.`ArtistName` IS NULL" ")" ") AND " "tracks2.`AlbumPath` = album.`AlbumPath` " ") as `IsSingleDiscAlbum` " "FROM " "`Albums` album, " "`Tracks` tracks LEFT JOIN " "`Genre` genres ON tracks.`Genre` = genres.`Name` " "WHERE " "tracks.`AlbumTitle` = album.`Title` AND " "(tracks.`AlbumArtistName` = album.`ArtistName` OR " "(tracks.`AlbumArtistName` IS NULL AND " "album.`ArtistName` IS NULL" ")" ") AND " "tracks.`AlbumPath` = album.`AlbumPath` " "GROUP BY album.`ID`, album.`Title`, album.`AlbumPath` " "ORDER BY album.`Title` COLLATE NOCASE"); auto result = prepareQuery(d->mSelectAllAlbumsShortQuery, selectAllAlbumsText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAllAlbumsShortQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAllAlbumsShortQuery.lastError(); Q_EMIT databaseError(); } } { auto selectAllAlbumsText = QStringLiteral("SELECT " "album.`ID`, " "album.`Title`, " "album.`ArtistName` as SecondaryText, " "album.`CoverFileName`, " "album.`ArtistName`, " "GROUP_CONCAT(tracks.`ArtistName`, ', ') as AllArtists, " "MAX(tracks.`Rating`) as HighestRating, " "GROUP_CONCAT(genres.`Name`, ', ') as AllGenres " "FROM " "`Albums` album, " "`Tracks` tracks LEFT JOIN " "`Genre` genres ON tracks.`Genre` = genres.`Name` " "WHERE " "tracks.`AlbumTitle` = album.`Title` AND " "(tracks.`AlbumArtistName` = album.`ArtistName` OR " "(tracks.`AlbumArtistName` IS NULL AND " "album.`ArtistName` IS NULL" ")" ") AND " "tracks.`AlbumPath` = album.`AlbumPath` AND " "EXISTS (" " SELECT tracks2.`Genre` " " FROM " " `Tracks` tracks2, " " `Genre` genre2 " " WHERE " " tracks2.`AlbumTitle` = album.`Title` AND " " tracks2.`AlbumArtistName` = album.`ArtistName` AND " " tracks2.`Genre` = genre2.`Name` AND " " genre2.`Name` = :genreFilter AND " " (tracks2.`ArtistName` = :artistFilter OR tracks2.`AlbumArtistName` = :artistFilter) " ") " "GROUP BY album.`ID`, album.`Title`, album.`AlbumPath` " "ORDER BY album.`Title` COLLATE NOCASE"); auto result = prepareQuery(d->mSelectAllAlbumsShortWithGenreArtistFilterQuery, selectAllAlbumsText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAllAlbumsShortWithGenreArtistFilterQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAllAlbumsShortWithGenreArtistFilterQuery.lastError(); Q_EMIT databaseError(); } } { auto selectAllAlbumsText = QStringLiteral("SELECT " "album.`ID`, " "album.`Title`, " "album.`ArtistName` as SecondaryText, " "album.`CoverFileName`, " "album.`ArtistName`, " "GROUP_CONCAT(tracks.`ArtistName`, ', ') as AllArtists, " "MAX(tracks.`Rating`) as HighestRating, " "GROUP_CONCAT(genres.`Name`, ', ') as AllGenres " "FROM " "`Albums` album, " "`Tracks` tracks LEFT JOIN " "`Genre` genres ON tracks.`Genre` = genres.`Name` " "WHERE " "tracks.`AlbumTitle` = album.`Title` AND " "(tracks.`AlbumArtistName` = album.`ArtistName` OR " "(tracks.`AlbumArtistName` IS NULL AND " "album.`ArtistName` IS NULL" ")" ") AND " "tracks.`AlbumPath` = album.`AlbumPath` AND " "EXISTS (" " SELECT tracks2.`Genre` " " FROM " " `Tracks` tracks2 " " WHERE " " tracks2.`AlbumTitle` = album.`Title` AND " " tracks2.`AlbumArtistName` = album.`ArtistName` AND " " (tracks2.`ArtistName` = :artistFilter OR tracks2.`AlbumArtistName` = :artistFilter) " ") " "GROUP BY album.`ID`, album.`Title`, album.`AlbumPath` " "ORDER BY album.`Title` COLLATE NOCASE"); auto result = prepareQuery(d->mSelectAllAlbumsShortWithArtistFilterQuery, selectAllAlbumsText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAllAlbumsShortWithArtistFilterQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAllAlbumsShortWithArtistFilterQuery.lastError(); Q_EMIT databaseError(); } } { auto selectAllArtistsWithFilterText = QStringLiteral("SELECT artists.`ID`, " "artists.`Name`, " "GROUP_CONCAT(genres.`Name`, ', ') as AllGenres " "FROM `Artists` artists LEFT JOIN " "`Tracks` tracks ON artists.`Name` = tracks.`ArtistName` LEFT JOIN " "`Genre` genres ON tracks.`Genre` = genres.`Name` " "GROUP BY artists.`ID` " "ORDER BY artists.`Name` COLLATE NOCASE"); auto result = prepareQuery(d->mSelectAllArtistsQuery, selectAllArtistsWithFilterText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAllArtistsQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAllArtistsQuery.lastError(); Q_EMIT databaseError(); } } { auto selectAllArtistsWithGenreFilterText = QStringLiteral("SELECT artists.`ID`, " "artists.`Name`, " "GROUP_CONCAT(genres.`Name`, ', ') as AllGenres " "FROM `Artists` artists LEFT JOIN " "`Tracks` tracks ON (tracks.`ArtistName` = artists.`Name` OR tracks.`AlbumArtistName` = artists.`Name`) LEFT JOIN " "`Genre` genres ON tracks.`Genre` = genres.`Name` " "WHERE " "EXISTS (" " SELECT tracks2.`Genre` " " FROM " " `Tracks` tracks2, " " `Genre` genre2 " " WHERE " " (tracks2.`ArtistName` = artists.`Name` OR tracks2.`AlbumArtistName` = artists.`Name`) AND " " tracks2.`Genre` = genre2.`Name` AND " " genre2.`Name` = :genreFilter " ") " "GROUP BY artists.`ID` " "ORDER BY artists.`Name` COLLATE NOCASE"); auto result = prepareQuery(d->mSelectAllArtistsWithGenreFilterQuery, selectAllArtistsWithGenreFilterText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAllArtistsWithGenreFilterQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAllArtistsWithGenreFilterQuery.lastError(); Q_EMIT databaseError(); } } { auto artistMatchGenreText = QStringLiteral("SELECT artists.`ID` " "FROM `Artists` artists LEFT JOIN " "`Tracks` tracks ON (tracks.`ArtistName` = artists.`Name` OR tracks.`AlbumArtistName` = artists.`Name`) LEFT JOIN " "`Genre` genres ON tracks.`Genre` = genres.`Name` " "WHERE " "EXISTS (" " SELECT tracks2.`Genre` " " FROM " " `Tracks` tracks2, " " `Genre` genre2 " " WHERE " " (tracks2.`ArtistName` = artists.`Name` OR tracks2.`AlbumArtistName` = artists.`Name`) AND " " tracks2.`Genre` = genre2.`Name` AND " " genre2.`Name` = :genreFilter " ") AND " "artists.`ID` = :databaseId"); auto result = prepareQuery(d->mArtistMatchGenreQuery, artistMatchGenreText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mArtistMatchGenreQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mArtistMatchGenreQuery.lastError(); Q_EMIT databaseError(); } } { auto selectAllComposersWithFilterText = QStringLiteral("SELECT `ID`, " "`Name` " "FROM `Artists` " "ORDER BY `Name` COLLATE NOCASE"); auto result = prepareQuery(d->mSelectAllComposersQuery, selectAllComposersWithFilterText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAllComposersQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAllComposersQuery.lastError(); Q_EMIT databaseError(); } } { auto selectAllLyricistsWithFilterText = QStringLiteral("SELECT `ID`, " "`Name` " "FROM `Lyricist` " "ORDER BY `Name` COLLATE NOCASE"); auto result = prepareQuery(d->mSelectAllLyricistsQuery, selectAllLyricistsWithFilterText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAllLyricistsQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAllLyricistsQuery.lastError(); Q_EMIT databaseError(); } } { auto selectAllTracksText = QStringLiteral("SELECT " "tracks.`ID`, " "tracks.`Title`, " "album.`ID`, " "tracks.`ArtistName`, " "tracks.`AlbumArtistName`, " "tracksMapping.`FileName`, " "tracksMapping.`FileModifiedTime`, " "tracks.`TrackNumber`, " "tracks.`DiscNumber`, " "tracks.`Duration`, " "tracks.`AlbumTitle`, " "tracks.`Rating`, " "album.`CoverFileName`, " "(" "SELECT " "COUNT(DISTINCT tracks2.DiscNumber) <= 1 " "FROM " "`Tracks` tracks2 " "WHERE " "tracks2.`AlbumTitle` = album.`Title` AND " "(tracks2.`AlbumArtistName` = album.`ArtistName` OR " "(tracks2.`AlbumArtistName` IS NULL AND " "album.`ArtistName` IS NULL" ")" ") AND " "tracks2.`AlbumPath` = album.`AlbumPath` " ") as `IsSingleDiscAlbum`, " "trackGenre.`Name`, " "trackComposer.`Name`, " "trackLyricist.`Name`, " "tracks.`Comment`, " "tracks.`Year`, " "tracks.`Channels`, " "tracks.`BitRate`, " "tracks.`SampleRate`, " "tracks.`HasEmbeddedCover`, " "tracksMapping.`ImportDate`, " "tracksMapping.`FirstPlayDate`, " "tracksMapping.`LastPlayDate`, " "tracksMapping.`PlayCounter`, " "tracksMapping.`PlayCounter` / (strftime('%s', 'now') - tracksMapping.`FirstPlayDate`) as PlayFrequency " "FROM " "`Tracks` tracks, " "`TracksData` tracksMapping " "LEFT JOIN " "`Albums` album " "ON " "tracks.`AlbumTitle` = album.`Title` AND " "(tracks.`AlbumArtistName` = album.`ArtistName` OR tracks.`AlbumArtistName` IS NULL ) AND " "tracks.`AlbumPath` = album.`AlbumPath` " "LEFT JOIN `Genre` trackGenre ON trackGenre.`Name` = tracks.`Genre` " "LEFT JOIN `Composer` trackComposer ON trackComposer.`Name` = tracks.`Composer` " "LEFT JOIN `Lyricist` trackLyricist ON trackLyricist.`Name` = tracks.`Lyricist` " "WHERE " "tracksMapping.`FileName` = tracks.`FileName` AND " "tracks.`Priority` = (" " SELECT " " MIN(`Priority`) " " FROM " " `Tracks` tracks2 " " WHERE " " tracks.`Title` = tracks2.`Title` AND " " (tracks.`ArtistName` IS NULL OR tracks.`ArtistName` = tracks2.`ArtistName`) AND " " (tracks.`AlbumTitle` IS NULL OR tracks.`AlbumTitle` = tracks2.`AlbumTitle`) AND " " (tracks.`AlbumArtistName` IS NULL OR tracks.`AlbumArtistName` = tracks2.`AlbumArtistName`) AND " " (tracks.`AlbumPath` IS NULL OR tracks.`AlbumPath` = tracks2.`AlbumPath`)" ")" ""); auto result = prepareQuery(d->mSelectAllTracksQuery, selectAllTracksText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAllTracksQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAllTracksQuery.lastError(); Q_EMIT databaseError(); } } { auto selectAllTracksText = QStringLiteral("SELECT " "tracks.`ID`, " "tracks.`Title`, " "album.`ID`, " "tracks.`ArtistName`, " "tracks.`AlbumArtistName`, " "tracksMapping.`FileName`, " "tracksMapping.`FileModifiedTime`, " "tracks.`TrackNumber`, " "tracks.`DiscNumber`, " "tracks.`Duration`, " "tracks.`AlbumTitle`, " "tracks.`Rating`, " "album.`CoverFileName`, " "(" "SELECT " "COUNT(DISTINCT tracks2.DiscNumber) <= 1 " "FROM " "`Tracks` tracks2 " "WHERE " "tracks2.`AlbumTitle` = album.`Title` AND " "(tracks2.`AlbumArtistName` = album.`ArtistName` OR " "(tracks2.`AlbumArtistName` IS NULL AND " "album.`ArtistName` IS NULL" ")" ") AND " "tracks2.`AlbumPath` = album.`AlbumPath` " ") as `IsSingleDiscAlbum`, " "trackGenre.`Name`, " "trackComposer.`Name`, " "trackLyricist.`Name`, " "tracks.`Comment`, " "tracks.`Year`, " "tracks.`Channels`, " "tracks.`BitRate`, " "tracks.`SampleRate`, " "tracks.`HasEmbeddedCover`, " "tracksMapping.`ImportDate`, " "tracksMapping.`FirstPlayDate`, " "tracksMapping.`LastPlayDate`, " "tracksMapping.`PlayCounter`, " "tracksMapping.`PlayCounter` / (strftime('%s', 'now') - tracksMapping.`FirstPlayDate`) as PlayFrequency " "FROM " "`Tracks` tracks, " "`TracksData` tracksMapping " "LEFT JOIN " "`Albums` album " "ON " "tracks.`AlbumTitle` = album.`Title` AND " "(tracks.`AlbumArtistName` = album.`ArtistName` OR tracks.`AlbumArtistName` IS NULL ) AND " "tracks.`AlbumPath` = album.`AlbumPath` " "LEFT JOIN `Genre` trackGenre ON trackGenre.`Name` = tracks.`Genre` " "LEFT JOIN `Composer` trackComposer ON trackComposer.`Name` = tracks.`Composer` " "LEFT JOIN `Lyricist` trackLyricist ON trackLyricist.`Name` = tracks.`Lyricist` " "WHERE " "tracksMapping.`FileName` = tracks.`FileName` AND " "tracksMapping.`PlayCounter` > 0 AND " "tracks.`Priority` = (" " SELECT " " MIN(`Priority`) " " FROM " " `Tracks` tracks2 " " WHERE " " tracks.`Title` = tracks2.`Title` AND " " (tracks.`ArtistName` IS NULL OR tracks.`ArtistName` = tracks2.`ArtistName`) AND " " (tracks.`AlbumTitle` IS NULL OR tracks.`AlbumTitle` = tracks2.`AlbumTitle`) AND " " (tracks.`AlbumArtistName` IS NULL OR tracks.`AlbumArtistName` = tracks2.`AlbumArtistName`) AND " " (tracks.`AlbumPath` IS NULL OR tracks.`AlbumPath` = tracks2.`AlbumPath`)" ")" "ORDER BY tracksMapping.`LastPlayDate` DESC " "LIMIT :maximumResults"); auto result = prepareQuery(d->mSelectAllRecentlyPlayedTracksQuery, selectAllTracksText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAllRecentlyPlayedTracksQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAllRecentlyPlayedTracksQuery.lastError(); Q_EMIT databaseError(); } } { auto selectAllTracksText = QStringLiteral("SELECT " "tracks.`ID`, " "tracks.`Title`, " "album.`ID`, " "tracks.`ArtistName`, " "tracks.`AlbumArtistName`, " "tracksMapping.`FileName`, " "tracksMapping.`FileModifiedTime`, " "tracks.`TrackNumber`, " "tracks.`DiscNumber`, " "tracks.`Duration`, " "tracks.`AlbumTitle`, " "tracks.`Rating`, " "album.`CoverFileName`, " "(" "SELECT " "COUNT(DISTINCT tracks2.DiscNumber) <= 1 " "FROM " "`Tracks` tracks2 " "WHERE " "tracks2.`AlbumTitle` = album.`Title` AND " "(tracks2.`AlbumArtistName` = album.`ArtistName` OR " "(tracks2.`AlbumArtistName` IS NULL AND " "album.`ArtistName` IS NULL" ")" ") AND " "tracks2.`AlbumPath` = album.`AlbumPath` " ") as `IsSingleDiscAlbum`, " "trackGenre.`Name`, " "trackComposer.`Name`, " "trackLyricist.`Name`, " "tracks.`Comment`, " "tracks.`Year`, " "tracks.`Channels`, " "tracks.`BitRate`, " "tracks.`SampleRate`, " "tracks.`HasEmbeddedCover`, " "tracksMapping.`ImportDate`, " "tracksMapping.`FirstPlayDate`, " "tracksMapping.`LastPlayDate`, " "tracksMapping.`PlayCounter`, " "CAST(tracksMapping.`PlayCounter` AS REAL) / ((CAST(strftime('%s','now') as INTEGER) - CAST(tracksMapping.`FirstPlayDate` / 1000 as INTEGER)) / CAST(1000 AS REAL)) as PlayFrequency " "FROM " "`Tracks` tracks, " "`TracksData` tracksMapping " "LEFT JOIN " "`Albums` album " "ON " "tracks.`AlbumTitle` = album.`Title` AND " "(tracks.`AlbumArtistName` = album.`ArtistName` OR tracks.`AlbumArtistName` IS NULL ) AND " "tracks.`AlbumPath` = album.`AlbumPath` " "LEFT JOIN `Genre` trackGenre ON trackGenre.`Name` = tracks.`Genre` " "LEFT JOIN `Composer` trackComposer ON trackComposer.`Name` = tracks.`Composer` " "LEFT JOIN `Lyricist` trackLyricist ON trackLyricist.`Name` = tracks.`Lyricist` " "WHERE " "tracksMapping.`FileName` = tracks.`FileName` AND " "tracksMapping.`PlayCounter` > 0 AND " "tracks.`Priority` = (" " SELECT " " MIN(`Priority`) " " FROM " " `Tracks` tracks2 " " WHERE " " tracks.`Title` = tracks2.`Title` AND " " (tracks.`ArtistName` IS NULL OR tracks.`ArtistName` = tracks2.`ArtistName`) AND " " (tracks.`AlbumTitle` IS NULL OR tracks.`AlbumTitle` = tracks2.`AlbumTitle`) AND " " (tracks.`AlbumArtistName` IS NULL OR tracks.`AlbumArtistName` = tracks2.`AlbumArtistName`) AND " " (tracks.`AlbumPath` IS NULL OR tracks.`AlbumPath` = tracks2.`AlbumPath`)" ")" "ORDER BY CAST(tracksMapping.`PlayCounter` AS REAL) / ((CAST(strftime('%s','now') as INTEGER) - CAST(tracksMapping.`FirstPlayDate` / 1000 as INTEGER)) / CAST(1000 AS REAL)) DESC " "LIMIT :maximumResults"); auto result = prepareQuery(d->mSelectAllFrequentlyPlayedTracksQuery, selectAllTracksText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAllFrequentlyPlayedTracksQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAllFrequentlyPlayedTracksQuery.lastError(); Q_EMIT databaseError(); } } { auto clearAlbumsTableText = QStringLiteral("DELETE FROM `Albums`"); auto result = prepareQuery(d->mClearAlbumsTable, clearAlbumsTableText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mClearAlbumsTable.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mClearAlbumsTable.lastError(); Q_EMIT databaseError(); } } { auto clearArtistsTableText = QStringLiteral("DELETE FROM `Artists`"); auto result = prepareQuery(d->mClearArtistsTable, clearArtistsTableText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mClearArtistsTable.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mClearArtistsTable.lastError(); Q_EMIT databaseError(); } } { auto clearComposerTableText = QStringLiteral("DELETE FROM `Composer`"); auto result = prepareQuery(d->mClearComposerTable, clearComposerTableText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mClearComposerTable.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mClearComposerTable.lastError(); Q_EMIT databaseError(); } } { auto clearGenreTableText = QStringLiteral("DELETE FROM `Genre`"); auto result = prepareQuery(d->mClearGenreTable, clearGenreTableText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mClearGenreTable.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mClearGenreTable.lastError(); Q_EMIT databaseError(); } } { auto clearLyricistTableText = QStringLiteral("DELETE FROM `Lyricist`"); auto result = prepareQuery(d->mClearLyricistTable, clearLyricistTableText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mClearLyricistTable.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mClearLyricistTable.lastError(); Q_EMIT databaseError(); } } { auto clearTracksTableText = QStringLiteral("DELETE FROM `Tracks`"); auto result = prepareQuery(d->mClearTracksTable, clearTracksTableText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mClearTracksTable.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mClearTracksTable.lastError(); Q_EMIT databaseError(); } } { auto selectAllTracksShortText = QStringLiteral("SELECT " "tracks.`ID`, " "tracks.`Title`, " "tracks.`ArtistName`, " "tracks.`AlbumTitle`, " "tracks.`AlbumArtistName`, " "tracks.`Duration`, " "album.`CoverFileName`, " "tracks.`TrackNumber`, " "tracks.`DiscNumber`, " "tracks.`Rating` " "FROM " "`Tracks` tracks " "LEFT JOIN " "`Albums` album " "ON " "tracks.`AlbumTitle` = album.`Title` AND " "(tracks.`AlbumArtistName` = album.`ArtistName` OR tracks.`AlbumArtistName` IS NULL ) AND " "tracks.`AlbumPath` = album.`AlbumPath` " ""); auto result = prepareQuery(d->mSelectAllTracksShortQuery, selectAllTracksShortText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAllTracksShortQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAllTracksShortQuery.lastError(); Q_EMIT databaseError(); } } { auto selectArtistByNameText = QStringLiteral("SELECT `ID`, " "`Name` " "FROM `Artists` " "WHERE " "`Name` = :name"); auto result = prepareQuery(d->mSelectArtistByNameQuery, selectArtistByNameText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectArtistByNameQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectArtistByNameQuery.lastError(); Q_EMIT databaseError(); } } { auto selectComposerByNameText = QStringLiteral("SELECT `ID`, " "`Name` " "FROM `Composer` " "WHERE " "`Name` = :name"); auto result = prepareQuery(d->mSelectComposerByNameQuery, selectComposerByNameText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectComposerByNameQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectComposerByNameQuery.lastError(); } } { auto selectLyricistByNameText = QStringLiteral("SELECT `ID`, " "`Name` " "FROM `Lyricist` " "WHERE " "`Name` = :name"); auto result = prepareQuery(d->mSelectLyricistByNameQuery, selectLyricistByNameText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectLyricistByNameQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectLyricistByNameQuery.lastError(); } } { auto selectGenreByNameText = QStringLiteral("SELECT `ID`, " "`Name` " "FROM `Genre` " "WHERE " "`Name` = :name"); auto result = prepareQuery(d->mSelectGenreByNameQuery, selectGenreByNameText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectGenreByNameQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectGenreByNameQuery.lastError(); Q_EMIT databaseError(); } } { auto insertArtistsText = QStringLiteral("INSERT INTO `Artists` (`ID`, `Name`) " "VALUES (:artistId, :name)"); auto result = prepareQuery(d->mInsertArtistsQuery, insertArtistsText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mInsertArtistsQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mInsertArtistsQuery.lastError(); Q_EMIT databaseError(); } } { auto insertGenreText = QStringLiteral("INSERT INTO `Genre` (`ID`, `Name`) " "VALUES (:genreId, :name)"); auto result = prepareQuery(d->mInsertGenreQuery, insertGenreText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mInsertGenreQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mInsertGenreQuery.lastError(); Q_EMIT databaseError(); } } { auto insertComposerText = QStringLiteral("INSERT INTO `Composer` (`ID`, `Name`) " "VALUES (:composerId, :name)"); auto result = prepareQuery(d->mInsertComposerQuery, insertComposerText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mInsertComposerQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mInsertComposerQuery.lastError(); } } { auto insertLyricistText = QStringLiteral("INSERT INTO `Lyricist` (`ID`, `Name`) " "VALUES (:lyricistId, :name)"); auto result = prepareQuery(d->mInsertLyricistQuery, insertLyricistText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mInsertLyricistQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mInsertLyricistQuery.lastError(); } } { auto selectTrackQueryText = QStringLiteral("SELECT " "tracks.`ID`, " "tracks.`Title`, " "album.`ID`, " "tracks.`ArtistName`, " "tracks.`AlbumArtistName`, " "tracksMapping.`FileName`, " "tracksMapping.`FileModifiedTime`, " "tracks.`TrackNumber`, " "tracks.`DiscNumber`, " "tracks.`Duration`, " "tracks.`AlbumTitle`, " "tracks.`Rating`, " "album.`CoverFileName`, " "(" "SELECT " "COUNT(DISTINCT tracks2.DiscNumber) <= 1 " "FROM " "`Tracks` tracks2 " "WHERE " "tracks2.`AlbumTitle` = album.`Title` AND " "(tracks2.`AlbumArtistName` = album.`ArtistName` OR " "(tracks2.`AlbumArtistName` IS NULL AND " "album.`ArtistName` IS NULL" ")" ") AND " "tracks2.`AlbumPath` = album.`AlbumPath` " ") as `IsSingleDiscAlbum`, " "trackGenre.`Name`, " "trackComposer.`Name`, " "trackLyricist.`Name`, " "tracks.`Comment`, " "tracks.`Year`, " "tracks.`Channels`, " "tracks.`BitRate`, " "tracks.`SampleRate`, " "tracks.`HasEmbeddedCover`, " "tracksMapping.`ImportDate`, " "tracksMapping.`FirstPlayDate`, " "tracksMapping.`LastPlayDate`, " "tracksMapping.`PlayCounter`, " "tracksMapping.`PlayCounter` / (strftime('%s', 'now') - tracksMapping.`FirstPlayDate`) as PlayFrequency " "FROM " "`Tracks` tracks, " "`TracksData` tracksMapping " "LEFT JOIN " "`Albums` album " "ON " "album.`ID` = :albumId AND " "tracks.`AlbumTitle` = album.`Title` AND " "(tracks.`AlbumArtistName` = album.`ArtistName` OR tracks.`AlbumArtistName` IS NULL ) AND " "tracks.`AlbumPath` = album.`AlbumPath` " "LEFT JOIN `Composer` trackComposer ON trackComposer.`Name` = tracks.`Composer` " "LEFT JOIN `Lyricist` trackLyricist ON trackLyricist.`Name` = tracks.`Lyricist` " "LEFT JOIN `Genre` trackGenre ON trackGenre.`Name` = tracks.`Genre` " "WHERE " "tracksMapping.`FileName` = tracks.`FileName` AND " "album.`ID` = :albumId AND " "tracks.`Priority` = (" " SELECT " " MIN(`Priority`) " " FROM " " `Tracks` tracks2 " " WHERE " " tracks.`Title` = tracks2.`Title` AND " " (tracks.`ArtistName` IS NULL OR tracks.`ArtistName` = tracks2.`ArtistName`) AND " " (tracks.`AlbumTitle` IS NULL OR tracks.`AlbumTitle` = tracks2.`AlbumTitle`) AND " " (tracks.`AlbumArtistName` IS NULL OR tracks.`AlbumArtistName` = tracks2.`AlbumArtistName`) AND " " (tracks.`AlbumPath` IS NULL OR tracks.`AlbumPath` = tracks2.`AlbumPath`)" ")" "ORDER BY tracks.`DiscNumber` ASC, " "tracks.`TrackNumber` ASC"); auto result = prepareQuery(d->mSelectTrackQuery, selectTrackQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectTrackQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectTrackQuery.lastError(); Q_EMIT databaseError(); } } { auto selectTrackQueryText = QStringLiteral("SELECT " "tracks.`ID` " "FROM " "`Tracks` tracks, " "`TracksData` tracksMapping " "LEFT JOIN " "`Albums` album " "ON " "album.`ID` = :albumId AND " "tracks.`AlbumTitle` = album.`Title` AND " "(tracks.`AlbumArtistName` = album.`ArtistName` OR tracks.`AlbumArtistName` IS NULL ) AND " "tracks.`AlbumPath` = album.`AlbumPath` " "WHERE " "tracksMapping.`FileName` = tracks.`FileName` AND " "album.`ID` = :albumId AND " "tracks.`Priority` = (" " SELECT " " MIN(`Priority`) " " FROM " " `Tracks` tracks2 " " WHERE " " tracks.`Title` = tracks2.`Title` AND " " (tracks.`ArtistName` IS NULL OR tracks.`ArtistName` = tracks2.`ArtistName`) AND " " (tracks.`AlbumTitle` IS NULL OR tracks.`AlbumTitle` = tracks2.`AlbumTitle`) AND " " (tracks.`AlbumArtistName` IS NULL OR tracks.`AlbumArtistName` = tracks2.`AlbumArtistName`) AND " " (tracks.`AlbumPath` IS NULL OR tracks.`AlbumPath` = tracks2.`AlbumPath`)" ")" "ORDER BY tracks.`DiscNumber` ASC, " "tracks.`TrackNumber` ASC"); auto result = prepareQuery(d->mSelectTrackIdQuery, selectTrackQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectTrackIdQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectTrackIdQuery.lastError(); Q_EMIT databaseError(); } } { auto selectTrackFromIdQueryText = QStringLiteral("SELECT " "tracks.`Id`, " "tracks.`Title`, " "album.`ID`, " "tracks.`ArtistName`, " "tracks.`AlbumArtistName`, " "tracksMapping.`FileName`, " "tracksMapping.`FileModifiedTime`, " "tracks.`TrackNumber`, " "tracks.`DiscNumber`, " "tracks.`Duration`, " "tracks.`AlbumTitle`, " "tracks.`Rating`, " "album.`CoverFileName`, " "(" "SELECT " "COUNT(DISTINCT tracks2.DiscNumber) <= 1 " "FROM " "`Tracks` tracks2 " "WHERE " "tracks2.`AlbumTitle` = album.`Title` AND " "(tracks2.`AlbumArtistName` = album.`ArtistName` OR " "(tracks2.`AlbumArtistName` IS NULL AND " "album.`ArtistName` IS NULL" ")" ") AND " "tracks2.`AlbumPath` = album.`AlbumPath` " ") as `IsSingleDiscAlbum`, " "trackGenre.`Name`, " "trackComposer.`Name`, " "trackLyricist.`Name`, " "tracks.`Comment`, " "tracks.`Year`, " "tracks.`Channels`, " "tracks.`BitRate`, " "tracks.`SampleRate`, " "tracks.`HasEmbeddedCover`, " "tracksMapping.`ImportDate`, " "tracksMapping.`FirstPlayDate`, " "tracksMapping.`LastPlayDate`, " "tracksMapping.`PlayCounter`, " "tracksMapping.`PlayCounter` / (strftime('%s', 'now') - tracksMapping.`FirstPlayDate`) as PlayFrequency " "FROM " "`Tracks` tracks, " "`TracksData` tracksMapping " "LEFT JOIN " "`Albums` album " "ON " "tracks.`AlbumTitle` = album.`Title` AND " "(tracks.`AlbumArtistName` = album.`ArtistName` OR tracks.`AlbumArtistName` IS NULL ) AND " "tracks.`AlbumPath` = album.`AlbumPath` " "LEFT JOIN `Composer` trackComposer ON trackComposer.`Name` = tracks.`Composer` " "LEFT JOIN `Lyricist` trackLyricist ON trackLyricist.`Name` = tracks.`Lyricist` " "LEFT JOIN `Genre` trackGenre ON trackGenre.`Name` = tracks.`Genre` " "WHERE " "tracks.`ID` = :trackId AND " "tracksMapping.`FileName` = tracks.`FileName` AND " "tracks.`Priority` = (" " SELECT " " MIN(`Priority`) " " FROM " " `Tracks` tracks2 " " WHERE " " tracks.`Title` = tracks2.`Title` AND " " (tracks.`ArtistName` IS NULL OR tracks.`ArtistName` = tracks2.`ArtistName`) AND " " (tracks.`AlbumTitle` IS NULL OR tracks.`AlbumTitle` = tracks2.`AlbumTitle`) AND " " (tracks.`AlbumArtistName` IS NULL OR tracks.`AlbumArtistName` = tracks2.`AlbumArtistName`) AND " " (tracks.`AlbumPath` IS NULL OR tracks.`AlbumPath` = tracks2.`AlbumPath`)" ")" ""); auto result = prepareQuery(d->mSelectTrackFromIdQuery, selectTrackFromIdQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectTrackFromIdQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectTrackFromIdQuery.lastError(); Q_EMIT databaseError(); } } { auto selectCountAlbumsQueryText = QStringLiteral("SELECT count(*) " "FROM `Albums` album " "WHERE album.`ArtistName` = :artistName "); const auto result = prepareQuery(d->mSelectCountAlbumsForArtistQuery, selectCountAlbumsQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectCountAlbumsForArtistQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectCountAlbumsForArtistQuery.lastError(); Q_EMIT databaseError(); } } { auto selectGenreForArtistQueryText = QStringLiteral("SELECT DISTINCT trackGenre.`Name` " "FROM " "`Tracks` tracks " "LEFT JOIN " "`Albums` album " "ON " "tracks.`AlbumTitle` = album.`Title` AND " "(tracks.`AlbumArtistName` = album.`ArtistName` OR tracks.`AlbumArtistName` IS NULL ) AND " "tracks.`AlbumPath` = album.`AlbumPath` " "LEFT JOIN `Genre` trackGenre ON trackGenre.`Name` = tracks.`Genre` " "WHERE " "album.`ArtistName` = :artistName"); const auto result = prepareQuery(d->mSelectGenreForArtistQuery, selectGenreForArtistQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectGenreForArtistQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectGenreForArtistQuery.lastError(); Q_EMIT databaseError(); } } { auto selectGenreForAlbumQueryText = QStringLiteral("SELECT DISTINCT trackGenre.`Name` " "FROM " "`Tracks` tracks " "LEFT JOIN " "`Albums` album " "ON " "tracks.`AlbumTitle` = album.`Title` AND " "(tracks.`AlbumArtistName` = album.`ArtistName` OR tracks.`AlbumArtistName` IS NULL ) AND " "tracks.`AlbumPath` = album.`AlbumPath` " "LEFT JOIN `Genre` trackGenre ON trackGenre.`Name` = tracks.`Genre` " "WHERE " "album.`ID` = :albumId"); const auto result = prepareQuery(d->mSelectGenreForAlbumQuery, selectGenreForAlbumQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectGenreForAlbumQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectGenreForAlbumQuery.lastError(); Q_EMIT databaseError(); } } { auto selectCountAlbumsQueryText = QStringLiteral("SELECT distinct count(album.`ID`) " "FROM " "`Tracks` tracks, " "`Albums` album " "LEFT JOIN `Composer` albumComposer ON albumComposer.`Name` = tracks.`Composer` " "WHERE " "(tracks.`AlbumTitle` = album.`Title` OR tracks.`AlbumTitle` IS NULL ) AND " "(tracks.`AlbumArtistName` = album.`ArtistName` OR tracks.`AlbumArtistName` IS NULL ) AND " "(tracks.`AlbumPath` = album.`AlbumPath` OR tracks.`AlbumPath` IS NULL ) AND " "albumComposer.`Name` = :artistName"); const auto result = prepareQuery(d->mSelectCountAlbumsForComposerQuery, selectCountAlbumsQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectCountAlbumsForComposerQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectCountAlbumsForComposerQuery.lastError(); Q_EMIT databaseError(); } } { auto selectCountAlbumsQueryText = QStringLiteral("SELECT distinct count(album.`ID`) " "FROM " "`Tracks` tracks, " "`Albums` album " "LEFT JOIN `Lyricist` albumLyricist ON albumLyricist.`Name` = tracks.`Lyricist` " "WHERE " "(tracks.`AlbumTitle` = album.`Title` OR tracks.`AlbumTitle` IS NULL ) AND " "(tracks.`AlbumArtistName` = album.`ArtistName` OR tracks.`AlbumArtistName` IS NULL ) AND " "(tracks.`AlbumPath` = album.`AlbumPath` OR tracks.`AlbumPath` IS NULL ) AND " "albumLyricist.`Name` = :artistName"); const auto result = prepareQuery(d->mSelectCountAlbumsForLyricistQuery, selectCountAlbumsQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectCountAlbumsForLyricistQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectCountAlbumsForLyricistQuery.lastError(); Q_EMIT databaseError(); } } { auto selectAlbumIdFromTitleQueryText = QStringLiteral("SELECT " "album.`ID` " "FROM " "`Albums` album " "WHERE " "album.`ArtistName` = :artistName AND " "album.`Title` = :title"); auto result = prepareQuery(d->mSelectAlbumIdFromTitleQuery, selectAlbumIdFromTitleQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAlbumIdFromTitleQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAlbumIdFromTitleQuery.lastError(); Q_EMIT databaseError(); } } { auto selectAlbumIdFromTitleAndArtistQueryText = QStringLiteral("SELECT " "album.`ID` " "FROM " "`Albums` album " "WHERE " "album.`ArtistName` = :artistName AND " "album.`Title` = :title AND " "album.`AlbumPath` = :albumPath"); auto result = prepareQuery(d->mSelectAlbumIdFromTitleAndArtistQuery, selectAlbumIdFromTitleAndArtistQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAlbumIdFromTitleAndArtistQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAlbumIdFromTitleAndArtistQuery.lastError(); Q_EMIT databaseError(); } } { auto selectAlbumIdFromTitleWithoutArtistQueryText = QStringLiteral("SELECT " "album.`ID` " "FROM " "`Albums` album " "WHERE " "album.`AlbumPath` = :albumPath AND " "album.`Title` = :title AND " "album.`ArtistName` IS NULL"); auto result = prepareQuery(d->mSelectAlbumIdFromTitleWithoutArtistQuery, selectAlbumIdFromTitleWithoutArtistQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAlbumIdFromTitleWithoutArtistQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAlbumIdFromTitleWithoutArtistQuery.lastError(); Q_EMIT databaseError(); } } { auto insertAlbumQueryText = QStringLiteral("INSERT INTO `Albums` " "(`ID`, " "`Title`, " "`ArtistName`, " "`AlbumPath`, " "`CoverFileName`) " "VALUES " "(:albumId, " ":title, " ":albumArtist, " ":albumPath, " ":coverFileName)"); auto result = prepareQuery(d->mInsertAlbumQuery, insertAlbumQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mInsertAlbumQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mInsertAlbumQuery.lastError(); Q_EMIT databaseError(); } } { auto insertTrackMappingQueryText = QStringLiteral("INSERT INTO " "`TracksData` " "(`FileName`, " "`FileModifiedTime`, " "`ImportDate`, " "`PlayCounter`) " "VALUES (:fileName, :mtime, :importDate, 0)"); auto result = prepareQuery(d->mInsertTrackMapping, insertTrackMappingQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mInsertTrackMapping.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mInsertTrackMapping.lastError(); Q_EMIT databaseError(); } } { auto initialUpdateTracksValidityQueryText = QStringLiteral("UPDATE `TracksData` " "SET " "`FileModifiedTime` = :mtime " "WHERE `FileName` = :fileName"); auto result = prepareQuery(d->mUpdateTrackFileModifiedTime, initialUpdateTracksValidityQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mUpdateTrackFileModifiedTime.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mUpdateTrackFileModifiedTime.lastError(); Q_EMIT databaseError(); } } { auto initialUpdateTracksValidityQueryText = QStringLiteral("UPDATE `Tracks` " "SET " "`Priority` = :priority " "WHERE `FileName` = :fileName"); auto result = prepareQuery(d->mUpdateTrackPriority, initialUpdateTracksValidityQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mUpdateTrackPriority.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mUpdateTrackPriority.lastError(); Q_EMIT databaseError(); } } { auto removeTracksMappingFromSourceQueryText = QStringLiteral("DELETE FROM `TracksData` " "WHERE `FileName` = :fileName"); auto result = prepareQuery(d->mRemoveTracksMappingFromSource, removeTracksMappingFromSourceQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mRemoveTracksMappingFromSource.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mRemoveTracksMappingFromSource.lastError(); Q_EMIT databaseError(); } } { auto removeTracksMappingQueryText = QStringLiteral("DELETE FROM `TracksData` " "WHERE `FileName` = :fileName"); auto result = prepareQuery(d->mRemoveTracksMapping, removeTracksMappingQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mRemoveTracksMapping.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mRemoveTracksMapping.lastError(); Q_EMIT databaseError(); } } { auto selectTracksWithoutMappingQueryText = QStringLiteral("SELECT " "tracks.`Id`, " "tracks.`Title`, " "album.`ID`, " "tracks.`ArtistName`, " "tracks.`AlbumArtistName`, " "\"\" as FileName, " "NULL as FileModifiedTime, " "tracks.`TrackNumber`, " "tracks.`DiscNumber`, " "tracks.`Duration`, " "tracks.`AlbumTitle`, " "tracks.`Rating`, " "album.`CoverFileName`, " "(" "SELECT " "COUNT(DISTINCT tracks2.DiscNumber) <= 1 " "FROM " "`Tracks` tracks2 " "WHERE " "tracks2.`AlbumTitle` = album.`Title` AND " "(tracks2.`AlbumArtistName` = album.`ArtistName` OR " "(tracks2.`AlbumArtistName` IS NULL AND " "album.`ArtistName` IS NULL" ")" ") AND " "tracks2.`AlbumPath` = album.`AlbumPath` " ") as `IsSingleDiscAlbum`, " "trackGenre.`Name`, " "trackComposer.`Name`, " "trackLyricist.`Name`, " "tracks.`Comment`, " "tracks.`Year`, " "tracks.`Channels`, " "tracks.`BitRate`, " "tracks.`SampleRate`, " "tracks.`HasEmbeddedCover`, " "tracksMapping.`ImportDate`, " "tracksMapping.`FirstPlayDate`, " "tracksMapping.`LastPlayDate`, " "tracksMapping.`PlayCounter`, " "tracksMapping.`PlayCounter` / (strftime('%s', 'now') - tracksMapping.`FirstPlayDate`) as PlayFrequency " "FROM " "`Tracks` tracks, " "`TracksData` tracksMapping " "LEFT JOIN " "`Albums` album " "ON " "tracks.`AlbumTitle` = album.`Title` AND " "(tracks.`AlbumArtistName` = album.`ArtistName` OR tracks.`AlbumArtistName` IS NULL ) AND " "tracks.`AlbumPath` = album.`AlbumPath` " "LEFT JOIN `Composer` trackComposer ON trackComposer.`Name` = tracks.`Composer` " "LEFT JOIN `Lyricist` trackLyricist ON trackLyricist.`Name` = tracks.`Lyricist` " "LEFT JOIN `Genre` trackGenre ON trackGenre.`Name` = tracks.`Genre` " "WHERE " "tracks.`FileName` = tracksMapping.`FileName` AND " "tracks.`FileName` NOT IN (SELECT tracksMapping2.`FileName` FROM `TracksData` tracksMapping2)"); auto result = prepareQuery(d->mSelectTracksWithoutMappingQuery, selectTracksWithoutMappingQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectTracksWithoutMappingQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectTracksWithoutMappingQuery.lastError(); Q_EMIT databaseError(); } } { auto selectTracksMappingQueryText = QStringLiteral("SELECT " "track.`ID`, " "trackData.`FileName`, " "track.`Priority`, " "trackData.`FileModifiedTime` " "FROM " "`TracksData` trackData " "LEFT JOIN " "`Tracks` track " "ON " "track.`FileName` = trackData.`FileName` " "WHERE " "trackData.`FileName` = :fileName"); auto result = prepareQuery(d->mSelectTracksMapping, selectTracksMappingQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectTracksMapping.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectTracksMapping.lastError(); Q_EMIT databaseError(); } } { auto selectTracksMappingPriorityQueryText = QStringLiteral("SELECT " "max(tracks.`Priority`) AS Priority " "FROM " "`Tracks` tracks, " "`Albums` albums " "WHERE " "tracks.`Title` = :title AND " "(tracks.`ArtistName` = :trackArtist OR tracks.`ArtistName` IS NULL) AND " "(tracks.`AlbumTitle` = :album OR tracks.`AlbumTitle` IS NULL) AND " "(tracks.`AlbumArtistName` = :albumArtist OR tracks.`AlbumArtistName` IS NULL) AND " "(tracks.`AlbumPath` = :albumPath OR tracks.`AlbumPath` IS NULL)"); auto result = prepareQuery(d->mSelectTracksMappingPriority, selectTracksMappingPriorityQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectTracksMappingPriority.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectTracksMappingPriority.lastError(); Q_EMIT databaseError(); } } { auto selectTracksMappingPriorityQueryByTrackIdText = QStringLiteral("SELECT " "MAX(track.`Priority`) " "FROM " "`TracksData` trackData, " "`Tracks` track " "WHERE " "track.`ID` = :trackId AND " "trackData.`FileName` = track.`FileName`"); auto result = prepareQuery(d->mSelectTracksMappingPriorityByTrackId, selectTracksMappingPriorityQueryByTrackIdText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectTracksMappingPriorityByTrackId.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectTracksMappingPriorityByTrackId.lastError(); Q_EMIT databaseError(); } } { auto selectAllTrackFilesFromSourceQueryText = QStringLiteral("SELECT " "tracksMapping.`FileName`, " "tracksMapping.`FileModifiedTime` " "FROM " "`TracksData` tracksMapping, " "`Tracks` tracks " "WHERE " "tracks.`FileName` = tracksMapping.`FileName`"); auto result = prepareQuery(d->mSelectAllTrackFilesQuery, selectAllTrackFilesFromSourceQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAllTrackFilesQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAllTrackFilesQuery.lastError(); Q_EMIT databaseError(); } } { auto insertMusicSourceQueryText = QStringLiteral("INSERT OR IGNORE INTO `DiscoverSource` (`ID`, `Name`) " "VALUES (:discoverId, :name)"); auto result = prepareQuery(d->mInsertMusicSource, insertMusicSourceQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mInsertMusicSource.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mInsertMusicSource.lastError(); Q_EMIT databaseError(); } } { auto selectMusicSourceQueryText = QStringLiteral("SELECT `ID` FROM `DiscoverSource` WHERE `Name` = :name"); auto result = prepareQuery(d->mSelectMusicSource, selectMusicSourceQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectMusicSource.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectMusicSource.lastError(); Q_EMIT databaseError(); } } { auto selectTrackQueryText = QStringLiteral("SELECT " "tracks.`ID`, tracksMapping.`FileName` " "FROM " "`Tracks` tracks, " "`Albums` album, " "`TracksData` tracksMapping " "WHERE " "tracks.`Title` = :title AND " "album.`ID` = :album AND " "(tracks.`AlbumTitle` = album.`Title` OR tracks.`AlbumTitle` IS NULL ) AND " "(tracks.`AlbumArtistName` = album.`ArtistName` OR tracks.`AlbumArtistName` IS NULL ) AND " "(tracks.`AlbumPath` = album.`AlbumPath` OR tracks.`AlbumPath` IS NULL ) AND " "tracks.`ArtistName` = :artist AND " "tracksMapping.`FileName` = tracks.`FileName` AND " "tracks.`Priority` = (" " SELECT " " MIN(`Priority`) " " FROM " " `Tracks` tracks2 " " WHERE " " tracks.`Title` = tracks2.`Title` AND " " (tracks.`ArtistName` IS NULL OR tracks.`ArtistName` = tracks2.`ArtistName`) AND " " (tracks.`AlbumTitle` IS NULL OR tracks.`AlbumTitle` = tracks2.`AlbumTitle`) AND " " (tracks.`AlbumArtistName` IS NULL OR tracks.`AlbumArtistName` = tracks2.`AlbumArtistName`) AND " " (tracks.`AlbumPath` IS NULL OR tracks.`AlbumPath` = tracks2.`AlbumPath`)" ")" ""); auto result = prepareQuery(d->mSelectTrackIdFromTitleAlbumIdArtistQuery, selectTrackQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectTrackIdFromTitleAlbumIdArtistQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectTrackIdFromTitleAlbumIdArtistQuery.lastError(); Q_EMIT databaseError(); } } { auto insertTrackQueryText = QStringLiteral("INSERT INTO `Tracks` " "(" "`ID`, " "`FileName`, " "`Priority`, " "`Title`, " "`ArtistName`, " "`AlbumTitle`, " "`AlbumArtistName`, " "`AlbumPath`, " "`Genre`, " "`Composer`, " "`Lyricist`, " "`Comment`, " "`TrackNumber`, " "`DiscNumber`, " "`Channels`, " "`BitRate`, " "`SampleRate`, " "`Year`, " "`Duration`, " "`Rating`, " "`HasEmbeddedCover`) " "VALUES " "(" ":trackId, " ":fileName, " ":priority, " ":title, " ":artistName, " ":albumTitle, " ":albumArtistName, " ":albumPath, " ":genre, " ":composer, " ":lyricist, " ":comment, " ":trackNumber, " ":discNumber, " ":channels, " ":bitRate, " ":sampleRate, " ":year, " ":trackDuration, " ":trackRating, " ":hasEmbeddedCover)"); auto result = prepareQuery(d->mInsertTrackQuery, insertTrackQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mInsertTrackQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mInsertTrackQuery.lastError(); Q_EMIT databaseError(); } } { auto updateTrackQueryText = QStringLiteral("UPDATE `Tracks` " "SET " "`FileName` = :fileName, " "`Title` = :title, " "`ArtistName` = :artistName, " "`AlbumTitle` = :albumTitle, " "`AlbumArtistName` = :albumArtistName, " "`AlbumPath` = :albumPath, " "`Genre` = :genre, " "`Composer` = :composer, " "`Lyricist` = :lyricist, " "`Comment` = :comment, " "`TrackNumber` = :trackNumber, " "`DiscNumber` = :discNumber, " "`Channels` = :channels, " "`BitRate` = :bitRate, " "`SampleRate` = :sampleRate, " "`Year` = :year, " " `Duration` = :trackDuration, " "`Rating` = :trackRating " "WHERE " "`ID` = :trackId"); auto result = prepareQuery(d->mUpdateTrackQuery, updateTrackQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mUpdateTrackQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mUpdateTrackQuery.lastError(); Q_EMIT databaseError(); } } { auto updateAlbumArtistQueryText = QStringLiteral("UPDATE `Albums` " "SET " "`ArtistName` = :artistName " "WHERE " "`ID` = :albumId"); auto result = prepareQuery(d->mUpdateAlbumArtistQuery, updateAlbumArtistQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mUpdateAlbumArtistQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mUpdateAlbumArtistQuery.lastError(); Q_EMIT databaseError(); } } { auto updateAlbumArtistInTracksQueryText = QStringLiteral("UPDATE `Tracks` " "SET " "`AlbumArtistName` = :artistName " "WHERE " "`AlbumTitle` = :albumTitle AND " "`AlbumPath` = :albumPath AND " "`AlbumArtistName` IS NULL"); auto result = prepareQuery(d->mUpdateAlbumArtistInTracksQuery, updateAlbumArtistInTracksQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mUpdateAlbumArtistInTracksQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mUpdateAlbumArtistInTracksQuery.lastError(); Q_EMIT databaseError(); } } { auto queryMaximumTrackIdQueryText = QStringLiteral("SELECT MAX(tracks.`ID`)" "FROM " "`Tracks` tracks"); auto result = prepareQuery(d->mQueryMaximumTrackIdQuery, queryMaximumTrackIdQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mQueryMaximumTrackIdQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mQueryMaximumTrackIdQuery.lastError(); Q_EMIT databaseError(); } } { auto queryMaximumAlbumIdQueryText = QStringLiteral("SELECT MAX(albums.`ID`)" "FROM " "`Albums` albums"); auto result = prepareQuery(d->mQueryMaximumAlbumIdQuery, queryMaximumAlbumIdQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mQueryMaximumAlbumIdQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mQueryMaximumAlbumIdQuery.lastError(); Q_EMIT databaseError(); } } { auto queryMaximumArtistIdQueryText = QStringLiteral("SELECT MAX(artists.`ID`)" "FROM " "`Artists` artists"); auto result = prepareQuery(d->mQueryMaximumArtistIdQuery, queryMaximumArtistIdQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mQueryMaximumArtistIdQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mQueryMaximumArtistIdQuery.lastError(); Q_EMIT databaseError(); } } { auto queryMaximumLyricistIdQueryText = QStringLiteral("SELECT MAX(lyricists.`ID`)" "FROM " "`Lyricist` lyricists"); auto result = prepareQuery(d->mQueryMaximumLyricistIdQuery, queryMaximumLyricistIdQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mQueryMaximumLyricistIdQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mQueryMaximumLyricistIdQuery.lastError(); Q_EMIT databaseError(); } } { auto queryMaximumComposerIdQueryText = QStringLiteral("SELECT MAX(composers.`ID`)" "FROM " "`Composer` composers"); auto result = prepareQuery(d->mQueryMaximumComposerIdQuery, queryMaximumComposerIdQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mQueryMaximumComposerIdQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mQueryMaximumComposerIdQuery.lastError(); Q_EMIT databaseError(); } } { auto queryMaximumGenreIdQueryText = QStringLiteral("SELECT MAX(genres.`ID`)" "FROM " "`Genre` genres"); auto result = prepareQuery(d->mQueryMaximumGenreIdQuery, queryMaximumGenreIdQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mQueryMaximumGenreIdQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mQueryMaximumGenreIdQuery.lastError(); Q_EMIT databaseError(); } } { auto selectTrackQueryText = QStringLiteral("SELECT " "tracks.ID " "FROM " "`Tracks` tracks " "WHERE " "tracks.`Title` = :title AND " "tracks.`AlbumTitle` = :album AND " "tracks.`TrackNumber` = :trackNumber AND " "tracks.`DiscNumber` = :discNumber AND " "tracks.`ArtistName` = :artist"); auto result = prepareQuery(d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery, selectTrackQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery.lastError(); Q_EMIT databaseError(); } } { auto selectTrackQueryText = QStringLiteral("SELECT " "tracks.ID " "FROM " "`Tracks` tracks, " "`Albums` albums " "WHERE " "tracks.`Title` = :title AND " "tracks.`Priority` = :priority AND " "(tracks.`ArtistName` = :trackArtist OR tracks.`ArtistName` IS NULL) AND " "(tracks.`AlbumTitle` = :album OR tracks.`AlbumTitle` IS NULL) AND " "(tracks.`AlbumArtistName` = :albumArtist OR tracks.`AlbumArtistName` IS NULL) AND " "(tracks.`AlbumPath` = :albumPath OR tracks.`AlbumPath` IS NULL)"); auto result = prepareQuery(d->mSelectTrackIdFromTitleAlbumTrackDiscNumberQuery, selectTrackQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectTrackIdFromTitleAlbumTrackDiscNumberQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectTrackIdFromTitleAlbumTrackDiscNumberQuery.lastError(); Q_EMIT databaseError(); } } { auto selectAlbumArtUriFromAlbumIdQueryText = QStringLiteral("SELECT `CoverFileName`" "FROM " "`Albums` " "WHERE " "`ID` = :albumId"); auto result = prepareQuery(d->mSelectAlbumArtUriFromAlbumIdQuery, selectAlbumArtUriFromAlbumIdQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAlbumArtUriFromAlbumIdQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAlbumArtUriFromAlbumIdQuery.lastError(); Q_EMIT databaseError(); } } { auto updateAlbumArtUriFromAlbumIdQueryText = QStringLiteral("UPDATE `Albums` " "SET `CoverFileName` = :coverFileName " "WHERE " "`ID` = :albumId"); auto result = prepareQuery(d->mUpdateAlbumArtUriFromAlbumIdQuery, updateAlbumArtUriFromAlbumIdQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mUpdateAlbumArtUriFromAlbumIdQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mUpdateAlbumArtUriFromAlbumIdQuery.lastError(); Q_EMIT databaseError(); } } { auto selectTracksFromArtistQueryText = QStringLiteral("SELECT " "tracks.`ID`, " "tracks.`Title`, " "album.`ID`, " "tracks.`ArtistName`, " "tracks.`AlbumArtistName`, " "tracksMapping.`FileName`, " "tracksMapping.`FileModifiedTime`, " "tracks.`TrackNumber`, " "tracks.`DiscNumber`, " "tracks.`Duration`, " "tracks.`AlbumTitle`, " "tracks.`Rating`, " "album.`CoverFileName`, " "(" "SELECT " "COUNT(DISTINCT tracks2.DiscNumber) <= 1 " "FROM " "`Tracks` tracks2 " "WHERE " "tracks2.`AlbumTitle` = album.`Title` AND " "(tracks2.`AlbumArtistName` = album.`ArtistName` OR " "(tracks2.`AlbumArtistName` IS NULL AND " "album.`ArtistName` IS NULL" ")" ") AND " "tracks2.`AlbumPath` = album.`AlbumPath` " ") as `IsSingleDiscAlbum`, " "trackGenre.`Name`, " "trackComposer.`Name`, " "trackLyricist.`Name`, " "tracks.`Comment`, " "tracks.`Year`, " "tracks.`Channels`, " "tracks.`BitRate`, " "tracks.`SampleRate`, " "tracks.`HasEmbeddedCover`, " "tracksMapping.`ImportDate`, " "tracksMapping.`FirstPlayDate`, " "tracksMapping.`LastPlayDate`, " "tracksMapping.`PlayCounter`, " "tracksMapping.`PlayCounter` / (strftime('%s', 'now') - tracksMapping.`FirstPlayDate`) as PlayFrequency " "FROM " "`Tracks` tracks, " "`TracksData` tracksMapping " "LEFT JOIN " "`Albums` album " "ON " "tracks.`AlbumTitle` = album.`Title` AND " "(tracks.`AlbumArtistName` = album.`ArtistName` OR tracks.`AlbumArtistName` IS NULL ) AND " "tracks.`AlbumPath` = album.`AlbumPath` " "LEFT JOIN `Composer` trackComposer ON trackComposer.`Name` = tracks.`Composer` " "LEFT JOIN `Lyricist` trackLyricist ON trackLyricist.`Name` = tracks.`Lyricist` " "LEFT JOIN `Genre` trackGenre ON trackGenre.`Name` = tracks.`Genre` " "WHERE " "tracks.`ArtistName` = :artistName AND " "tracksMapping.`FileName` = tracks.`FileName` AND " "tracks.`Priority` = (" " SELECT " " MIN(`Priority`) " " FROM " " `Tracks` tracks2 " " WHERE " " tracks.`Title` = tracks2.`Title` AND " " (tracks.`ArtistName` IS NULL OR tracks.`ArtistName` = tracks2.`ArtistName`) AND " " (tracks.`AlbumTitle` IS NULL OR tracks.`AlbumTitle` = tracks2.`AlbumTitle`) AND " " (tracks.`AlbumArtistName` IS NULL OR tracks.`AlbumArtistName` = tracks2.`AlbumArtistName`) AND " " (tracks.`AlbumPath` IS NULL OR tracks.`AlbumPath` = tracks2.`AlbumPath`)" ")" "ORDER BY tracks.`Title` ASC, " "album.`Title` ASC"); auto result = prepareQuery(d->mSelectTracksFromArtist, selectTracksFromArtistQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectTracksFromArtist.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectTracksFromArtist.lastError(); Q_EMIT databaseError(); } } { auto selectAlbumIdsFromArtistQueryText = QStringLiteral("SELECT " "album.`ID` " "FROM " "`Albums` album " "WHERE " "album.`ArtistName` = :artistName"); auto result = prepareQuery(d->mSelectAlbumIdsFromArtist, selectAlbumIdsFromArtistQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAlbumIdsFromArtist.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectAlbumIdsFromArtist.lastError(); Q_EMIT databaseError(); } } { auto selectArtistQueryText = QStringLiteral("SELECT `ID`, " "`Name` " "FROM `Artists` " "WHERE " "`ID` = :artistId"); auto result = prepareQuery(d->mSelectArtistQuery, selectArtistQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectArtistQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectArtistQuery.lastError(); Q_EMIT databaseError(); } } { auto updateTrackStatisticsQueryText = QStringLiteral("UPDATE `TracksData` " "SET " "`LastPlayDate` = :playDate, " "`PlayCounter` = `PlayCounter` + 1 " "WHERE " "`FileName` = :fileName"); auto result = prepareQuery(d->mUpdateTrackStatistics, updateTrackStatisticsQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mUpdateTrackStatistics.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mUpdateTrackStatistics.lastError(); Q_EMIT databaseError(); } } { auto updateTrackFirstPlayStatisticsQueryText = QStringLiteral("UPDATE `TracksData` " "SET " "`FirstPlayDate` = :playDate " "WHERE " "`FileName` = :fileName AND " "`FirstPlayDate` IS NULL"); auto result = prepareQuery(d->mUpdateTrackFirstPlayStatistics, updateTrackFirstPlayStatisticsQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mUpdateTrackFirstPlayStatistics.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mUpdateTrackFirstPlayStatistics.lastError(); Q_EMIT databaseError(); } } { auto selectGenreQueryText = QStringLiteral("SELECT `ID`, " "`Name` " "FROM `Genre` " "WHERE " "`ID` = :genreId"); auto result = prepareQuery(d->mSelectGenreQuery, selectGenreQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectGenreQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectGenreQuery.lastError(); Q_EMIT databaseError(); } } { auto selectComposerQueryText = QStringLiteral("SELECT `ID`, " "`Name` " "FROM `Composer` " "WHERE " "`ID` = :composerId"); auto result = prepareQuery(d->mSelectComposerQuery, selectComposerQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectComposerQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectComposerQuery.lastError(); } } { auto selectLyricistQueryText = QStringLiteral("SELECT `ID`, " "`Name` " "FROM `Lyricist` " "WHERE " "`ID` = :lyricistId"); auto result = prepareQuery(d->mSelectLyricistQuery, selectLyricistQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectLyricistQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mSelectLyricistQuery.lastError(); } } { auto removeTrackQueryText = QStringLiteral("DELETE FROM `Tracks` " "WHERE " "`ID` = :trackId"); auto result = prepareQuery(d->mRemoveTrackQuery, removeTrackQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mRemoveTrackQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mRemoveTrackQuery.lastError(); Q_EMIT databaseError(); } } { auto removeAlbumQueryText = QStringLiteral("DELETE FROM `Albums` " "WHERE " "`ID` = :albumId"); auto result = prepareQuery(d->mRemoveAlbumQuery, removeAlbumQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mRemoveAlbumQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mRemoveAlbumQuery.lastError(); Q_EMIT databaseError(); } } { auto removeAlbumQueryText = QStringLiteral("DELETE FROM `Artists` " "WHERE " "`ID` = :artistId"); auto result = prepareQuery(d->mRemoveArtistQuery, removeAlbumQueryText); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mRemoveArtistQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << d->mRemoveArtistQuery.lastError(); Q_EMIT databaseError(); } } finishTransaction(); d->mInitFinished = true; Q_EMIT requestsInitDone(); } qulonglong DatabaseInterface::insertAlbum(const QString &title, const QString &albumArtist, const QString &trackArtist, const QString &trackPath, const QUrl &albumArtURI) { auto result = qulonglong(0); if (title.isEmpty()) { return result; } if (!albumArtist.isEmpty() || !trackArtist.isEmpty()) { d->mSelectAlbumIdFromTitleAndArtistQuery.bindValue(QStringLiteral(":title"), title); d->mSelectAlbumIdFromTitleAndArtistQuery.bindValue(QStringLiteral(":albumPath"), trackPath); if (!albumArtist.isEmpty()) { d->mSelectAlbumIdFromTitleAndArtistQuery.bindValue(QStringLiteral(":artistName"), albumArtist); } else { d->mSelectAlbumIdFromTitleAndArtistQuery.bindValue(QStringLiteral(":artistName"), trackArtist); } auto queryResult = execQuery(d->mSelectAlbumIdFromTitleAndArtistQuery); if (!queryResult || !d->mSelectAlbumIdFromTitleAndArtistQuery.isSelect() || !d->mSelectAlbumIdFromTitleAndArtistQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertAlbum" << d->mSelectAlbumIdFromTitleAndArtistQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertAlbum" << d->mSelectAlbumIdFromTitleAndArtistQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertAlbum" << d->mSelectAlbumIdFromTitleAndArtistQuery.lastError(); d->mSelectAlbumIdFromTitleAndArtistQuery.finish(); return result; } if (d->mSelectAlbumIdFromTitleAndArtistQuery.next()) { result = d->mSelectAlbumIdFromTitleAndArtistQuery.record().value(0).toULongLong(); d->mSelectAlbumIdFromTitleAndArtistQuery.finish(); return result; } d->mSelectAlbumIdFromTitleAndArtistQuery.finish(); } if (result == 0) { d->mSelectAlbumIdFromTitleWithoutArtistQuery.bindValue(QStringLiteral(":title"), title); d->mSelectAlbumIdFromTitleWithoutArtistQuery.bindValue(QStringLiteral(":albumPath"), trackPath); auto queryResult = execQuery(d->mSelectAlbumIdFromTitleWithoutArtistQuery); if (!queryResult || !d->mSelectAlbumIdFromTitleWithoutArtistQuery.isSelect() || !d->mSelectAlbumIdFromTitleWithoutArtistQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertAlbum" << d->mSelectAlbumIdFromTitleWithoutArtistQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertAlbum" << d->mSelectAlbumIdFromTitleWithoutArtistQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertAlbum" << d->mSelectAlbumIdFromTitleWithoutArtistQuery.lastError(); d->mSelectAlbumIdFromTitleWithoutArtistQuery.finish(); return result; } if (d->mSelectAlbumIdFromTitleWithoutArtistQuery.next()) { result = d->mSelectAlbumIdFromTitleWithoutArtistQuery.record().value(0).toULongLong(); d->mSelectAlbumIdFromTitleWithoutArtistQuery.finish(); return result; } d->mSelectAlbumIdFromTitleWithoutArtistQuery.finish(); } d->mInsertAlbumQuery.bindValue(QStringLiteral(":albumId"), d->mAlbumId); d->mInsertAlbumQuery.bindValue(QStringLiteral(":title"), title); if (!albumArtist.isEmpty()) { insertArtist(albumArtist); d->mInsertAlbumQuery.bindValue(QStringLiteral(":albumArtist"), albumArtist); } else { d->mInsertAlbumQuery.bindValue(QStringLiteral(":albumArtist"), {}); } d->mInsertAlbumQuery.bindValue(QStringLiteral(":albumPath"), trackPath); d->mInsertAlbumQuery.bindValue(QStringLiteral(":coverFileName"), albumArtURI); auto queryResult = execQuery(d->mInsertAlbumQuery); if (!queryResult || !d->mInsertAlbumQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertAlbum" << d->mInsertAlbumQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertAlbum" << d->mInsertAlbumQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertAlbum" << d->mInsertAlbumQuery.lastError(); d->mInsertAlbumQuery.finish(); return result; } result = d->mAlbumId; d->mInsertAlbumQuery.finish(); ++d->mAlbumId; d->mInsertedAlbums.insert(result); return result; } bool DatabaseInterface::updateAlbumFromId(qulonglong albumId, const QUrl &albumArtUri, const MusicAudioTrack ¤tTrack, const QString &albumPath) { auto modifiedAlbum = false; modifiedAlbum = true; if (!albumArtUri.isValid()) { return modifiedAlbum; } auto storedAlbumArtUri = internalAlbumArtUriFromAlbumId(albumId); if (!storedAlbumArtUri.isValid() || storedAlbumArtUri != albumArtUri) { d->mUpdateAlbumArtUriFromAlbumIdQuery.bindValue(QStringLiteral(":albumId"), albumId); d->mUpdateAlbumArtUriFromAlbumIdQuery.bindValue(QStringLiteral(":coverFileName"), albumArtUri); auto result = execQuery(d->mUpdateAlbumArtUriFromAlbumIdQuery); if (!result || !d->mUpdateAlbumArtUriFromAlbumIdQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::updateAlbumFromId" << d->mUpdateAlbumArtUriFromAlbumIdQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::updateAlbumFromId" << d->mUpdateAlbumArtUriFromAlbumIdQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::updateAlbumFromId" << d->mUpdateAlbumArtUriFromAlbumIdQuery.lastError(); d->mUpdateAlbumArtUriFromAlbumIdQuery.finish(); return modifiedAlbum; } d->mUpdateAlbumArtUriFromAlbumIdQuery.finish(); modifiedAlbum = true; } if (!isValidArtist(albumId) && currentTrack.isValidAlbumArtist()) { updateAlbumArtist(albumId, currentTrack.albumName(), albumPath, currentTrack.albumArtist()); modifiedAlbum = true; } return modifiedAlbum; } qulonglong DatabaseInterface::insertArtist(const QString &name) { auto result = qulonglong(0); if (name.isEmpty()) { return result; } d->mSelectArtistByNameQuery.bindValue(QStringLiteral(":name"), name); auto queryResult = execQuery(d->mSelectArtistByNameQuery); if (!queryResult || !d->mSelectArtistByNameQuery.isSelect() || !d->mSelectArtistByNameQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertArtist" << d->mSelectArtistByNameQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertArtist" << d->mSelectArtistByNameQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertArtist" << d->mSelectArtistByNameQuery.lastError(); d->mSelectArtistByNameQuery.finish(); return result; } if (d->mSelectArtistByNameQuery.next()) { result = d->mSelectArtistByNameQuery.record().value(0).toULongLong(); d->mSelectArtistByNameQuery.finish(); return result; } d->mSelectArtistByNameQuery.finish(); d->mInsertArtistsQuery.bindValue(QStringLiteral(":artistId"), d->mArtistId); d->mInsertArtistsQuery.bindValue(QStringLiteral(":name"), name); queryResult = execQuery(d->mInsertArtistsQuery); if (!queryResult || !d->mInsertArtistsQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertArtist" << d->mInsertArtistsQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertArtist" << d->mInsertArtistsQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertArtist" << d->mInsertArtistsQuery.lastError(); d->mInsertArtistsQuery.finish(); return result; } result = d->mArtistId; ++d->mArtistId; d->mInsertedArtists.insert(result); d->mInsertArtistsQuery.finish(); return result; } qulonglong DatabaseInterface::insertComposer(const QString &name) { auto result = qulonglong(0); if (name.isEmpty()) { return result; } d->mSelectComposerByNameQuery.bindValue(QStringLiteral(":name"), name); auto queryResult = execQuery(d->mSelectComposerByNameQuery); if (!queryResult || !d->mSelectComposerByNameQuery.isSelect() || !d->mSelectComposerByNameQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertComposer" << d->mSelectComposerByNameQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertComposer" << d->mSelectComposerByNameQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertComposer" << d->mSelectComposerByNameQuery.lastError(); d->mSelectComposerByNameQuery.finish(); return result; } if (d->mSelectComposerByNameQuery.next()) { result = d->mSelectComposerByNameQuery.record().value(0).toULongLong(); d->mSelectComposerByNameQuery.finish(); return result; } d->mSelectComposerByNameQuery.finish(); d->mInsertComposerQuery.bindValue(QStringLiteral(":composerId"), d->mComposerId); d->mInsertComposerQuery.bindValue(QStringLiteral(":name"), name); queryResult = execQuery(d->mInsertComposerQuery); if (!queryResult || !d->mInsertComposerQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertComposer" << d->mInsertComposerQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertComposer" << d->mInsertComposerQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertComposer" << d->mInsertComposerQuery.lastError(); d->mInsertComposerQuery.finish(); return result; } result = d->mComposerId; ++d->mComposerId; d->mInsertComposerQuery.finish(); Q_EMIT composersAdded(internalAllComposersPartialData()); return result; } qulonglong DatabaseInterface::insertGenre(const QString &name) { auto result = qulonglong(0); if (name.isEmpty()) { return result; } d->mSelectGenreByNameQuery.bindValue(QStringLiteral(":name"), name); auto queryResult = execQuery(d->mSelectGenreByNameQuery); if (!queryResult || !d->mSelectGenreByNameQuery.isSelect() || !d->mSelectGenreByNameQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertGenre" << d->mSelectGenreByNameQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertGenre" << d->mSelectGenreByNameQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertGenre" << d->mSelectGenreByNameQuery.lastError(); d->mSelectGenreByNameQuery.finish(); return result; } if (d->mSelectGenreByNameQuery.next()) { result = d->mSelectGenreByNameQuery.record().value(0).toULongLong(); d->mSelectGenreByNameQuery.finish(); return result; } d->mSelectGenreByNameQuery.finish(); d->mInsertGenreQuery.bindValue(QStringLiteral(":genreId"), d->mGenreId); d->mInsertGenreQuery.bindValue(QStringLiteral(":name"), name); queryResult = execQuery(d->mInsertGenreQuery); if (!queryResult || !d->mInsertGenreQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertGenre" << d->mInsertGenreQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertGenre" << d->mInsertGenreQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertGenre" << d->mInsertGenreQuery.lastError(); d->mInsertGenreQuery.finish(); return result; } result = d->mGenreId; ++d->mGenreId; d->mInsertGenreQuery.finish(); Q_EMIT genresAdded({{{DatabaseIdRole, result}}}); return result; } void DatabaseInterface::insertTrackOrigin(const QUrl &fileNameURI, const QDateTime &fileModifiedTime, const QDateTime &importDate) { d->mInsertTrackMapping.bindValue(QStringLiteral(":fileName"), fileNameURI); d->mInsertTrackMapping.bindValue(QStringLiteral(":priority"), 1); d->mInsertTrackMapping.bindValue(QStringLiteral(":mtime"), fileModifiedTime); d->mInsertTrackMapping.bindValue(QStringLiteral(":importDate"), importDate.toMSecsSinceEpoch()); auto queryResult = execQuery(d->mInsertTrackMapping); if (!queryResult || !d->mInsertTrackMapping.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertArtist" << d->mInsertTrackMapping.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertArtist" << d->mInsertTrackMapping.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertArtist" << d->mInsertTrackMapping.lastError(); d->mInsertTrackMapping.finish(); return; } d->mInsertTrackMapping.finish(); } void DatabaseInterface::updateTrackOrigin(const QUrl &fileName, const QDateTime &fileModifiedTime) { d->mUpdateTrackFileModifiedTime.bindValue(QStringLiteral(":fileName"), fileName); d->mUpdateTrackFileModifiedTime.bindValue(QStringLiteral(":mtime"), fileModifiedTime); auto queryResult = execQuery(d->mUpdateTrackFileModifiedTime); if (!queryResult || !d->mUpdateTrackFileModifiedTime.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::updateTrackOrigin" << d->mUpdateTrackFileModifiedTime.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::updateTrackOrigin" << d->mUpdateTrackFileModifiedTime.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::updateTrackOrigin" << d->mUpdateTrackFileModifiedTime.lastError(); d->mUpdateTrackFileModifiedTime.finish(); return; } d->mUpdateTrackFileModifiedTime.finish(); } qulonglong DatabaseInterface::internalInsertTrack(const MusicAudioTrack &oneTrack, const QHash &covers, bool &isInserted) { qulonglong resultId = 0; if (oneTrack.title().isEmpty()) { return resultId; } QUrl::FormattingOptions currentOptions = QUrl::PreferLocalFile | QUrl::RemoveAuthority | QUrl::RemoveFilename | QUrl::RemoveFragment | QUrl::RemovePassword | QUrl::RemovePort | QUrl::RemoveQuery | QUrl::RemoveScheme | QUrl::RemoveUserInfo; const auto &trackPath = oneTrack.resourceURI().toString(currentOptions); auto albumId = insertAlbum(oneTrack.albumName(), (oneTrack.isValidAlbumArtist() ? oneTrack.albumArtist() : QString()), oneTrack.artist(), trackPath, covers[oneTrack.resourceURI().toString()]); auto oldAlbumId = albumId; auto existingTrackId = internalTrackIdFromFileName(oneTrack.resourceURI()); bool isModifiedTrack = (existingTrackId != 0); if (isModifiedTrack) { resultId = existingTrackId; auto oldTrack = internalTrackFromDatabaseId(existingTrackId); oldAlbumId = oldTrack.albumId(); auto isSameTrack = true; isSameTrack = isSameTrack && (oldTrack.title() == oneTrack.title()); isSameTrack = isSameTrack && (oldTrack.albumName() == oneTrack.albumName()); isSameTrack = isSameTrack && (oldTrack.artist() == oneTrack.artist()); isSameTrack = isSameTrack && (oldTrack.albumArtist() == oneTrack.albumArtist()); isSameTrack = isSameTrack && (oldTrack.trackNumberIsValid() == oneTrack.trackNumberIsValid()); if (isSameTrack && oldTrack.trackNumberIsValid()) { isSameTrack = isSameTrack && (oldTrack.trackNumber() == oneTrack.trackNumber()); } isSameTrack = isSameTrack && (oldTrack.discNumberIsValid() == oneTrack.discNumberIsValid()); if (isSameTrack && oldTrack.discNumberIsValid()) { isSameTrack = isSameTrack && (oldTrack.discNumber() == oneTrack.discNumber()); } isSameTrack = isSameTrack && (oldTrack.duration() == oneTrack.duration()); isSameTrack = isSameTrack && (oldTrack.rating() == oneTrack.rating()); isSameTrack = isSameTrack && (oldTrack.resourceURI() == oneTrack.resourceURI()); isSameTrack = isSameTrack && (oldTrack.genre() == oneTrack.genre()); isSameTrack = isSameTrack && (oldTrack.composer() == oneTrack.composer()); isSameTrack = isSameTrack && (oldTrack.lyricist() == oneTrack.lyricist()); isSameTrack = isSameTrack && (oldTrack.comment() == oneTrack.comment()); isSameTrack = isSameTrack && (oldTrack.year() == oneTrack.year()); isSameTrack = isSameTrack && (oldTrack.channelsIsValid() == oneTrack.channelsIsValid()); if (isSameTrack && oldTrack.channelsIsValid()) { isSameTrack = isSameTrack && (oldTrack.channels() == oneTrack.channels()); } isSameTrack = isSameTrack && (oldTrack.bitRateIsValid() == oneTrack.bitRateIsValid()); if (isSameTrack && oldTrack.bitRateIsValid()) { isSameTrack = isSameTrack && (oldTrack.bitRate() == oneTrack.bitRate()); } isSameTrack = isSameTrack && (oldTrack.sampleRateIsValid() == oneTrack.sampleRateIsValid()); if (isSameTrack && oldTrack.sampleRateIsValid()) { isSameTrack = isSameTrack && (oldTrack.sampleRate() == oneTrack.sampleRate()); } if (isSameTrack) { return resultId; } auto newTrack = oneTrack; newTrack.setDatabaseId(resultId); updateTrackInDatabase(newTrack, trackPath); updateTrackOrigin(oneTrack.resourceURI(), oneTrack.fileModificationTime()); updateAlbumFromId(albumId, oneTrack.albumCover(), oneTrack, trackPath); recordModifiedTrack(existingTrackId); if (albumId != 0) { recordModifiedAlbum(albumId); } if (oldAlbumId != 0) { auto tracksCount = fetchTrackIds(oldAlbumId).count(); if (tracksCount) { recordModifiedAlbum(oldAlbumId); } else { removeAlbumInDatabase(oldAlbumId); Q_EMIT albumRemoved(oldAlbumId); } } isInserted = false; return resultId; } else { oldAlbumId = 0; existingTrackId = d->mTrackId; isInserted = true; } int priority = 1; while(true) { auto otherTrackId = getDuplicateTrackIdFromTitleAlbumTrackDiscNumber(oneTrack.title(), oneTrack.artist(), oneTrack.albumName(), oneTrack.albumArtist(), trackPath, priority); if (otherTrackId) { ++priority; } else { break; } } resultId = existingTrackId; const auto &albumData = internalOneAlbumPartialData(albumId); d->mInsertTrackQuery.bindValue(QStringLiteral(":trackId"), existingTrackId); d->mInsertTrackQuery.bindValue(QStringLiteral(":fileName"), oneTrack.resourceURI()); d->mInsertTrackQuery.bindValue(QStringLiteral(":priority"), priority); d->mInsertTrackQuery.bindValue(QStringLiteral(":title"), oneTrack.title()); insertArtist(oneTrack.artist()); d->mInsertTrackQuery.bindValue(QStringLiteral(":artistName"), oneTrack.artist()); d->mInsertTrackQuery.bindValue(QStringLiteral(":albumTitle"), albumData[AlbumDataType::key_type::TitleRole]); d->mInsertTrackQuery.bindValue(QStringLiteral(":albumArtistName"), albumData[AlbumDataType::key_type::ArtistRole]); d->mInsertTrackQuery.bindValue(QStringLiteral(":albumPath"), trackPath); if (oneTrack.trackNumberIsValid()) { d->mInsertTrackQuery.bindValue(QStringLiteral(":trackNumber"), oneTrack.trackNumber()); } if (oneTrack.discNumberIsValid()) { d->mInsertTrackQuery.bindValue(QStringLiteral(":discNumber"), oneTrack.discNumber()); } d->mInsertTrackQuery.bindValue(QStringLiteral(":trackDuration"), QVariant::fromValue(oneTrack.duration().msecsSinceStartOfDay())); d->mInsertTrackQuery.bindValue(QStringLiteral(":trackRating"), oneTrack.rating()); if (insertGenre(oneTrack.genre()) != 0) { d->mInsertTrackQuery.bindValue(QStringLiteral(":genre"), oneTrack.genre()); } else { d->mInsertTrackQuery.bindValue(QStringLiteral(":genre"), {}); } if (insertComposer(oneTrack.composer()) != 0) { d->mInsertTrackQuery.bindValue(QStringLiteral(":composer"), oneTrack.composer()); } else { d->mInsertTrackQuery.bindValue(QStringLiteral(":composer"), {}); } if (insertLyricist(oneTrack.lyricist()) != 0) { d->mInsertTrackQuery.bindValue(QStringLiteral(":lyricist"), oneTrack.lyricist()); } else { d->mInsertTrackQuery.bindValue(QStringLiteral(":lyricist"), {}); } d->mInsertTrackQuery.bindValue(QStringLiteral(":comment"), oneTrack.comment()); d->mInsertTrackQuery.bindValue(QStringLiteral(":year"), oneTrack.year()); if (oneTrack.channelsIsValid()) { d->mInsertTrackQuery.bindValue(QStringLiteral(":channels"), oneTrack.channels()); } if (oneTrack.bitRateIsValid()) { d->mInsertTrackQuery.bindValue(QStringLiteral(":bitRate"), oneTrack.bitRate()); } if (oneTrack.sampleRateIsValid()) { d->mInsertTrackQuery.bindValue(QStringLiteral(":sampleRate"), oneTrack.sampleRate()); } d->mInsertTrackQuery.bindValue(QStringLiteral(":hasEmbeddedCover"), oneTrack.hasEmbeddedCover()); auto result = execQuery(d->mInsertTrackQuery); if (result && d->mInsertTrackQuery.isActive()) { d->mInsertTrackQuery.finish(); if (!isModifiedTrack) { ++d->mTrackId; } updateTrackOrigin(oneTrack.resourceURI(), oneTrack.fileModificationTime()); if (isModifiedTrack) { recordModifiedTrack(existingTrackId); if (albumId != 0) { recordModifiedAlbum(albumId); } if (oldAlbumId != 0) { recordModifiedAlbum(oldAlbumId); } } if (albumId != 0) { if (updateAlbumFromId(albumId, covers[oneTrack.resourceURI().toString()], oneTrack, trackPath)) { auto modifiedTracks = fetchTrackIds(albumId); for (auto oneModifiedTrack : modifiedTracks) { if (oneModifiedTrack != resultId) { recordModifiedTrack(oneModifiedTrack); } } } recordModifiedAlbum(albumId); } } else { d->mInsertTrackQuery.finish(); Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::internalInsertTrack" << oneTrack << oneTrack.resourceURI(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::internalInsertTrack" << d->mInsertTrackQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::internalInsertTrack" << d->mInsertTrackQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::internalInsertTrack" << d->mInsertTrackQuery.lastError(); } return resultId; } MusicAudioTrack DatabaseInterface::buildTrackFromDatabaseRecord(const QSqlRecord &trackRecord) const { auto id = trackRecord.value(0).toULongLong(); auto result = MusicAudioTrack{}; if (result.isValid()) { return result; } result.setDatabaseId(id); result.setTitle(trackRecord.value(1).toString()); result.setParentId(trackRecord.value(2).toString()); result.setArtist(trackRecord.value(3).toString()); if (trackRecord.value(4).isValid()) { result.setAlbumArtist(trackRecord.value(4).toString()); } result.setResourceURI(trackRecord.value(5).toUrl()); result.setFileModificationTime(trackRecord.value(6).toDateTime()); if (trackRecord.value(7).isValid()) { result.setTrackNumber(trackRecord.value(7).toInt()); } if (trackRecord.value(8).isValid()) { result.setDiscNumber(trackRecord.value(8).toInt()); } result.setDuration(QTime::fromMSecsSinceStartOfDay(trackRecord.value(9).toInt())); result.setAlbumName(trackRecord.value(10).toString()); result.setRating(trackRecord.value(11).toInt()); result.setAlbumCover(trackRecord.value(12).toUrl()); result.setIsSingleDiscAlbum(trackRecord.value(13).toBool()); result.setGenre(trackRecord.value(14).toString()); result.setComposer(trackRecord.value(15).toString()); result.setLyricist(trackRecord.value(16).toString()); result.setComment(trackRecord.value(17).toString()); result.setYear(trackRecord.value(18).toInt()); if (trackRecord.value(19).isValid()) { bool isValid; auto value = trackRecord.value(19).toInt(&isValid); if (isValid) { result.setChannels(value); } } if (trackRecord.value(20).isValid()) { bool isValid; auto value = trackRecord.value(20).toInt(&isValid); if (isValid) { result.setBitRate(value); } } if (trackRecord.value(21).isValid()) { bool isValid; auto value = trackRecord.value(21).toInt(&isValid); if (isValid) { result.setSampleRate(value); } } result.setAlbumId(trackRecord.value(2).toULongLong()); result.setHasEmbeddedCover(trackRecord.value(22).toBool()); result.setValid(true); return result; } DatabaseInterface::TrackDataType DatabaseInterface::buildTrackDataFromDatabaseRecord(const QSqlRecord &trackRecord) const { TrackDataType result; result[TrackDataType::key_type::DatabaseIdRole] = trackRecord.value(0); result[TrackDataType::key_type::TitleRole] = trackRecord.value(1); if (!trackRecord.value(10).isNull()) { result[TrackDataType::key_type::AlbumRole] = trackRecord.value(10); result[TrackDataType::key_type::AlbumIdRole] = trackRecord.value(2); } if (!trackRecord.value(3).isNull()) { result[TrackDataType::key_type::ArtistRole] = trackRecord.value(3); } if (!trackRecord.value(4).isNull()) { result[TrackDataType::key_type::AlbumArtistRole] = trackRecord.value(4); } result[TrackDataType::key_type::ResourceRole] = trackRecord.value(5); if (!trackRecord.value(7).isNull()) { result[TrackDataType::key_type::TrackNumberRole] = trackRecord.value(7); } if (!trackRecord.value(8).isNull()) { result[TrackDataType::key_type::DiscNumberRole] = trackRecord.value(8); } result[TrackDataType::key_type::DurationRole] = QTime::fromMSecsSinceStartOfDay(trackRecord.value(9).toInt()); result[TrackDataType::key_type::MilliSecondsDurationRole] = trackRecord.value(9).toInt(); result[TrackDataType::key_type::RatingRole] = trackRecord.value(11); if (!trackRecord.value(12).isNull()) { result[TrackDataType::key_type::ImageUrlRole] = QUrl(trackRecord.value(12).toString()); } result[TrackDataType::key_type::IsSingleDiscAlbumRole] = trackRecord.value(13); if (!trackRecord.value(14).isNull()) { result[TrackDataType::key_type::GenreRole] = trackRecord.value(14); } if (!trackRecord.value(15).isNull()) { result[TrackDataType::key_type::ComposerRole] = trackRecord.value(15); } if (!trackRecord.value(16).isNull()) { result[TrackDataType::key_type::LyricistRole] = trackRecord.value(16); } result[TrackDataType::key_type::HasEmbeddedCover] = trackRecord.value(22); result[TrackDataType::key_type::FileModificationTime] = trackRecord.value(6); if (!trackRecord.value(24).isNull()) { result[TrackDataType::key_type::FirstPlayDate] = trackRecord.value(24); } if (!trackRecord.value(25).isNull()) { result[TrackDataType::key_type::LastPlayDate] = trackRecord.value(25); } result[TrackDataType::key_type::PlayCounter] = trackRecord.value(26); result[TrackDataType::key_type::PlayFrequency] = trackRecord.value(27); result[DataType::key_type::ElementTypeRole] = ElisaUtils::Track; return result; } void DatabaseInterface::internalRemoveTracksList(const QList &removedTracks) { QSet modifiedAlbums; QUrl::FormattingOptions currentOptions = QUrl::PreferLocalFile | QUrl::RemoveAuthority | QUrl::RemoveFilename | QUrl::RemoveFragment | QUrl::RemovePassword | QUrl::RemovePort | QUrl::RemoveQuery | QUrl::RemoveScheme | QUrl::RemoveUserInfo; for (const auto &removedTrackFileName : removedTracks) { auto removedTrackId = internalTrackIdFromFileName(removedTrackFileName); Q_EMIT trackRemoved(removedTrackId); auto oneRemovedTrack = internalTrackFromDatabaseId(removedTrackId); removeTrackInDatabase(removedTrackId); const auto &modifiedAlbumId = internalAlbumIdFromTitleAndArtist(oneRemovedTrack.albumName(), oneRemovedTrack.albumArtist()); const auto &allTracksFromArtist = internalTracksFromAuthor(oneRemovedTrack.artist()); const auto &allAlbumsFromArtist = internalAlbumIdsFromAuthor(oneRemovedTrack.artist()); const auto &removedArtistId = internalArtistIdFromName(oneRemovedTrack.artist()); const auto &trackPath = oneRemovedTrack.resourceURI().toString(currentOptions); if (modifiedAlbumId) { recordModifiedAlbum(modifiedAlbumId); modifiedAlbums.insert(modifiedAlbumId); updateAlbumFromId(modifiedAlbumId, oneRemovedTrack.albumCover(), oneRemovedTrack, trackPath); } if (removedArtistId != 0 && allTracksFromArtist.isEmpty() && allAlbumsFromArtist.isEmpty()) { removeArtistInDatabase(removedArtistId); Q_EMIT artistRemoved(removedArtistId); } d->mRemoveTracksMapping.bindValue(QStringLiteral(":fileName"), removedTrackFileName.toString()); auto result = execQuery(d->mRemoveTracksMapping); if (!result || !d->mRemoveTracksMapping.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::internalRemoveTracksList" << d->mRemoveTracksMapping.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::internalRemoveTracksList" << d->mRemoveTracksMapping.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::internalRemoveTracksList" << d->mRemoveTracksMapping.lastError(); continue; } d->mRemoveTracksMapping.finish(); } for (auto modifiedAlbumId : modifiedAlbums) { const auto &modifiedAlbumData = internalOneAlbumPartialData(modifiedAlbumId); auto tracksCount = fetchTrackIds(modifiedAlbumId).count(); if (!modifiedAlbumData.isEmpty() && tracksCount) { Q_EMIT albumModified({{DatabaseIdRole, modifiedAlbumId}}, modifiedAlbumId); } else { removeAlbumInDatabase(modifiedAlbumId); Q_EMIT albumRemoved(modifiedAlbumId); const auto &allTracksFromArtist = internalTracksFromAuthor(modifiedAlbumData[AlbumDataType::key_type::ArtistRole].toString()); const auto &allAlbumsFromArtist = internalAlbumIdsFromAuthor(modifiedAlbumData[AlbumDataType::key_type::ArtistRole].toString()); const auto &removedArtistId = internalArtistIdFromName(modifiedAlbumData[AlbumDataType::key_type::ArtistRole].toString()); if (removedArtistId != 0 && allTracksFromArtist.isEmpty() && allAlbumsFromArtist.isEmpty()) { removeArtistInDatabase(removedArtistId); Q_EMIT artistRemoved(removedArtistId); } } } } QUrl DatabaseInterface::internalAlbumArtUriFromAlbumId(qulonglong albumId) { auto result = QUrl(); d->mSelectAlbumArtUriFromAlbumIdQuery.bindValue(QStringLiteral(":albumId"), albumId); auto queryResult = execQuery(d->mSelectAlbumArtUriFromAlbumIdQuery); if (!queryResult || !d->mSelectAlbumArtUriFromAlbumIdQuery.isSelect() || !d->mSelectAlbumArtUriFromAlbumIdQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertArtist" << d->mSelectAlbumArtUriFromAlbumIdQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertArtist" << d->mSelectAlbumArtUriFromAlbumIdQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertArtist" << d->mSelectAlbumArtUriFromAlbumIdQuery.lastError(); d->mSelectAlbumArtUriFromAlbumIdQuery.finish(); return result; } if (!d->mSelectAlbumArtUriFromAlbumIdQuery.next()) { d->mSelectAlbumArtUriFromAlbumIdQuery.finish(); return result; } result = d->mSelectAlbumArtUriFromAlbumIdQuery.record().value(0).toUrl(); d->mSelectAlbumArtUriFromAlbumIdQuery.finish(); return result; } bool DatabaseInterface::isValidArtist(qulonglong albumId) { auto result = false; d->mSelectAlbumQuery.bindValue(QStringLiteral(":albumId"), albumId); auto queryResult = execQuery(d->mSelectAlbumQuery); if (!queryResult || !d->mSelectAlbumQuery.isSelect() || !d->mSelectAlbumQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::internalAlbumFromId" << d->mSelectAlbumQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::internalAlbumFromId" << d->mSelectAlbumQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::internalAlbumFromId" << d->mSelectAlbumQuery.lastError(); d->mSelectAlbumQuery.finish(); return result; } if (!d->mSelectAlbumQuery.next()) { d->mSelectAlbumQuery.finish(); return result; } const auto ¤tRecord = d->mSelectAlbumQuery.record(); result = !currentRecord.value(2).toString().isEmpty(); return result; } bool DatabaseInterface::internalGenericPartialData(QSqlQuery &query) { auto result = false; auto queryResult = execQuery(query); if (!queryResult || !query.isSelect() || !query.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::internalAllGenericPartialData" << query.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::internalAllGenericPartialData" << query.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::internalAllGenericPartialData" << query.lastError(); query.finish(); auto transactionResult = finishTransaction(); if (!transactionResult) { return result; } return result; } result = true; return result; } qulonglong DatabaseInterface::insertLyricist(const QString &name) { auto result = qulonglong(0); if (name.isEmpty()) { return result; } d->mSelectLyricistByNameQuery.bindValue(QStringLiteral(":name"), name); auto queryResult = execQuery(d->mSelectLyricistByNameQuery); if (!queryResult || !d->mSelectLyricistByNameQuery.isSelect() || !d->mSelectLyricistByNameQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertLyricist" << d->mSelectLyricistByNameQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertLyricist" << d->mSelectLyricistByNameQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertLyricist" << d->mSelectLyricistByNameQuery.lastError(); d->mSelectLyricistByNameQuery.finish(); return result; } if (d->mSelectLyricistByNameQuery.next()) { result = d->mSelectLyricistByNameQuery.record().value(0).toULongLong(); d->mSelectLyricistByNameQuery.finish(); return result; } d->mSelectLyricistByNameQuery.finish(); d->mInsertLyricistQuery.bindValue(QStringLiteral(":lyricistId"), d->mLyricistId); d->mInsertLyricistQuery.bindValue(QStringLiteral(":name"), name); queryResult = execQuery(d->mInsertLyricistQuery); if (!queryResult || !d->mInsertLyricistQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertLyricist" << d->mInsertLyricistQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertLyricist" << d->mInsertLyricistQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertLyricist" << d->mInsertLyricistQuery.lastError(); d->mInsertLyricistQuery.finish(); return result; } result = d->mLyricistId; ++d->mLyricistId; d->mInsertLyricistQuery.finish(); Q_EMIT lyricistsAdded(internalAllLyricistsPartialData()); return result; } QHash DatabaseInterface::internalAllFileName() { auto allFileNames = QHash{}; auto queryResult = execQuery(d->mSelectAllTrackFilesQuery); if (!queryResult || !d->mSelectAllTrackFilesQuery.isSelect() || !d->mSelectAllTrackFilesQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertMusicSource" << d->mSelectAllTrackFilesQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertMusicSource" << d->mSelectAllTrackFilesQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertMusicSource" << d->mSelectAllTrackFilesQuery.lastError(); d->mSelectAllTrackFilesQuery.finish(); return allFileNames; } while(d->mSelectAllTrackFilesQuery.next()) { auto fileName = d->mSelectAllTrackFilesQuery.record().value(0).toUrl(); auto fileModificationTime = d->mSelectAllTrackFilesQuery.record().value(1).toDateTime(); allFileNames[fileName] = fileModificationTime; } d->mSelectAllTrackFilesQuery.finish(); return allFileNames; } qulonglong DatabaseInterface::internalArtistIdFromName(const QString &name) { auto result = qulonglong(0); if (name.isEmpty()) { return result; } d->mSelectArtistByNameQuery.bindValue(QStringLiteral(":name"), name); auto queryResult = execQuery(d->mSelectArtistByNameQuery); if (!queryResult || !d->mSelectArtistByNameQuery.isSelect() || !d->mSelectArtistByNameQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertArtist" << d->mSelectArtistByNameQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertArtist" << d->mSelectArtistByNameQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertArtist" << d->mSelectArtistByNameQuery.lastError(); d->mSelectArtistByNameQuery.finish(); return result; } if (!d->mSelectArtistByNameQuery.next()) { d->mSelectArtistByNameQuery.finish(); return result; } result = d->mSelectArtistByNameQuery.record().value(0).toULongLong(); d->mSelectArtistByNameQuery.finish(); return result; } void DatabaseInterface::removeTrackInDatabase(qulonglong trackId) { d->mRemoveTrackQuery.bindValue(QStringLiteral(":trackId"), trackId); auto result = execQuery(d->mRemoveTrackQuery); if (!result || !d->mRemoveTrackQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::removeTrackInDatabase" << d->mRemoveTrackQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::removeTrackInDatabase" << d->mRemoveTrackQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::removeTrackInDatabase" << d->mRemoveTrackQuery.lastError(); } d->mRemoveTrackQuery.finish(); } void DatabaseInterface::updateTrackInDatabase(const MusicAudioTrack &oneTrack, const QString &albumPath) { d->mUpdateTrackQuery.bindValue(QStringLiteral(":fileName"), oneTrack.resourceURI()); d->mUpdateTrackQuery.bindValue(QStringLiteral(":trackId"), oneTrack.databaseId()); d->mUpdateTrackQuery.bindValue(QStringLiteral(":title"), oneTrack.title()); insertArtist(oneTrack.artist()); d->mUpdateTrackQuery.bindValue(QStringLiteral(":artistName"), oneTrack.artist()); d->mUpdateTrackQuery.bindValue(QStringLiteral(":albumTitle"), oneTrack.albumName()); if (oneTrack.isValidAlbumArtist()) { d->mUpdateTrackQuery.bindValue(QStringLiteral(":albumArtistName"), oneTrack.albumArtist()); } else { d->mUpdateTrackQuery.bindValue(QStringLiteral(":albumArtistName"), {}); } d->mUpdateTrackQuery.bindValue(QStringLiteral(":albumPath"), albumPath); if (oneTrack.trackNumberIsValid()) { d->mUpdateTrackQuery.bindValue(QStringLiteral(":trackNumber"), oneTrack.trackNumber()); } else { d->mUpdateTrackQuery.bindValue(QStringLiteral(":trackNumber"), {}); } if (oneTrack.discNumberIsValid()) { d->mUpdateTrackQuery.bindValue(QStringLiteral(":discNumber"), oneTrack.discNumber()); } else { d->mUpdateTrackQuery.bindValue(QStringLiteral(":discNumber"), {}); } d->mUpdateTrackQuery.bindValue(QStringLiteral(":trackDuration"), QVariant::fromValue(oneTrack.duration().msecsSinceStartOfDay())); d->mUpdateTrackQuery.bindValue(QStringLiteral(":trackRating"), oneTrack.rating()); if (insertGenre(oneTrack.genre()) != 0) { d->mUpdateTrackQuery.bindValue(QStringLiteral(":genre"), oneTrack.genre()); } else { d->mUpdateTrackQuery.bindValue(QStringLiteral(":genre"), {}); } if (insertComposer(oneTrack.composer()) != 0) { d->mUpdateTrackQuery.bindValue(QStringLiteral(":composer"), oneTrack.composer()); } else { d->mUpdateTrackQuery.bindValue(QStringLiteral(":composer"), {}); } if (insertLyricist(oneTrack.lyricist()) != 0) { d->mUpdateTrackQuery.bindValue(QStringLiteral(":lyricist"), oneTrack.lyricist()); } else { d->mUpdateTrackQuery.bindValue(QStringLiteral(":lyricist"), {}); } d->mUpdateTrackQuery.bindValue(QStringLiteral(":comment"), oneTrack.comment()); d->mUpdateTrackQuery.bindValue(QStringLiteral(":year"), oneTrack.year()); if (oneTrack.channelsIsValid()) { d->mUpdateTrackQuery.bindValue(QStringLiteral(":channels"), oneTrack.channels()); } else { d->mUpdateTrackQuery.bindValue(QStringLiteral(":channels"), {}); } if (oneTrack.bitRateIsValid()) { d->mUpdateTrackQuery.bindValue(QStringLiteral(":bitRate"), oneTrack.bitRate()); } else { d->mUpdateTrackQuery.bindValue(QStringLiteral(":bitRate"), {}); } if (oneTrack.sampleRateIsValid()) { d->mUpdateTrackQuery.bindValue(QStringLiteral(":sampleRate"), oneTrack.sampleRate()); } else { d->mUpdateTrackQuery.bindValue(QStringLiteral(":sampleRate"), {}); } auto result = execQuery(d->mUpdateTrackQuery); if (!result || !d->mUpdateTrackQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::updateTrackInDatabase" << d->mUpdateTrackQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::updateTrackInDatabase" << d->mUpdateTrackQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::updateTrackInDatabase" << d->mUpdateTrackQuery.lastError(); } d->mUpdateTrackQuery.finish(); } void DatabaseInterface::removeAlbumInDatabase(qulonglong albumId) { d->mRemoveAlbumQuery.bindValue(QStringLiteral(":albumId"), albumId); auto result = execQuery(d->mRemoveAlbumQuery); if (!result || !d->mRemoveAlbumQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::removeAlbumInDatabase" << d->mRemoveAlbumQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::removeAlbumInDatabase" << d->mRemoveAlbumQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::removeAlbumInDatabase" << d->mRemoveAlbumQuery.lastError(); } d->mRemoveAlbumQuery.finish(); } void DatabaseInterface::removeArtistInDatabase(qulonglong artistId) { d->mRemoveArtistQuery.bindValue(QStringLiteral(":artistId"), artistId); auto result = execQuery(d->mRemoveArtistQuery); if (!result || !d->mRemoveArtistQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::removeArtistInDatabase" << d->mRemoveArtistQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::removeArtistInDatabase" << d->mRemoveArtistQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::removeArtistInDatabase" << d->mRemoveArtistQuery.lastError(); } d->mRemoveArtistQuery.finish(); } void DatabaseInterface::reloadExistingDatabase() { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::reloadExistingDatabase"; d->mArtistId = initialId(DataUtils::DataType::AllArtists); d->mComposerId = initialId(DataUtils::DataType::AllComposers); d->mLyricistId = initialId(DataUtils::DataType::AllLyricists); d->mAlbumId = initialId(DataUtils::DataType::AllAlbums); d->mTrackId = initialId(DataUtils::DataType::AllTracks); d->mGenreId = initialId(DataUtils::DataType::AllGenres);; } qulonglong DatabaseInterface::initialId(DataUtils::DataType aType) { switch (aType) { case DataUtils::DataType::AllAlbums: return genericInitialId(d->mQueryMaximumAlbumIdQuery); case DataUtils::DataType::AllArtists: return genericInitialId(d->mQueryMaximumArtistIdQuery); case DataUtils::DataType::AllComposers: return genericInitialId(d->mQueryMaximumComposerIdQuery); case DataUtils::DataType::AllGenres: return genericInitialId(d->mQueryMaximumGenreIdQuery); case DataUtils::DataType::AllLyricists: return genericInitialId(d->mQueryMaximumLyricistIdQuery); case DataUtils::DataType::AllTracks: return genericInitialId(d->mQueryMaximumTrackIdQuery); case DataUtils::DataType::UnknownType: break; } return 1; } qulonglong DatabaseInterface::genericInitialId(QSqlQuery &request) { auto result = qulonglong(0); auto transactionResult = startTransaction(); if (!transactionResult) { return result; } auto queryResult = execQuery(request); if (!queryResult || !request.isSelect() || !request.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertMusicSource" << request.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertMusicSource" << request.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::insertMusicSource" << request.lastError(); request.finish(); transactionResult = finishTransaction(); if (!transactionResult) { return result; } return result; } if (request.next()) { result = request.record().value(0).toULongLong() + 1; request.finish(); } transactionResult = finishTransaction(); if (!transactionResult) { return result; } return result; } QList DatabaseInterface::fetchTrackIds(qulonglong albumId) { auto allTracks = QList(); d->mSelectTrackIdQuery.bindValue(QStringLiteral(":albumId"), albumId); auto result = execQuery(d->mSelectTrackIdQuery); if (!result || !d->mSelectTrackIdQuery.isSelect() || !d->mSelectTrackIdQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::fetchTrackIds" << d->mSelectTrackIdQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::fetchTrackIds" << d->mSelectTrackIdQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::fetchTrackIds" << d->mSelectTrackIdQuery.lastError(); } while (d->mSelectTrackIdQuery.next()) { const auto ¤tRecord = d->mSelectTrackIdQuery.record(); allTracks.push_back(currentRecord.value(0).toULongLong()); } d->mSelectTrackIdQuery.finish(); return allTracks; } qulonglong DatabaseInterface::internalAlbumIdFromTitleAndArtist(const QString &title, const QString &artist) { auto result = qulonglong(0); d->mSelectAlbumIdFromTitleQuery.bindValue(QStringLiteral(":title"), title); d->mSelectAlbumIdFromTitleQuery.bindValue(QStringLiteral(":artistName"), artist); auto queryResult = execQuery(d->mSelectAlbumIdFromTitleQuery); if (!queryResult || !d->mSelectAlbumIdFromTitleQuery.isSelect() || !d->mSelectAlbumIdFromTitleQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::internalAlbumIdFromTitleAndArtist" << d->mSelectAlbumIdFromTitleQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::internalAlbumIdFromTitleAndArtist" << d->mSelectAlbumIdFromTitleQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::internalAlbumIdFromTitleAndArtist" << d->mSelectAlbumIdFromTitleQuery.lastError(); d->mSelectAlbumIdFromTitleQuery.finish(); return result; } if (d->mSelectAlbumIdFromTitleQuery.next()) { result = d->mSelectAlbumIdFromTitleQuery.record().value(0).toULongLong(); } d->mSelectAlbumIdFromTitleQuery.finish(); if (result == 0) { d->mSelectAlbumIdFromTitleWithoutArtistQuery.bindValue(QStringLiteral(":title"), title); auto queryResult = execQuery(d->mSelectAlbumIdFromTitleWithoutArtistQuery); if (!queryResult || !d->mSelectAlbumIdFromTitleWithoutArtistQuery.isSelect() || !d->mSelectAlbumIdFromTitleWithoutArtistQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::internalAlbumIdFromTitleAndArtist" << d->mSelectAlbumIdFromTitleWithoutArtistQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::internalAlbumIdFromTitleAndArtist" << d->mSelectAlbumIdFromTitleWithoutArtistQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::internalAlbumIdFromTitleAndArtist" << d->mSelectAlbumIdFromTitleWithoutArtistQuery.lastError(); d->mSelectAlbumIdFromTitleWithoutArtistQuery.finish(); return result; } if (d->mSelectAlbumIdFromTitleWithoutArtistQuery.next()) { result = d->mSelectAlbumIdFromTitleWithoutArtistQuery.record().value(0).toULongLong(); } d->mSelectAlbumIdFromTitleWithoutArtistQuery.finish(); } return result; } MusicAudioTrack DatabaseInterface::internalTrackFromDatabaseId(qulonglong id) { auto result = MusicAudioTrack(); if (result.isValid()) { return result; } if (!d || !d->mTracksDatabase.isValid() || !d->mInitFinished) { return result; } d->mSelectTrackFromIdQuery.bindValue(QStringLiteral(":trackId"), id); auto queryResult = execQuery(d->mSelectTrackFromIdQuery); if (!queryResult || !d->mSelectTrackFromIdQuery.isSelect() || !d->mSelectTrackFromIdQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::internalTrackFromDatabaseId" << d->mSelectTrackFromIdQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::internalTrackFromDatabaseId" << d->mSelectTrackFromIdQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::internalTrackFromDatabaseId" << d->mSelectTrackFromIdQuery.lastError(); d->mSelectTrackFromIdQuery.finish(); return result; } if (!d->mSelectTrackFromIdQuery.next()) { d->mSelectTrackFromIdQuery.finish(); return result; } const auto ¤tRecord = d->mSelectTrackFromIdQuery.record(); result = buildTrackFromDatabaseRecord(currentRecord); d->mSelectTrackFromIdQuery.finish(); return result; } qulonglong DatabaseInterface::internalTrackIdFromTitleAlbumTracDiscNumber(const QString &title, const QString &artist, const QString &album, int trackNumber, int discNumber) { auto result = qulonglong(0); if (!d) { return result; } 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); auto queryResult = execQuery(d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery); if (!queryResult || !d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery.isSelect() || !d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::trackIdFromTitleAlbumArtist" << d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::trackIdFromTitleAlbumArtist" << d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::trackIdFromTitleAlbumArtist" << d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery.lastError(); d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery.finish(); return result; } if (d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery.next()) { result = d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery.record().value(0).toULongLong(); } d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery.finish(); return result; } qulonglong DatabaseInterface::getDuplicateTrackIdFromTitleAlbumTrackDiscNumber(const QString &title, const QString &trackArtist, const QString &album, const QString &albumArtist, const QString &trackPath, int priority) { auto result = qulonglong(0); if (!d) { return result; } d->mSelectTrackIdFromTitleAlbumTrackDiscNumberQuery.bindValue(QStringLiteral(":title"), title); d->mSelectTrackIdFromTitleAlbumTrackDiscNumberQuery.bindValue(QStringLiteral(":trackArtist"), trackArtist); d->mSelectTrackIdFromTitleAlbumTrackDiscNumberQuery.bindValue(QStringLiteral(":album"), album); d->mSelectTrackIdFromTitleAlbumTrackDiscNumberQuery.bindValue(QStringLiteral(":albumPath"), trackPath); d->mSelectTrackIdFromTitleAlbumTrackDiscNumberQuery.bindValue(QStringLiteral(":albumArtist"), albumArtist); d->mSelectTrackIdFromTitleAlbumTrackDiscNumberQuery.bindValue(QStringLiteral(":priority"), priority); auto queryResult = execQuery(d->mSelectTrackIdFromTitleAlbumTrackDiscNumberQuery); if (!queryResult || !d->mSelectTrackIdFromTitleAlbumTrackDiscNumberQuery.isSelect() || !d->mSelectTrackIdFromTitleAlbumTrackDiscNumberQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::trackIdFromTitleAlbumArtist" << d->mSelectTrackIdFromTitleAlbumTrackDiscNumberQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::trackIdFromTitleAlbumArtist" << d->mSelectTrackIdFromTitleAlbumTrackDiscNumberQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::trackIdFromTitleAlbumArtist" << d->mSelectTrackIdFromTitleAlbumTrackDiscNumberQuery.lastError(); d->mSelectTrackIdFromTitleAlbumTrackDiscNumberQuery.finish(); return result; } if (d->mSelectTrackIdFromTitleAlbumTrackDiscNumberQuery.next()) { result = d->mSelectTrackIdFromTitleAlbumTrackDiscNumberQuery.record().value(0).toULongLong(); } d->mSelectTrackIdFromTitleAlbumTrackDiscNumberQuery.finish(); return result; } qulonglong DatabaseInterface::internalTrackIdFromFileName(const QUrl &fileName) { auto result = qulonglong(0); if (!d) { return result; } d->mSelectTracksMapping.bindValue(QStringLiteral(":fileName"), fileName.toString()); auto queryResult = execQuery(d->mSelectTracksMapping); if (!queryResult || !d->mSelectTracksMapping.isSelect() || !d->mSelectTracksMapping.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::internalTrackIdFromFileName" << d->mSelectTracksMapping.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::internalTrackIdFromFileName" << d->mSelectTracksMapping.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::internalTrackIdFromFileName" << d->mSelectTracksMapping.lastError(); d->mSelectTracksMapping.finish(); return result; } if (d->mSelectTracksMapping.next()) { const auto ¤tRecordValue = d->mSelectTracksMapping.record().value(0); if (currentRecordValue.isValid()) { result = currentRecordValue.toULongLong(); } } d->mSelectTracksMapping.finish(); return result; } DatabaseInterface::ListTrackDataType DatabaseInterface::internalTracksFromAuthor(const QString &ArtistName) { auto allTracks = ListTrackDataType{}; d->mSelectTracksFromArtist.bindValue(QStringLiteral(":artistName"), ArtistName); auto result = execQuery(d->mSelectTracksFromArtist); if (!result || !d->mSelectTracksFromArtist.isSelect() || !d->mSelectTracksFromArtist.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::tracksFromAuthor" << d->mSelectTracksFromArtist.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::tracksFromAuthor" << d->mSelectTracksFromArtist.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::tracksFromAuthor" << d->mSelectTracksFromArtist.lastError(); return allTracks; } while (d->mSelectTracksFromArtist.next()) { const auto ¤tRecord = d->mSelectTracksFromArtist.record(); allTracks.push_back(buildTrackDataFromDatabaseRecord(currentRecord)); } d->mSelectTracksFromArtist.finish(); return allTracks; } QList DatabaseInterface::internalAlbumIdsFromAuthor(const QString &ArtistName) { auto allAlbumIds = QList(); d->mSelectAlbumIdsFromArtist.bindValue(QStringLiteral(":artistName"), ArtistName); auto result = execQuery(d->mSelectAlbumIdsFromArtist); if (!result || !d->mSelectAlbumIdsFromArtist.isSelect() || !d->mSelectAlbumIdsFromArtist.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::tracksFromAuthor" << d->mSelectAlbumIdsFromArtist.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::tracksFromAuthor" << d->mSelectAlbumIdsFromArtist.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::tracksFromAuthor" << d->mSelectAlbumIdsFromArtist.lastError(); return allAlbumIds; } while (d->mSelectAlbumIdsFromArtist.next()) { const auto ¤tRecord = d->mSelectAlbumIdsFromArtist.record(); allAlbumIds.push_back(currentRecord.value(0).toULongLong()); } d->mSelectAlbumIdsFromArtist.finish(); return allAlbumIds; } DatabaseInterface::ListArtistDataType DatabaseInterface::internalAllArtistsPartialData(QSqlQuery &artistsQuery) { auto result = ListArtistDataType{}; if (!internalGenericPartialData(artistsQuery)) { return result; } while(artistsQuery.next()) { auto newData = ArtistDataType{}; const auto ¤tRecord = artistsQuery.record(); newData[DataType::key_type::DatabaseIdRole] = currentRecord.value(0); newData[DataType::key_type::TitleRole] = currentRecord.value(1); newData[DataType::key_type::GenreRole] = QVariant::fromValue(currentRecord.value(2).toString().split(QStringLiteral(", "))); newData[DataType::key_type::ElementTypeRole] = ElisaUtils::Artist; result.push_back(newData); } artistsQuery.finish(); return result; } DatabaseInterface::ListAlbumDataType DatabaseInterface::internalAllAlbumsPartialData(QSqlQuery &query) { auto result = ListAlbumDataType{}; if (!internalGenericPartialData(query)) { return result; } while(query.next()) { auto newData = AlbumDataType{}; const auto ¤tRecord = query.record(); newData[DataType::key_type::DatabaseIdRole] = currentRecord.value(0); newData[DataType::key_type::TitleRole] = currentRecord.value(1); newData[DataType::key_type::SecondaryTextRole] = currentRecord.value(2); newData[DataType::key_type::ImageUrlRole] = currentRecord.value(3); newData[DataType::key_type::ArtistRole] = currentRecord.value(4); newData[DataType::key_type::AllArtistsRole] = QVariant::fromValue(currentRecord.value(5).toString().split(QStringLiteral(", "))); newData[DataType::key_type::HighestTrackRating] = currentRecord.value(6); newData[DataType::key_type::IsSingleDiscAlbumRole] = currentRecord.value(8); newData[DataType::key_type::GenreRole] = QVariant::fromValue(currentRecord.value(7).toString().split(QStringLiteral(", "))); newData[DataType::key_type::ElementTypeRole] = ElisaUtils::Album; result.push_back(newData); } query.finish(); return result; } DatabaseInterface::AlbumDataType DatabaseInterface::internalOneAlbumPartialData(qulonglong databaseId) { auto result = AlbumDataType{}; d->mSelectAlbumQuery.bindValue(QStringLiteral(":albumId"), databaseId); if (!internalGenericPartialData(d->mSelectAlbumQuery)) { return result; } if (d->mSelectAlbumQuery.next()) { const auto ¤tRecord = d->mSelectAlbumQuery.record(); result[DataType::key_type::DatabaseIdRole] = currentRecord.value(0); result[DataType::key_type::TitleRole] = currentRecord.value(1); result[DataType::key_type::SecondaryTextRole] = currentRecord.value(2); result[DataType::key_type::ImageUrlRole] = currentRecord.value(4); result[DataType::key_type::ArtistRole] = currentRecord.value(2); result[DataType::key_type::AllArtistsRole] = QVariant::fromValue(currentRecord.value(7).toString().split(QStringLiteral(", "))); result[DataType::key_type::HighestTrackRating] = currentRecord.value(8); result[DataType::key_type::IsSingleDiscAlbumRole] = currentRecord.value(6); result[DataType::key_type::GenreRole] = QVariant::fromValue(currentRecord.value(9).toString().split(QStringLiteral(", "))); result[DataType::key_type::ElementTypeRole] = ElisaUtils::Album; } d->mSelectAlbumQuery.finish(); return result; } DatabaseInterface::ListTrackDataType DatabaseInterface::internalAllTracksPartialData() { auto result = ListTrackDataType{}; if (!internalGenericPartialData(d->mSelectAllTracksQuery)) { return result; } while(d->mSelectAllTracksQuery.next()) { const auto ¤tRecord = d->mSelectAllTracksQuery.record(); auto newData = buildTrackDataFromDatabaseRecord(currentRecord); result.push_back(newData); } d->mSelectAllTracksQuery.finish(); return result; } DatabaseInterface::ListTrackDataType DatabaseInterface::internalRecentlyPlayedTracksData(int count) { auto result = ListTrackDataType{}; d->mSelectAllRecentlyPlayedTracksQuery.bindValue(QStringLiteral(":maximumResults"), count); if (!internalGenericPartialData(d->mSelectAllRecentlyPlayedTracksQuery)) { return result; } while(d->mSelectAllRecentlyPlayedTracksQuery.next()) { const auto ¤tRecord = d->mSelectAllRecentlyPlayedTracksQuery.record(); auto newData = buildTrackDataFromDatabaseRecord(currentRecord); result.push_back(newData); } d->mSelectAllRecentlyPlayedTracksQuery.finish(); return result; } DatabaseInterface::ListTrackDataType DatabaseInterface::internalFrequentlyPlayedTracksData(int count) { auto result = ListTrackDataType{}; d->mSelectAllFrequentlyPlayedTracksQuery.bindValue(QStringLiteral(":maximumResults"), count); if (!internalGenericPartialData(d->mSelectAllFrequentlyPlayedTracksQuery)) { return result; } while(d->mSelectAllFrequentlyPlayedTracksQuery.next()) { const auto ¤tRecord = d->mSelectAllFrequentlyPlayedTracksQuery.record(); auto newData = buildTrackDataFromDatabaseRecord(currentRecord); result.push_back(newData); } d->mSelectAllFrequentlyPlayedTracksQuery.finish(); return result; } DatabaseInterface::TrackDataType DatabaseInterface::internalOneTrackPartialData(qulonglong databaseId) { auto result = TrackDataType{}; d->mSelectTrackFromIdQuery.bindValue(QStringLiteral(":trackId"), databaseId); if (!internalGenericPartialData(d->mSelectTrackFromIdQuery)) { return result; } if (d->mSelectTrackFromIdQuery.next()) { const auto ¤tRecord = d->mSelectTrackFromIdQuery.record(); result = buildTrackDataFromDatabaseRecord(currentRecord); } d->mSelectTrackFromIdQuery.finish(); return result; } DatabaseInterface::ListGenreDataType DatabaseInterface::internalAllGenresPartialData() { ListGenreDataType result; if (!internalGenericPartialData(d->mSelectAllGenresQuery)) { return result; } while(d->mSelectAllGenresQuery.next()) { auto newData = GenreDataType{}; const auto ¤tRecord = d->mSelectAllGenresQuery.record(); newData[DataType::key_type::DatabaseIdRole] = currentRecord.value(0); newData[DataType::key_type::TitleRole] = currentRecord.value(1); newData[DataType::key_type::ElementTypeRole] = ElisaUtils::Genre; result.push_back(newData); } d->mSelectAllGenresQuery.finish(); return result; } DatabaseInterface::ListArtistDataType DatabaseInterface::internalAllComposersPartialData() { ListArtistDataType result; if (!internalGenericPartialData(d->mSelectAllComposersQuery)) { return result; } while(d->mSelectAllComposersQuery.next()) { auto newData = ArtistDataType{}; const auto ¤tRecord = d->mSelectAllComposersQuery.record(); newData[DataType::key_type::DatabaseIdRole] = currentRecord.value(0); newData[DataType::key_type::TitleRole] = currentRecord.value(1); newData[DataType::key_type::ElementTypeRole] = ElisaUtils::Composer; result.push_back(newData); } d->mSelectAllComposersQuery.finish(); return result; } DatabaseInterface::ListArtistDataType DatabaseInterface::internalAllLyricistsPartialData() { ListArtistDataType result; if (!internalGenericPartialData(d->mSelectAllLyricistsQuery)) { return result; } while(d->mSelectAllLyricistsQuery.next()) { auto newData = ArtistDataType{}; const auto ¤tRecord = d->mSelectAllLyricistsQuery.record(); newData[DataType::key_type::DatabaseIdRole] = currentRecord.value(0); newData[DataType::key_type::TitleRole] = currentRecord.value(1); newData[DataType::key_type::ElementTypeRole] = ElisaUtils::Lyricist; result.push_back(newData); } d->mSelectAllLyricistsQuery.finish(); return result; } bool DatabaseInterface::prepareQuery(QSqlQuery &query, const QString &queryText) const { query.setForwardOnly(true); return query.prepare(queryText); } bool DatabaseInterface::execQuery(QSqlQuery &query) { #if !defined NDEBUG auto timer = QElapsedTimer{}; timer.start(); #endif auto result = query.exec(); #if !defined NDEBUG if (timer.nsecsElapsed() > 10000000) { qCDebug(orgKdeElisaDatabase) << "[[" << timer.nsecsElapsed() << "]]" << query.lastQuery(); } #endif return result; } void DatabaseInterface::updateAlbumArtist(qulonglong albumId, const QString &title, const QString &albumPath, const QString &artistName) { d->mUpdateAlbumArtistQuery.bindValue(QStringLiteral(":albumId"), albumId); insertArtist(artistName); d->mUpdateAlbumArtistQuery.bindValue(QStringLiteral(":artistName"), artistName); auto queryResult = execQuery(d->mUpdateAlbumArtistQuery); if (!queryResult || !d->mUpdateAlbumArtistQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::updateAlbumArtist" << d->mUpdateAlbumArtistQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::updateAlbumArtist" << d->mUpdateAlbumArtistQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::updateAlbumArtist" << d->mUpdateAlbumArtistQuery.lastError(); d->mUpdateAlbumArtistQuery.finish(); return; } d->mUpdateAlbumArtistQuery.finish(); d->mUpdateAlbumArtistInTracksQuery.bindValue(QStringLiteral(":albumTitle"), title); d->mUpdateAlbumArtistInTracksQuery.bindValue(QStringLiteral(":albumPath"), albumPath); d->mUpdateAlbumArtistInTracksQuery.bindValue(QStringLiteral(":artistName"), artistName); queryResult = execQuery(d->mUpdateAlbumArtistInTracksQuery); if (!queryResult || !d->mUpdateAlbumArtistInTracksQuery.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::updateAlbumArtist" << d->mUpdateAlbumArtistInTracksQuery.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::updateAlbumArtist" << d->mUpdateAlbumArtistInTracksQuery.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::updateAlbumArtist" << d->mUpdateAlbumArtistInTracksQuery.lastError(); d->mUpdateAlbumArtistInTracksQuery.finish(); return; } d->mUpdateAlbumArtistInTracksQuery.finish(); } void DatabaseInterface::updateTrackStatistics(const QUrl &fileName, const QDateTime &time) { d->mUpdateTrackStatistics.bindValue(QStringLiteral(":fileName"), fileName); d->mUpdateTrackStatistics.bindValue(QStringLiteral(":playDate"), time.toMSecsSinceEpoch()); auto queryResult = execQuery(d->mUpdateTrackStatistics); if (!queryResult || !d->mUpdateTrackStatistics.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::updateTrackStatistics" << d->mUpdateTrackStatistics.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::updateTrackStatistics" << d->mUpdateTrackStatistics.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::updateTrackStatistics" << d->mUpdateTrackStatistics.lastError(); d->mUpdateTrackStatistics.finish(); return; } d->mUpdateTrackStatistics.finish(); d->mUpdateTrackFirstPlayStatistics.bindValue(QStringLiteral(":fileName"), fileName); d->mUpdateTrackFirstPlayStatistics.bindValue(QStringLiteral(":playDate"), time.toMSecsSinceEpoch()); queryResult = execQuery(d->mUpdateTrackFirstPlayStatistics); if (!queryResult || !d->mUpdateTrackFirstPlayStatistics.isActive()) { Q_EMIT databaseError(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::updateTrackStatistics" << d->mUpdateTrackFirstPlayStatistics.lastQuery(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::updateTrackStatistics" << d->mUpdateTrackFirstPlayStatistics.boundValues(); qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::updateTrackStatistics" << d->mUpdateTrackFirstPlayStatistics.lastError(); d->mUpdateTrackFirstPlayStatistics.finish(); return; } d->mUpdateTrackFirstPlayStatistics.finish(); } #include "moc_databaseinterface.cpp" diff --git a/src/databaseinterface.h b/src/databaseinterface.h index b166c25b..42e1a522 100644 --- a/src/databaseinterface.h +++ b/src/databaseinterface.h @@ -1,584 +1,590 @@ /* * Copyright 2016-2017 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef DATABASEINTERFACE_H #define DATABASEINTERFACE_H #include "elisaLib_export.h" #include "datatype.h" #include "elisautils.h" #include #include #include #include #include #include #include #include #include class DatabaseInterfacePrivate; class QMutex; class QSqlRecord; class QSqlQuery; class MusicAudioTrack; class ELISALIB_EXPORT DatabaseInterface : public QObject { Q_OBJECT public: enum ColumnsRoles { TitleRole = Qt::UserRole + 1, SecondaryTextRole, ImageUrlRole, ShadowForImageRole, ChildModelRole, DurationRole, StringDurationRole, MilliSecondsDurationRole, ArtistRole, AllArtistsRole, HighestTrackRating, AlbumRole, AlbumArtistRole, TrackNumberRole, DiscNumberRole, RatingRole, GenreRole, LyricistRole, ComposerRole, CommentRole, YearRole, ChannelsRole, BitRateRole, SampleRateRole, ResourceRole, IdRole, DatabaseIdRole, IsSingleDiscAlbumRole, ContainerDataRole, IsPartialDataRole, AlbumIdRole, HasEmbeddedCover, FileModificationTime, FirstPlayDate, LastPlayDate, PlayCounter, PlayFrequency, ElementTypeRole, + LyricsRole, }; Q_ENUM(ColumnsRoles) private: using DataType = QMap; public: class TrackDataType : public DataType { public: using DataType::DataType; bool isValid() const { return !isEmpty(); } qulonglong databaseId() const { return operator[](key_type::DatabaseIdRole).toULongLong(); } QString title() const { return operator[](key_type::TitleRole).toString(); } QString artist() const { return operator[](key_type::ArtistRole).toString(); } qulonglong albumId() const { return operator[](key_type::AlbumIdRole).toULongLong(); } QString album() const { return operator[](key_type::AlbumRole).toString(); } QString albumArtist() const { return operator[](key_type::AlbumArtistRole).toString(); } int trackNumber() const { return operator[](key_type::TrackNumberRole).toInt(); } int discNumber() const { return operator[](key_type::DiscNumberRole).toInt(); } QTime duration() const { return operator[](key_type::DurationRole).toTime(); } QUrl resourceURI() const { return operator[](key_type::ResourceRole).toUrl(); } QUrl albumCover() const { return operator[](key_type::ImageUrlRole).toUrl(); } bool isSingleDiscAlbum() const { return operator[](key_type::IsSingleDiscAlbumRole).toBool(); } int rating() const { return operator[](key_type::RatingRole).toInt(); } QString genre() const { return operator[](key_type::GenreRole).toString(); } QString composer() const { return operator[](key_type::ComposerRole).toString(); } QString lyricist() const { return operator[](key_type::LyricistRole).toString(); } + QString lyrics() const + { + return operator[](key_type::LyricsRole).toString(); + } + QString comment() const { return operator[](key_type::CommentRole).toString(); } int year() const { return operator[](key_type::YearRole).toInt(); } int channels() const { return operator[](key_type::ChannelsRole).toInt(); } int bitRate() const { return operator[](key_type::BitRateRole).toInt(); } int sampleRate() const { return operator[](key_type::SampleRateRole).toInt(); } bool hasEmbeddedCover() const { return operator[](key_type::HasEmbeddedCover).toBool(); } QDateTime fileModificationTime() const { return operator[](key_type::FileModificationTime).toDateTime(); } }; using ListTrackDataType = QList; class AlbumDataType : public DataType { public: using DataType::DataType; qulonglong databaseId() const { return operator[](key_type::DatabaseIdRole).toULongLong(); } QString title() const { return operator[](key_type::TitleRole).toString(); } QString artist() const { return operator[](key_type::ArtistRole).toString(); } bool isValidArtist() const { const auto &artistData = operator[](key_type::ArtistRole); return artistData.isValid() && !artistData.toString().isEmpty(); } QStringList genres() const { return operator[](key_type::GenreRole).toStringList(); } QUrl albumArtURI() const { return operator[](key_type::ImageUrlRole).toUrl(); } bool isSingleDiscAlbum() const { return operator[](key_type::IsSingleDiscAlbumRole).toBool(); } bool isValid() const { return !isEmpty(); } }; using ListAlbumDataType = QList; class ArtistDataType : public DataType { public: using DataType::DataType; qulonglong databaseId() const { return operator[](key_type::DatabaseIdRole).toULongLong(); } }; using ListArtistDataType = QList; class GenreDataType : public DataType { public: using DataType::DataType; qulonglong databaseId() const { return operator[](key_type::DatabaseIdRole).toULongLong(); } QString title() const { return operator[](key_type::TitleRole).toString(); } }; using ListGenreDataType = QList; enum PropertyType { DatabaseId, DisplayRole, SecondaryRole, }; Q_ENUM(PropertyType) enum AlbumDiscsCount { SingleDiscAlbum, MultipleDiscsAlbum, }; Q_ENUM(AlbumDiscsCount) explicit DatabaseInterface(QObject *parent = nullptr); ~DatabaseInterface() override; Q_INVOKABLE void init(const QString &dbName, const QString &databaseFileName = {}); qulonglong albumIdFromTitleAndArtist(const QString &title, const QString &artist); ListTrackDataType allTracksData(); ListTrackDataType recentlyPlayedTracksData(int count); ListTrackDataType frequentlyPlayedTracksData(int count); ListAlbumDataType allAlbumsData(); ListAlbumDataType allAlbumsDataByGenreAndArtist(const QString &genre, const QString &artist); ListAlbumDataType allAlbumsDataByArtist(const QString &artist); AlbumDataType albumDataFromDatabaseId(qulonglong id); ListTrackDataType albumData(qulonglong databaseId); ListArtistDataType allArtistsData(); ListArtistDataType allArtistsDataByGenre(const QString &genre); ListGenreDataType allGenresData(); bool internalArtistMatchGenre(qulonglong databaseId, const QString &genre); ListTrackDataType tracksDataFromAuthor(const QString &artistName); TrackDataType trackDataFromDatabaseId(qulonglong id); qulonglong trackIdFromTitleAlbumTrackDiscNumber(const QString &title, const QString &artist, const QString &album, int trackNumber, int discNumber); qulonglong trackIdFromFileName(const QUrl &fileName); void applicationAboutToQuit(); Q_SIGNALS: void artistsAdded(const DatabaseInterface::ListArtistDataType &newArtists); void composersAdded(const DatabaseInterface::ListArtistDataType &newComposers); void lyricistsAdded(const DatabaseInterface::ListArtistDataType &newLyricists); void albumsAdded(const DatabaseInterface::ListAlbumDataType &newAlbums); void tracksAdded(const DatabaseInterface::ListTrackDataType &allTracks); void genresAdded(const DatabaseInterface::ListGenreDataType &allGenres); void artistRemoved(qulonglong removedArtistId); void albumRemoved(qulonglong removedAlbumId); void trackRemoved(qulonglong id); void albumModified(const DatabaseInterface::AlbumDataType &modifiedAlbum, qulonglong modifiedAlbumId); void trackModified(const DatabaseInterface::TrackDataType &modifiedTrack); void requestsInitDone(); void databaseError(); void restoredTracks(QHash allFiles); void cleanedDatabase(); void finishInsertingTracksList(); void finishRemovingTracksList(); public Q_SLOTS: void insertTracksList(const QList &tracks, const QHash &covers); void removeTracksList(const QList &removedTracks); void askRestoredTracks(); void trackHasStartedPlaying(const QUrl &fileName, const QDateTime &time); void clearData(); private: enum class TrackFileInsertType { NewTrackFileInsert, ModifiedTrackFileInsert, }; void initChangesTrackers(); void recordModifiedTrack(qulonglong trackId); void recordModifiedAlbum(qulonglong albumId); bool startTransaction() const; bool finishTransaction() const; bool rollBackTransaction() const; QList fetchTrackIds(qulonglong albumId); qulonglong internalAlbumIdFromTitleAndArtist(const QString &title, const QString &artist); MusicAudioTrack internalTrackFromDatabaseId(qulonglong id); qulonglong internalTrackIdFromTitleAlbumTracDiscNumber(const QString &title, const QString &artist, const QString &album, int trackNumber, int discNumber); qulonglong getDuplicateTrackIdFromTitleAlbumTrackDiscNumber(const QString &title, const QString &trackArtist, const QString &album, const QString &albumArtist, const QString &trackPath, int priority); qulonglong internalTrackIdFromFileName(const QUrl &fileName); ListTrackDataType internalTracksFromAuthor(const QString &artistName); QList internalAlbumIdsFromAuthor(const QString &artistName); void initDatabase(); void initRequest(); qulonglong insertAlbum(const QString &title, const QString &albumArtist, const QString &trackArtist, const QString &trackPath, const QUrl &albumArtURI); bool updateAlbumFromId(qulonglong albumId, const QUrl &albumArtUri, const MusicAudioTrack ¤tTrack, const QString &albumPath); qulonglong insertArtist(const QString &name); qulonglong internalArtistIdFromName(const QString &name); qulonglong insertGenre(const QString &name); void removeTrackInDatabase(qulonglong trackId); void updateTrackInDatabase(const MusicAudioTrack &oneTrack, const QString &albumPath); void removeAlbumInDatabase(qulonglong albumId); void removeArtistInDatabase(qulonglong artistId); void reloadExistingDatabase(); qulonglong initialId(DataUtils::DataType aType); qulonglong genericInitialId(QSqlQuery &request); void insertTrackOrigin(const QUrl &fileNameURI, const QDateTime &fileModifiedTime, const QDateTime &importDate); void updateTrackOrigin(const QUrl &fileName, const QDateTime &fileModifiedTime); qulonglong internalInsertTrack(const MusicAudioTrack &oneModifiedTrack, const QHash &covers, bool &isInserted); MusicAudioTrack buildTrackFromDatabaseRecord(const QSqlRecord &trackRecord) const; TrackDataType buildTrackDataFromDatabaseRecord(const QSqlRecord &trackRecord) const; void internalRemoveTracksList(const QList &removedTracks); void internalRemoveTracksList(const QHash &removedTracks, qulonglong sourceId); QUrl internalAlbumArtUriFromAlbumId(qulonglong albumId); bool isValidArtist(qulonglong albumId); qulonglong insertComposer(const QString &name); qulonglong insertLyricist(const QString &name); QHash internalAllFileName(); bool internalGenericPartialData(QSqlQuery &query); ListArtistDataType internalAllArtistsPartialData(QSqlQuery &artistsQuery); ListAlbumDataType internalAllAlbumsPartialData(QSqlQuery &query); AlbumDataType internalOneAlbumPartialData(qulonglong databaseId); ListTrackDataType internalAllTracksPartialData(); ListTrackDataType internalRecentlyPlayedTracksData(int count); ListTrackDataType internalFrequentlyPlayedTracksData(int count); TrackDataType internalOneTrackPartialData(qulonglong databaseId); ListGenreDataType internalAllGenresPartialData(); ListArtistDataType internalAllComposersPartialData(); ListArtistDataType internalAllLyricistsPartialData(); bool prepareQuery(QSqlQuery &query, const QString &queryText) const; bool execQuery(QSqlQuery &query); void updateAlbumArtist(qulonglong albumId, const QString &title, const QString &albumPath, const QString &artistName); void updateTrackStatistics(const QUrl &fileName, const QDateTime &time); void createDatabaseV9(); void upgradeDatabaseV9(); void upgradeDatabaseV11(); void upgradeDatabaseV12(); void checkDatabaseSchema(); void checkAlbumsTableSchema(); void checkArtistsTableSchema(); void checkComposerTableSchema(); void checkGenreTableSchema(); void checkLyricistTableSchema(); void checkTracksTableSchema(); void checkTracksDataTableSchema(); void genericCheckTable(const QString &tableName, const QStringList &expectedColumns); void resetDatabase(); std::unique_ptr d; }; Q_DECLARE_METATYPE(DatabaseInterface::TrackDataType) Q_DECLARE_METATYPE(DatabaseInterface::AlbumDataType) Q_DECLARE_METATYPE(DatabaseInterface::ArtistDataType) Q_DECLARE_METATYPE(DatabaseInterface::GenreDataType) Q_DECLARE_METATYPE(DatabaseInterface::ListTrackDataType) Q_DECLARE_METATYPE(DatabaseInterface::ListAlbumDataType) Q_DECLARE_METATYPE(DatabaseInterface::ListArtistDataType) Q_DECLARE_METATYPE(DatabaseInterface::ListGenreDataType) #endif // DATABASEINTERFACE_H diff --git a/src/elisaapplication.cpp b/src/elisaapplication.cpp index 4df97acb..6f78f48d 100644 --- a/src/elisaapplication.cpp +++ b/src/elisaapplication.cpp @@ -1,483 +1,485 @@ /* * Copyright 2017 Matthieu Gallien * Copyright (C) 2012 Aleix Pol Gonzalez * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "elisaapplication.h" #include "musiclistenersmanager.h" #include "mediaplaylist.h" #include "audiowrapper.h" #include "manageaudioplayer.h" #include "managemediaplayercontrol.h" #include "manageheaderbar.h" #include "elisa_settings.h" #include #if defined KF5ConfigWidgets_FOUND && KF5ConfigWidgets_FOUND #include #endif #if defined KF5XmlGui_FOUND && KF5XmlGui_FOUND #include #include #include #include #include #endif #if defined KF5KCMUtils_FOUND && KF5KCMUtils_FOUND #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include class ElisaApplicationPrivate { public: explicit ElisaApplicationPrivate(QObject *parent) #if defined KF5XmlGui_FOUND && KF5XmlGui_FOUND : mCollection(parent) #endif { Q_UNUSED(parent) auto configurationFileName = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation); configurationFileName += QStringLiteral("/elisarc"); Elisa::ElisaConfiguration::instance(configurationFileName); Elisa::ElisaConfiguration::self()->load(); Elisa::ElisaConfiguration::self()->save(); } #if defined KF5XmlGui_FOUND && KF5XmlGui_FOUND KActionCollection mCollection; #endif ElisaUtils::EntryDataList mArguments; std::unique_ptr mMusicManager; std::unique_ptr mMediaPlayList; std::unique_ptr mAudioWrapper; std::unique_ptr mAudioControl; std::unique_ptr mPlayerControl; std::unique_ptr mManageHeaderBar; }; ElisaApplication::ElisaApplication(QObject *parent) : QObject(parent), d(std::make_unique(this)) { } ElisaApplication::~ElisaApplication() = default; void ElisaApplication::setupActions(const QString &actionName) { #if defined KF5XmlGui_FOUND && KF5XmlGui_FOUND if (actionName == QStringLiteral("file_quit")) { auto quitAction = KStandardAction::quit(QCoreApplication::instance(), &QCoreApplication::quit, &d->mCollection); d->mCollection.addAction(actionName, quitAction); } if (actionName == QStringLiteral("help_contents") && KAuthorized::authorizeAction(actionName)) { auto handBookAction = KStandardAction::helpContents(this, &ElisaApplication::appHelpActivated, &d->mCollection); d->mCollection.addAction(handBookAction->objectName(), handBookAction); } if (actionName == QStringLiteral("help_report_bug") && KAuthorized::authorizeAction(actionName) && !KAboutData::applicationData().bugAddress().isEmpty()) { auto reportBugAction = KStandardAction::reportBug(this, &ElisaApplication::reportBug, &d->mCollection); d->mCollection.addAction(reportBugAction->objectName(), reportBugAction); } if (actionName == QStringLiteral("help_about_app") && KAuthorized::authorizeAction(actionName)) { auto aboutAppAction = KStandardAction::aboutApp(this, &ElisaApplication::aboutApplication, this); d->mCollection.addAction(aboutAppAction->objectName(), aboutAppAction); } if (actionName == QStringLiteral("options_configure") && KAuthorized::authorizeAction(actionName)) { auto preferencesAction = KStandardAction::preferences(this, &ElisaApplication::configureElisa, this); d->mCollection.addAction(preferencesAction->objectName(), preferencesAction); } if (actionName == QStringLiteral("options_configure_keybinding") && KAuthorized::authorizeAction(actionName)) { auto keyBindingsAction = KStandardAction::keyBindings(this, &ElisaApplication::configureShortcuts, this); d->mCollection.addAction(keyBindingsAction->objectName(), keyBindingsAction); } if (actionName == QStringLiteral("go_back") && KAuthorized::authorizeAction(actionName)) { auto goBackAction = KStandardAction::back(this, &ElisaApplication::goBack, this); d->mCollection.addAction(goBackAction->objectName(), goBackAction); } if (actionName == QStringLiteral("toggle_playlist") && KAuthorized::authorizeAction(actionName)) { auto togglePlaylistAction = d->mCollection.addAction(actionName, this, &ElisaApplication::togglePlaylist); togglePlaylistAction->setShortcut(QKeySequence(Qt::Key_F9)); togglePlaylistAction->setText(QStringLiteral("Toggle Playlist")); } if (actionName == QStringLiteral("Seek") && KAuthorized::authorizeAction(actionName)) { auto seekAction = d->mCollection.addAction(actionName, this, &ElisaApplication::seek); d->mCollection.setDefaultShortcut(seekAction, QKeySequence(tr("Shift+Right"))); } if (actionName == QStringLiteral("Scrub") && KAuthorized::authorizeAction(actionName)) { auto scrubAction = d->mCollection.addAction(actionName, this, &ElisaApplication::scrub); d->mCollection.setDefaultShortcut(scrubAction, QKeySequence(tr("Shift+Left"))); } if (actionName == QStringLiteral("Play-Pause") && KAuthorized::authorizeAction(actionName)) { auto playPauseAction = d->mCollection.addAction(actionName, this, &ElisaApplication::playPause); d->mCollection.setDefaultShortcut(playPauseAction, QKeySequence(tr("Space"))); } if (actionName == QStringLiteral("edit_find") && KAuthorized::authorizeAction(actionName)) { auto findAction = KStandardAction::find(this, &ElisaApplication::find, this); d->mCollection.addAction(findAction->objectName(), findAction); } d->mCollection.readSettings(); #endif } void ElisaApplication::setArguments(const ElisaUtils::EntryDataList &newArguments) { if (d->mArguments == newArguments) { return; } d->mArguments = checkFileListAndMakeAbsolute(newArguments, QDir::currentPath()); Q_EMIT argumentsChanged(); if (!d->mArguments.isEmpty()) { Q_EMIT enqueue(d->mArguments, ElisaUtils::FileName, ElisaUtils::PlayListEnqueueMode::AppendPlayList, ElisaUtils::PlayListEnqueueTriggerPlay::TriggerPlay); } } void ElisaApplication::activateActionRequested(const QString &actionName, const QVariant ¶meter) { Q_UNUSED(actionName) Q_UNUSED(parameter) } void ElisaApplication::activateRequested(const QStringList &arguments, const QString &workingDirectory) { if (arguments.size() > 1) { auto realArguments = ElisaUtils::EntryDataList{}; bool isFirst = true; for (const auto &oneArgument : arguments) { if (isFirst) { isFirst = false; continue; } realArguments.push_back(ElisaUtils::EntryData{0, oneArgument}); } Q_EMIT enqueue(checkFileListAndMakeAbsolute(realArguments, workingDirectory), ElisaUtils::FileName, ElisaUtils::PlayListEnqueueMode::AppendPlayList, ElisaUtils::PlayListEnqueueTriggerPlay::TriggerPlay); } } void ElisaApplication::openRequested(const QList &uris) { Q_UNUSED(uris) } void ElisaApplication::appHelpActivated() { QDesktopServices::openUrl(QUrl(QStringLiteral("help:/"))); } void ElisaApplication::aboutApplication() { #if defined KF5XmlGui_FOUND && KF5XmlGui_FOUND static QPointer dialog; if (!dialog) { dialog = new KAboutApplicationDialog(KAboutData::applicationData(), nullptr); dialog->setAttribute(Qt::WA_DeleteOnClose); } dialog->show(); #endif } void ElisaApplication::reportBug() { #if defined KF5XmlGui_FOUND && KF5XmlGui_FOUND static QPointer dialog; if (!dialog) { dialog = new KBugReport(KAboutData::applicationData(), nullptr); dialog->setAttribute(Qt::WA_DeleteOnClose); } dialog->show(); #endif } void ElisaApplication::configureShortcuts() { #if defined KF5XmlGui_FOUND && KF5XmlGui_FOUND KShortcutsDialog dlg(KShortcutsEditor::AllActions, KShortcutsEditor::LetterShortcutsAllowed, nullptr); dlg.setModal(true); dlg.addCollection(&d->mCollection); dlg.configure(); #endif } void ElisaApplication::configureElisa() { #if defined KF5KCMUtils_FOUND && KF5KCMUtils_FOUND KCMultiDialog configurationDialog; configurationDialog.addModule(QStringLiteral("kcm_elisa_local_file")); configurationDialog.setModal(true); configurationDialog.exec(); #endif } void ElisaApplication::goBack() {} void ElisaApplication::find() {} void ElisaApplication::togglePlaylist() {} void ElisaApplication::seek() {} void ElisaApplication::scrub() {} void ElisaApplication::playPause() {} ElisaUtils::EntryDataList ElisaApplication::checkFileListAndMakeAbsolute(const ElisaUtils::EntryDataList &filesList, const QString &workingDirectory) const { auto filesToOpen = ElisaUtils::EntryDataList{}; for (const auto &oneFile : filesList) { auto newFile = QFileInfo(std::get<1>(oneFile)); if (newFile.isRelative()) { newFile = QFileInfo(workingDirectory + QStringLiteral("/") + std::get<1>(oneFile)); } if (newFile.exists()) { filesToOpen.push_back(ElisaUtils::EntryData{0, newFile.canonicalFilePath()}); } } return filesToOpen; } void ElisaApplication::initialize() { initializeModels(); initializePlayer(); Q_EMIT initializationDone(); } void ElisaApplication::initializeModels() { d->mMusicManager = std::make_unique(); Q_EMIT musicManagerChanged(); d->mMediaPlayList = std::make_unique(); Q_EMIT mediaPlayListChanged(); d->mMusicManager->setElisaApplication(this); d->mMediaPlayList->setMusicListenersManager(d->mMusicManager.get()); QObject::connect(this, &ElisaApplication::enqueue, d->mMediaPlayList.get(), static_cast(&MediaPlayList::enqueue)); } void ElisaApplication::initializePlayer() { d->mAudioWrapper = std::make_unique(); Q_EMIT audioPlayerChanged(); d->mAudioControl = std::make_unique(); Q_EMIT audioControlChanged(); d->mPlayerControl = std::make_unique(); Q_EMIT playerControlChanged(); d->mManageHeaderBar = std::make_unique(); Q_EMIT manageHeaderBarChanged(); d->mAudioControl->setAlbumNameRole(MediaPlayList::AlbumRole); d->mAudioControl->setArtistNameRole(MediaPlayList::ArtistRole); d->mAudioControl->setTitleRole(MediaPlayList::TitleRole); d->mAudioControl->setUrlRole(MediaPlayList::ResourceRole); d->mAudioControl->setIsPlayingRole(MediaPlayList::IsPlayingRole); d->mAudioControl->setPlayListModel(d->mMediaPlayList.get()); QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::playerPlay, d->mAudioWrapper.get(), &AudioWrapper::play); QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::playerPause, d->mAudioWrapper.get(), &AudioWrapper::pause); QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::playerStop, d->mAudioWrapper.get(), &AudioWrapper::stop); QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::seek, d->mAudioWrapper.get(), &AudioWrapper::seek); QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::saveUndoPositionInAudioWrapper, d->mAudioWrapper.get(), &AudioWrapper::saveUndoPosition); QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::restoreUndoPositionInAudioWrapper, d->mAudioWrapper.get(), &AudioWrapper::restoreUndoPosition); QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::skipNextTrack, d->mMediaPlayList.get(), &MediaPlayList::skipNextTrack); QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::sourceInError, d->mMediaPlayList.get(), &MediaPlayList::trackInError); QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::sourceInError, d->mMusicManager.get(), &MusicListenersManager::playBackError); QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::playerSourceChanged, d->mAudioWrapper.get(), &AudioWrapper::setSource); QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::startedPlayingTrack, d->mMusicManager->viewDatabase(), &DatabaseInterface::trackHasStartedPlaying); QObject::connect(d->mMediaPlayList.get(), &MediaPlayList::ensurePlay, d->mAudioControl.get(), &ManageAudioPlayer::ensurePlay); QObject::connect(d->mMediaPlayList.get(), &MediaPlayList::playListFinished, d->mAudioControl.get(), &ManageAudioPlayer::playListFinished); QObject::connect(d->mMediaPlayList.get(), &MediaPlayList::currentTrackChanged, d->mAudioControl.get(), &ManageAudioPlayer::setCurrentTrack); QObject::connect(d->mMediaPlayList.get(), &MediaPlayList::clearPlayListPlayer, d->mAudioControl.get(), &ManageAudioPlayer::saveForUndoClearPlaylist); QObject::connect(d->mMediaPlayList.get(), &MediaPlayList::undoClearPlayListPlayer, d->mAudioControl.get(), &ManageAudioPlayer::restoreForUndoClearPlaylist); QObject::connect(d->mAudioWrapper.get(), &AudioWrapper::playbackStateChanged, d->mAudioControl.get(), &ManageAudioPlayer::setPlayerPlaybackState); QObject::connect(d->mAudioWrapper.get(), &AudioWrapper::statusChanged, d->mAudioControl.get(), &ManageAudioPlayer::setPlayerStatus); QObject::connect(d->mAudioWrapper.get(), &AudioWrapper::errorChanged, d->mAudioControl.get(), &ManageAudioPlayer::setPlayerError); QObject::connect(d->mAudioWrapper.get(), &AudioWrapper::durationChanged, d->mAudioControl.get(), &ManageAudioPlayer::setAudioDuration); QObject::connect(d->mAudioWrapper.get(), &AudioWrapper::seekableChanged, d->mAudioControl.get(), &ManageAudioPlayer::setPlayerIsSeekable); QObject::connect(d->mAudioWrapper.get(), &AudioWrapper::positionChanged, d->mAudioControl.get(), &ManageAudioPlayer::setPlayerPosition); d->mPlayerControl->setPlayListModel(d->mMediaPlayList.get()); QObject::connect(d->mMediaPlayList.get(), &MediaPlayList::currentTrackChanged, d->mPlayerControl.get(), &ManageMediaPlayerControl::setCurrentTrack); QObject::connect(d->mAudioWrapper.get(), &AudioWrapper::playing, d->mPlayerControl.get(), &ManageMediaPlayerControl::playerPlaying); QObject::connect(d->mAudioWrapper.get(), &AudioWrapper::paused, d->mPlayerControl.get(), &ManageMediaPlayerControl::playerPaused); QObject::connect(d->mAudioWrapper.get(), &AudioWrapper::stopped, d->mPlayerControl.get(), &ManageMediaPlayerControl::playerStopped); d->mManageHeaderBar->setTitleRole(MediaPlayList::TitleRole); d->mManageHeaderBar->setAlbumRole(MediaPlayList::AlbumRole); d->mManageHeaderBar->setAlbumArtistRole(MediaPlayList::AlbumArtistRole); d->mManageHeaderBar->setArtistRole(MediaPlayList::ArtistRole); + d->mManageHeaderBar->setFileNameRole(MediaPlayList::ResourceRole); d->mManageHeaderBar->setImageRole(MediaPlayList::ImageUrlRole); + d->mManageHeaderBar->setDatabaseIdRole(MediaPlayList::DatabaseIdRole); d->mManageHeaderBar->setAlbumIdRole(MediaPlayList::AlbumIdRole); d->mManageHeaderBar->setIsValidRole(MediaPlayList::IsValidRole); d->mManageHeaderBar->setPlayListModel(d->mMediaPlayList.get()); QObject::connect(d->mMediaPlayList.get(), &MediaPlayList::currentTrackChanged, d->mManageHeaderBar.get(), &ManageHeaderBar::setCurrentTrack); if (!d->mArguments.isEmpty()) { Q_EMIT enqueue(d->mArguments, ElisaUtils::FileName, ElisaUtils::PlayListEnqueueMode::AppendPlayList, ElisaUtils::PlayListEnqueueTriggerPlay::TriggerPlay); } } QAction * ElisaApplication::action(const QString& name) { #if defined KF5XmlGui_FOUND && KF5XmlGui_FOUND auto resultAction = d->mCollection.action(name); if (!resultAction) { setupActions(name); resultAction = d->mCollection.action(name); } return resultAction; #else Q_UNUSED(name); return new QAction(); #endif } QString ElisaApplication::iconName(const QIcon& icon) { return icon.name(); } void ElisaApplication::installKeyEventFilter(QObject *object) { if(!object) { return; } object->installEventFilter(this); } bool ElisaApplication::eventFilter(QObject *object, QEvent *event) { Q_UNUSED(object); QKeyEvent *keyEvent = static_cast(event); auto playPauseAction = d->mCollection.action(tr("Play-Pause")); if (keyEvent->key() == Qt::Key_Space && playPauseAction->shortcut()[0] == Qt::Key_Space) { return true; } return false; } const ElisaUtils::EntryDataList &ElisaApplication::arguments() const { return d->mArguments; } MusicListenersManager *ElisaApplication::musicManager() const { return d->mMusicManager.get(); } MediaPlayList *ElisaApplication::mediaPlayList() const { return d->mMediaPlayList.get(); } AudioWrapper *ElisaApplication::audioPlayer() const { return d->mAudioWrapper.get(); } ManageAudioPlayer *ElisaApplication::audioControl() const { return d->mAudioControl.get(); } ManageMediaPlayerControl *ElisaApplication::playerControl() const { return d->mPlayerControl.get(); } ManageHeaderBar *ElisaApplication::manageHeaderBar() const { return d->mManageHeaderBar.get(); } #include "moc_elisaapplication.cpp" diff --git a/src/elisaqmlplugin.cpp b/src/elisaqmlplugin.cpp index eb32c3df..42554f01 100644 --- a/src/elisaqmlplugin.cpp +++ b/src/elisaqmlplugin.cpp @@ -1,184 +1,186 @@ /* * Copyright 2018 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "elisaqmlplugin.h" #if defined UPNPQT_FOUND && UPNPQT_FOUND #include "upnp/upnpcontrolconnectionmanager.h" #include "upnp/upnpcontrolmediaserver.h" #include "upnp/upnpcontrolcontentdirectory.h" #include "upnp/upnpcontentdirectorymodel.h" #include "upnpdevicedescription.h" #include "upnp/didlparser.h" #include "upnp/upnpdiscoverallmusic.h" #include "upnpssdpengine.h" #include "upnpabstractservice.h" #include "upnpcontrolabstractdevice.h" #include "upnpcontrolabstractservice.h" #include "upnpbasictypes.h" #endif #include "elisautils.h" #include "elisaapplication.h" #include "progressindicator.h" #include "mediaplaylist.h" #include "managemediaplayercontrol.h" #include "manageheaderbar.h" #include "manageaudioplayer.h" #include "musicaudiotrack.h" #include "musiclistenersmanager.h" #include "trackslistener.h" #include "viewmanager.h" #include "databaseinterface.h" #include "models/datamodel.h" #include "models/trackmetadatamodel.h" +#include "models/trackcontextmetadatamodel.h" #include "models/viewsmodel.h" #include "models/gridviewproxymodel.h" #include "models/alltracksproxymodel.h" #include "models/singlealbumproxymodel.h" #if defined KF5FileMetaData_FOUND && KF5FileMetaData_FOUND #include "embeddedcoverageimageprovider.h" #endif #if defined KF5KIO_FOUND && KF5KIO_FOUND #include "models/filebrowsermodel.h" #include "models/filebrowserproxymodel.h" #endif #include "audiowrapper.h" #include "notificationitem.h" #include "topnotificationmanager.h" #include "elisautils.h" #include "datatype.h" #if defined Qt5DBus_FOUND && Qt5DBus_FOUND #include "mpris2/mpris2.h" #include "mpris2/mediaplayer2player.h" #endif #include #include #include #include #include #include void ElisaQmlTestPlugin::initializeEngine(QQmlEngine *engine, const char *uri) { QQmlExtensionPlugin::initializeEngine(engine, uri); #if defined KF5FileMetaData_FOUND && KF5FileMetaData_FOUND engine->addImageProvider(QStringLiteral("cover"), new EmbeddedCoverageImageProvider); #endif } void ElisaQmlTestPlugin::registerTypes(const char *uri) { #if defined UPNPQT_FOUND && UPNPQT_FOUND qmlRegisterType(uri, 1, 0, "UpnpSsdpEngine"); qmlRegisterType(uri, 1, 0, "UpnpDiscoverAllMusic"); qmlRegisterType(uri, 1, 0, "UpnpAbstractDevice"); qmlRegisterType(uri, 1, 0, "UpnpAbstractService"); qmlRegisterType(uri, 1, 0, "UpnpControlAbstractDevice"); qmlRegisterType(uri, 1, 0, "UpnpControlAbstractService"); qmlRegisterType(uri, 1, 0, "UpnpControlConnectionManager"); qmlRegisterType(uri, 1, 0, "UpnpControlMediaServer"); qmlRegisterType(uri, 1, 0, "UpnpContentDirectoryModel"); qmlRegisterType(uri, 1, 0, "DidlParser"); qmlRegisterType(uri, 1, 0, "UpnpControlContentDirectory"); qmlRegisterType(uri, 1, 0, "UpnpDeviceDescription"); qRegisterMetaType(); qRegisterMetaType >(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); #endif qRegisterMetaType("DataUtils::DataType"); qmlRegisterType(uri, 1, 0, "MediaPlayList"); qmlRegisterType(uri, 1, 0, "ManageMediaPlayerControl"); qmlRegisterType(uri, 1, 0, "ManageHeaderBar"); qmlRegisterType(uri, 1, 0, "ManageAudioPlayer"); qmlRegisterType(uri, 1, 0, "ProgressIndicator"); qmlRegisterType(uri, 1, 0, "MusicListenersManager"); qmlRegisterType(uri, 1, 0, "ViewManager"); qmlRegisterType(uri, 1, 0, "DataModel"); qmlRegisterType(uri, 1, 0, "TrackMetadataModel"); + qmlRegisterType(uri, 1, 0, "TrackContextMetaDataModel"); qmlRegisterType(uri, 1, 0, "ViewsModel"); qmlRegisterType(uri, 1, 0, "GridViewProxyModel"); qmlRegisterType(uri, 1, 0, "AllTracksProxyModel"); qmlRegisterType(uri, 1, 0, "SingleAlbumProxyModel"); #if defined KF5KIO_FOUND && KF5KIO_FOUND qmlRegisterType(uri, 1, 0, "FileBrowserModel"); qmlRegisterType(uri, 1, 0, "FileBrowserProxyModel"); #endif qmlRegisterType(uri, 1, 0, "AudioWrapper"); qmlRegisterType(uri, 1, 0, "TopNotificationManager"); qmlRegisterUncreatableMetaObject(DataUtils::staticMetaObject, uri, 1, 0, "DataUtils", QStringLiteral("Only enums")); qmlRegisterUncreatableType(uri, 1, 0, "DatabaseInterface", QStringLiteral("Only created in c++")); #if defined Qt5DBus_FOUND && Qt5DBus_FOUND qmlRegisterType(uri, 1, 0, "Mpris2"); qRegisterMetaType(); #endif qRegisterMetaType(); qRegisterMetaType>("QHash"); qRegisterMetaType>("QHash"); qRegisterMetaType>("QList"); qRegisterMetaType>("QVector"); qRegisterMetaType>("QVector"); qRegisterMetaType>("QHash"); qRegisterMetaType("DatabaseInterface::ListTrackDataType"); qRegisterMetaType("DatabaseInterface::ListAlbumDataType"); qRegisterMetaType("DatabaseInterface::ListArtistDataType"); qRegisterMetaType("DatabaseInterface::ListGenreDataType"); qRegisterMetaType("ModelDataLoader::ListTrackDataType"); qRegisterMetaType("ModelDataLoader::ListAlbumDataType"); qRegisterMetaType("ModelDataLoader::ListArtistDataType"); qRegisterMetaType("ModelDataLoader::ListGenreDataType"); qRegisterMetaType("ModelDataLoader::AlbumDataType"); qRegisterMetaType("TracksListener::ListTrackDataType"); qRegisterMetaType>(); qRegisterMetaType(); qRegisterMetaType("NotificationItem"); qRegisterMetaType>("QMap"); qRegisterMetaType("PlayListEnqueueMode"); qRegisterMetaType("PlayListEnqueueTriggerPlay"); qRegisterMetaType("PlayListEntryType"); qRegisterMetaType("EntryData"); qRegisterMetaType("EntryDataList"); qRegisterMetaType("DatabaseInterface::TrackDataType"); qRegisterMetaType("DatabaseInterface::AlbumDataType"); qRegisterMetaType("DatabaseInterface::ArtistDataType"); qRegisterMetaType("DatabaseInterface::GenreDataType"); qRegisterMetaType("ModelDataLoader::TrackDataType"); qRegisterMetaType("TracksListener::TrackDataType"); qRegisterMetaType("ViewManager::ViewsType"); qRegisterMetaTypeStreamOperators("PlayListControler::PlayerState"); qmlRegisterUncreatableType(uri, 1, 0, "ElisaApplication", QStringLiteral("only one and done in c++")); qmlRegisterUncreatableMetaObject(ElisaUtils::staticMetaObject, uri, 1, 0, "ElisaUtils", QStringLiteral("Namespace ElisaUtils")); } diff --git a/src/filescanner.cpp b/src/filescanner.cpp index e1ac85a6..57ddaafe 100644 --- a/src/filescanner.cpp +++ b/src/filescanner.cpp @@ -1,234 +1,237 @@ /* * Copyright 2018 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "filescanner.h" #include "config-upnp-qt.h" #if defined KF5FileMetaData_FOUND && KF5FileMetaData_FOUND #include #include #include #include #include #if defined KF5Baloo_FOUND && KF5Baloo_FOUND #include #endif #endif #include class FileScannerPrivate { public: #if defined KF5FileMetaData_FOUND && KF5FileMetaData_FOUND KFileMetaData::ExtractorCollection mAllExtractors; KFileMetaData::PropertyMap mAllProperties; #endif }; FileScanner::FileScanner() : d(std::make_unique()) { } FileScanner::~FileScanner() = default; MusicAudioTrack FileScanner::scanOneFile(const QUrl &scanFile, const QMimeDatabase &mimeDatabase) { #if defined KF5FileMetaData_FOUND && KF5FileMetaData_FOUND MusicAudioTrack newTrack; auto localFileName = scanFile.toLocalFile(); QFileInfo scanFileInfo(localFileName); newTrack.setFileModificationTime(scanFileInfo.fileTime(QFile::FileModificationTime)); newTrack.setResourceURI(scanFile); const auto &fileMimeType = mimeDatabase.mimeTypeForFile(localFileName); if (!fileMimeType.name().startsWith(QStringLiteral("audio/"))) { return newTrack; } QString mimetype = fileMimeType.name(); QList exList = d->mAllExtractors.fetchExtractors(mimetype); if (exList.isEmpty()) { return newTrack; } KFileMetaData::Extractor* ex = exList.first(); KFileMetaData::SimpleExtractionResult result(localFileName, mimetype, KFileMetaData::ExtractionResult::ExtractMetaData); ex->extract(&result); d->mAllProperties = result.properties(); scanProperties(localFileName, newTrack); return newTrack; #else Q_UNUSED(scanFile) Q_UNUSED(mimeDatabase) return {}; #endif } void FileScanner::scanProperties(const Baloo::File &match, MusicAudioTrack &trackData) { #if defined KF5Baloo_FOUND && KF5Baloo_FOUND d->mAllProperties = match.properties(); scanProperties(match.path(), trackData); #else Q_UNUSED(match) Q_UNUSED(trackData) #endif } void FileScanner::scanProperties(const QString &localFileName, MusicAudioTrack &trackData) { #if defined KF5FileMetaData_FOUND && KF5FileMetaData_FOUND auto titleProperty = d->mAllProperties.find(KFileMetaData::Property::Title); auto durationProperty = d->mAllProperties.find(KFileMetaData::Property::Duration); auto artistProperty = d->mAllProperties.find(KFileMetaData::Property::Artist); auto albumProperty = d->mAllProperties.find(KFileMetaData::Property::Album); auto albumArtistProperty = d->mAllProperties.find(KFileMetaData::Property::AlbumArtist); auto trackNumberProperty = d->mAllProperties.find(KFileMetaData::Property::TrackNumber); auto discNumberProperty = d->mAllProperties.find(KFileMetaData::Property::DiscNumber); auto genreProperty = d->mAllProperties.find(KFileMetaData::Property::Genre); auto yearProperty = d->mAllProperties.find(KFileMetaData::Property::ReleaseYear); auto composerProperty = d->mAllProperties.find(KFileMetaData::Property::Composer); auto lyricistProperty = d->mAllProperties.find(KFileMetaData::Property::Lyricist); + auto lyricsProperty = d->mAllProperties.find(KFileMetaData::Property::Lyrics); auto channelsProperty = d->mAllProperties.find(KFileMetaData::Property::Channels); auto bitRateProperty = d->mAllProperties.find(KFileMetaData::Property::BitRate); auto sampleRateProperty = d->mAllProperties.find(KFileMetaData::Property::SampleRate); auto commentProperty = d->mAllProperties.find(KFileMetaData::Property::Comment); auto ratingProperty = d->mAllProperties.find(KFileMetaData::Property::Rating); #if !defined Q_OS_ANDROID auto fileData = KFileMetaData::UserMetaData(localFileName); #endif if (albumProperty != d->mAllProperties.end()) { trackData.setAlbumName(albumProperty->toString()); } if (artistProperty != d->mAllProperties.end()) { trackData.setArtist(artistProperty->toStringList().join(QStringLiteral(", "))); } if (durationProperty != d->mAllProperties.end()) { trackData.setDuration(QTime::fromMSecsSinceStartOfDay(int(1000 * durationProperty->toDouble()))); } if (titleProperty != d->mAllProperties.end()) { trackData.setTitle(titleProperty->toString()); } if (trackNumberProperty != d->mAllProperties.end()) { trackData.setTrackNumber(trackNumberProperty->toInt()); } if (discNumberProperty != d->mAllProperties.end()) { trackData.setDiscNumber(discNumberProperty->toInt()); - } else { - trackData.setDiscNumber(1); } if (albumArtistProperty != d->mAllProperties.end()) { trackData.setAlbumArtist(albumArtistProperty->toStringList().join(QStringLiteral(", "))); } if (yearProperty != d->mAllProperties.end()) { trackData.setYear(yearProperty->toInt()); } if (channelsProperty != d->mAllProperties.end()) { trackData.setChannels(channelsProperty->toInt()); } if (bitRateProperty != d->mAllProperties.end()) { trackData.setBitRate(bitRateProperty->toInt()); } if (sampleRateProperty != d->mAllProperties.end()) { trackData.setSampleRate(sampleRateProperty->toInt()); } if (genreProperty != d->mAllProperties.end()) { trackData.setGenre(genreProperty->toStringList().join(QStringLiteral(", "))); } if (composerProperty != d->mAllProperties.end()) { trackData.setComposer(composerProperty->toStringList().join(QStringLiteral(", "))); } if (lyricistProperty != d->mAllProperties.end()) { trackData.setLyricist(lyricistProperty->toStringList().join(QStringLiteral(", "))); } + if (lyricsProperty != d->mAllProperties.end()) { + trackData.setLyrics(lyricsProperty->toString()); + } + if (trackData.artist().isEmpty()) { trackData.setArtist(trackData.albumArtist()); } #if !defined Q_OS_ANDROID QString comment = fileData.userComment(); if (!comment.isEmpty()) { trackData.setComment(comment); } else if (commentProperty != d->mAllProperties.end()) { trackData.setComment(commentProperty->toString()); } int rating = fileData.rating(); if (rating > 0) { trackData.setRating(rating); } else if (ratingProperty != d->mAllProperties.end()) { trackData.setRating(ratingProperty->toInt()); } else { trackData.setRating(0); } #else if (ratingProperty != d->mAllProperties.end()) { trackData.setRating(ratingProperty->toInt()); } else { trackData.setRating(0); } if (commentProperty != d->mAllProperties.end()) { trackData.setComment(commentProperty->toString()); } #endif if (!trackData.duration().isValid()) { return; } trackData.setValid(true); #else Q_UNUSED(localFileName) Q_UNUSED(trackData) #endif } diff --git a/src/filescanner.h b/src/filescanner.h index 39191224..dd455c8d 100644 --- a/src/filescanner.h +++ b/src/filescanner.h @@ -1,63 +1,65 @@ /* * Copyright 2018 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef FILESCANNER_H #define FILESCANNER_H +#include "elisaLib_export.h" + #include "musicaudiotrack.h" #include #include #include #include namespace KFileMetaData { class ExtractorCollection; } namespace Baloo { class File; } class FileScannerPrivate; -class FileScanner +class ELISALIB_EXPORT FileScanner { public: FileScanner(); virtual ~FileScanner(); MusicAudioTrack scanOneFile(const QUrl &scanFile, const QMimeDatabase &mimeDatabase); void scanProperties(const Baloo::File &match, MusicAudioTrack &trackData); void scanProperties(const QString &localFileName, MusicAudioTrack &trackData); private: std::unique_ptr d; }; #endif // FILESCANNER_H diff --git a/src/manageheaderbar.cpp b/src/manageheaderbar.cpp index 16d5e055..e2519074 100644 --- a/src/manageheaderbar.cpp +++ b/src/manageheaderbar.cpp @@ -1,448 +1,534 @@ /* * Copyright 2016 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "manageheaderbar.h" #include #include #include #include ManageHeaderBar::ManageHeaderBar(QObject *parent) : QObject(parent) { } void ManageHeaderBar::setArtistRole(int value) { mArtistRole = value; Q_EMIT artistRoleChanged(); } int ManageHeaderBar::artistRole() const { return mArtistRole; } void ManageHeaderBar::setTitleRole(int value) { mTitleRole = value; Q_EMIT titleRoleChanged(); } int ManageHeaderBar::titleRole() const { return mTitleRole; } void ManageHeaderBar::setAlbumRole(int value) { mAlbumRole = value; Q_EMIT albumRoleChanged(); } void ManageHeaderBar::setAlbumArtistRole(int value) { mAlbumArtistRole = value; Q_EMIT albumArtistRoleChanged(); } +void ManageHeaderBar::setFileNameRole(int value) +{ + mFileNameRole = value; + Q_EMIT fileNameRoleChanged(); +} + int ManageHeaderBar::albumRole() const { return mAlbumRole; } int ManageHeaderBar::albumArtistRole() const { return mAlbumArtistRole; } +int ManageHeaderBar::fileNameRole() const +{ + return mFileNameRole; +} + void ManageHeaderBar::setImageRole(int value) { mImageRole = value; Q_EMIT imageRoleChanged(); } +void ManageHeaderBar::setDatabaseIdRole(int databaseIdRole) +{ + mDatabaseIdRole = databaseIdRole; + Q_EMIT databaseIdRoleChanged(); +} + int ManageHeaderBar::imageRole() const { return mImageRole; } +int ManageHeaderBar::databaseIdRole() const +{ + return mDatabaseIdRole; +} + void ManageHeaderBar::setAlbumIdRole(int albumIdRole) { mAlbumIdRole = albumIdRole; Q_EMIT albumIdRoleChanged(); } int ManageHeaderBar::albumIdRole() const { return mAlbumIdRole; } QVariant ManageHeaderBar::album() const { if (!mCurrentTrack.isValid()) { return QString(); } return mCurrentTrack.data(mAlbumRole); } QVariant ManageHeaderBar::albumArtist() const { if (!mCurrentTrack.isValid()) { return QString(); } return mCurrentTrack.data(mAlbumArtistRole); } +QString ManageHeaderBar::fileName() const +{ + QString result; + + if (!mCurrentTrack.isValid()) { + return result; + } + + auto fileNameUrl = mCurrentTrack.data(mFileNameRole).toUrl(); + if (fileNameUrl.isLocalFile()) { + result = fileNameUrl.toLocalFile(); + } else { + result = fileNameUrl.toString(); + } + + return result; +} + QVariant ManageHeaderBar::title() const { if (!mCurrentTrack.isValid()) { return QString(); } return mCurrentTrack.data(mTitleRole); } QVariant ManageHeaderBar::artist() const { if (!mCurrentTrack.isValid()) { return QString(); } return mCurrentTrack.data(mArtistRole); } QUrl ManageHeaderBar::image() const { if (!mCurrentTrack.isValid()) { return {}; } return mCurrentTrack.data(mImageRole).toUrl(); } +qulonglong ManageHeaderBar::databaseId() const +{ + if (!mCurrentTrack.isValid()) { + return 0; + } + + return mCurrentTrack.data(mDatabaseIdRole).toULongLong(); +} + qulonglong ManageHeaderBar::albumId() const { if (!mCurrentTrack.isValid()) { return 0; } return mCurrentTrack.data(mAlbumIdRole).toULongLong(); } bool ManageHeaderBar::isValid() const { if (!mCurrentTrack.isValid()) { return false; } return mCurrentTrack.data(mIsValidRole).toBool(); } int ManageHeaderBar::remainingTracks() const { if (!mCurrentTrack.isValid()) { return 0; } return mPlayListModel->rowCount(mCurrentTrack.parent()) - mCurrentTrack.row() - 1; } int ManageHeaderBar::isValidRole() const { return mIsValidRole; } QPersistentModelIndex ManageHeaderBar::currentTrack() const { return mCurrentTrack; } void ManageHeaderBar::playListLayoutChanged(const QList &parents, QAbstractItemModel::LayoutChangeHint hint) { Q_UNUSED(parents); Q_UNUSED(hint); qDebug() << "ManageHeaderBar::playListLayoutChanged" << "not implemented"; } void ManageHeaderBar::tracksInserted(const QModelIndex &parent, int first, int last) { Q_UNUSED(parent); Q_UNUSED(first); Q_UNUSED(last); if (!mCurrentTrack.isValid()) { return; } if (mCurrentTrack.row() >= first) { return; } Q_EMIT remainingTracksChanged(); mOldRemainingTracks = remainingTracks(); } void ManageHeaderBar::tracksDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles) { if (!mCurrentTrack.isValid()) { return; } if (mCurrentTrack.row() > bottomRight.row() || mCurrentTrack.row() < topLeft.row()) { return; } if (mCurrentTrack.column() > bottomRight.column() || mCurrentTrack.column() < topLeft.column()) { return; } if (roles.isEmpty()) { notifyArtistProperty(); notifyTitleProperty(); notifyAlbumProperty(); notifyAlbumArtistProperty(); + notifyFileNameProperty(); notifyImageProperty(); + notifyDatabaseIdProperty(); notifyAlbumIdProperty(); notifyIsValidProperty(); } else { for(auto oneRole : roles) { if (oneRole == mArtistRole) { notifyArtistProperty(); } if (oneRole == mTitleRole) { notifyTitleProperty(); } if (oneRole == mAlbumRole) { notifyAlbumProperty(); } if (oneRole == mAlbumArtistRole) { notifyAlbumArtistProperty(); } + if (oneRole == mFileNameRole) { + notifyFileNameProperty(); + } if (oneRole == mImageRole) { notifyImageProperty(); } + if (oneRole == mDatabaseIdRole) { + notifyDatabaseIdProperty(); + } if (oneRole == mAlbumIdRole) { notifyAlbumIdProperty(); } if (oneRole == mIsValidRole) { notifyIsValidProperty(); } } } } void ManageHeaderBar::tracksAboutToBeMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row) { Q_UNUSED(parent); Q_UNUSED(start); Q_UNUSED(end); Q_UNUSED(destination); Q_UNUSED(row); mOldRemainingTracks = remainingTracks(); } void ManageHeaderBar::tracksMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row) { Q_UNUSED(parent); Q_UNUSED(start); Q_UNUSED(end); Q_UNUSED(destination); Q_UNUSED(row); auto newRemainingTracks = remainingTracks(); if (mOldRemainingTracks != newRemainingTracks) { Q_EMIT remainingTracksChanged(); } } void ManageHeaderBar::tracksRemoved(const QModelIndex &parent, int first, int last) { Q_UNUSED(parent); Q_UNUSED(first); Q_UNUSED(last); if (!mCurrentTrack.isValid()) { notifyArtistProperty(); notifyTitleProperty(); notifyAlbumProperty(); notifyAlbumArtistProperty(); + notifyFileNameProperty(); notifyImageProperty(); + notifyDatabaseIdProperty(); notifyAlbumIdProperty(); notifyIsValidProperty(); notifyRemainingTracksProperty(); return; } notifyRemainingTracksProperty(); } void ManageHeaderBar::notifyArtistProperty() { auto newArtistValue = mCurrentTrack.data(mArtistRole); if (mOldArtist != newArtistValue) { Q_EMIT artistChanged(); mOldArtist = newArtistValue; } } void ManageHeaderBar::notifyTitleProperty() { auto newTitleValue = mCurrentTrack.data(mTitleRole); if (mOldTitle != newTitleValue) { Q_EMIT titleChanged(); mOldTitle = newTitleValue; } } void ManageHeaderBar::notifyAlbumProperty() { auto newAlbumValue = mCurrentTrack.data(mAlbumRole); if (mOldAlbum != newAlbumValue) { Q_EMIT albumChanged(); mOldAlbum = newAlbumValue; } } void ManageHeaderBar::notifyAlbumArtistProperty() { auto newAlbumArtistValue = mCurrentTrack.data(mAlbumArtistRole); if (mOldAlbumArtist != newAlbumArtistValue) { Q_EMIT albumArtistChanged(); mOldAlbumArtist = newAlbumArtistValue; } } +void ManageHeaderBar::notifyFileNameProperty() +{ + auto newFileNameValue = mCurrentTrack.data(mFileNameRole); + if (mOldFileName != newFileNameValue) { + Q_EMIT fileNameChanged(); + + mOldFileName = newFileNameValue; + } +} + void ManageHeaderBar::notifyImageProperty() { auto newImageValue = mCurrentTrack.data(mImageRole); if (mOldImage != newImageValue) { Q_EMIT imageChanged(); mOldImage = newImageValue; } } +void ManageHeaderBar::notifyDatabaseIdProperty() +{ + bool conversionOk; + auto newDatabaseIdValue = mCurrentTrack.data(mDatabaseIdRole).toULongLong(&conversionOk); + if (conversionOk && mOldDatabaseId != newDatabaseIdValue) { + Q_EMIT databaseIdChanged(); + + mOldDatabaseId = newDatabaseIdValue; + } else if (!conversionOk && mOldDatabaseId != 0) { + Q_EMIT databaseIdChanged(); + + mOldDatabaseId = 0; + } +} + void ManageHeaderBar::notifyAlbumIdProperty() { bool conversionOk; auto newAlbumIdValue = mCurrentTrack.data(mAlbumIdRole).toULongLong(&conversionOk); if (conversionOk && mOldAlbumId != newAlbumIdValue) { Q_EMIT albumIdChanged(); mOldAlbumId = newAlbumIdValue; } else if (!conversionOk && mOldAlbumId != 0) { Q_EMIT albumIdChanged(); mOldAlbumId = 0; } } void ManageHeaderBar::notifyIsValidProperty() { auto newIsValidValue = mCurrentTrack.data(mIsValidRole).toBool(); if (mOldIsValid != newIsValidValue) { Q_EMIT isValidChanged(); mOldIsValid = newIsValidValue; } } void ManageHeaderBar::notifyRemainingTracksProperty() { auto newRemainingTracksValue = remainingTracks(); if (mOldRemainingTracks != newRemainingTracksValue) { Q_EMIT remainingTracksChanged(); mOldRemainingTracks = newRemainingTracksValue; } } void ManageHeaderBar::setIsValidRole(int isValidRole) { mIsValidRole = isValidRole; emit isValidRoleChanged(); } void ManageHeaderBar::setCurrentTrack(const QPersistentModelIndex ¤tTrack) { if (mCurrentTrack == currentTrack) { return; } auto oldRemainingTracksCount = remainingTracks(); mCurrentTrack = currentTrack; Q_EMIT currentTrackChanged(); if (mCurrentTrack.isValid() && oldRemainingTracksCount != remainingTracks()) { Q_EMIT remainingTracksChanged(); mOldRemainingTracks = remainingTracks(); } notifyArtistProperty(); notifyTitleProperty(); notifyAlbumProperty(); notifyAlbumArtistProperty(); + notifyFileNameProperty(); notifyImageProperty(); + notifyDatabaseIdProperty(); notifyAlbumIdProperty(); notifyIsValidProperty(); } void ManageHeaderBar::setPlayListModel(QAbstractItemModel *aPlayListModel) { if (mPlayListModel) { disconnect(mPlayListModel, &QAbstractItemModel::rowsInserted, this, &ManageHeaderBar::tracksInserted); disconnect(mPlayListModel, &QAbstractItemModel::rowsAboutToBeMoved, this, &ManageHeaderBar::tracksAboutToBeMoved); disconnect(mPlayListModel, &QAbstractItemModel::rowsMoved, this, &ManageHeaderBar::tracksMoved); disconnect(mPlayListModel, &QAbstractItemModel::rowsRemoved, this, &ManageHeaderBar::tracksRemoved); disconnect(mPlayListModel, &QAbstractItemModel::dataChanged, this, &ManageHeaderBar::tracksDataChanged); disconnect(mPlayListModel, &QAbstractItemModel::layoutChanged, this, &ManageHeaderBar::playListLayoutChanged); } mPlayListModel = aPlayListModel; if (mPlayListModel) { connect(mPlayListModel, &QAbstractItemModel::rowsInserted, this, &ManageHeaderBar::tracksInserted); connect(mPlayListModel, &QAbstractItemModel::rowsAboutToBeMoved, this, &ManageHeaderBar::tracksAboutToBeMoved); connect(mPlayListModel, &QAbstractItemModel::rowsMoved, this, &ManageHeaderBar::tracksMoved); connect(mPlayListModel, &QAbstractItemModel::rowsRemoved, this, &ManageHeaderBar::tracksRemoved); connect(mPlayListModel, &QAbstractItemModel::dataChanged, this, &ManageHeaderBar::tracksDataChanged); connect(mPlayListModel, &QAbstractItemModel::layoutChanged, this, &ManageHeaderBar::playListLayoutChanged); } Q_EMIT playListModelChanged(); } QAbstractItemModel *ManageHeaderBar::playListModel() const { return mPlayListModel; } #include "moc_manageheaderbar.cpp" diff --git a/src/manageheaderbar.h b/src/manageheaderbar.h index 37ff5d04..a9ad5a0d 100644 --- a/src/manageheaderbar.h +++ b/src/manageheaderbar.h @@ -1,273 +1,323 @@ /* * Copyright 2016 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef MANAGEHEADERBAR_H #define MANAGEHEADERBAR_H #include "elisaLib_export.h" #include #include #include #include #include #include class ELISALIB_EXPORT ManageHeaderBar : public QObject { Q_OBJECT Q_PROPERTY(QPersistentModelIndex currentTrack READ currentTrack WRITE setCurrentTrack NOTIFY currentTrackChanged) Q_PROPERTY(QAbstractItemModel* playListModel READ playListModel WRITE setPlayListModel NOTIFY playListModelChanged) Q_PROPERTY(int artistRole READ artistRole WRITE setArtistRole NOTIFY artistRoleChanged) Q_PROPERTY(int titleRole READ titleRole WRITE setTitleRole NOTIFY titleRoleChanged) Q_PROPERTY(int albumRole READ albumRole WRITE setAlbumRole NOTIFY albumRoleChanged) Q_PROPERTY(int albumArtistRole READ albumArtistRole WRITE setAlbumArtistRole NOTIFY albumArtistRoleChanged) + Q_PROPERTY(int fileNameRole + READ fileNameRole + WRITE setFileNameRole + NOTIFY fileNameRoleChanged) + Q_PROPERTY(int imageRole READ imageRole WRITE setImageRole NOTIFY imageRoleChanged) + Q_PROPERTY(int databaseIdRole + READ databaseIdRole + WRITE setDatabaseIdRole + NOTIFY databaseIdRoleChanged) + Q_PROPERTY(int albumIdRole READ albumIdRole WRITE setAlbumIdRole NOTIFY albumIdRoleChanged) Q_PROPERTY(int isValidRole READ isValidRole WRITE setIsValidRole NOTIFY isValidRoleChanged) Q_PROPERTY(QVariant artist READ artist NOTIFY artistChanged) Q_PROPERTY(QVariant title READ title NOTIFY titleChanged) Q_PROPERTY(QVariant album READ album NOTIFY albumChanged) Q_PROPERTY(QVariant albumArtist READ albumArtist NOTIFY albumArtistChanged) + Q_PROPERTY(QString fileName + READ fileName + NOTIFY fileNameChanged) + Q_PROPERTY(QUrl image READ image NOTIFY imageChanged) + Q_PROPERTY(qulonglong databaseId + READ databaseId + NOTIFY databaseIdChanged) + Q_PROPERTY(qulonglong albumId READ albumId NOTIFY albumIdChanged) Q_PROPERTY(bool isValid READ isValid NOTIFY isValidChanged) Q_PROPERTY(int remainingTracks READ remainingTracks NOTIFY remainingTracksChanged) public: explicit ManageHeaderBar(QObject *parent = nullptr); QPersistentModelIndex currentTrack() const; QAbstractItemModel* playListModel() const; int artistRole() const; int titleRole() const; int albumRole() const; int albumArtistRole() const; + int fileNameRole() const; + int imageRole() const; + int databaseIdRole() const; + int albumIdRole() const; int isValidRole() const; QVariant artist() const; QVariant title() const; QVariant album() const; QVariant albumArtist() const; + QString fileName() const; + QUrl image() const; + qulonglong databaseId() const; + qulonglong albumId() const; bool isValid() const; int remainingTracks() const; Q_SIGNALS: void currentTrackChanged(); void playListModelChanged(); void artistRoleChanged(); void titleRoleChanged(); void albumRoleChanged(); void albumArtistRoleChanged(); + void fileNameRoleChanged(); + void imageRoleChanged(); + void databaseIdRoleChanged(); + void albumIdRoleChanged(); void isValidRoleChanged(); void artistChanged(); void titleChanged(); void albumChanged(); void albumArtistChanged(); + void fileNameChanged(); + void imageChanged(); void remainingTracksChanged(); + void databaseIdChanged(); + void albumIdChanged(); void isValidChanged(); public Q_SLOTS: void setCurrentTrack(const QPersistentModelIndex ¤tTrack); void setPlayListModel(QAbstractItemModel* aPlayListModel); void setArtistRole(int value); void setTitleRole(int value); void setAlbumRole(int value); void setAlbumArtistRole(int value); + void setFileNameRole(int value); + void setImageRole(int value); + void setDatabaseIdRole(int databaseIdRole); + void setAlbumIdRole(int albumIdRole); void setIsValidRole(int isValidRole); void playListLayoutChanged(const QList &parents, QAbstractItemModel::LayoutChangeHint hint); void tracksInserted(const QModelIndex &parent, int first, int last); void tracksDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles); void tracksAboutToBeMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row); void tracksMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row); void tracksRemoved(const QModelIndex &parent, int first, int last); private: void notifyArtistProperty(); void notifyTitleProperty(); void notifyAlbumProperty(); void notifyAlbumArtistProperty(); + void notifyFileNameProperty(); + void notifyImageProperty(); + void notifyDatabaseIdProperty(); + void notifyAlbumIdProperty(); void notifyIsValidProperty(); void notifyRemainingTracksProperty(); QPersistentModelIndex mCurrentTrack; QAbstractItemModel *mPlayListModel = nullptr; int mArtistRole = Qt::DisplayRole; int mTitleRole = Qt::DisplayRole; int mAlbumRole = Qt::DisplayRole; int mAlbumArtistRole = Qt::DisplayRole; + int mFileNameRole = Qt::DisplayRole; + int mImageRole = Qt::DisplayRole; + int mDatabaseIdRole = Qt::DisplayRole; + int mAlbumIdRole = Qt::DisplayRole; int mIsValidRole = Qt::DisplayRole; QVariant mOldArtist; QVariant mOldTitle; QVariant mOldAlbum; QVariant mOldAlbumArtist; + QVariant mOldFileName; + QVariant mOldImage; + qulonglong mOldDatabaseId = 0; + qulonglong mOldAlbumId = 0; bool mOldIsValid = false; int mOldRemainingTracks = 0; }; #endif // MANAGEHEADERBAR_H diff --git a/src/models/trackcontextmetadatamodel.cpp b/src/models/trackcontextmetadatamodel.cpp new file mode 100644 index 00000000..95d69548 --- /dev/null +++ b/src/models/trackcontextmetadatamodel.cpp @@ -0,0 +1,41 @@ +/* + * Copyright 2019 Matthieu Gallien + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "trackcontextmetadatamodel.h" + +TrackContextMetaDataModel::TrackContextMetaDataModel(QObject *parent) : TrackMetadataModel(parent) +{ +} + +void TrackContextMetaDataModel::filterDataFromTrackData() +{ + removeMetaData(DatabaseInterface::TitleRole); + removeMetaData(DatabaseInterface::ArtistRole); + removeMetaData(DatabaseInterface::AlbumRole); + + if (dataFromType(DatabaseInterface::IsSingleDiscAlbumRole).toBool() && + dataFromType(DatabaseInterface::DiscNumberRole).toInt() == 1) { + removeMetaData(DatabaseInterface::DiscNumberRole); + } +} + +void TrackContextMetaDataModel::fillLyricsDataFromTrack() +{ +} + + +#include "moc_trackcontextmetadatamodel.cpp" diff --git a/src/models/trackcontextmetadatamodel.h b/src/models/trackcontextmetadatamodel.h new file mode 100644 index 00000000..0deac342 --- /dev/null +++ b/src/models/trackcontextmetadatamodel.h @@ -0,0 +1,42 @@ +/* + * Copyright 2019 Matthieu Gallien + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef TRACKCONTEXTMETADATAMODEL_H +#define TRACKCONTEXTMETADATAMODEL_H + +#include "elisaLib_export.h" + +#include "trackmetadatamodel.h" + +class ELISALIB_EXPORT TrackContextMetaDataModel : public TrackMetadataModel +{ + + Q_OBJECT + +public: + + TrackContextMetaDataModel(QObject *parent = nullptr); + +protected: + + void filterDataFromTrackData() override; + + void fillLyricsDataFromTrack() override; + +}; + +#endif // TRACKCONTEXTMETADATAMODEL_H diff --git a/src/models/trackmetadatamodel.cpp b/src/models/trackmetadatamodel.cpp index 4a6e213a..75adcbe7 100644 --- a/src/models/trackmetadatamodel.cpp +++ b/src/models/trackmetadatamodel.cpp @@ -1,326 +1,425 @@ /* * Copyright 2018 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "trackmetadatamodel.h" #include "musiclistenersmanager.h" #include +#include + TrackMetadataModel::TrackMetadataModel(QObject *parent) : QAbstractListModel(parent) { + connect(&mLyricsValueWatcher, &QFutureWatcher::finished, + this, &TrackMetadataModel::lyricsValueIsReady); +} + +TrackMetadataModel::~TrackMetadataModel() +{ + if (mLyricsValueWatcher.isRunning() && !mLyricsValueWatcher.isFinished()) { + mLyricsValueWatcher.waitForFinished(); + } } int TrackMetadataModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return mTrackData.count(); } QVariant TrackMetadataModel::data(const QModelIndex &index, int role) const { auto result = QVariant{}; const auto currentKey = mTrackKeys[index.row()]; switch (role) { case Qt::DisplayRole: result = mTrackData[currentKey]; break; case ItemNameRole: switch (currentKey) { case DatabaseInterface::TitleRole: - result = i18nc("Track title for track metadata view", "Title:"); + result = i18nc("Track title for track metadata view", "Title"); break; case DatabaseInterface::DurationRole: - result = i18nc("Duration label for track metadata view", "Duration:"); + result = i18nc("Duration label for track metadata view", "Duration"); break; case DatabaseInterface::ArtistRole: - result = i18nc("Track artist for track metadata view", "Artist:"); + result = i18nc("Track artist for track metadata view", "Artist"); break; case DatabaseInterface::AlbumRole: - result = i18nc("Album name for track metadata view", "Album:"); + result = i18nc("Album name for track metadata view", "Album"); break; case DatabaseInterface::AlbumArtistRole: - result = i18nc("Album artist for track metadata view", "Album Artist:"); + result = i18nc("Album artist for track metadata view", "Album Artist"); break; case DatabaseInterface::TrackNumberRole: - result = i18nc("Track number for track metadata view", "Track Number:"); + result = i18nc("Track number for track metadata view", "Track Number"); break; case DatabaseInterface::DiscNumberRole: - result = i18nc("Disc number for track metadata view", "Disc Number:"); + result = i18nc("Disc number for track metadata view", "Disc Number"); break; case DatabaseInterface::RatingRole: - result = i18nc("Rating label for information panel", "Rating:"); + result = i18nc("Rating label for information panel", "Rating"); break; case DatabaseInterface::GenreRole: - result = i18nc("Genre label for track metadata view", "Genre:"); + result = i18nc("Genre label for track metadata view", "Genre"); break; case DatabaseInterface::LyricistRole: - result = i18nc("Lyricist label for track metadata view", "Lyricist:"); + result = i18nc("Lyricist label for track metadata view", "Lyricist"); break; case DatabaseInterface::ComposerRole: - result = i18nc("Composer name for track metadata view", "Composer:"); + result = i18nc("Composer name for track metadata view", "Composer"); break; case DatabaseInterface::CommentRole: - result = i18nc("Comment label for track metadata view", "Comment:"); + result = i18nc("Comment label for track metadata view", "Comment"); break; case DatabaseInterface::YearRole: - result = i18nc("Year label for track metadata view", "Year:"); + result = i18nc("Year label for track metadata view", "Year"); break; case DatabaseInterface::ChannelsRole: - result = i18nc("Channels label for track metadata view", "Channels:"); + result = i18nc("Channels label for track metadata view", "Channels"); break; case DatabaseInterface::BitRateRole: - result = i18nc("Bit rate label for track metadata view", "Bit Rate:"); + result = i18nc("Bit rate label for track metadata view", "Bit Rate"); break; case DatabaseInterface::SampleRateRole: - result = i18nc("Sample Rate label for track metadata view", "Sample Rate:"); + result = i18nc("Sample Rate label for track metadata view", "Sample Rate"); break; case DatabaseInterface::LastPlayDate: - result = i18nc("Last play date label for track metadata view", "Last played:"); + result = i18nc("Last play date label for track metadata view", "Last played"); break; case DatabaseInterface::PlayCounter: - result = i18nc("Play counter label for track metadata view", "Play count:"); + result = i18nc("Play counter label for track metadata view", "Play count"); + break; + case DatabaseInterface::LyricsRole: + result = i18nc("Lyrics label for track metadata view", "Lyrics"); break; case DatabaseInterface::SecondaryTextRole: case DatabaseInterface::ImageUrlRole: case DatabaseInterface::ShadowForImageRole: case DatabaseInterface::ChildModelRole: case DatabaseInterface::StringDurationRole: case DatabaseInterface::MilliSecondsDurationRole: case DatabaseInterface::AllArtistsRole: case DatabaseInterface::HighestTrackRating: case DatabaseInterface::ResourceRole: case DatabaseInterface::IdRole: case DatabaseInterface::DatabaseIdRole: case DatabaseInterface::IsSingleDiscAlbumRole: case DatabaseInterface::ContainerDataRole: case DatabaseInterface::IsPartialDataRole: case DatabaseInterface::AlbumIdRole: case DatabaseInterface::HasEmbeddedCover: case DatabaseInterface::FileModificationTime: case DatabaseInterface::FirstPlayDate: case DatabaseInterface::PlayFrequency: case DatabaseInterface::ElementTypeRole: break; } break; case ItemTypeRole: switch (currentKey) { case DatabaseInterface::TitleRole: result = TextEntry; break; case DatabaseInterface::ArtistRole: result = TextEntry; break; case DatabaseInterface::AlbumRole: result = TextEntry; break; case DatabaseInterface::AlbumArtistRole: result = TextEntry; break; case DatabaseInterface::TrackNumberRole: result = IntegerEntry; break; case DatabaseInterface::DiscNumberRole: result = IntegerEntry; break; case DatabaseInterface::RatingRole: result = RatingEntry; break; case DatabaseInterface::GenreRole: result = TextEntry; break; case DatabaseInterface::LyricistRole: result = TextEntry; break; case DatabaseInterface::ComposerRole: result = TextEntry; break; case DatabaseInterface::CommentRole: result = TextEntry; break; case DatabaseInterface::YearRole: result = IntegerEntry; break; case DatabaseInterface::LastPlayDate: result = DateEntry; break; case DatabaseInterface::PlayCounter: result = IntegerEntry; break; + case DatabaseInterface::LyricsRole: + result = LongTextEntry; + break; case DatabaseInterface::DurationRole: case DatabaseInterface::SampleRateRole: case DatabaseInterface::BitRateRole: case DatabaseInterface::ChannelsRole: case DatabaseInterface::SecondaryTextRole: case DatabaseInterface::ImageUrlRole: case DatabaseInterface::ShadowForImageRole: case DatabaseInterface::ChildModelRole: case DatabaseInterface::StringDurationRole: case DatabaseInterface::MilliSecondsDurationRole: case DatabaseInterface::AllArtistsRole: case DatabaseInterface::HighestTrackRating: case DatabaseInterface::ResourceRole: case DatabaseInterface::IdRole: case DatabaseInterface::DatabaseIdRole: case DatabaseInterface::IsSingleDiscAlbumRole: case DatabaseInterface::ContainerDataRole: case DatabaseInterface::IsPartialDataRole: case DatabaseInterface::AlbumIdRole: case DatabaseInterface::HasEmbeddedCover: case DatabaseInterface::FileModificationTime: case DatabaseInterface::FirstPlayDate: case DatabaseInterface::PlayFrequency: case DatabaseInterface::ElementTypeRole: break; } break; } return result; } bool TrackMetadataModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (data(index, role) != value) { // FIXME: Implement me! emit dataChanged(index, index, QVector() << role); return true; } return false; } QHash TrackMetadataModel::roleNames() const { auto names = QAbstractListModel::roleNames(); names[ItemNameRole] = "name"; names[ItemTypeRole] = "type"; return names; } -Qt::ItemFlags TrackMetadataModel::flags(const QModelIndex &index) const -{ - if (!index.isValid()) - return Qt::NoItemFlags; - - return Qt::ItemIsEditable | QAbstractListModel::flags(index); -} - QString TrackMetadataModel::fileUrl() const { return mFileUrl; } -bool TrackMetadataModel::insertRows(int row, int count, const QModelIndex &parent) +const QUrl &TrackMetadataModel::coverUrl() const { - beginInsertRows(parent, row, row + count - 1); - endInsertRows(); - - return true; + return mCoverImage; } -bool TrackMetadataModel::removeRows(int row, int count, const QModelIndex &parent) +MusicListenersManager *TrackMetadataModel::manager() const { - beginRemoveRows(parent, row, row + count - 1); - endRemoveRows(); - - return true; + return mManager; } -const QUrl &TrackMetadataModel::coverUrl() const +QString TrackMetadataModel::lyrics() const { - return mCoverImage; + return mFullData[TrackDataType::key_type::LyricsRole].toString(); } void TrackMetadataModel::trackData(const TrackMetadataModel::TrackDataType &trackData) { - beginResetModel(); - if (mTrackData.isValid()) { - mTrackData.clear(); - mTrackKeys.clear(); + if (!mFullData.isEmpty() && trackData.databaseId() != mFullData.databaseId()) { + return; } + fillDataFromTrackData(trackData); +} + +void TrackMetadataModel::fillDataFromTrackData(const TrackMetadataModel::TrackDataType &trackData) +{ + beginResetModel(); + mFullData = trackData; + mTrackData.clear(); + mTrackKeys.clear(); + for (auto role : {DatabaseInterface::TitleRole, DatabaseInterface::ArtistRole, DatabaseInterface::AlbumRole, DatabaseInterface::AlbumArtistRole, DatabaseInterface::TrackNumberRole, DatabaseInterface::DiscNumberRole, DatabaseInterface::RatingRole, DatabaseInterface::GenreRole, DatabaseInterface::LyricistRole, DatabaseInterface::ComposerRole, DatabaseInterface::CommentRole, DatabaseInterface::YearRole, DatabaseInterface::LastPlayDate, DatabaseInterface::PlayCounter}) { if (trackData.constFind(role) != trackData.constEnd()) { if (role == DatabaseInterface::RatingRole) { if (trackData[role].toInt() == 0) { continue; } } mTrackKeys.push_back(role); mTrackData[role] = trackData[role]; } } + filterDataFromTrackData(); endResetModel(); + fetchLyrics(); + mCoverImage = trackData[DatabaseInterface::ImageUrlRole].toUrl(); Q_EMIT coverUrlChanged(); auto rawFileUrl = trackData[DatabaseInterface::ResourceRole].toUrl(); if (rawFileUrl.isLocalFile()) { mFileUrl = rawFileUrl.toLocalFile(); } else { mFileUrl = rawFileUrl.toString(); } Q_EMIT fileUrlChanged(); } -void TrackMetadataModel::initializeByTrackId(MusicListenersManager *manager, qulonglong databaseId) +void TrackMetadataModel::filterDataFromTrackData() +{ +} + +void TrackMetadataModel::removeMetaData(DatabaseInterface::ColumnsRoles metaData) +{ + auto itMetaData = std::find(mTrackKeys.begin(), mTrackKeys.end(), metaData); + if (itMetaData == mTrackKeys.end()) { + return; + } + + mTrackKeys.erase(itMetaData); + mTrackData.remove(metaData); +} + +TrackMetadataModel::TrackDataType::mapped_type TrackMetadataModel::dataFromType(TrackDataType::key_type metaData) const +{ + return mFullData[metaData]; +} + +void TrackMetadataModel::fillLyricsDataFromTrack() { - mDataLoader.setDatabase(manager->viewDatabase()); - manager->connectModel(&mDataLoader); + beginInsertRows({}, mTrackData.size(), mTrackData.size()); + mTrackKeys.push_back(DatabaseInterface::LyricsRole); + mTrackData[DatabaseInterface::LyricsRole] = mLyricsValueWatcher.result(); + endInsertRows(); +} + +void TrackMetadataModel::lyricsValueIsReady() +{ + if (!mLyricsValueWatcher.result().isEmpty()) { + fillLyricsDataFromTrack(); + + mFullData[DatabaseInterface::LyricsRole] = mLyricsValueWatcher.result(); + + Q_EMIT lyricsChanged(); + } +} + +void TrackMetadataModel::initialize(MusicListenersManager *newManager, DatabaseInterface *trackDatabase) +{ + mManager = newManager; + Q_EMIT managerChanged(); + + if (mManager) { + mDataLoader.setDatabase(mManager->viewDatabase()); + } else if (trackDatabase) { + mDataLoader.setDatabase(trackDatabase); + } + + if (mManager) { + mManager->connectModel(&mDataLoader); + } connect(this, &TrackMetadataModel::needDataByDatabaseId, &mDataLoader, &ModelDataLoader::loadDataByDatabaseId); + connect(this, &TrackMetadataModel::needDataByFileName, + &mDataLoader, &ModelDataLoader::loadDataByFileName); connect(&mDataLoader, &ModelDataLoader::allTrackData, this, &TrackMetadataModel::trackData); + connect(&mDataLoader, &ModelDataLoader::trackModified, + this, &TrackMetadataModel::trackData); +} + +void TrackMetadataModel::fetchLyrics() +{ + auto lyricicsValue = QtConcurrent::run(QThreadPool::globalInstance(), [=]() { + auto trackData = mFileScanner.scanOneFile(mFullData[DatabaseInterface::ResourceRole].toUrl(), mMimeDatabase); + if (!trackData.lyrics().isEmpty()) { + return trackData.lyrics(); + } + return QString{}; + }); + + mLyricsValueWatcher.setFuture(lyricicsValue); +} + +void TrackMetadataModel::initializeByTrackId(qulonglong databaseId) +{ + mFullData.clear(); + mTrackData.clear(); + mCoverImage.clear(); + mFileUrl.clear(); + + Q_EMIT lyricsChanged(); Q_EMIT needDataByDatabaseId(ElisaUtils::Track, databaseId); } -void TrackMetadataModel::initializeByTrackFileName(MusicListenersManager *manager, const QUrl &fileName) +void TrackMetadataModel::initializeByTrackFileName(const QUrl &fileName) { - mDataLoader.setDatabase(manager->viewDatabase()); - manager->connectModel(&mDataLoader); + mFullData.clear(); + mTrackData.clear(); + mCoverImage.clear(); + mFileUrl.clear(); - connect(this, &TrackMetadataModel::needDataByFileName, - &mDataLoader, &ModelDataLoader::loadDataByFileName); - connect(&mDataLoader, &ModelDataLoader::allTrackData, - this, &TrackMetadataModel::trackData); + Q_EMIT lyricsChanged(); Q_EMIT needDataByFileName(ElisaUtils::FileName, fileName); } +void TrackMetadataModel::setManager(MusicListenersManager *newManager) +{ + initialize(newManager, nullptr); +} + +void TrackMetadataModel::setDatabase(DatabaseInterface *trackDatabase) +{ + initialize(nullptr, trackDatabase); +} + #include "moc_trackmetadatamodel.cpp" diff --git a/src/models/trackmetadatamodel.h b/src/models/trackmetadatamodel.h index 3b751f22..e125a940 100644 --- a/src/models/trackmetadatamodel.h +++ b/src/models/trackmetadatamodel.h @@ -1,117 +1,169 @@ /* * Copyright 2018 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef TRACKMETADATAMODEL_H #define TRACKMETADATAMODEL_H #include "elisaLib_export.h" #include "elisautils.h" #include "databaseinterface.h" #include "modeldataloader.h" +#include "filescanner.h" #include #include +#include +#include class MusicListenersManager; class ELISALIB_EXPORT TrackMetadataModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(QUrl coverUrl READ coverUrl NOTIFY coverUrlChanged) Q_PROPERTY(QString fileUrl READ fileUrl NOTIFY fileUrlChanged) + Q_PROPERTY(MusicListenersManager* manager + READ manager + WRITE setManager + NOTIFY managerChanged) + + Q_PROPERTY(QString lyrics + READ lyrics + NOTIFY lyricsChanged) + public: enum ColumnRoles { ItemNameRole = Qt::UserRole + 1, ItemTypeRole, }; enum ItemType { TextEntry, IntegerEntry, RatingEntry, DateEntry, + LongTextEntry, }; Q_ENUM(ItemType) using TrackDataType = DatabaseInterface::TrackDataType; explicit TrackMetadataModel(QObject *parent = nullptr); + ~TrackMetadataModel() override; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; QHash roleNames() const override; - Qt::ItemFlags flags(const QModelIndex& index) const override; - - bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) override; - - bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override; - const QUrl& coverUrl() const; QString fileUrl() const; + MusicListenersManager* manager() const; + + QString lyrics() const; + Q_SIGNALS: void needDataByDatabaseId(ElisaUtils::PlayListEntryType dataType, qulonglong databaseId); void needDataByFileName(ElisaUtils::PlayListEntryType dataType, const QUrl &fileName); void coverUrlChanged(); void fileUrlChanged(); + void managerChanged(); + + void lyricsChanged(); + public Q_SLOTS: void trackData(const TrackMetadataModel::TrackDataType &trackData); - void initializeByTrackId(MusicListenersManager *manager, qulonglong databaseId); + void initializeByTrackId(qulonglong databaseId); + + void initializeByTrackFileName(const QUrl &fileName); + + void setManager(MusicListenersManager *newManager); + + void setDatabase(DatabaseInterface *trackDatabase); + +protected: - void initializeByTrackFileName(MusicListenersManager *manager, const QUrl &fileName); + void fillDataFromTrackData(const TrackMetadataModel::TrackDataType &trackData); + + virtual void filterDataFromTrackData(); + + void removeMetaData(DatabaseInterface::ColumnsRoles metaData); + + TrackDataType::mapped_type dataFromType(TrackDataType::key_type metaData) const; + + virtual void fillLyricsDataFromTrack(); + +private Q_SLOTS: + + void lyricsValueIsReady(); private: + void initialize(MusicListenersManager *newManager, + DatabaseInterface *trackDatabase); + + void fetchLyrics(); + + TrackDataType mFullData; + TrackDataType mTrackData; QUrl mCoverImage; QString mFileUrl; QList mTrackKeys; ModelDataLoader mDataLoader; + MusicListenersManager *mManager = nullptr; + + FileScanner mFileScanner; + + QMimeDatabase mMimeDatabase; + + QFutureWatcher mLyricsValueWatcher; + }; #endif // TRACKMETADATAMODEL_H diff --git a/src/musicaudiotrack.cpp b/src/musicaudiotrack.cpp index ef50b6cf..505cb4fb 100644 --- a/src/musicaudiotrack.cpp +++ b/src/musicaudiotrack.cpp @@ -1,590 +1,605 @@ /* * Copyright 2016-2017 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "musicaudiotrack.h" #include #include #include #include class MusicAudioTrackPrivate : public QSharedData { public: MusicAudioTrackPrivate() = default; MusicAudioTrackPrivate(bool aValid, QString aId, QString aParentId, QString aTitle, QString aArtist, QString aAlbumName, QString aAlbumArtist, int aTrackNumber, int aDiscNumber, QTime aDuration, QUrl aResourceURI, QDateTime fileModificationTime, QUrl aAlbumCover, int rating, bool aIsSingleDiscAlbum, QString aGenre, QString aComposer, QString aLyricist, bool aHasEmbeddedCover) : QSharedData(), mId(std::move(aId)), mParentId(std::move(aParentId)), mTitle(std::move(aTitle)), mArtist(std::move(aArtist)), mAlbumName(std::move(aAlbumName)), mAlbumArtist(std::move(aAlbumArtist)), mGenre(std::move(aGenre)), mComposer(std::move(aComposer)), mLyricist(std::move(aLyricist)), - mResourceURI(std::move(aResourceURI)), mAlbumCover(std::move(aAlbumCover)), + mLyrics(), mResourceURI(std::move(aResourceURI)), mAlbumCover(std::move(aAlbumCover)), mFileModificationTime(std::move(fileModificationTime)), mDuration(aDuration), mTrackNumber(aTrackNumber), mDiscNumber(aDiscNumber), mRating(rating), mIsValid(aValid), mIsSingleDiscAlbum(aIsSingleDiscAlbum), mHasBooleanCover(aHasEmbeddedCover), mTrackNumberIsValid(true), mDiscNumberIsValid(true) { } QString mId; QString mParentId; QString mTitle; QString mArtist; QString mAlbumName; QString mAlbumArtist; QString mGenre; QString mComposer; QString mLyricist; + QString mLyrics; + QString mComment; QUrl mResourceURI; QUrl mAlbumCover; qulonglong mDatabaseId = 0; qulonglong mAlbumId = 0; QDateTime mFileModificationTime; QTime mDuration; int mTrackNumber = -1; int mDiscNumber = -1; int mChannels = -1; int mBitRate = -1; int mSampleRate = -1; int mYear = 0; int mRating = -1; bool mIsValid = false; bool mIsSingleDiscAlbum = true; bool mHasBooleanCover = false; bool mTrackNumberIsValid = false; bool mDiscNumberIsValid = false; bool mChannelsIsValid = false; bool mBitRateIsValid = false; bool mSampleRateIsValid = false; }; MusicAudioTrack::MusicAudioTrack() : d(new MusicAudioTrackPrivate()) { } MusicAudioTrack::MusicAudioTrack(bool aValid, QString aId, QString aParentId, QString aTitle, QString aArtist, QString aAlbumName, QString aAlbumArtist, int aTrackNumber, int aDiscNumber, QTime aDuration, QUrl aResourceURI, const QDateTime &fileModificationTime, QUrl aAlbumCover, int rating, bool aIsSingleDiscAlbum, QString aGenre, QString aComposer, QString aLyricist, bool aHasEmbeddedCover) : d(new MusicAudioTrackPrivate(aValid, std::move(aId), std::move(aParentId), std::move(aTitle), std::move(aArtist), std::move(aAlbumName), std::move(aAlbumArtist), aTrackNumber, aDiscNumber, aDuration, std::move(aResourceURI), fileModificationTime, std::move(aAlbumCover), rating, aIsSingleDiscAlbum, std::move(aGenre), std::move(aComposer), std::move(aLyricist), aHasEmbeddedCover)) { } MusicAudioTrack::MusicAudioTrack(MusicAudioTrack &&other) noexcept = default; MusicAudioTrack::MusicAudioTrack(const MusicAudioTrack &other) = default; MusicAudioTrack::~MusicAudioTrack() = default; MusicAudioTrack& MusicAudioTrack::operator=(MusicAudioTrack &&other) noexcept = default; MusicAudioTrack& MusicAudioTrack::operator=(const MusicAudioTrack &other) = default; bool MusicAudioTrack::operator <(const MusicAudioTrack &other) const { return d->mDiscNumber < other.d->mDiscNumber || (d->mDiscNumber == other.d->mDiscNumber && d->mTrackNumber < other.d->mTrackNumber); } bool MusicAudioTrack::operator ==(const MusicAudioTrack &other) const { return d->mTitle == other.d->mTitle && d->mArtist == other.d->mArtist && d->mAlbumName == other.d->mAlbumName && d->mAlbumArtist == other.d->mAlbumArtist && d->mTrackNumber == other.d->mTrackNumber && d->mDiscNumber == other.d->mDiscNumber && d->mDuration == other.d->mDuration && d->mResourceURI == other.d->mResourceURI && d->mFileModificationTime == other.d->mFileModificationTime && d->mAlbumCover == other.d->mAlbumCover && d->mRating == other.d->mRating && d->mGenre == other.d->mGenre && d->mComposer == other.d->mComposer && - d->mLyricist == other.d->mLyricist && d->mComment == other.d->mComment && + d->mLyricist == other.d->mLyricist && d->mLyrics == other.d->mLyrics && + d->mComment == other.d->mComment && d->mYear == other.d->mYear && d->mChannels == other.d->mChannels && d->mBitRate == other.d->mBitRate && d->mSampleRate == other.d->mSampleRate; } bool MusicAudioTrack::operator !=(const MusicAudioTrack &other) const { return d->mTitle != other.d->mTitle || d->mArtist != other.d->mArtist || d->mAlbumName != other.d->mAlbumName || d->mAlbumArtist != other.d->mAlbumArtist || d->mTrackNumber != other.d->mTrackNumber || d->mDiscNumber != other.d->mDiscNumber || d->mDuration != other.d->mDuration || d->mResourceURI != other.d->mResourceURI || d->mFileModificationTime != other.d->mFileModificationTime || d->mAlbumCover != other.d->mAlbumCover || d->mRating != other.d->mRating || d->mGenre != other.d->mGenre || d->mComposer != other.d->mComposer || - d->mLyricist != other.d->mLyricist || d->mComment != other.d->mComment || + d->mLyricist != other.d->mLyricist || d->mLyrics != other.d->mLyrics || + d->mComment != other.d->mComment || d->mYear != other.d->mYear || d->mChannels != other.d->mChannels || d->mBitRate != other.d->mBitRate || d->mSampleRate != other.d->mSampleRate; } MusicAudioTrack MusicAudioTrack::trackFromData(const DatabaseInterface::TrackDataType &data) { auto result = MusicAudioTrack{}; result.setDatabaseId(data.databaseId()); result.setTitle(data.title()); result.setArtist(data.artist()); result.setAlbumName(data.album()); result.setAlbumArtist(data.albumArtist()); result.setGenre(data.genre()); result.setComposer(data.composer()); result.setLyricist(data.lyricist()); + result.setLyrics(data.lyrics()); result.setComment(data.comment()); result.setAlbumCover(data.albumCover()); result.setTrackNumber(data.trackNumber()); result.setDiscNumber(data.discNumber()); result.setYear(data.year()); result.setChannels(data.channels()); result.setBitRate(data.bitRate()); result.setSampleRate(data.sampleRate()); result.setResourceURI(data.resourceURI()); result.setRating(data.rating()); result.setDuration(data[MusicAudioTrack::TrackDataType::key_type::DurationRole].toTime()); result.setFileModificationTime(data.fileModificationTime()); return result; } void MusicAudioTrack::setValid(bool value) { d->mIsValid = value; } bool MusicAudioTrack::isValid() const { return d->mIsValid; } void MusicAudioTrack::setDatabaseId(qulonglong value) { d->mDatabaseId = value; } qulonglong MusicAudioTrack::databaseId() const { return d->mDatabaseId; } void MusicAudioTrack::setAlbumId(qulonglong value) { d->mAlbumId = value; } qulonglong MusicAudioTrack::albumId() const { return d->mAlbumId; } void MusicAudioTrack::setId(const QString &value) { d->mId = value; } QString MusicAudioTrack::id() const { return d->mId; } void MusicAudioTrack::setParentId(const QString &value) { d->mParentId = value; } QString MusicAudioTrack::parentId() const { return d->mParentId; } void MusicAudioTrack::setTitle(const QString &value) { d->mTitle = value; } QString MusicAudioTrack::title() const { return d->mTitle; } void MusicAudioTrack::setArtist(const QString &value) { d->mArtist = value; } QString MusicAudioTrack::artist() const { return d->mArtist; } void MusicAudioTrack::setAlbumName(const QString &value) { d->mAlbumName = value; } QString MusicAudioTrack::albumName() const { return d->mAlbumName; } void MusicAudioTrack::setAlbumArtist(const QString &value) { d->mAlbumArtist = value; } QString MusicAudioTrack::albumArtist() const { return (d->mAlbumArtist.isEmpty() ? d->mArtist : d->mAlbumArtist); } bool MusicAudioTrack::isValidAlbumArtist() const { return !d->mAlbumArtist.isEmpty(); } void MusicAudioTrack::setAlbumCover(const QUrl &value) { d->mAlbumCover = value; } QUrl MusicAudioTrack::albumCover() const { if (d->mAlbumCover.isValid() || !hasEmbeddedCover()) { return d->mAlbumCover; } else { return QUrl(QStringLiteral("image://cover/") + d->mResourceURI.toLocalFile()); } } void MusicAudioTrack::setGenre(const QString &value) { d->mGenre = value; } QString MusicAudioTrack::genre() const { return d->mGenre; } void MusicAudioTrack::setComposer(const QString &value) { d->mComposer = value; } QString MusicAudioTrack::composer() const { return d->mComposer; } void MusicAudioTrack::setLyricist(const QString &value) { d->mLyricist = value; } QString MusicAudioTrack::lyricist() const { return d->mLyricist; } +void MusicAudioTrack::setLyrics(const QString &value) +{ + d->mLyrics = value; +} + +QString MusicAudioTrack::lyrics() const +{ + return d->mLyrics; +} + void MusicAudioTrack::setComment(const QString &value) { d->mComment = value; } QString MusicAudioTrack::comment() const { return d->mComment; } void MusicAudioTrack::setTrackNumber(int value) { d->mTrackNumber = value; d->mTrackNumberIsValid = true; } int MusicAudioTrack::trackNumber() const { return d->mTrackNumber; } bool MusicAudioTrack::trackNumberIsValid() const { return d->mTrackNumberIsValid; } void MusicAudioTrack::setDiscNumber(int value) { d->mDiscNumber = value; d->mDiscNumberIsValid = true; } int MusicAudioTrack::discNumber() const { return d->mDiscNumber; } bool MusicAudioTrack::discNumberIsValid() const { return d->mDiscNumberIsValid; } void MusicAudioTrack::setYear(int value) { d->mYear = value; } int MusicAudioTrack::year() const { return d->mYear; } void MusicAudioTrack::setChannels(int value) { d->mChannels = value; d->mChannelsIsValid = true; } int MusicAudioTrack::channels() const { return d->mChannels; } bool MusicAudioTrack::channelsIsValid() const { return d->mChannelsIsValid; } void MusicAudioTrack::setBitRate(int value) { d->mBitRate = value; d->mBitRateIsValid = true; } int MusicAudioTrack::bitRate() const { return d->mBitRate; } bool MusicAudioTrack::bitRateIsValid() const { return d->mBitRateIsValid; } void MusicAudioTrack::setSampleRate(int value) { d->mSampleRate = value; d->mSampleRateIsValid = true; } int MusicAudioTrack::sampleRate() const { return d->mSampleRate; } bool MusicAudioTrack::sampleRateIsValid() const { return d->mSampleRateIsValid; } void MusicAudioTrack::setDuration(QTime value) { d->mDuration = value; } QTime MusicAudioTrack::duration() const { return d->mDuration; } void MusicAudioTrack::setFileModificationTime(const QDateTime &value) { d->mFileModificationTime = value; } const QDateTime &MusicAudioTrack::fileModificationTime() const { return d->mFileModificationTime; } void MusicAudioTrack::setResourceURI(const QUrl &value) { d->mResourceURI = value; } const QUrl &MusicAudioTrack::resourceURI() const { return d->mResourceURI; } void MusicAudioTrack::setRating(int value) { d->mRating = value; } int MusicAudioTrack::rating() const { return d->mRating; } void MusicAudioTrack::setIsSingleDiscAlbum(bool value) { d->mIsSingleDiscAlbum = value; } bool MusicAudioTrack::isSingleDiscAlbum() const { return d->mIsSingleDiscAlbum; } void MusicAudioTrack::setHasEmbeddedCover(bool value) { d->mHasBooleanCover = value; } bool MusicAudioTrack::hasEmbeddedCover() const { return d->mHasBooleanCover; } MusicAudioTrack::TrackDataType MusicAudioTrack::toTrackData() const { auto result = MusicAudioTrack::TrackDataType{}; result[MusicAudioTrack::TrackDataType::key_type::DatabaseIdRole] = databaseId(); if (!title().isEmpty()) { result[MusicAudioTrack::TrackDataType::key_type::TitleRole] = title(); } if (!artist().isEmpty()) { result[MusicAudioTrack::TrackDataType::key_type::ArtistRole] = artist(); } if (!albumName().isEmpty()) { result[MusicAudioTrack::TrackDataType::key_type::AlbumRole] = albumName(); } if (!albumArtist().isEmpty()) { result[MusicAudioTrack::TrackDataType::key_type::AlbumArtistRole] = albumArtist(); } if (!genre().isEmpty()) { result[MusicAudioTrack::TrackDataType::key_type::GenreRole] = genre(); } if (!composer().isEmpty()) { result[MusicAudioTrack::TrackDataType::key_type::ComposerRole] = composer(); } if (!lyricist().isEmpty()) { result[MusicAudioTrack::TrackDataType::key_type::LyricistRole] = lyricist(); } if (!comment().isEmpty()) { result[MusicAudioTrack::TrackDataType::key_type::CommentRole] = comment(); } if (!albumCover().isEmpty()) { result[MusicAudioTrack::TrackDataType::key_type::ImageUrlRole] = albumCover(); } if (trackNumber() != -1) { result[MusicAudioTrack::TrackDataType::key_type::TrackNumberRole] = trackNumber(); } if (discNumber()) { result[MusicAudioTrack::TrackDataType::key_type::DiscNumberRole] = discNumber(); } if (year()) { result[MusicAudioTrack::TrackDataType::key_type::YearRole] = year(); } if (channels()) { result[MusicAudioTrack::TrackDataType::key_type::ChannelsRole] = channels(); } if (bitRate()) { result[MusicAudioTrack::TrackDataType::key_type::BitRateRole] = bitRate(); } if (sampleRate()) { result[MusicAudioTrack::TrackDataType::key_type::SampleRateRole] = sampleRate(); } if (!resourceURI().isEmpty()) { result[MusicAudioTrack::TrackDataType::key_type::ResourceRole] = resourceURI(); } if (rating()) { result[MusicAudioTrack::TrackDataType::key_type::RatingRole] = rating(); } if (duration().isValid()) { result[MusicAudioTrack::TrackDataType::key_type::DurationRole] = duration(); } return result; } ELISALIB_EXPORT QDebug operator<<(QDebug stream, const MusicAudioTrack &data) { stream << data.title() << data.artist() << data.albumName() << data.albumArtist() << data.duration() << data.resourceURI(); return stream; } diff --git a/src/musicaudiotrack.h b/src/musicaudiotrack.h index 26c1c8c5..f351da09 100644 --- a/src/musicaudiotrack.h +++ b/src/musicaudiotrack.h @@ -1,198 +1,202 @@ /* * Copyright 2016-2017 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef MUSICAUDIOTRACK_H #define MUSICAUDIOTRACK_H #include "elisaLib_export.h" #include "databaseinterface.h" #include #include #include #include #include #include class MusicAudioTrackPrivate; class QDebug; class ELISALIB_EXPORT MusicAudioTrack { public: using TrackDataType = DatabaseInterface::TrackDataType; MusicAudioTrack(); MusicAudioTrack(bool aValid, QString aId, QString aParentId, QString aTitle, QString aArtist, QString aAlbumName, QString aAlbumArtist, int aTrackNumber, int aDiscNumber, QTime aDuration, QUrl aResourceURI, const QDateTime &fileModificationTime, QUrl aAlbumCover, int rating, bool aIsSingleDiscAlbum, QString aGenre, QString aComposer, QString aLyricist, bool aHasEmbeddedCover); MusicAudioTrack(MusicAudioTrack &&other) noexcept; MusicAudioTrack(const MusicAudioTrack &other); ~MusicAudioTrack(); MusicAudioTrack& operator=(MusicAudioTrack &&other) noexcept; MusicAudioTrack& operator=(const MusicAudioTrack &other); bool operator <(const MusicAudioTrack &other) const; bool operator ==(const MusicAudioTrack &other) const; bool operator !=(const MusicAudioTrack &other) const; static MusicAudioTrack trackFromData(const DatabaseInterface::TrackDataType &data); void setValid(bool value); bool isValid() const; void setDatabaseId(qulonglong value); qulonglong databaseId() const; void setAlbumId(qulonglong value); qulonglong albumId() const; void setId(const QString &value); QString id() const; void setParentId(const QString &value); QString parentId() const; void setTitle(const QString &value); QString title() const; void setArtist(const QString &value); QString artist() const; void setAlbumName(const QString &value); QString albumName() const; void setAlbumArtist(const QString &value); QString albumArtist() const; void setGenre(const QString &value); QString genre() const; void setComposer(const QString &value); QString composer() const; void setLyricist(const QString &value); QString lyricist() const; + void setLyrics(const QString &value); + + QString lyrics() const; + void setComment(const QString &value); QString comment() const; bool isValidAlbumArtist() const; void setAlbumCover(const QUrl &value); QUrl albumCover() const; void setTrackNumber(int value); int trackNumber() const; bool trackNumberIsValid() const; void setDiscNumber(int value); int discNumber() const; bool discNumberIsValid() const; void setYear(int value); int year() const; void setChannels(int value); int channels() const; bool channelsIsValid() const; void setBitRate(int value); int bitRate() const; bool bitRateIsValid() const; void setSampleRate(int value); int sampleRate() const; bool sampleRateIsValid() const; void setDuration(QTime value); QTime duration() const; void setFileModificationTime(const QDateTime &value); const QDateTime &fileModificationTime() const; void setResourceURI(const QUrl &value); const QUrl& resourceURI() const; void setRating(int value); int rating() const; void setIsSingleDiscAlbum(bool value); bool isSingleDiscAlbum() const; void setHasEmbeddedCover(bool value); bool hasEmbeddedCover() const; TrackDataType toTrackData() const; private: QSharedDataPointer d; }; ELISALIB_EXPORT QDebug operator<<(QDebug stream, const MusicAudioTrack &data); Q_DECLARE_TYPEINFO(MusicAudioTrack, Q_MOVABLE_TYPE); Q_DECLARE_METATYPE(MusicAudioTrack) #endif // MUSICAUDIOTRACK_H diff --git a/src/qml/BaseTheme.qml b/src/qml/BaseTheme.qml index f7957915..fc35a868 100644 --- a/src/qml/BaseTheme.qml +++ b/src/qml/BaseTheme.qml @@ -1,122 +1,120 @@ /* * Copyright 2017 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ import QtQuick 2.7 import QtQuick.Controls 2.2 Item { function dp(pixel) { // 96 - common, "base" DPI value return Math.round(pixel * logicalDpi / 96); } property string defaultAlbumImage: 'image://icon/media-optical-audio' property string defaultArtistImage: 'image://icon/view-media-artist' property string defaultBackgroundImage: 'qrc:///background.png' property string artistIcon: 'image://icon/view-media-artist' property string albumIcon: 'image://icon/view-media-album-cover' property string albumCoverIcon: 'image://icon/media-optical-audio' property string playlistIcon: 'image://icon/view-media-playlist' property string tracksIcon: 'image://icon/view-media-track' property string genresIcon: 'image://icon/view-media-genre' property string clearIcon: 'image://icon/edit-clear' property string recentlyPlayedTracksIcon: 'image://icon/media-playlist-play' property string frequentlyPlayedTracksIcon: 'image://icon/amarok_playcount' property string pausedIndicatorIcon: 'image://icon/media-playback-paused' property string playingIndicatorIcon: 'image://icon/media-playback-playing' property string ratingIcon: 'image://icon/rating' property string ratingUnratedIcon: 'image://icon/rating-unrated' property string errorIcon: 'image://icon/error' property string folderIcon: 'image://icon/document-open-folder' property int layoutHorizontalMargin: dp(8) property int layoutVerticalMargin: dp(6) property int delegateHeight: dp(28) FontMetrics { id: playListAuthorTextHeight font.weight: Font.Light } FontMetrics { id: playListAlbumTextHeight font.weight: Font.Bold font.pointSize: elisaTheme.defaultFontPointSize * 1.4 } FontMetrics { id: playListTrackTextHeight font.weight: Font.Bold } property int playListDelegateHeight: (playListTrackTextHeight.height > dp(28)) ? playListTrackTextHeight.height : dp(28) - property int playListDelegateWithHeaderHeight: playListDelegateHeight + - elisaTheme.layoutVerticalMargin * 5 + - playListAuthorTextHeight.height + - playListAlbumTextHeight.height + property int playListHeaderHeight: elisaTheme.layoutVerticalMargin * 5 + playListAuthorTextHeight.height + playListAlbumTextHeight.height property int trackDelegateHeight: dp(45) property int coverImageSize: dp(180) + property int contextCoverImageSize: dp(100) property int smallImageSize: dp(32) property int maximumMetadataWidth: dp(300) property int tooltipRadius: dp(3) property int shadowOffset: dp(2) property int delegateToolButtonSize: dp(34) property int smallDelegateToolButtonSize: dp(20) property int ratingStarSize: dp(15) property int mediaPlayerControlHeight: dp(42) property int mediaPlayerHorizontalMargin: dp(10) property real mediaPlayerControlOpacity: 0.6 property int smallControlButtonSize: dp(22) property int volumeSliderWidth: dp(100) property int dragDropPlaceholderHeight: dp(28) property int navigationBarHeight: dp(100) property int navigationBarFilterHeight: dp(44) property int gridDelegateHeight: dp(100) + layoutVerticalMargin + fontSize.height * 2 property int gridDelegateWidth: dp(100) property int viewSelectorDelegateHeight: dp(24) property int filterClearButtonMargin: layoutVerticalMargin property alias defaultFontPointSize: fontSize.font.pointSize TextMetrics { id: bigTextSize font.pointSize: defaultFontPointSize * 1.4 text: "Albums" } property int viewSelectorSmallSizeThreshold: 3 * layoutHorizontalMargin + viewSelectorDelegateHeight + bigTextSize.width Label { id: fontSize } } diff --git a/src/qml/ContentView.qml b/src/qml/ContentView.qml index fd192f1a..8332dea6 100644 --- a/src/qml/ContentView.qml +++ b/src/qml/ContentView.qml @@ -1,558 +1,565 @@ /* * Copyright 2016-2018 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ import QtQuick 2.7 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.2 import QtQuick.Window 2.2 import org.kde.elisa 1.0 RowLayout { id: contentViewContainer spacing: 0 property bool showPlaylist property alias currentViewIndex: listViews.currentIndex signal toggleSearch() function goBack() { viewManager.goBack() } function openArtist(name) { viewManager.openChildView(name, '', elisaTheme.artistIcon, 0, ElisaUtils.Artist) } function openAlbum(album, artist, image, albumID) { image = !image ? elisaTheme.defaultAlbumImage : image; viewManager.openChildView(album, artist, image, albumID, ElisaUtils.Album); } function openNowPlaying() { viewManager.closeAllViews(); - - // This is needed to trigger the state change - listViews.currentIndex = 0; } ViewManager { id: viewManager onSwitchOffAllViews: { listViews.setCurrentIndex(pageModel.indexFromViewType(viewType)) while(browseStackView.depth > 1) { browseStackView.pop() } } onSwitchRecentlyPlayedTracksView: { listViews.setCurrentIndex(pageModel.indexFromViewType(viewType)) while(browseStackView.depth > expectedDepth) { browseStackView.pop() } browseStackView.push(allRecentlyPlayedTracksView, { viewType: viewType, mainTitle: mainTitle, image: imageUrl, modelType: dataType, stackView: browseStackView, opacity: 0, }) } onSwitchFrequentlyPlayedTracksView: { listViews.setCurrentIndex(pageModel.indexFromViewType(viewType)) while(browseStackView.depth > expectedDepth) { browseStackView.pop() } browseStackView.push(allFrequentlyPlayedTracksView, { viewType: viewType, mainTitle: mainTitle, image: imageUrl, modelType: dataType, stackView: browseStackView, opacity: 0, }) } onOpenGridView: { if (expectedDepth === 1) { listViews.setCurrentIndex(pageModel.indexFromViewType(viewType)) } while(browseStackView.depth > expectedDepth) { browseStackView.pop() } browseStackView.push(dataGridView, { viewType: viewType, mainTitle: pageModel.viewMainTitle(viewType, mainTitle), secondaryTitle: secondaryTitle, image: pageModel.viewImageUrl(viewType, imageUrl), modelType: dataType, defaultIcon: viewDefaultIcon, showRating: viewShowRating, delegateDisplaySecondaryText: viewDelegateDisplaySecondaryText, genreFilterText: genreNameFilter, artistFilter: artistNameFilter, isSubPage: (browseStackView.depth >= 2), stackView: browseStackView, opacity: 0, }) } onSwitchOneAlbumView: { while(browseStackView.depth > expectedDepth) { browseStackView.pop() } browseStackView.push(albumView, { viewType: viewType, mainTitle: mainTitle, secondaryTitle: secondaryTitle, image: imageUrl, databaseId: databaseId, stackView: browseStackView, opacity: 0, }) } onSwitchAllTracksView: { listViews.setCurrentIndex(pageModel.indexFromViewType(viewType)) while(browseStackView.depth > expectedDepth) { browseStackView.pop() } browseStackView.push(allTracksView, { viewType: viewType, mainTitle: mainTitle, image: imageUrl, modelType: dataType, stackView: browseStackView, opacity: 0, }) } onSwitchFilesBrowserView: { listViews.setCurrentIndex(pageModel.indexFromViewType(viewType)) while(browseStackView.depth > expectedDepth) { browseStackView.pop() } browseStackView.push(filesBrowserView, { viewType: viewType, mainTitle: mainTitle, image: imageUrl, opacity: 0, }) } onPopOneView: { browseStackView.pop() } } ViewsModel { id: pageModel } ViewSelector { id: listViews model: pageModel Layout.fillHeight: true Layout.maximumWidth: mainWindow.width * 0.14 maximumSize: mainWindow.width * 0.14 Behavior on Layout.maximumWidth { NumberAnimation { duration: 150 } } onSwitchView: viewManager.openParentView(viewType, pageModel.viewMainTitle(viewType, ""), pageModel.viewImageUrl(viewType, "")) } Rectangle { id: viewSelectorSeparatorItem border.width: 1 border.color: myPalette.mid color: myPalette.mid visible: true Layout.bottomMargin: elisaTheme.layoutVerticalMargin Layout.topMargin: elisaTheme.layoutVerticalMargin Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter Layout.fillHeight: true Layout.preferredWidth: 1 Layout.minimumWidth: 1 Layout.maximumWidth: 1 } ColumnLayout { Layout.fillHeight: true Layout.fillWidth: true spacing: 0 TopNotification { id: invalidBalooConfiguration Layout.fillWidth: true musicManager: elisa.musicManager focus: true } Item { Layout.fillHeight: true Layout.fillWidth: true RowLayout { anchors.fill: parent spacing: 0 id: contentZone FocusScope { id: mainContentView focus: true Layout.fillHeight: true Layout.minimumWidth: 0 Layout.maximumWidth: 0 Layout.preferredWidth: 0 visible: Layout.minimumWidth != 0 Rectangle { border { color: (mainContentView.activeFocus ? myPalette.highlight : myPalette.base) width: 1 } radius: 3 color: myPalette.base anchors.fill: parent StackView { id: browseStackView anchors.fill: parent clip: true initialItem: Item { } popEnter: Transition { OpacityAnimator { from: 0.0 to: 1.0 duration: 300 } } popExit: Transition { OpacityAnimator { from: 1.0 to: 0.0 duration: 300 } } pushEnter: Transition { OpacityAnimator { from: 0.0 to: 1.0 duration: 300 } } pushExit: Transition { OpacityAnimator { from: 1.0 to: 0.0 duration: 300 } } replaceEnter: Transition { OpacityAnimator { from: 0.0 to: 1.0 duration: 300 } } replaceExit: Transition { OpacityAnimator { from: 1.0 to: 0.0 duration: 300 } } } Behavior on border.color { ColorAnimation { duration: 300 } } } } Rectangle { id: firstViewSeparatorItem border.width: 1 border.color: myPalette.mid color: myPalette.mid visible: true Layout.bottomMargin: elisaTheme.layoutVerticalMargin Layout.topMargin: elisaTheme.layoutVerticalMargin Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter Layout.fillHeight: true Layout.preferredWidth: 1 Layout.minimumWidth: 1 Layout.maximumWidth: 1 } MediaPlayListView { id: playList Layout.fillHeight: true Layout.leftMargin: elisaTheme.layoutHorizontalMargin - Layout.rightMargin: elisaTheme.layoutHorizontalMargin Layout.minimumWidth: contentZone.width Layout.maximumWidth: contentZone.width Layout.preferredWidth: contentZone.width onStartPlayback: elisa.audioControl.ensurePlay() onPausePlayback: elisa.audioControl.playPause() onDisplayError: messageNotification.showNotification(errorText) } Rectangle { id: viewSeparatorItem border.width: 1 border.color: myPalette.mid color: myPalette.mid visible: Layout.minimumWidth != 0 Layout.bottomMargin: elisaTheme.layoutVerticalMargin Layout.topMargin: elisaTheme.layoutVerticalMargin Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter Layout.fillHeight: true Layout.preferredWidth: 1 Layout.minimumWidth: 1 Layout.maximumWidth: 1 } - ContextView { + Loader { id: albumContext + active: Layout.minimumWidth != 0 + + sourceComponent: ContextView { + + anchors.fill: parent + + databaseId: elisa.manageHeaderBar.databaseId + title: elisa.manageHeaderBar.title + artistName: elisa.manageHeaderBar.artist + albumName: elisa.manageHeaderBar.album + albumArtUrl: elisa.manageHeaderBar.image + fileUrl: elisa.manageHeaderBar.fileName + } + Layout.fillHeight: true - Layout.minimumWidth: contentZone.width - Layout.maximumWidth: contentZone.width - Layout.preferredWidth: contentZone.width + Layout.minimumWidth: 0 + Layout.maximumWidth: 0 + Layout.preferredWidth: 0 + Layout.leftMargin: elisaTheme.layoutHorizontalMargin * 1.5 visible: Layout.minimumWidth != 0 - - artistName: elisa.manageHeaderBar.artist - albumName: elisa.manageHeaderBar.album - albumArtUrl: elisa.manageHeaderBar.image } } } states: [ State { name: 'playList' when: listViews.currentIndex === 0 PropertyChanges { target: mainContentView Layout.minimumWidth: 0 Layout.maximumWidth: 0 Layout.preferredWidth: 0 } PropertyChanges { target: firstViewSeparatorItem Layout.minimumWidth: 0 Layout.maximumWidth: 0 Layout.preferredWidth: 0 } PropertyChanges { target: playList - Layout.minimumWidth: contentZone.width / 2 - Layout.maximumWidth: contentZone.width / 2 - Layout.preferredWidth: contentZone.width / 2 + Layout.minimumWidth: contentZone.width * 2 / 5 + elisaTheme.layoutHorizontalMargin + Layout.maximumWidth: contentZone.width * 2 / 5 + elisaTheme.layoutHorizontalMargin + Layout.preferredWidth: contentZone.width * 2 / 5 + elisaTheme.layoutHorizontalMargin } PropertyChanges { target: viewSeparatorItem Layout.minimumWidth: 1 Layout.maximumWidth: 1 Layout.preferredWidth: 1 } PropertyChanges { target: albumContext - Layout.minimumWidth: contentZone.width / 2 - Layout.maximumWidth: contentZone.width / 2 - Layout.preferredWidth: contentZone.width / 2 + Layout.minimumWidth: contentZone.width * 3 / 5 - 2 - 3.5 * elisaTheme.layoutHorizontalMargin + Layout.maximumWidth: contentZone.width * 3 / 5 - 2 - 3.5 * elisaTheme.layoutHorizontalMargin + Layout.preferredWidth: contentZone.width * 3 / 5 - 2 - 3.5 * elisaTheme.layoutHorizontalMargin } }, State { name: "browsingViewsNoPlaylist" when: listViews.currentIndex !== 0 && contentViewContainer.showPlaylist !== true extend: "browsingViews" PropertyChanges { target: mainContentView Layout.minimumWidth: contentZone.width Layout.maximumWidth: contentZone.width Layout.preferredWidth: contentZone.width } PropertyChanges { target: playList Layout.minimumWidth: 0 Layout.maximumWidth: 0 Layout.preferredWidth: 0 } }, State { name: 'browsingViews' when: listViews.currentIndex !== 0 PropertyChanges { target: mainContentView Layout.minimumWidth: contentZone.width * 0.66 Layout.maximumWidth: contentZone.width * 0.68 Layout.preferredWidth: contentZone.width * 0.68 } PropertyChanges { target: firstViewSeparatorItem Layout.minimumWidth: 1 Layout.maximumWidth: 1 Layout.preferredWidth: 1 } PropertyChanges { target: playList Layout.minimumWidth: contentZone.width * 0.33 - 3 * elisaTheme.layoutHorizontalMargin + 2 Layout.maximumWidth: contentZone.width * 0.33 - 3 * elisaTheme.layoutHorizontalMargin + 2 Layout.preferredWidth: contentZone.width * 0.33 - 3 * elisaTheme.layoutHorizontalMargin + 2 } PropertyChanges { target: viewSeparatorItem Layout.minimumWidth: 0 Layout.maximumWidth: 0 Layout.preferredWidth: 0 } PropertyChanges { target: albumContext Layout.minimumWidth: 0 Layout.maximumWidth: 0 Layout.preferredWidth: 0 } } ] transitions: Transition { NumberAnimation { properties: "Layout.minimumWidth, Layout.maximumWidth, Layout.preferredWidth, opacity" easing.type: Easing.InOutQuad duration: 300 } } } Component { id: allFrequentlyPlayedTracksView FrequentlyPlayedTracks { StackView.onActivated: viewManager.viewIsLoaded(viewType) } } Component { id: allRecentlyPlayedTracksView RecentlyPlayedTracks { StackView.onActivated: viewManager.viewIsLoaded(viewType) } } Component { id: dataGridView DataGridView { StackView.onActivated: viewManager.viewIsLoaded(viewType) } } Component { id: allTracksView TracksView { StackView.onActivated: viewManager.viewIsLoaded(viewType) } } Component { id: albumView AlbumView { StackView.onActivated: viewManager.viewIsLoaded(viewType) } } Component { id: filesBrowserView FileBrowserView { StackView.onActivated: viewManager.viewIsLoaded(viewType) } } } diff --git a/src/qml/ContextView.qml b/src/qml/ContextView.qml index c1d2ed80..a3936a35 100644 --- a/src/qml/ContextView.qml +++ b/src/qml/ContextView.qml @@ -1,168 +1,234 @@ /* * Copyright 2016 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ -import QtQuick 2.7 +import QtQuick 2.10 import QtQuick.Window 2.2 import QtQuick.Controls 2.2 import QtQml.Models 2.2 -import org.kde.elisa 1.0 import QtQuick.Layouts 1.2 -Item { +import org.kde.elisa 1.0 + +FocusScope { id: topItem - property var albumName - property var artistName - property var tracksCount - property var albumArtUrl + property int databaseId: 0 + property alias title: titleLabel.text + property string albumName: '' + property string artistName: '' + property url albumArtUrl: '' + property string fileUrl: '' + + TrackContextMetaDataModel { + id: metaDataModel + + manager: elisa.musicManager + } ColumnLayout { anchors.fill: parent spacing: 0 - Item { - Layout.fillHeight: true + TextMetrics { + id: titleHeight + text: viewTitleHeight.text + font + { + pointSize: viewTitleHeight.font.pointSize + bold: viewTitleHeight.font.bold + } + } + + LabelWithToolTip { + id: viewTitleHeight + text: i18nc("Title of the context view related to the currently playing track", "Now Playing") + + font.pointSize: elisaTheme.defaultFontPointSize * 2 + + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + Layout.topMargin: elisaTheme.layoutVerticalMargin * 3 + Layout.bottomMargin: titleHeight.height } Image { id: albumIcon source: albumArtUrl.toString() === '' ? Qt.resolvedUrl(elisaTheme.defaultAlbumImage) : albumArtUrl - Layout.preferredWidth: elisaTheme.coverImageSize - Layout.preferredHeight: elisaTheme.coverImageSize - Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter - Layout.maximumWidth: elisaTheme.coverImageSize - Layout.maximumHeight: elisaTheme.coverImageSize + + Layout.fillWidth: true + Layout.maximumHeight: elisaTheme.contextCoverImageSize + Layout.preferredHeight: elisaTheme.contextCoverImageSize + Layout.bottomMargin: elisaTheme.layoutVerticalMargin - width: elisaTheme.coverImageSize - height: elisaTheme.coverImageSize + width: elisaTheme.contextCoverImageSize + height: elisaTheme.contextCoverImageSize - sourceSize.width: elisaTheme.coverImageSize - sourceSize.height: elisaTheme.coverImageSize + sourceSize.width: parent.width + sourceSize.height: elisaTheme.contextCoverImageSize asynchronous: true - fillMode: Image.PreserveAspectFit + fillMode: Image.PreserveAspectCrop } LabelWithToolTip { id: titleLabel - text: if (albumName !== undefined) - albumName - else - '' - + font.pointSize: elisaTheme.defaultFontPointSize * 2 font.weight: Font.Bold - color: myPalette.text - horizontalAlignment: Text.AlignHCenter + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + Layout.topMargin: elisaTheme.layoutVerticalMargin - Layout.fillWidth: true - Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom + elide: Text.ElideRight + } + + LabelWithToolTip { + id: albumArtistLabel + + text: (artistName && albumName ? i18nc('display of artist and album in context view', 'by %1 from %2', artistName, albumName) : '') + + font.pointSize: elisaTheme.defaultFontPointSize * 1.4 + + visible: artistName !== '' && albumName !== '' + + Layout.alignment: Qt.AlignLeft | Qt.AlignTop Layout.bottomMargin: elisaTheme.layoutVerticalMargin elide: Text.ElideRight } LabelWithToolTip { - id: artistLabel + id: albumLabel - text: if (artistName !== undefined) - artistName - else - '' + text: (albumName ? i18nc('display of album in context view', 'from %1', albumName) : '') - font.weight: Font.Normal - color: myPalette.text + font.pointSize: elisaTheme.defaultFontPointSize * 1.4 - horizontalAlignment: Text.AlignHCenter + visible: artistName === '' && albumName !== '' - Layout.fillWidth: true - Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + Layout.bottomMargin: elisaTheme.layoutVerticalMargin elide: Text.ElideRight } LabelWithToolTip { - id: numberLabel - - text: i18np("1 track", "%1 track", tracksCount) + id: artistLabel - visible: tracksCount !== undefined + text: (artistName ? i18nc('display of artist in context view', 'by %1', artistName) : '') - font.weight: Font.Light - color: myPalette.text + font.pointSize: elisaTheme.defaultFontPointSize * 1.4 - horizontalAlignment: Text.AlignHCenter + visible: artistName !== '' && albumName === '' - Layout.fillWidth: true - Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom + Layout.alignment: Qt.AlignLeft | Qt.AlignTop Layout.bottomMargin: elisaTheme.layoutVerticalMargin elide: Text.ElideRight } - Item { - Layout.fillHeight: true - } + Flickable { + id: flickable + clip: true + + contentWidth: topItem.width + contentHeight: allMetaData.height - RowLayout { Layout.fillWidth: true - Layout.bottomMargin: elisaTheme.layoutVerticalMargin * 2 + Layout.fillHeight: true - spacing: 0 + boundsBehavior: Flickable.StopAtBounds - Image { - id: artistJumpIcon + ScrollBar.vertical: ScrollBar { + id: scrollBar + policy: ScrollBar.AlwaysOn + } + + ColumnLayout { + id: allMetaData + + spacing: 0 + + width: topItem.width + + Repeater { + id: trackData + + model: metaDataModel + + delegate: MetaDataDelegate { + Layout.fillWidth: true + } + } + + ContextViewLyrics { + id: lyricsContextView - source: Qt.resolvedUrl(elisaTheme.defaultArtistImage) + Layout.fillWidth: true - Layout.preferredWidth: elisaTheme.smallImageSize - Layout.preferredHeight: elisaTheme.smallImageSize - Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter - Layout.maximumWidth: elisaTheme.smallImageSize - Layout.maximumHeight: elisaTheme.smallImageSize - Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 - Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 + visible: metaDataModel.lyrics !== "" - visible: artistName !== undefined - width: elisaTheme.smallImageSize - height: elisaTheme.smallImageSize + lyrics: metaDataModel.lyrics + } + } + } + + Row { + Layout.alignment: Qt.AlignLeft | Qt.AlignBottom + Layout.topMargin: elisaTheme.layoutVerticalMargin + Layout.bottomMargin: elisaTheme.layoutVerticalMargin - sourceSize.width: elisaTheme.smallImageSize - sourceSize.height: elisaTheme.smallImageSize + spacing: elisaTheme.layoutHorizontalMargin - fillMode: Image.PreserveAspectFit + Image { + sourceSize.width: fileNameLabel.height + sourceSize.height: fileNameLabel.height + + source: elisaTheme.folderIcon } LabelWithToolTip { - text: if (artistName !== undefined) - artistName - else - '' + id: fileNameLabel - font.weight: Font.Normal - color: myPalette.text + text: fileUrl - horizontalAlignment: Text.AlignLeft + elide: Text.ElideRight } } } + + onDatabaseIdChanged: { + metaDataModel.initializeByTrackId(databaseId) + } + + Connections { + target: elisa + + onMusicManagerChanged: { + metaDataModel.initializeByTrackId(databaseId) + } + } + + Component.onCompleted: { + if (elisa.musicManager) { + metaDataModel.initializeByTrackId(databaseId) + } + } } diff --git a/src/qml/ContextViewLyrics.qml b/src/qml/ContextViewLyrics.qml new file mode 100644 index 00000000..cf406433 --- /dev/null +++ b/src/qml/ContextViewLyrics.qml @@ -0,0 +1,48 @@ +/* + * Copyright 2016 Matthieu Gallien + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +import QtQuick 2.10 +import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.2 + +import org.kde.elisa 1.0 + +ColumnLayout { + property string lyrics + + Label { + id: title + + horizontalAlignment: Label.AlignHCenter + + text: i18nc("Lyrics label for track metadata view", "Lyrics") + + font.weight: Font.Bold + + Layout.fillWidth: true + } + + Label { + text: lyrics + + horizontalAlignment: Text.AlignLeft + + Layout.fillWidth: true + + wrapMode: Text.WordWrap + } +} diff --git a/src/qml/MediaTrackMetadataView.qml b/src/qml/MediaTrackMetadataView.qml index e8fb5955..5db25d56 100644 --- a/src/qml/MediaTrackMetadataView.qml +++ b/src/qml/MediaTrackMetadataView.qml @@ -1,243 +1,174 @@ /* * Copyright 2017 Alexander Stippich * Copyright 2018 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ import QtQuick 2.7 import QtQuick.Controls 2.2 import QtQuick.Window 2.2 import QtQml.Models 2.2 import QtQuick.Layouts 1.2 import QtGraphicalEffects 1.0 import org.kde.elisa 1.0 Window { id: trackMetadata property int databaseId: 0 property url fileName signal rejected() LayoutMirroring.enabled: Qt.application.layoutDirection == Qt.RightToLeft LayoutMirroring.childrenInherit: true title: i18nc("Window title for track metadata", "View Details") TrackMetadataModel { id: realModel + + manager: elisa.musicManager } modality: Qt.NonModal flags: Qt.Dialog | Qt.WindowCloseButtonHint color: myPalette.window minimumHeight: elisaTheme.coverImageSize * 1.8 minimumWidth: elisaTheme.coverImageSize * 2.8 ColumnLayout { anchors.fill: parent anchors.margins: elisaTheme.layoutVerticalMargin spacing: elisaTheme.layoutVerticalMargin RowLayout { id: metadataView Layout.fillHeight: true Layout.fillWidth: true spacing: 0 Image { source: (realModel.coverUrl !== "" ? realModel.coverUrl : elisaTheme.tracksIcon) sourceSize.width: elisaTheme.coverImageSize sourceSize.height: elisaTheme.coverImageSize fillMode: Image.PreserveAspectFit Layout.alignment: Qt.AlignTop | Qt.AlignHCenter Layout.preferredHeight: elisaTheme.coverImageSize Layout.preferredWidth: elisaTheme.coverImageSize Layout.minimumHeight: elisaTheme.coverImageSize Layout.minimumWidth: elisaTheme.coverImageSize Layout.maximumHeight: elisaTheme.coverImageSize Layout.maximumWidth: elisaTheme.coverImageSize } ListView { id: trackData Layout.fillWidth: true Layout.fillHeight: true + Layout.leftMargin: 2 * elisaTheme.layoutHorizontalMargin focus: true ScrollBar.vertical: ScrollBar { id: scrollBar } boundsBehavior: Flickable.StopAtBounds clip: true - ScrollHelper { id: scrollHelper flickable: trackData anchors.fill: trackData } model: realModel - delegate: metadataDelegate + delegate: MetaDataDelegate { + width: scrollBar.visible ? (!LayoutMirroring.enabled ? trackData.width - scrollBar.width : trackData.width) : trackData.width + } } } RowLayout { Layout.alignment: Qt.AlignLeft | Qt.AlignBottom Layout.topMargin: elisaTheme.layoutVerticalMargin Layout.bottomMargin: elisaTheme.layoutVerticalMargin spacing: elisaTheme.layoutHorizontalMargin Image { Layout.preferredWidth: fileNameLabel.height Layout.preferredHeight: fileNameLabel.height sourceSize.width: fileNameLabel.height sourceSize.height: fileNameLabel.height source: elisaTheme.folderIcon } LabelWithToolTip { id: fileNameLabel Layout.fillWidth: true text: realModel.fileUrl elide: Text.ElideRight } } DialogButtonBox { id: buttons Layout.fillWidth: true Layout.minimumHeight: implicitHeight standardButtons: DialogButtonBox.Close alignment: Qt.AlignRight onRejected: trackMetadata.rejected() } } - Component { - id: metadataDelegate - - RowLayout { - id: delegateRow - spacing: 0 - - width: scrollBar.visible ? trackData.width - scrollBar.width : trackData.width - - Label { - id: metaDataLabels - text: model.name - color: myPalette.text - horizontalAlignment: Text.AlignRight - - Layout.preferredWidth: 0.8 * elisaTheme.coverImageSize - Layout.rightMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 - Layout.leftMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 - } - - Loader { - active: model.type === TrackMetadataModel.TextEntry || model.type === TrackMetadataModel.IntegerEntry - - Layout.fillWidth: true - - sourceComponent: LabelWithToolTip { - text: model.display - - horizontalAlignment: Text.AlignLeft - elide: Text.ElideRight - - anchors.fill: parent - } - } - - Loader { - active: model.type === TrackMetadataModel.DateEntry - - Layout.fillWidth: true - - sourceComponent: LabelWithToolTip { - text: rawDate.toLocaleDateString() - - horizontalAlignment: Text.AlignLeft - elide: Text.ElideRight - - anchors.fill: parent - - property date rawDate: new Date(model.display) - } - } - - Loader { - active: model.type === TrackMetadataModel.RatingEntry - - Layout.fillWidth: true - - sourceComponent: RatingStar { - starRating: model.display - starSize: elisaTheme.ratingStarSize - - readOnly: true - - anchors { - left: parent.left - top: parent.top - bottom: parent.bottom - } - } - } - } - } - Connections { target: elisa onMusicManagerChanged: { if (databaseId !== 0) { - realModel.initializeByTrackId(elisa.musicManager, databaseId) + realModel.initializeByTrackId(databaseId) } else { - realModel.initializeByTrackFileName(elisa.musicManager, fileName) + realModel.initializeByTrackFileName(fileName) } } } Component.onCompleted: { if (elisa.musicManager) { if (databaseId !== 0) { - realModel.initializeByTrackId(elisa.musicManager, databaseId) + realModel.initializeByTrackId(databaseId) } else { - realModel.initializeByTrackFileName(elisa.musicManager, fileName) + realModel.initializeByTrackFileName(fileName) } } } } diff --git a/src/qml/MetaDataDelegate.qml b/src/qml/MetaDataDelegate.qml new file mode 100644 index 00000000..f68e70c3 --- /dev/null +++ b/src/qml/MetaDataDelegate.qml @@ -0,0 +1,133 @@ +/* + * Copyright 2016 Matthieu Gallien + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +import QtQuick 2.10 +import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.2 + +import org.kde.elisa 1.0 + +RowLayout { + id: delegateRow + spacing: 0 + + height: (model.type === TrackMetadataModel.LongTextEntry ? longTextDisplayLoader.height : metaDataLabelMetric.height) + (elisaTheme.layoutVerticalMargin / 2) + + TextMetrics { + id: metaDataLabelMetric + + text: 'Metadata Name' + + font.weight: Font.Bold + } + + Label { + id: metaDataLabels + + text: model.name + + font.weight: Font.Bold + + horizontalAlignment: Text.AlignLeft + + Layout.alignment: Qt.AlignTop + Layout.preferredWidth: 0.8 * elisaTheme.coverImageSize + Layout.rightMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin * 2 : 0 + Layout.leftMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin * 2 : 0 + } + + Loader { + id: textDisplayLoader + + active: model.type === TrackMetadataModel.TextEntry || model.type === TrackMetadataModel.IntegerEntry + visible: model.type === TrackMetadataModel.TextEntry || model.type === TrackMetadataModel.IntegerEntry + + Layout.fillWidth: true + Layout.alignment: Qt.AlignTop + + sourceComponent: LabelWithToolTip { + text: model.display + + horizontalAlignment: Text.AlignLeft + elide: Text.ElideRight + + anchors.fill: parent + } + } + + Loader { + id: longTextDisplayLoader + + active: model.type === TrackMetadataModel.LongTextEntry + visible: model.type === TrackMetadataModel.LongTextEntry + + Layout.fillWidth: true + Layout.maximumWidth: delegateRow.width - (0.8 * elisaTheme.coverImageSize + elisaTheme.layoutHorizontalMargin * 2) + Layout.alignment: Qt.AlignTop + + sourceComponent: Label { + text: model.display + + horizontalAlignment: Text.AlignLeft + elide: Text.ElideRight + + anchors.fill: parent + + wrapMode: Text.WordWrap + } + } + + Loader { + active: model.type === TrackMetadataModel.DateEntry + visible: model.type === TrackMetadataModel.DateEntry + + Layout.fillWidth: true + Layout.alignment: Qt.AlignTop + + sourceComponent: LabelWithToolTip { + text: rawDate.toLocaleDateString() + + horizontalAlignment: Text.AlignLeft + elide: Text.ElideRight + + anchors.fill: parent + + property date rawDate: new Date(model.display) + } + } + + Loader { + active: model.type === TrackMetadataModel.RatingEntry + visible: model.type === TrackMetadataModel.RatingEntry + + Layout.fillWidth: true + Layout.alignment: Qt.AlignTop + + sourceComponent: RatingStar { + starRating: model.display + starSize: elisaTheme.ratingStarSize + + readOnly: true + + anchors { + left: parent.left + top: parent.top + bottom: parent.bottom + } + } + } +} diff --git a/src/resources.qrc b/src/resources.qrc index d068eb55..f10baa37 100644 --- a/src/resources.qrc +++ b/src/resources.qrc @@ -1,60 +1,62 @@ qml/MediaPlayerControl.qml qml/RatingStar.qml qml/MediaPlayListView.qml qml/ElisaMainWindow.qml qml/ApplicationMenu.qml qml/HeaderBar.qml qml/ContextView.qml qml/ContentView.qml qml/DraggableItem.qml qml/PassiveNotification.qml qml/NavigationActionBar.qml qml/PlayListEntry.qml qml/Theme.qml qml/PlatformIntegration.qml qml/LabelWithToolTip.qml qml/TopNotification.qml qml/TrackImportNotification.qml qml/TopNotificationItem.qml qml/MediaTrackDelegate.qml qml/MediaAlbumTrackDelegate.qml qml/MediaTrackMetadataView.qml qml/GridBrowserView.qml qml/GridBrowserDelegate.qml qml/ListBrowserView.qml qml/FileBrowserDelegate.qml qml/FileBrowserView.qml qtquickcontrols2.conf background.png qml/BaseTheme.qml qml/ScrollHelper.qml qml/FlatButtonWithToolTip.qml qml/DataGridView.qml qml/TracksView.qml qml/AlbumView.qml qml/RecentlyPlayedTracks.qml qml/FrequentlyPlayedTracks.qml qml/PlayListBasicView.qml qml/SimplePlayListView.qml qml/SimplePlayListEntry.qml qml/ViewSelector.qml qml/PlayListAlbumHeader.qml qml/BasicPlayListAlbumHeader.qml + qml/MetaDataDelegate.qml + qml/ContextViewLyrics.qml windows/WindowsTheme.qml windows/PlatformIntegration.qml windows/LabelWithToolTip.qml android/ElisaMainWindow.qml android/AndroidTheme.qml android/PlatformIntegration.qml android/AlbumsView.qml android/ArtistsView.qml android/TracksView.qml android/GenresView.qml