diff --git a/autotests/databaseinterfacetest.cpp b/autotests/databaseinterfacetest.cpp --- a/autotests/databaseinterfacetest.cpp +++ b/autotests/databaseinterfacetest.cpp @@ -180,6 +180,100 @@ QCOMPARE(album.isSingleDiscAlbum(), true); } + void addAndRemoveOneTrackWithoutTitle() + { + QTemporaryFile databaseFile; + databaseFile.open(); + + 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("artist8"), QStringLiteral("album4"), 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(), 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 trackId = musicDb.trackIdFromFileName(QUrl::fromLocalFile(QStringLiteral("/$24"))); + QVERIFY(trackId != 0); + auto track = musicDb.trackDataFromDatabaseId(trackId); + + QCOMPARE(track.isValid(), true); + QCOMPARE(track.title(), QString()); + QCOMPARE(track.artist(), QStringLiteral("artist8")); + QCOMPARE(track.album(), QStringLiteral("album4")); + QCOMPARE(track.albumCover(), QUrl::fromLocalFile(QStringLiteral("album4"))); + 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(), 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 addAndRemoveOneTrackWithoutAlbum() { QTemporaryFile databaseFile; @@ -4339,81 +4433,6 @@ 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; diff --git a/src/databaseinterface.h b/src/databaseinterface.h --- a/src/databaseinterface.h +++ b/src/databaseinterface.h @@ -87,6 +87,7 @@ PlayFrequency, ElementTypeRole, LyricsRole, + FileNameRole, }; Q_ENUM(ColumnsRoles) @@ -173,6 +174,11 @@ return operator[](key_type::ResourceRole).toUrl(); } + QString fileName() const + { + return operator[](key_type::FileNameRole).toString(); + } + QUrl albumCover() const { return operator[](key_type::ImageUrlRole).toUrl(); @@ -595,6 +601,8 @@ void upgradeDatabaseV14(); + void upgradeDatabaseV15(); + void checkDatabaseSchema(); void checkAlbumsTableSchema(); diff --git a/src/databaseinterface.cpp b/src/databaseinterface.cpp --- a/src/databaseinterface.cpp +++ b/src/databaseinterface.cpp @@ -1217,6 +1217,7 @@ upgradeDatabaseV12(); upgradeDatabaseV13(); upgradeDatabaseV14(); + upgradeDatabaseV15(); checkDatabaseSchema(); } else if (listTables.contains(QStringLiteral("DatabaseVersionV9"))) { @@ -1232,14 +1233,18 @@ if (!listTables.contains(QStringLiteral("DatabaseVersionV14"))) { upgradeDatabaseV14(); } + if (!listTables.contains(QStringLiteral("DatabaseVersionV15"))) { + upgradeDatabaseV15(); + } checkDatabaseSchema(); } else { createDatabaseV9(); upgradeDatabaseV11(); upgradeDatabaseV12(); upgradeDatabaseV13(); upgradeDatabaseV14(); + upgradeDatabaseV15(); } } @@ -2904,6 +2909,267 @@ qCInfo(orgKdeElisaDatabase) << "finished update to v14 of database schema"; } +void DatabaseInterface::upgradeDatabaseV15() { + qCInfo(orgKdeElisaDatabase) << "begin update to v15 of database schema"; + + { + QSqlQuery createSchemaQuery(d->mTracksDatabase); + + const auto &result = createSchemaQuery.exec(QStringLiteral("CREATE TABLE `DatabaseVersionV15` (`Version` INTEGER PRIMARY KEY NOT NULL)")); + + if (!result) { + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << createSchemaQuery.lastQuery(); + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << createSchemaQuery.lastError(); + + Q_EMIT databaseError(); + } + } + + { + QSqlQuery disableForeignKeys(d->mTracksDatabase); + + auto result = disableForeignKeys.exec(QStringLiteral(" PRAGMA foreign_keys=OFF")); + + if (!result) { + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << disableForeignKeys.lastQuery(); + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << 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), " + "`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`, " + "`TrackNumber`, `DiscNumber`" + "), " + "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::upgradeDatabaseV15" << createSchemaQuery.lastQuery(); + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << createSchemaQuery.lastError(); + } + } + + { + 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::upgradeDatabaseV15" << copyDataQuery.lastQuery(); + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << copyDataQuery.lastError(); + + Q_EMIT databaseError(); + } + } + + { + QSqlQuery createSchemaQuery(d->mTracksDatabase); + + auto result = createSchemaQuery.exec(QStringLiteral("DROP TABLE `Tracks`")); + + if (!result) { + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << createSchemaQuery.lastQuery(); + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << 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::upgradeDatabaseV15" << createSchemaQuery.lastQuery(); + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << 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::upgradeDatabaseV15" << enableForeignKeys.lastQuery(); + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << 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::upgradeDatabaseV15" << createTrackIndex.lastQuery(); + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << 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::upgradeDatabaseV15" << createTrackIndex.lastQuery(); + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << 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::upgradeDatabaseV15" << createTrackIndex.lastQuery(); + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << 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`, " + "`TrackNumber`, `DiscNumber`)")); + + if (!result) { + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << createTrackIndex.lastQuery(); + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << 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`, " + "`TrackNumber`, `DiscNumber`)")); + + if (!result) { + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << createTrackIndex.lastQuery(); + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << 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::upgradeDatabaseV15" << createTrackIndex.lastQuery(); + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << createTrackIndex.lastError(); + + Q_EMIT databaseError(); + } + } + + qCInfo(orgKdeElisaDatabase) << "finished update to v14 of database schema"; +} + void DatabaseInterface::checkDatabaseSchema() { checkAlbumsTableSchema(); @@ -3602,7 +3868,7 @@ " FROM " " `Tracks` tracks2 " " WHERE " - " tracks.`Title` = tracks2.`Title` AND " + " (tracks.`Title` IS NULL OR 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 " @@ -3749,7 +4015,7 @@ " FROM " " `Tracks` tracks2 " " WHERE " - " tracks.`Title` = tracks2.`Title` AND " + " (tracks.`Title` IS NULL OR 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 " @@ -3874,7 +4140,7 @@ " FROM " " `Tracks` tracks2 " " WHERE " - " tracks.`Title` = tracks2.`Title` AND " + " (tracks.`Title` IS NULL OR 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 " @@ -4254,7 +4520,7 @@ " FROM " " `Tracks` tracks2 " " WHERE " - " tracks.`Title` = tracks2.`Title` AND " + " (tracks.`Title` IS NULL OR 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 " @@ -4420,7 +4686,7 @@ " FROM " " `Tracks` tracks2 " " WHERE " - " tracks.`Title` = tracks2.`Title` AND " + " (tracks.`Title` IS NULL OR 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 " @@ -6029,10 +6295,6 @@ { 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 | @@ -6347,8 +6609,13 @@ result[TrackDataType::key_type::AlbumArtistRole] = QStringLiteral("Various Artists"); } } - result[TrackDataType::key_type::ResourceRole] = trackRecord.value(7); + auto resourceUrl = trackRecord.value(7).toUrl(); + if (resourceUrl.isLocalFile()) { + result[TrackDataType::key_type::FileNameRole] = resourceUrl.fileName(); + } else { + result[TrackDataType::key_type::FileNameRole] = resourceUrl.toDisplayString(); + } if (!trackRecord.value(9).isNull()) { result[TrackDataType::key_type::TrackNumberRole] = trackRecord.value(9); } diff --git a/src/elisaapplication.cpp b/src/elisaapplication.cpp --- a/src/elisaapplication.cpp +++ b/src/elisaapplication.cpp @@ -388,7 +388,7 @@ d->mManageHeaderBar->setAlbumRole(MediaPlayList::AlbumRole); d->mManageHeaderBar->setAlbumArtistRole(MediaPlayList::AlbumArtistRole); d->mManageHeaderBar->setArtistRole(MediaPlayList::ArtistRole); - d->mManageHeaderBar->setFileNameRole(MediaPlayList::ResourceRole); + d->mManageHeaderBar->setFileNameRole(MediaPlayList::FileNameRole); d->mManageHeaderBar->setImageRole(MediaPlayList::ImageUrlRole); d->mManageHeaderBar->setDatabaseIdRole(MediaPlayList::DatabaseIdRole); d->mManageHeaderBar->setAlbumIdRole(MediaPlayList::AlbumIdRole); diff --git a/src/manageheaderbar.h b/src/manageheaderbar.h --- a/src/manageheaderbar.h +++ b/src/manageheaderbar.h @@ -97,7 +97,7 @@ READ albumArtist NOTIFY albumArtistChanged) - Q_PROPERTY(QString fileName + Q_PROPERTY(QVariant fileName READ fileName NOTIFY fileNameChanged) @@ -149,7 +149,7 @@ QVariant albumArtist() const; - QString fileName() const; + QVariant fileName() const; QUrl image() const; diff --git a/src/manageheaderbar.cpp b/src/manageheaderbar.cpp --- a/src/manageheaderbar.cpp +++ b/src/manageheaderbar.cpp @@ -131,22 +131,13 @@ return mCurrentTrack.data(mAlbumArtistRole); } -QString ManageHeaderBar::fileName() const +QVariant 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 QString(); } - return result; + return mCurrentTrack.data(mFileNameRole); } QVariant ManageHeaderBar::title() const diff --git a/src/mediaplaylist.h b/src/mediaplaylist.h --- a/src/mediaplaylist.h +++ b/src/mediaplaylist.h @@ -119,6 +119,7 @@ PlayFrequency, ElementTypeRole, LyricsRole, + FileNameRole, IsValidRole, TrackDataRole, CountRole, diff --git a/src/mediaplaylist.cpp b/src/mediaplaylist.cpp --- a/src/mediaplaylist.cpp +++ b/src/mediaplaylist.cpp @@ -113,6 +113,7 @@ roles[static_cast(ColumnsRoles::TrackDataRole)] = "trackData"; roles[static_cast(ColumnsRoles::AlbumIdRole)] = "albumId"; roles[static_cast(ColumnsRoles::AlbumSectionRole)] = "albumSection"; + roles[static_cast(ColumnsRoles::FileNameRole)] = "fileName"; return roles; } diff --git a/src/models/alltracksproxymodel.cpp b/src/models/alltracksproxymodel.cpp --- a/src/models/alltracksproxymodel.cpp +++ b/src/models/alltracksproxymodel.cpp @@ -37,6 +37,7 @@ const auto &titleValue = sourceModel()->data(currentIndex, Qt::DisplayRole).toString(); const auto &artistValue = sourceModel()->data(currentIndex, DatabaseInterface::ColumnsRoles::ArtistRole).toString(); + const auto &fileNameValue = sourceModel()->data(currentIndex, DatabaseInterface::ColumnsRoles::FileNameRole).toString(); const auto maximumRatingValue = sourceModel()->data(currentIndex, DatabaseInterface::ColumnsRoles::RatingRole).toInt(); if (maximumRatingValue < mFilterRating) { @@ -51,6 +52,10 @@ result = true; } + if (mFilterExpression.match(fileNameValue).hasMatch()) { + result = true; + } + return result; } diff --git a/src/models/datamodel.cpp b/src/models/datamodel.cpp --- a/src/models/datamodel.cpp +++ b/src/models/datamodel.cpp @@ -91,6 +91,7 @@ roles[static_cast(DatabaseInterface::ColumnsRoles::ImageUrlRole)] = "imageUrl"; roles[static_cast(DatabaseInterface::ColumnsRoles::DatabaseIdRole)] = "databaseId"; roles[static_cast(DatabaseInterface::ColumnsRoles::ElementTypeRole)] = "dataType"; + roles[static_cast(DatabaseInterface::ColumnsRoles::FileNameRole)] = "fileName"; roles[static_cast(DatabaseInterface::ColumnsRoles::ArtistRole)] = "artist"; roles[static_cast(DatabaseInterface::ColumnsRoles::AllArtistsRole)] = "allArtists"; diff --git a/src/models/trackmetadatamodel.cpp b/src/models/trackmetadatamodel.cpp --- a/src/models/trackmetadatamodel.cpp +++ b/src/models/trackmetadatamodel.cpp @@ -195,6 +195,7 @@ case DatabaseInterface::FirstPlayDate: case DatabaseInterface::PlayFrequency: case DatabaseInterface::ElementTypeRole: + case DatabaseInterface::FileNameRole: break; } break; @@ -391,6 +392,7 @@ case DatabaseInterface::FirstPlayDate: case DatabaseInterface::PlayFrequency: case DatabaseInterface::ElementTypeRole: + case DatabaseInterface::FileNameRole: break; } break; diff --git a/src/qml/DataListView.qml b/src/qml/DataListView.qml --- a/src/qml/DataListView.qml +++ b/src/qml/DataListView.qml @@ -78,6 +78,7 @@ album: model.album ? model.album : '' albumArtist: model.albumArtist ? model.albumArtist : '' duration: model.duration ? model.duration : '' + fileName: model.fileName ? model.fileName : '' imageUrl: model.imageUrl ? model.imageUrl : '' trackNumber: model.trackNumber ? model.trackNumber : -1 discNumber: model.discNumber ? model.discNumber : -1 @@ -127,6 +128,7 @@ album: model.album ? model.album : '' albumArtist: model.albumArtist ? model.albumArtist : '' duration: model.duration ? model.duration : '' + fileName: model.fileName ? model.fileName : '' imageUrl: model.imageUrl ? model.imageUrl : '' trackNumber: model.trackNumber ? model.trackNumber : -1 discNumber: model.discNumber ? model.discNumber : -1 diff --git a/src/qml/ElisaMainWindow.qml b/src/qml/ElisaMainWindow.qml --- a/src/qml/ElisaMainWindow.qml +++ b/src/qml/ElisaMainWindow.qml @@ -190,6 +190,7 @@ title: elisa.manageHeaderBar.title artist: elisa.manageHeaderBar.artist albumArtist: elisa.manageHeaderBar.albumArtist + fileName: elisa.manageHeaderBar.fileName image: elisa.manageHeaderBar.image albumID: elisa.manageHeaderBar.albumId diff --git a/src/qml/HeaderBar.qml b/src/qml/HeaderBar.qml --- a/src/qml/HeaderBar.qml +++ b/src/qml/HeaderBar.qml @@ -32,6 +32,7 @@ property string newImage property string oldImage property string tracksCount + property string fileName property int trackRating property int albumID property bool ratingVisible @@ -218,7 +219,7 @@ LabelWithToolTip { id: mainLabel - text: title + text: title ? title : fileName Layout.alignment: Qt.AlignLeft elide: Text.ElideRight // Hardcoded because the headerbar blur always makes a dark-ish diff --git a/src/qml/ListBrowserDelegate.qml b/src/qml/ListBrowserDelegate.qml --- a/src/qml/ListBrowserDelegate.qml +++ b/src/qml/ListBrowserDelegate.qml @@ -32,23 +32,25 @@ property string album property string albumArtist property string duration + property string fileName property url imageUrl property int trackNumber property int discNumber property int rating property bool isSingleDiscAlbum property bool isSelected property bool isAlternateColor property bool detailedView: true + property string displayTitle: title ? title : fileName signal clicked() signal enqueue(var databaseId, var name) signal replaceAndPlay(var databaseId, var name) signal callOpenMetaDataView(var databaseId) Accessible.role: Accessible.ListItem - Accessible.name: title - Accessible.description: title + Accessible.name: displayTitle + Accessible.description: displayTitle Action { id: enqueueAction @@ -115,21 +117,21 @@ return i18nc("%1: track number. %2: track title. %3: artist name", "%1 - %2 - %3", trackNumber.toLocaleString(Qt.locale(), 'f', 0), - title, artist); + displayTitle, artist); else return i18nc("%1: track number. %2: track title.", "%1 - %2", trackNumber.toLocaleString(Qt.locale(), 'f', 0), - title); + displayTitle); } else { if (artist !== albumArtist) return i18nc("%1: track title. %2: artist name", "%1 - %2", - title, artist); + displayTitle, artist); else return i18nc("%1: track title", "%1", - title); + displayTitle); } } @@ -205,9 +207,9 @@ text: { if (trackNumber >= 0) { return i18nc("%1: track number. %2: track title", "%1 - %2", - trackNumber.toLocaleString(Qt.locale(), 'f', 0), title); + trackNumber.toLocaleString(Qt.locale(), 'f', 0), displayTitle); } else { - return title; + return displayTitle; } } diff --git a/src/qml/MetaDataDelegate.qml b/src/qml/MetaDataDelegate.qml --- a/src/qml/MetaDataDelegate.qml +++ b/src/qml/MetaDataDelegate.qml @@ -59,7 +59,7 @@ sourceComponent: LabelWithToolTip { - text: model.display + text: model.display ? model.display : '' horizontalAlignment: Text.AlignLeft elide: Text.ElideRight @@ -79,7 +79,7 @@ Layout.alignment: Qt.AlignTop sourceComponent: Label { - text: model.display + text: model.display ? model.display : '' horizontalAlignment: Text.AlignLeft elide: Text.ElideRight diff --git a/src/qml/PlayListBasicView.qml b/src/qml/PlayListBasicView.qml --- a/src/qml/PlayListBasicView.qml +++ b/src/qml/PlayListBasicView.qml @@ -124,7 +124,8 @@ album: model.album ? model.album : '' albumArtist: model.albumArtist ? model.albumArtist : '' duration: model.duration ? model.duration : '' - fileName: model.trackResource ? model.trackResource : '' + fileName: model.fileName ? model.fileName : '' + trackResource: model.trackResource ? model.trackResource : '' imageUrl: model.imageUrl ? model.imageUrl : '' trackNumber: model.trackNumber ? model.trackNumber : -1 discNumber: model.discNumber ? model.discNumber : -1 diff --git a/src/qml/PlayListEntry.qml b/src/qml/PlayListEntry.qml --- a/src/qml/PlayListEntry.qml +++ b/src/qml/PlayListEntry.qml @@ -38,22 +38,24 @@ property string album property string albumArtist property string duration - property url fileName + property string fileName + property url trackResource property url imageUrl property int trackNumber property int discNumber property int rating property bool hasValidDiscNumber: true property int scrollBarWidth property bool simpleMode: false + property string displayTitle: title ? title : fileName signal startPlayback() signal pausePlayback() signal removeFromPlaylist(var trackIndex) signal switchToTrack(var trackIndex) Accessible.role: Accessible.ListItem - Accessible.name: title + ' ' + album + ' ' + artist + Accessible.name: displayTitle + ' ' + album + ' ' + artist height: elisaTheme.playListDelegateHeight @@ -110,7 +112,7 @@ sourceComponent: MediaTrackMetadataView { databaseId: playListEntry.databaseId - fileName: playListEntry.fileName + fileName: playListEntry.trackResource onRejected: metadataLoader.active = false; } } @@ -292,7 +294,7 @@ LabelWithToolTip { id: mainCompactLabel - text: title + text: displayTitle font.weight: (isPlaying ? Font.Bold : Font.Normal) color: simpleMode ? myPalette.highlightedText : myPalette.text @@ -310,7 +312,7 @@ LabelWithToolTip { id: mainInvalidCompactLabel - text: title + text: displayTitle font.weight: Font.Normal color: simpleMode ? myPalette.highlightedText : myPalette.text diff --git a/src/qml/SimplePlayListView.qml b/src/qml/SimplePlayListView.qml --- a/src/qml/SimplePlayListView.qml +++ b/src/qml/SimplePlayListView.qml @@ -113,7 +113,8 @@ album: model.album ? model.album : '' albumArtist: model.albumArtist ? model.albumArtist : '' duration: model.duration ? model.duration : '' - fileName: model.trackResource ? model.trackResource : '' + fileName: model.fileName ? model.fileName : '' + trackResource: model.trackResource ? model.trackResource : '' imageUrl: model.imageUrl ? model.imageUrl : '' trackNumber: model.trackNumber ? model.trackNumber : -1 discNumber: model.discNumber ? model.discNumber : -1