diff --git a/src/databaseinterface.cpp b/src/databaseinterface.cpp index 13a69447..e95b0da2 100644 --- a/src/databaseinterface.cpp +++ b/src/databaseinterface.cpp @@ -1,5305 +1,5316 @@ /* * 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 "musicaudiotrack.h" #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), mSelectAllAlbumsQuery(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), mUpdateTrackMapping(mTracksDatabase), mSelectTracksMapping(mTracksDatabase), mSelectTracksMappingPriority(mTracksDatabase), mUpdateAlbumArtUriFromAlbumIdQuery(mTracksDatabase), mSelectTracksMappingPriorityByTrackId(mTracksDatabase), mSelectAllTrackFilesFromSourceQuery(mTracksDatabase), mSelectAlbumIdsFromArtist(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) { } QSqlDatabase mTracksDatabase; QSqlQuery mSelectAlbumQuery; QSqlQuery mSelectTrackQuery; QSqlQuery mSelectAlbumIdFromTitleQuery; QSqlQuery mInsertAlbumQuery; QSqlQuery mSelectTrackIdFromTitleAlbumIdArtistQuery; QSqlQuery mInsertTrackQuery; QSqlQuery mSelectTracksFromArtist; QSqlQuery mSelectTrackFromIdQuery; QSqlQuery mSelectCountAlbumsForArtistQuery; QSqlQuery mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery; QSqlQuery mSelectAllAlbumsQuery; 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 mUpdateTrackMapping; QSqlQuery mSelectTracksMapping; QSqlQuery mSelectTracksMappingPriority; QSqlQuery mUpdateAlbumArtUriFromAlbumIdQuery; QSqlQuery mSelectTracksMappingPriorityByTrackId; QSqlQuery mSelectAllTrackFilesFromSourceQuery; QSqlQuery mSelectAlbumIdsFromArtist; 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; 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; qulonglong mDiscoverId = 1; QAtomicInt mStopRequest = 0; bool mInitFinished = 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) { qInfo() << QCoreApplication::libraryPaths(); 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) { qDebug() << "database open"; } else { qDebug() << "database not open"; } qDebug() << "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 = d->mSelectTrackQuery.exec(); if (!queryResult || !d->mSelectTrackQuery.isSelect() || !d->mSelectTrackQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::albumData" << d->mSelectTrackQuery.lastQuery(); qDebug() << "DatabaseInterface::albumData" << d->mSelectTrackQuery.boundValues(); qDebug() << "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) { qDebug() << "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); qDebug() << "DatabaseInterface::allArtistsDataByGenre" << result.count(); 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; } DatabaseInterface::DataType DatabaseInterface::oneData(ElisaUtils::PlayListEntryType aType, qulonglong databaseId) { auto result = DataType{}; if (!d) { return result; } auto transactionResult = startTransaction(); if (!transactionResult) { return result; } switch (aType) { case ElisaUtils::Artist: result = internalOneArtistPartialData(databaseId); break; case ElisaUtils::Album: result = internalOneAlbumPartialData(databaseId); break; case ElisaUtils::Track: result = internalOneTrackPartialData(databaseId); break; case ElisaUtils::Genre: result = internalOneGenrePartialData(databaseId); break; case ElisaUtils::Composer: result = internalOneComposerPartialData(databaseId); break; case ElisaUtils::Lyricist: result = internalOneLyricistPartialData(databaseId); break; case ElisaUtils::Unknown: case ElisaUtils::FileName: break; }; transactionResult = finishTransaction(); if (!transactionResult) { return result; } 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::removeAllTracksFromSource(const QString &sourceName) { auto transactionResult = startTransaction(); if (!transactionResult) { return; } initChangesTrackers(); auto sourceId = internalSourceIdFromName(sourceName); auto allFileNames = internalAllFileNameFromSource(sourceId); internalRemoveTracksList(allFileNames, sourceId); 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) { return; } } void DatabaseInterface::askRestoredTracks(const QString &musicSource) { auto transactionResult = startTransaction(); if (!transactionResult) { return; } auto result = internalAllFileNameFromSource(internalSourceIdFromName(musicSource)); Q_EMIT restoredTracks(musicSource, result); transactionResult = finishTransaction(); if (!transactionResult) { return; } } void DatabaseInterface::trackHasStartedPlaying(const QUrl &fileName, const QDateTime &time) { auto transactionResult = startTransaction(); if (!transactionResult) { return; } auto trackId = internalTrackIdFromFileName(fileName); if (trackId != 0) { updateTrackStatistics(trackId, time); } transactionResult = finishTransaction(); if (!transactionResult) { return; } } 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, const QString &musicSource) { if (d->mStopRequest == 1) { return; } auto transactionResult = startTransaction(); if (!transactionResult) { return; } initChangesTrackers(); for(const auto &oneTrack : tracks) { d->mSelectTracksMapping.bindValue(QStringLiteral(":fileName"), oneTrack.resourceURI()); auto result = d->mSelectTracksMapping.exec(); if (!result || !d->mSelectTracksMapping.isSelect() || !d->mSelectTracksMapping.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::insertTracksList" << d->mSelectTracksMapping.lastQuery(); qDebug() << "DatabaseInterface::insertTracksList" << d->mSelectTracksMapping.boundValues(); qDebug() << "DatabaseInterface::insertTracksList" << d->mSelectTracksMapping.lastError(); d->mSelectTracksMapping.finish(); rollBackTransaction(); return; } bool isNewTrack = !d->mSelectTracksMapping.next(); if (isNewTrack) { insertTrackOrigin(oneTrack.resourceURI(), oneTrack.fileModificationTime(), insertMusicSource(musicSource)); } else if (!d->mSelectTracksMapping.record().value(0).isNull() && d->mSelectTracksMapping.record().value(0).toULongLong() != 0) { updateTrackOrigin(d->mSelectTracksMapping.record().value(0).toULongLong(), oneTrack.resourceURI(), oneTrack.fileModificationTime()); } else { continue; } d->mSelectTracksMapping.finish(); const auto insertedTrackId = internalInsertTrack(oneTrack, covers, 0, (isNewTrack ? TrackFileInsertType::NewTrackFileInsert : TrackFileInsertType::ModifiedTrackFileInsert)); if (isNewTrack && insertedTrackId != 0) { d->mInsertedTracks.insert(insertedTrackId); } if (d->mStopRequest == 1) { transactionResult = finishTransaction(); if (!transactionResult) { return; } return; } } if (!d->mInsertedArtists.isEmpty()) { ListArtistDataType newArtists; for (auto artistId : qAsConst(d->mInsertedArtists)) { newArtists.push_back({{DatabaseIdRole, artistId}}); } qInfo() << "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)); } qInfo() << "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); } qInfo() << "tracksAdded" << newTracks.size(); Q_EMIT tracksAdded(newTracks); } for (auto trackId : qAsConst(d->mModifiedTrackIds)) { Q_EMIT trackModified(internalOneTrackPartialData(trackId)); } transactionResult = finishTransaction(); if (!transactionResult) { return; } } void DatabaseInterface::removeTracksList(const QList &removedTracks) { auto transactionResult = startTransaction(); if (!transactionResult) { 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) { return; } } void DatabaseInterface::modifyTracksList(const QList &modifiedTracks, const QHash &covers, const QString &musicSource) { auto transactionResult = startTransaction(); if (!transactionResult) { return; } initChangesTrackers(); for (const auto &oneModifiedTrack : modifiedTracks) { if (oneModifiedTrack.albumArtist().isEmpty()) { continue; } bool modifyExistingTrack = internalTrackFromDatabaseId(oneModifiedTrack.databaseId()).isValid() || (internalTrackIdFromFileName(oneModifiedTrack.resourceURI()) != 0); auto originTrackId = oneModifiedTrack.databaseId(); if (!originTrackId) { originTrackId = internalTrackIdFromFileName(oneModifiedTrack.resourceURI()); } if (!modifyExistingTrack) { insertTrackOrigin(oneModifiedTrack.resourceURI(), oneModifiedTrack.fileModificationTime(), insertMusicSource(musicSource)); } else { updateTrackOrigin(originTrackId, oneModifiedTrack.resourceURI(), oneModifiedTrack.fileModificationTime()); } const auto insertedTrackId = internalInsertTrack(oneModifiedTrack, covers, (modifyExistingTrack ? originTrackId : 0), (modifyExistingTrack ? TrackFileInsertType::ModifiedTrackFileInsert : TrackFileInsertType::NewTrackFileInsert)); if (!modifyExistingTrack && insertedTrackId != 0) { d->mInsertedTracks.insert(insertedTrackId); } } if (!d->mInsertedArtists.isEmpty()) { ListArtistDataType newArtists; for (auto artistId : qAsConst(d->mInsertedArtists)) { newArtists.push_back({{DatabaseIdRole, artistId}}); } 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)); } 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); } Q_EMIT tracksAdded(newTracks); } for (auto trackId : qAsConst(d->mModifiedTrackIds)) { Q_EMIT trackModified(internalOneTrackPartialData(trackId)); } transactionResult = finishTransaction(); if (!transactionResult) { return; } } bool DatabaseInterface::startTransaction() const { auto result = false; auto transactionResult = d->mTracksDatabase.transaction(); if (!transactionResult) { qDebug() << "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) { qDebug() << "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) { qDebug() << "commit failed" << d->mTracksDatabase.lastError() << d->mTracksDatabase.lastError().nativeErrorCode(); return result; } result = true; return result; } void DatabaseInterface::initDatabase() { auto transactionResult = startTransaction(); if (!transactionResult) { return; } auto listTables = d->mTracksDatabase.tables(); if (!listTables.contains(QStringLiteral("DatabaseVersionV9"))) { auto oldTables = QStringList{ QStringLiteral("DatabaseVersionV2"), QStringLiteral("DatabaseVersionV3"), QStringLiteral("DatabaseVersionV4"), QStringLiteral("DatabaseVersionV5"), QStringLiteral("DatabaseVersionV6"), QStringLiteral("DatabaseVersionV7"), QStringLiteral("DatabaseVersionV8"), 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) { qDebug() << "DatabaseInterface::initDatabase" << createSchemaQuery.lastQuery(); qDebug() << "DatabaseInterface::initDatabase" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } listTables = d->mTracksDatabase.tables(); } if (!listTables.contains(QStringLiteral("DatabaseVersionV9"))) { QSqlQuery createSchemaQuery(d->mTracksDatabase); const auto &result = createSchemaQuery.exec(QStringLiteral("CREATE TABLE `DatabaseVersionV9` (`Version` INTEGER PRIMARY KEY NOT NULL)")); if (!result) { qDebug() << "DatabaseInterface::initDatabase" << createSchemaQuery.lastQuery(); qDebug() << "DatabaseInterface::initDatabase" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } if (!listTables.contains(QStringLiteral("DiscoverSource"))) { 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) { qDebug() << "DatabaseInterface::initDatabase" << createSchemaQuery.lastQuery(); qDebug() << "DatabaseInterface::initDatabase" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } if (!listTables.contains(QStringLiteral("Artists"))) { 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) { qDebug() << "DatabaseInterface::initDatabase" << createSchemaQuery.lastQuery(); qDebug() << "DatabaseInterface::initDatabase" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } if (!listTables.contains(QStringLiteral("Composer"))) { 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) { qDebug() << "DatabaseInterface::initDatabase" << createSchemaQuery.lastQuery(); qDebug() << "DatabaseInterface::initDatabase" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } if (!listTables.contains(QStringLiteral("Genre"))) { 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) { qDebug() << "DatabaseInterface::initDatabase" << createSchemaQuery.lastQuery(); qDebug() << "DatabaseInterface::initDatabase" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } if (!listTables.contains(QStringLiteral("Lyricist"))) { 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) { qDebug() << "DatabaseInterface::initDatabase" << createSchemaQuery.lastQuery(); qDebug() << "DatabaseInterface::initDatabase" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } if (!listTables.contains(QStringLiteral("Albums"))) { 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, " "`AlbumInternalID` VARCHAR(55), " "UNIQUE (`Title`, `ArtistName`, `AlbumPath`), " "CONSTRAINT fk_artists FOREIGN KEY (`ArtistName`) REFERENCES `Artists`(`Name`) " "ON DELETE CASCADE)")); if (!result) { qDebug() << "DatabaseInterface::initDatabase" << createSchemaQuery.lastQuery(); qDebug() << "DatabaseInterface::initDatabase" << createSchemaQuery.lastError(); } } if (!listTables.contains(QStringLiteral("Tracks"))) { 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) { qDebug() << "DatabaseInterface::initDatabase" << createSchemaQuery.lastQuery(); qDebug() << "DatabaseInterface::initDatabase" << createSchemaQuery.lastError(); Q_EMIT databaseError(); } } if (!listTables.contains(QStringLiteral("TracksMapping"))) { 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) { qDebug() << "DatabaseInterface::initDatabase" << createSchemaQuery.lastQuery(); qDebug() << "DatabaseInterface::initDatabase" << createSchemaQuery.lastError(); } } { QSqlQuery createTrackIndex(d->mTracksDatabase); const auto &result = createTrackIndex.exec(QStringLiteral("CREATE INDEX " "IF NOT EXISTS " "`TitleAlbumsIndex` ON `Albums` " "(`Title`)")); if (!result) { qDebug() << "DatabaseInterface::initDatabase" << createTrackIndex.lastQuery(); qDebug() << "DatabaseInterface::initDatabase" << 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) { qDebug() << "DatabaseInterface::initDatabase" << createTrackIndex.lastQuery(); qDebug() << "DatabaseInterface::initDatabase" << 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) { qDebug() << "DatabaseInterface::initDatabase" << createTrackIndex.lastQuery(); qDebug() << "DatabaseInterface::initDatabase" << 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) { qDebug() << "DatabaseInterface::initDatabase" << createTrackIndex.lastQuery(); qDebug() << "DatabaseInterface::initDatabase" << 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) { qDebug() << "DatabaseInterface::initDatabase" << createTrackIndex.lastQuery(); qDebug() << "DatabaseInterface::initDatabase" << 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) { qDebug() << "DatabaseInterface::initDatabase" << createTrackIndex.lastQuery(); qDebug() << "DatabaseInterface::initDatabase" << createTrackIndex.lastError(); Q_EMIT databaseError(); } } transactionResult = finishTransaction(); if (!transactionResult) { return; } } void DatabaseInterface::initRequest() { auto transactionResult = startTransaction(); if (!transactionResult) { return; } { auto selectAlbumQueryText = QStringLiteral("SELECT " "album.`ID`, " "album.`Title`, " "album.`AlbumInternalID`, " "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) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectAlbumQuery.lastQuery(); qDebug() << "DatabaseInterface::initRequest" << d->mSelectAlbumQuery.lastError(); Q_EMIT databaseError(); } } { auto selectAllAlbumsText = QStringLiteral("SELECT " "album.`ID`, " "album.`Title`, " "album.`AlbumInternalID`, " "album.`ArtistName`, " "album.`AlbumPath`, " "album.`CoverFileName`, " "(" "SELECT " "COUNT(*) " "FROM " "`Tracks` tracks " "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` " ") 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` " "FROM `Albums` album " "ORDER BY album.`Title` COLLATE NOCASE"); auto result = prepareQuery(d->mSelectAllAlbumsQuery, selectAllAlbumsText); if (!result) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectAllAlbumsQuery.lastQuery(); qDebug() << "DatabaseInterface::initRequest" << d->mSelectAllAlbumsQuery.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) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectAllAlbumsQuery.lastQuery(); qDebug() << "DatabaseInterface::initRequest" << d->mSelectAllAlbumsQuery.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) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectAllAlbumsShortQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectAllAlbumsShortWithGenreArtistFilterQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectAllAlbumsShortWithArtistFilterQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectAllArtistsQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectAllArtistsWithGenreFilterQuery.lastQuery(); qDebug() << "DatabaseInterface::initRequest" << d->mSelectAllArtistsWithGenreFilterQuery.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) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectAllComposersQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectAllLyricistsQuery.lastQuery(); qDebug() << "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`, " "tracks.`ImportDate`, " "tracks.`FirstPlayDate`, " "tracks.`LastPlayDate`, " "tracks.`PlayCounter`, " "tracks.`PlayCounter` / (strftime('%s', 'now') - tracks.`FirstPlayDate`) as PlayFrequency " "FROM " "`Tracks` tracks, " "`TracksMapping` 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.`TrackID` = tracks.`ID` AND " "tracksMapping.`Priority` = (SELECT MIN(`Priority`) FROM `TracksMapping` WHERE `TrackID` = tracks.`ID`)"); auto result = prepareQuery(d->mSelectAllTracksQuery, selectAllTracksText); if (!result) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectAllTracksQuery.lastQuery(); qDebug() << "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`, " "tracks.`ImportDate`, " "tracks.`FirstPlayDate`, " "tracks.`LastPlayDate`, " "tracks.`PlayCounter`, " "tracks.`PlayCounter` / (strftime('%s', 'now') - tracks.`FirstPlayDate`) as PlayFrequency " "FROM " "`Tracks` tracks, " "`TracksMapping` 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.`TrackID` = tracks.`ID` AND " "tracks.`PlayCounter` > 0 AND " "tracksMapping.`Priority` = (SELECT MIN(`Priority`) FROM `TracksMapping` WHERE `TrackID` = tracks.`ID`) " "ORDER BY tracks.`LastPlayDate` DESC " "LIMIT :maximumResults"); auto result = prepareQuery(d->mSelectAllRecentlyPlayedTracksQuery, selectAllTracksText); if (!result) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectAllRecentlyPlayedTracksQuery.lastQuery(); qDebug() << "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`, " "tracks.`ImportDate`, " "tracks.`FirstPlayDate`, " "tracks.`LastPlayDate`, " "tracks.`PlayCounter`, " "tracks.`PlayCounter` / (strftime('%s', 'now') - tracks.`FirstPlayDate`) as PlayFrequency " "FROM " "`Tracks` tracks, " "`TracksMapping` 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.`TrackID` = tracks.`ID` AND " "tracks.`PlayCounter` > 0 AND " "tracksMapping.`Priority` = (SELECT MIN(`Priority`) FROM `TracksMapping` WHERE `TrackID` = tracks.`ID`) " "ORDER BY tracks.`PlayCounter` / (strftime('%s', 'now') - tracks.`FirstPlayDate`) DESC " "LIMIT :maximumResults"); auto result = prepareQuery(d->mSelectAllFrequentlyPlayedTracksQuery, selectAllTracksText); if (!result) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectAllFrequentlyPlayedTracksQuery.lastQuery(); qDebug() << "DatabaseInterface::initRequest" << d->mSelectAllFrequentlyPlayedTracksQuery.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) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectAllTracksShortQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectArtistByNameQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectComposerByNameQuery.lastQuery(); qDebug() << "DatabaseInterface::initRequest" << d->mSelectComposerByNameQuery.lastError(); } } { auto selectLyricistByNameText = QStringLiteral("SELECT `ID`, " "`Name` " "FROM `Lyricist` " "WHERE " "`Name` = :name"); auto result = prepareQuery(d->mSelectLyricistByNameQuery, selectLyricistByNameText); if (!result) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectLyricistByNameQuery.lastQuery(); qDebug() << "DatabaseInterface::initRequest" << d->mSelectLyricistByNameQuery.lastError(); } } { auto selectGenreByNameText = QStringLiteral("SELECT `ID`, " "`Name` " "FROM `Genre` " "WHERE " "`Name` = :name"); auto result = prepareQuery(d->mSelectGenreByNameQuery, selectGenreByNameText); if (!result) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectGenreByNameQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mInsertArtistsQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mInsertGenreQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mInsertComposerQuery.lastQuery(); qDebug() << "DatabaseInterface::initRequest" << d->mInsertComposerQuery.lastError(); } } { auto insertLyricistText = QStringLiteral("INSERT INTO `Lyricist` (`ID`, `Name`) " "VALUES (:lyricistId, :name)"); auto result = prepareQuery(d->mInsertLyricistQuery, insertLyricistText); if (!result) { qDebug() << "DatabaseInterface::initRequest" << d->mInsertLyricistQuery.lastQuery(); qDebug() << "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`, " "tracks.`ImportDate`, " "tracks.`FirstPlayDate`, " "tracks.`LastPlayDate`, " "tracks.`PlayCounter`, " "tracks.`PlayCounter` / (strftime('%s', 'now') - tracks.`FirstPlayDate`) as PlayFrequency " "FROM " "`Tracks` tracks, " "`TracksMapping` 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 " "tracksMapping.`TrackID` = tracks.`ID` AND " "album.`ID` = :albumId AND " "tracksMapping.`Priority` = (SELECT MIN(`Priority`) FROM `TracksMapping` WHERE `TrackID` = tracks.`ID`) " "ORDER BY tracks.`DiscNumber` ASC, " "tracks.`TrackNumber` ASC"); auto result = prepareQuery(d->mSelectTrackQuery, selectTrackQueryText); if (!result) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectTrackQuery.lastQuery(); qDebug() << "DatabaseInterface::initRequest" << d->mSelectTrackQuery.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`, " "tracks.`ImportDate`, " "tracks.`FirstPlayDate`, " "tracks.`LastPlayDate`, " "tracks.`PlayCounter`, " "tracks.`PlayCounter` / (strftime('%s', 'now') - tracks.`FirstPlayDate`) as PlayFrequency " "FROM " "`Tracks` tracks, " "`TracksMapping` 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.`TrackID` = tracks.`ID` AND " "tracksMapping.`Priority` = (SELECT MIN(`Priority`) FROM `TracksMapping` WHERE `TrackID` = tracks.`ID`)"); auto result = prepareQuery(d->mSelectTrackFromIdQuery, selectTrackFromIdQueryText); if (!result) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectTrackFromIdQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectCountAlbumsForArtistQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectGenreForArtistQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectGenreForAlbumQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectCountAlbumsForComposerQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectCountAlbumsForLyricistQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectAlbumIdFromTitleQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectAlbumIdFromTitleAndArtistQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectAlbumIdFromTitleWithoutArtistQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mInsertAlbumQuery.lastQuery(); qDebug() << "DatabaseInterface::initRequest" << d->mInsertAlbumQuery.lastError(); Q_EMIT databaseError(); } } { auto insertTrackMappingQueryText = QStringLiteral("INSERT INTO " "`TracksMapping` " "(`FileName`, " "`DiscoverID`, " "`Priority`, " "`FileModifiedTime`) " "VALUES (:fileName, :discoverId, :priority, :mtime)"); auto result = prepareQuery(d->mInsertTrackMapping, insertTrackMappingQueryText); if (!result) { qDebug() << "DatabaseInterface::initRequest" << d->mInsertTrackMapping.lastQuery(); qDebug() << "DatabaseInterface::initRequest" << d->mInsertTrackMapping.lastError(); Q_EMIT databaseError(); } } { auto initialUpdateTracksValidityQueryText = QStringLiteral("UPDATE `TracksMapping` " "SET " "`TrackID` = :trackId, " "`Priority` = :priority, " "`FileModifiedTime` = :mtime " "WHERE `FileName` = :fileName"); auto result = prepareQuery(d->mUpdateTrackMapping, initialUpdateTracksValidityQueryText); if (!result) { qDebug() << "DatabaseInterface::initRequest" << d->mUpdateTrackMapping.lastQuery(); qDebug() << "DatabaseInterface::initRequest" << d->mUpdateTrackMapping.lastError(); Q_EMIT databaseError(); } } { auto removeTracksMappingFromSourceQueryText = QStringLiteral("DELETE FROM `TracksMapping` " "WHERE `FileName` = :fileName AND `DiscoverID` = :sourceId"); auto result = prepareQuery(d->mRemoveTracksMappingFromSource, removeTracksMappingFromSourceQueryText); if (!result) { qDebug() << "DatabaseInterface::initRequest" << d->mRemoveTracksMappingFromSource.lastQuery(); qDebug() << "DatabaseInterface::initRequest" << d->mRemoveTracksMappingFromSource.lastError(); Q_EMIT databaseError(); } } { auto removeTracksMappingQueryText = QStringLiteral("DELETE FROM `TracksMapping` " "WHERE `FileName` = :fileName"); auto result = prepareQuery(d->mRemoveTracksMapping, removeTracksMappingQueryText); if (!result) { qDebug() << "DatabaseInterface::initRequest" << d->mRemoveTracksMapping.lastQuery(); qDebug() << "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`, " "tracks.`ImportDate`, " "tracks.`FirstPlayDate`, " "tracks.`LastPlayDate`, " "tracks.`PlayCounter`, " "tracks.`PlayCounter` / (strftime('%s', 'now') - tracks.`FirstPlayDate`) as PlayFrequency " "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 `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` NOT IN (SELECT tracksMapping2.`TrackID` FROM `TracksMapping` tracksMapping2)"); auto result = prepareQuery(d->mSelectTracksWithoutMappingQuery, selectTracksWithoutMappingQueryText); if (!result) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectTracksWithoutMappingQuery.lastQuery(); qDebug() << "DatabaseInterface::initRequest" << d->mSelectTracksWithoutMappingQuery.lastError(); Q_EMIT databaseError(); } } { auto selectTracksMappingQueryText = QStringLiteral("SELECT " "`TrackID`, " "`FileName`, " "`DiscoverID`, " "`Priority`, " "`FileModifiedTime` " "FROM " "`TracksMapping` " "WHERE " "`FileName` = :fileName"); auto result = prepareQuery(d->mSelectTracksMapping, selectTracksMappingQueryText); if (!result) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectTracksMapping.lastQuery(); qDebug() << "DatabaseInterface::initRequest" << d->mSelectTracksMapping.lastError(); Q_EMIT databaseError(); } } { auto selectTracksMappingPriorityQueryText = QStringLiteral("SELECT " "`Priority` " "FROM " "`TracksMapping` " "WHERE " "`TrackID` = :trackId AND " "`FileName` = :fileName"); auto result = prepareQuery(d->mSelectTracksMappingPriority, selectTracksMappingPriorityQueryText); if (!result) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectTracksMappingPriority.lastQuery(); qDebug() << "DatabaseInterface::initRequest" << d->mSelectTracksMappingPriority.lastError(); Q_EMIT databaseError(); } } { auto selectTracksMappingPriorityQueryByTrackIdText = QStringLiteral("SELECT " "MAX(`Priority`) " "FROM " "`TracksMapping` " "WHERE " "`TrackID` = :trackId"); auto result = prepareQuery(d->mSelectTracksMappingPriorityByTrackId, selectTracksMappingPriorityQueryByTrackIdText); if (!result) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectTracksMappingPriorityByTrackId.lastQuery(); qDebug() << "DatabaseInterface::initRequest" << d->mSelectTracksMappingPriorityByTrackId.lastError(); Q_EMIT databaseError(); } } { auto selectAllTrackFilesFromSourceQueryText = QStringLiteral("SELECT " "tracksMapping.`FileName`, " "tracksMapping.`FileModifiedTime` " "FROM " "`TracksMapping` tracksMapping " "WHERE " "tracksMapping.`DiscoverID` = :discoverId"); auto result = prepareQuery(d->mSelectAllTrackFilesFromSourceQuery, selectAllTrackFilesFromSourceQueryText); if (!result) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectAllTrackFilesFromSourceQuery.lastQuery(); qDebug() << "DatabaseInterface::initRequest" << d->mSelectAllTrackFilesFromSourceQuery.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) { qDebug() << "DatabaseInterface::initRequest" << d->mInsertMusicSource.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectMusicSource.lastQuery(); qDebug() << "DatabaseInterface::initRequest" << d->mSelectMusicSource.lastError(); Q_EMIT databaseError(); } } { auto selectTrackQueryText = QStringLiteral("SELECT " "tracks.`ID`, tracksMapping.`FileName` " "FROM " "`Tracks` tracks, " "`Albums` album, " "`TracksMapping` 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.`TrackID` = tracks.`ID` AND " "tracksMapping.`Priority` = (SELECT MIN(`Priority`) FROM `TracksMapping` WHERE `TrackID` = tracks.`ID`)"); auto result = prepareQuery(d->mSelectTrackIdFromTitleAlbumIdArtistQuery, selectTrackQueryText); if (!result) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectTrackIdFromTitleAlbumIdArtistQuery.lastQuery(); qDebug() << "DatabaseInterface::initRequest" << d->mSelectTrackIdFromTitleAlbumIdArtistQuery.lastError(); Q_EMIT databaseError(); } } { auto insertTrackQueryText = QStringLiteral("INSERT INTO `Tracks` " "(" "`ID`, " "`Title`, " "`ArtistName`, " "`AlbumTitle`, " "`AlbumArtistName`, " "`AlbumPath`, " "`Genre`, " "`Composer`, " "`Lyricist`, " "`Comment`, " "`TrackNumber`, " "`DiscNumber`, " "`Channels`, " "`BitRate`, " "`SampleRate`, " "`Year`, " "`Duration`, " "`Rating`, " "`HasEmbeddedCover`, " "`ImportDate`, " "`PlayCounter`) " "VALUES " "(" ":trackId, " ":title, " ":artistName, " ":albumTitle, " ":albumArtistName, " ":albumPath, " ":genre, " ":composer, " ":lyricist, " ":comment, " ":trackNumber, " ":discNumber, " ":channels, " ":bitRate, " ":sampleRate, " ":year, " ":trackDuration, " ":trackRating, " ":hasEmbeddedCover, " ":importDate, " "0)"); auto result = prepareQuery(d->mInsertTrackQuery, insertTrackQueryText); if (!result) { qDebug() << "DatabaseInterface::initRequest" << d->mInsertTrackQuery.lastQuery(); qDebug() << "DatabaseInterface::initRequest" << d->mInsertTrackQuery.lastError(); Q_EMIT databaseError(); } } { auto updateTrackQueryText = QStringLiteral("UPDATE `Tracks` " "SET " "`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) { qDebug() << "DatabaseInterface::initRequest" << d->mUpdateTrackQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mUpdateAlbumArtistQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mUpdateAlbumArtistInTracksQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mQueryMaximumTrackIdQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mQueryMaximumAlbumIdQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mQueryMaximumArtistIdQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mQueryMaximumLyricistIdQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mQueryMaximumComposerIdQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mQueryMaximumGenreIdQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery.lastQuery(); qDebug() << "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.`ArtistName` = :trackArtist AND " "tracks.`AlbumTitle` = :album AND " "(tracks.`AlbumArtistName` = :albumArtist OR tracks.`AlbumArtistName` IS NULL) AND " "tracks.`AlbumPath` = :albumPath AND " "tracks.`TrackNumber` = :trackNumber"); auto result = prepareQuery(d->mSelectTrackIdFromTitleAlbumTrackDiscNumberQuery, selectTrackQueryText); if (!result) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectTrackIdFromTitleAlbumTrackDiscNumberQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectAlbumArtUriFromAlbumIdQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mUpdateAlbumArtUriFromAlbumIdQuery.lastQuery(); qDebug() << "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`, " "tracks.`ImportDate`, " "tracks.`FirstPlayDate`, " "tracks.`LastPlayDate`, " "tracks.`PlayCounter`, " "tracks.`PlayCounter` / (strftime('%s', 'now') - tracks.`FirstPlayDate`) as PlayFrequency " "FROM " "`Tracks` tracks, " "`TracksMapping` 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.`TrackID` = tracks.`ID` AND " "tracksMapping.`Priority` = (SELECT MIN(`Priority`) FROM `TracksMapping` WHERE `TrackID` = tracks.`ID`) " "ORDER BY tracks.`Title` ASC, " "album.`Title` ASC"); auto result = prepareQuery(d->mSelectTracksFromArtist, selectTracksFromArtistQueryText); if (!result) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectTracksFromArtist.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectAlbumIdsFromArtist.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectArtistQuery.lastQuery(); qDebug() << "DatabaseInterface::initRequest" << d->mSelectArtistQuery.lastError(); Q_EMIT databaseError(); } } { auto updateTrackStatisticsQueryText = QStringLiteral("UPDATE `Tracks` " "SET " "`LastPlayDate` = :playDate, " "`PlayCounter` = `PlayCounter` + 1 " "WHERE " "`ID` = :trackId"); auto result = prepareQuery(d->mUpdateTrackStatistics, updateTrackStatisticsQueryText); if (!result) { qDebug() << "DatabaseInterface::initRequest" << d->mUpdateTrackStatistics.lastQuery(); qDebug() << "DatabaseInterface::initRequest" << d->mUpdateTrackStatistics.lastError(); Q_EMIT databaseError(); } } { auto updateTrackFirstPlayStatisticsQueryText = QStringLiteral("UPDATE `Tracks` " "SET " "`FirstPlayDate` = :playDate " "WHERE " "`ID` = :trackId AND " "`FirstPlayDate` IS NULL"); auto result = prepareQuery(d->mUpdateTrackFirstPlayStatistics, updateTrackFirstPlayStatisticsQueryText); if (!result) { qDebug() << "DatabaseInterface::initRequest" << d->mUpdateTrackFirstPlayStatistics.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectGenreQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectComposerQuery.lastQuery(); qDebug() << "DatabaseInterface::initRequest" << d->mSelectComposerQuery.lastError(); } } { auto selectLyricistQueryText = QStringLiteral("SELECT `ID`, " "`Name` " "FROM `Lyricist` " "WHERE " "`ID` = :lyricistId"); auto result = prepareQuery(d->mSelectLyricistQuery, selectLyricistQueryText); if (!result) { qDebug() << "DatabaseInterface::initRequest" << d->mSelectLyricistQuery.lastQuery(); qDebug() << "DatabaseInterface::initRequest" << d->mSelectLyricistQuery.lastError(); } } { auto removeTrackQueryText = QStringLiteral("DELETE FROM `Tracks` " "WHERE " "`ID` = :trackId"); auto result = prepareQuery(d->mRemoveTrackQuery, removeTrackQueryText); if (!result) { qDebug() << "DatabaseInterface::initRequest" << d->mRemoveTrackQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mRemoveAlbumQuery.lastQuery(); qDebug() << "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) { qDebug() << "DatabaseInterface::initRequest" << d->mRemoveArtistQuery.lastQuery(); qDebug() << "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 = d->mSelectAlbumIdFromTitleAndArtistQuery.exec(); if (!queryResult || !d->mSelectAlbumIdFromTitleAndArtistQuery.isSelect() || !d->mSelectAlbumIdFromTitleAndArtistQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::insertAlbum" << d->mSelectAlbumIdFromTitleAndArtistQuery.lastQuery(); qDebug() << "DatabaseInterface::insertAlbum" << d->mSelectAlbumIdFromTitleAndArtistQuery.boundValues(); qDebug() << "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 = d->mSelectAlbumIdFromTitleWithoutArtistQuery.exec(); if (!queryResult || !d->mSelectAlbumIdFromTitleWithoutArtistQuery.isSelect() || !d->mSelectAlbumIdFromTitleWithoutArtistQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::insertAlbum" << d->mSelectAlbumIdFromTitleWithoutArtistQuery.lastQuery(); qDebug() << "DatabaseInterface::insertAlbum" << d->mSelectAlbumIdFromTitleWithoutArtistQuery.boundValues(); qDebug() << "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 = d->mInsertAlbumQuery.exec(); if (!queryResult || !d->mInsertAlbumQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::insertAlbum" << d->mInsertAlbumQuery.lastQuery(); qDebug() << "DatabaseInterface::insertAlbum" << d->mInsertAlbumQuery.boundValues(); qDebug() << "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 = d->mUpdateAlbumArtUriFromAlbumIdQuery.exec(); if (!result || !d->mUpdateAlbumArtUriFromAlbumIdQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::updateAlbumFromId" << d->mUpdateAlbumArtUriFromAlbumIdQuery.lastQuery(); qDebug() << "DatabaseInterface::updateAlbumFromId" << d->mUpdateAlbumArtUriFromAlbumIdQuery.boundValues(); qDebug() << "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 = d->mSelectArtistByNameQuery.exec(); if (!queryResult || !d->mSelectArtistByNameQuery.isSelect() || !d->mSelectArtistByNameQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::insertArtist" << d->mSelectArtistByNameQuery.lastQuery(); qDebug() << "DatabaseInterface::insertArtist" << d->mSelectArtistByNameQuery.boundValues(); qDebug() << "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 = d->mInsertArtistsQuery.exec(); if (!queryResult || !d->mInsertArtistsQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::insertArtist" << d->mInsertArtistsQuery.lastQuery(); qDebug() << "DatabaseInterface::insertArtist" << d->mInsertArtistsQuery.boundValues(); qDebug() << "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 = d->mSelectComposerByNameQuery.exec(); if (!queryResult || !d->mSelectComposerByNameQuery.isSelect() || !d->mSelectComposerByNameQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::insertComposer" << d->mSelectComposerByNameQuery.lastQuery(); qDebug() << "DatabaseInterface::insertComposer" << d->mSelectComposerByNameQuery.boundValues(); qDebug() << "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 = d->mInsertComposerQuery.exec(); if (!queryResult || !d->mInsertComposerQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::insertComposer" << d->mInsertComposerQuery.lastQuery(); qDebug() << "DatabaseInterface::insertComposer" << d->mInsertComposerQuery.boundValues(); qDebug() << "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 = d->mSelectGenreByNameQuery.exec(); if (!queryResult || !d->mSelectGenreByNameQuery.isSelect() || !d->mSelectGenreByNameQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::insertGenre" << d->mSelectGenreByNameQuery.lastQuery(); qDebug() << "DatabaseInterface::insertGenre" << d->mSelectGenreByNameQuery.boundValues(); qDebug() << "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 = d->mInsertGenreQuery.exec(); if (!queryResult || !d->mInsertGenreQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::insertGenre" << d->mInsertGenreQuery.lastQuery(); qDebug() << "DatabaseInterface::insertGenre" << d->mInsertGenreQuery.boundValues(); qDebug() << "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, qulonglong discoverId) { d->mInsertTrackMapping.bindValue(QStringLiteral(":discoverId"), discoverId); d->mInsertTrackMapping.bindValue(QStringLiteral(":fileName"), fileNameURI); d->mInsertTrackMapping.bindValue(QStringLiteral(":priority"), 1); d->mInsertTrackMapping.bindValue(QStringLiteral(":mtime"), fileModifiedTime); auto queryResult = d->mInsertTrackMapping.exec(); if (!queryResult || !d->mInsertTrackMapping.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::insertArtist" << d->mInsertTrackMapping.lastQuery(); qDebug() << "DatabaseInterface::insertArtist" << d->mInsertTrackMapping.boundValues(); qDebug() << "DatabaseInterface::insertArtist" << d->mInsertTrackMapping.lastError(); d->mInsertTrackMapping.finish(); return; } d->mInsertTrackMapping.finish(); } void DatabaseInterface::updateTrackOrigin(qulonglong trackId, const QUrl &fileName, const QDateTime &fileModifiedTime) { d->mUpdateTrackMapping.bindValue(QStringLiteral(":trackId"), trackId); d->mUpdateTrackMapping.bindValue(QStringLiteral(":fileName"), fileName); d->mUpdateTrackMapping.bindValue(QStringLiteral(":priority"), computeTrackPriority(trackId, fileName)); d->mUpdateTrackMapping.bindValue(QStringLiteral(":mtime"), fileModifiedTime); auto queryResult = d->mUpdateTrackMapping.exec(); if (!queryResult || !d->mUpdateTrackMapping.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::updateTrackOrigin" << d->mUpdateTrackMapping.lastQuery(); qDebug() << "DatabaseInterface::updateTrackOrigin" << d->mUpdateTrackMapping.boundValues(); qDebug() << "DatabaseInterface::updateTrackOrigin" << d->mUpdateTrackMapping.lastError(); d->mUpdateTrackMapping.finish(); return; } d->mInsertTrackMapping.finish(); } int DatabaseInterface::computeTrackPriority(qulonglong trackId, const QUrl &fileName) { auto result = int(1); if (!d) { return result; } d->mSelectTracksMappingPriority.bindValue(QStringLiteral(":trackId"), trackId); d->mSelectTracksMappingPriority.bindValue(QStringLiteral(":fileName"), fileName); auto queryResult = d->mSelectTracksMappingPriority.exec(); if (!queryResult || !d->mSelectTracksMappingPriority.isSelect() || !d->mSelectTracksMappingPriority.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::internalTrackIdFromFileName" << d->mSelectTracksMappingPriority.lastQuery(); qDebug() << "DatabaseInterface::internalTrackIdFromFileName" << d->mSelectTracksMappingPriority.boundValues(); qDebug() << "DatabaseInterface::internalTrackIdFromFileName" << d->mSelectTracksMappingPriority.lastError(); d->mSelectTracksMappingPriority.finish(); return result; } if (d->mSelectTracksMappingPriority.next()) { result = d->mSelectTracksMappingPriority.record().value(0).toInt(); d->mSelectTracksMappingPriority.finish(); return result; } d->mSelectTracksMappingPriority.finish(); d->mSelectTracksMappingPriorityByTrackId.bindValue(QStringLiteral(":trackId"), trackId); queryResult = d->mSelectTracksMappingPriorityByTrackId.exec(); if (!queryResult || !d->mSelectTracksMappingPriorityByTrackId.isSelect() || !d->mSelectTracksMappingPriorityByTrackId.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::internalTrackIdFromFileName" << d->mSelectTracksMappingPriorityByTrackId.lastQuery(); qDebug() << "DatabaseInterface::internalTrackIdFromFileName" << d->mSelectTracksMappingPriorityByTrackId.boundValues(); qDebug() << "DatabaseInterface::internalTrackIdFromFileName" << d->mSelectTracksMappingPriorityByTrackId.lastError(); d->mSelectTracksMappingPriorityByTrackId.finish(); return result; } if (d->mSelectTracksMappingPriorityByTrackId.next()) { result = d->mSelectTracksMappingPriorityByTrackId.record().value(0).toInt() + 1; } d->mSelectTracksMappingPriorityByTrackId.finish(); return result; } qulonglong DatabaseInterface::internalInsertTrack(const MusicAudioTrack &oneTrack, const QHash &covers, qulonglong originTrackId, TrackFileInsertType insertType) { qulonglong resultId = 0; if (oneTrack.title().isEmpty()) { return resultId; } auto oldTrack = oneTrack; 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 otherTrackId = getDuplicateTrackIdFromTitleAlbumTrackDiscNumber(oneTrack.title(), oneTrack.artist(), oneTrack.albumName(), oneTrack.albumArtist(), trackPath, oneTrack.trackNumber(), oneTrack.discNumber()); bool isModifiedTrack = (otherTrackId != 0) || (insertType == TrackFileInsertType::ModifiedTrackFileInsert); bool isSameTrack = false; qulonglong oldAlbumId = 0; if (isModifiedTrack) { if (otherTrackId == 0) { otherTrackId = internalTrackIdFromFileName(oneTrack.resourceURI()); } originTrackId = otherTrackId; oldTrack = internalTrackFromDatabaseId(originTrackId); 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.trackNumber() == oneTrack.trackNumber()); 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.channels() == oneTrack.channels()); isSameTrack = isSameTrack && (oldTrack.bitRate() == oneTrack.bitRate()); isSameTrack = isSameTrack && (oldTrack.sampleRate() == oneTrack.sampleRate()); oldAlbumId = internalAlbumIdFromTitleAndArtist(oldTrack.albumName(), oldTrack.albumArtist()); if (!isSameTrack) { auto newTrack = oneTrack; newTrack.setDatabaseId(oldTrack.databaseId()); updateTrackInDatabase(newTrack, trackPath); updateTrackOrigin(newTrack.databaseId(), oneTrack.resourceURI(), oneTrack.fileModificationTime()); updateAlbumFromId(albumId, oneTrack.albumCover(), oneTrack, trackPath); recordModifiedTrack(originTrackId); if (albumId != 0) { recordModifiedAlbum(albumId); } if (oldAlbumId != 0) { auto tracksCount = fetchTrackIds(oldAlbumId).count(); if (tracksCount) { recordModifiedAlbum(oldAlbumId); } else { removeAlbumInDatabase(oldAlbumId); Q_EMIT albumRemoved(oldAlbumId); } } isSameTrack = true; } } else { originTrackId = d->mTrackId; } resultId = originTrackId; const auto &albumData = internalOneAlbumPartialData(albumId); if (!isSameTrack) { d->mInsertTrackQuery.bindValue(QStringLiteral(":trackId"), originTrackId); 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); d->mInsertTrackQuery.bindValue(QStringLiteral(":trackNumber"), oneTrack.trackNumber()); 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()); d->mInsertTrackQuery.bindValue(QStringLiteral(":channels"), oneTrack.channels()); d->mInsertTrackQuery.bindValue(QStringLiteral(":bitRate"), oneTrack.bitRate()); d->mInsertTrackQuery.bindValue(QStringLiteral(":sampleRate"), oneTrack.sampleRate()); d->mInsertTrackQuery.bindValue(QStringLiteral(":hasEmbeddedCover"), oneTrack.hasEmbeddedCover()); d->mInsertTrackQuery.bindValue(QStringLiteral(":importDate"), QDateTime::currentDateTime().toMSecsSinceEpoch()); auto result = d->mInsertTrackQuery.exec(); if (result && d->mInsertTrackQuery.isActive()) { d->mInsertTrackQuery.finish(); if (!isModifiedTrack) { ++d->mTrackId; } updateTrackOrigin(originTrackId, oneTrack.resourceURI(), oneTrack.fileModificationTime()); if (isModifiedTrack) { recordModifiedTrack(originTrackId); 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(); qDebug() << "DatabaseInterface::internalInsertTrack" << oneTrack << oneTrack.resourceURI(); qDebug() << "DatabaseInterface::internalInsertTrack" << d->mInsertTrackQuery.lastQuery(); qDebug() << "DatabaseInterface::internalInsertTrack" << d->mInsertTrackQuery.boundValues(); qDebug() << "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()); result.setTrackNumber(trackRecord.value(7).toInt()); 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()); result.setChannels(trackRecord.value(19).toInt()); result.setBitRate(trackRecord.value(20).toInt()); result.setSampleRate(trackRecord.value(21).toInt()); 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); result[TrackDataType::key_type::AlbumRole] = trackRecord.value(10); result[TrackDataType::key_type::AlbumIdRole] = trackRecord.value(2); result[TrackDataType::key_type::ArtistRole] = trackRecord.value(3); result[TrackDataType::key_type::AlbumArtistRole] = trackRecord.value(4); result[TrackDataType::key_type::ResourceRole] = trackRecord.value(5); result[TrackDataType::key_type::TrackNumberRole] = trackRecord.value(7); 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); result[TrackDataType::key_type::ImageUrlRole] = QUrl(trackRecord.value(12).toString()); result[TrackDataType::key_type::IsSingleDiscAlbumRole] = trackRecord.value(13); result[TrackDataType::key_type::GenreRole] = trackRecord.value(14); result[TrackDataType::key_type::ComposerRole] = trackRecord.value(15); result[TrackDataType::key_type::LyricistRole] = trackRecord.value(16); result[TrackDataType::key_type::HasEmbeddedCover] = trackRecord.value(22); result[TrackDataType::key_type::FileModificationTime] = trackRecord.value(6); result[TrackDataType::key_type::FirstPlayDate] = trackRecord.value(24); 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) { for (const auto &removedTrackFileName : removedTracks) { d->mRemoveTracksMapping.bindValue(QStringLiteral(":fileName"), removedTrackFileName.toString()); auto result = d->mRemoveTracksMapping.exec(); if (!result || !d->mRemoveTracksMapping.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::internalRemoveTracksList" << d->mRemoveTracksMapping.lastQuery(); qDebug() << "DatabaseInterface::internalRemoveTracksList" << d->mRemoveTracksMapping.boundValues(); qDebug() << "DatabaseInterface::internalRemoveTracksList" << d->mRemoveTracksMapping.lastError(); continue; } d->mRemoveTracksMapping.finish(); } internalRemoveTracksWithoutMapping(); } void DatabaseInterface::internalRemoveTracksList(const QHash &removedTracks, qulonglong sourceId) { for (auto itRemovedTrack = removedTracks.begin(); itRemovedTrack != removedTracks.end(); ++itRemovedTrack) { d->mRemoveTracksMappingFromSource.bindValue(QStringLiteral(":fileName"), itRemovedTrack.key().toString()); d->mRemoveTracksMappingFromSource.bindValue(QStringLiteral(":sourceId"), sourceId); auto result = d->mRemoveTracksMappingFromSource.exec(); if (!result || !d->mRemoveTracksMappingFromSource.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::removeTracksList" << d->mRemoveTracksMappingFromSource.lastQuery(); qDebug() << "DatabaseInterface::removeTracksList" << d->mRemoveTracksMappingFromSource.boundValues(); qDebug() << "DatabaseInterface::removeTracksList" << d->mRemoveTracksMappingFromSource.lastError(); continue; } d->mRemoveTracksMappingFromSource.finish(); } internalRemoveTracksWithoutMapping(); } void DatabaseInterface::internalRemoveTracksWithoutMapping() { auto queryResult = d->mSelectTracksWithoutMappingQuery.exec(); if (!queryResult || !d->mSelectTracksWithoutMappingQuery.isSelect() || !d->mSelectTracksWithoutMappingQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::insertArtist" << d->mSelectTracksWithoutMappingQuery.lastQuery(); qDebug() << "DatabaseInterface::insertArtist" << d->mSelectTracksWithoutMappingQuery.boundValues(); qDebug() << "DatabaseInterface::insertArtist" << d->mSelectTracksWithoutMappingQuery.lastError(); d->mSelectTracksWithoutMappingQuery.finish(); return; } QList willRemoveTrack; while (d->mSelectTracksWithoutMappingQuery.next()) { const auto ¤tRecord = d->mSelectTracksWithoutMappingQuery.record(); willRemoveTrack.push_back(buildTrackFromDatabaseRecord(currentRecord)); } d->mSelectTracksWithoutMappingQuery.finish(); 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 &oneRemovedTrack : willRemoveTrack) { removeTrackInDatabase(oneRemovedTrack.databaseId()); Q_EMIT trackRemoved(oneRemovedTrack.databaseId()); 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); recordModifiedAlbum(modifiedAlbumId); modifiedAlbums.insert(modifiedAlbumId); updateAlbumFromId(modifiedAlbumId, oneRemovedTrack.albumCover(), oneRemovedTrack, trackPath); if (removedArtistId != 0 && allTracksFromArtist.isEmpty() && allAlbumsFromArtist.isEmpty()) { removeArtistInDatabase(removedArtistId); Q_EMIT artistRemoved(removedArtistId); } } 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 = d->mSelectAlbumArtUriFromAlbumIdQuery.exec(); if (!queryResult || !d->mSelectAlbumArtUriFromAlbumIdQuery.isSelect() || !d->mSelectAlbumArtUriFromAlbumIdQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::insertArtist" << d->mSelectAlbumArtUriFromAlbumIdQuery.lastQuery(); qDebug() << "DatabaseInterface::insertArtist" << d->mSelectAlbumArtUriFromAlbumIdQuery.boundValues(); qDebug() << "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 = d->mSelectAlbumQuery.exec(); if (!queryResult || !d->mSelectAlbumQuery.isSelect() || !d->mSelectAlbumQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::internalAlbumFromId" << d->mSelectAlbumQuery.lastQuery(); qDebug() << "DatabaseInterface::internalAlbumFromId" << d->mSelectAlbumQuery.boundValues(); qDebug() << "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(3).toString().isEmpty(); return result; } qulonglong DatabaseInterface::internalSourceIdFromName(const QString &sourceName) { qulonglong sourceId = 0; d->mSelectMusicSource.bindValue(QStringLiteral(":name"), sourceName); auto queryResult = d->mSelectMusicSource.exec(); if (!queryResult || !d->mSelectMusicSource.isSelect() || !d->mSelectMusicSource.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::insertMusicSource" << d->mSelectMusicSource.lastQuery(); qDebug() << "DatabaseInterface::insertMusicSource" << d->mSelectMusicSource.boundValues(); qDebug() << "DatabaseInterface::insertMusicSource" << d->mSelectMusicSource.lastError(); d->mSelectMusicSource.finish(); return sourceId; } if (!d->mSelectMusicSource.next()) { return sourceId; } sourceId = d->mSelectMusicSource.record().value(0).toULongLong(); d->mSelectMusicSource.finish(); return sourceId; } QHash DatabaseInterface::internalAllFileNameFromSource(qulonglong sourceId) { QHash allFileNames; d->mSelectAllTrackFilesFromSourceQuery.bindValue(QStringLiteral(":discoverId"), sourceId); auto queryResult = d->mSelectAllTrackFilesFromSourceQuery.exec(); if (!queryResult || !d->mSelectAllTrackFilesFromSourceQuery.isSelect() || !d->mSelectAllTrackFilesFromSourceQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::insertMusicSource" << d->mSelectAllTrackFilesFromSourceQuery.lastQuery(); qDebug() << "DatabaseInterface::insertMusicSource" << d->mSelectAllTrackFilesFromSourceQuery.boundValues(); qDebug() << "DatabaseInterface::insertMusicSource" << d->mSelectAllTrackFilesFromSourceQuery.lastError(); d->mSelectAllTrackFilesFromSourceQuery.finish(); return allFileNames; } while(d->mSelectAllTrackFilesFromSourceQuery.next()) { auto fileName = d->mSelectAllTrackFilesFromSourceQuery.record().value(0).toUrl(); auto fileModificationTime = d->mSelectAllTrackFilesFromSourceQuery.record().value(1).toDateTime(); allFileNames[fileName] = fileModificationTime; } d->mSelectAllTrackFilesFromSourceQuery.finish(); return allFileNames; } bool DatabaseInterface::internalGenericPartialData(QSqlQuery &query) { auto result = false; auto queryResult = query.exec(); if (!queryResult || !query.isSelect() || !query.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::internalAllGenericPartialData" << query.lastQuery(); qDebug() << "DatabaseInterface::internalAllGenericPartialData" << query.boundValues(); qDebug() << "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 = d->mSelectLyricistByNameQuery.exec(); if (!queryResult || !d->mSelectLyricistByNameQuery.isSelect() || !d->mSelectLyricistByNameQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::insertLyricist" << d->mSelectLyricistByNameQuery.lastQuery(); qDebug() << "DatabaseInterface::insertLyricist" << d->mSelectLyricistByNameQuery.boundValues(); qDebug() << "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 = d->mInsertLyricistQuery.exec(); if (!queryResult || !d->mInsertLyricistQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::insertLyricist" << d->mInsertLyricistQuery.lastQuery(); qDebug() << "DatabaseInterface::insertLyricist" << d->mInsertLyricistQuery.boundValues(); qDebug() << "DatabaseInterface::insertLyricist" << d->mInsertLyricistQuery.lastError(); d->mInsertLyricistQuery.finish(); return result; } result = d->mLyricistId; ++d->mLyricistId; d->mInsertLyricistQuery.finish(); Q_EMIT lyricistsAdded(internalAllLyricistsPartialData()); return result; } qulonglong DatabaseInterface::internalArtistIdFromName(const QString &name) { auto result = qulonglong(0); if (name.isEmpty()) { return result; } d->mSelectArtistByNameQuery.bindValue(QStringLiteral(":name"), name); auto queryResult = d->mSelectArtistByNameQuery.exec(); if (!queryResult || !d->mSelectArtistByNameQuery.isSelect() || !d->mSelectArtistByNameQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::insertArtist" << d->mSelectArtistByNameQuery.lastQuery(); qDebug() << "DatabaseInterface::insertArtist" << d->mSelectArtistByNameQuery.boundValues(); qDebug() << "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 = d->mRemoveTrackQuery.exec(); if (!result || !d->mRemoveTrackQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::removeTrackInDatabase" << d->mRemoveTrackQuery.lastQuery(); qDebug() << "DatabaseInterface::removeTrackInDatabase" << d->mRemoveTrackQuery.boundValues(); qDebug() << "DatabaseInterface::removeTrackInDatabase" << d->mRemoveTrackQuery.lastError(); } d->mRemoveTrackQuery.finish(); } void DatabaseInterface::updateTrackInDatabase(const MusicAudioTrack &oneTrack, const QString &albumPath) { 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); d->mUpdateTrackQuery.bindValue(QStringLiteral(":trackNumber"), oneTrack.trackNumber()); d->mUpdateTrackQuery.bindValue(QStringLiteral(":discNumber"), oneTrack.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()); d->mUpdateTrackQuery.bindValue(QStringLiteral(":channels"), oneTrack.channels()); d->mUpdateTrackQuery.bindValue(QStringLiteral(":bitRate"), oneTrack.bitRate()); d->mUpdateTrackQuery.bindValue(QStringLiteral(":sampleRate"), oneTrack.sampleRate()); auto result = d->mUpdateTrackQuery.exec(); if (!result || !d->mUpdateTrackQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::updateTrackInDatabase" << d->mUpdateTrackQuery.lastQuery(); qDebug() << "DatabaseInterface::updateTrackInDatabase" << d->mUpdateTrackQuery.boundValues(); qDebug() << "DatabaseInterface::updateTrackInDatabase" << d->mUpdateTrackQuery.lastError(); } d->mUpdateTrackQuery.finish(); } void DatabaseInterface::removeAlbumInDatabase(qulonglong albumId) { d->mRemoveAlbumQuery.bindValue(QStringLiteral(":albumId"), albumId); auto result = d->mRemoveAlbumQuery.exec(); if (!result || !d->mRemoveAlbumQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::removeAlbumInDatabase" << d->mRemoveAlbumQuery.lastQuery(); qDebug() << "DatabaseInterface::removeAlbumInDatabase" << d->mRemoveAlbumQuery.boundValues(); qDebug() << "DatabaseInterface::removeAlbumInDatabase" << d->mRemoveAlbumQuery.lastError(); } d->mRemoveAlbumQuery.finish(); } void DatabaseInterface::removeArtistInDatabase(qulonglong artistId) { d->mRemoveArtistQuery.bindValue(QStringLiteral(":artistId"), artistId); auto result = d->mRemoveArtistQuery.exec(); if (!result || !d->mRemoveArtistQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::removeArtistInDatabase" << d->mRemoveArtistQuery.lastQuery(); qDebug() << "DatabaseInterface::removeArtistInDatabase" << d->mRemoveArtistQuery.boundValues(); qDebug() << "DatabaseInterface::removeArtistInDatabase" << d->mRemoveArtistQuery.lastError(); } d->mRemoveArtistQuery.finish(); } void DatabaseInterface::reloadExistingDatabase() { qDebug() << "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 = request.exec(); if (!queryResult || !request.isSelect() || !request.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::insertMusicSource" << request.lastQuery(); qDebug() << "DatabaseInterface::insertMusicSource" << request.boundValues(); qDebug() << "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; } qulonglong DatabaseInterface::insertMusicSource(const QString &name) { qulonglong result = 0; d->mSelectMusicSource.bindValue(QStringLiteral(":name"), name); auto queryResult = d->mSelectMusicSource.exec(); if (!queryResult || !d->mSelectMusicSource.isSelect() || !d->mSelectMusicSource.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::insertMusicSource" << d->mSelectMusicSource.lastQuery(); qDebug() << "DatabaseInterface::insertMusicSource" << d->mSelectMusicSource.boundValues(); qDebug() << "DatabaseInterface::insertMusicSource" << d->mSelectMusicSource.lastError(); d->mSelectMusicSource.finish(); return result; } if (d->mSelectMusicSource.next()) { result = d->mSelectMusicSource.record().value(0).toULongLong(); d->mSelectMusicSource.finish(); return result; } d->mSelectMusicSource.finish(); d->mInsertMusicSource.bindValue(QStringLiteral(":discoverId"), d->mDiscoverId); d->mInsertMusicSource.bindValue(QStringLiteral(":name"), name); queryResult = d->mInsertMusicSource.exec(); if (!queryResult || !d->mInsertMusicSource.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::insertMusicSource" << d->mInsertMusicSource.lastQuery(); qDebug() << "DatabaseInterface::insertMusicSource" << d->mInsertMusicSource.boundValues(); qDebug() << "DatabaseInterface::insertMusicSource" << d->mInsertMusicSource.lastError(); d->mInsertMusicSource.finish(); return d->mDiscoverId; } d->mInsertMusicSource.finish(); ++d->mDiscoverId; return d->mDiscoverId - 1; } QList DatabaseInterface::fetchTrackIds(qulonglong albumId) { auto allTracks = QList(); d->mSelectTrackQuery.bindValue(QStringLiteral(":albumId"), albumId); auto result = d->mSelectTrackQuery.exec(); if (!result || !d->mSelectTrackQuery.isSelect() || !d->mSelectTrackQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::fetchTrackIds" << d->mSelectTrackQuery.lastQuery(); qDebug() << "DatabaseInterface::fetchTrackIds" << d->mSelectTrackQuery.boundValues(); qDebug() << "DatabaseInterface::fetchTrackIds" << d->mSelectTrackQuery.lastError(); } while (d->mSelectTrackQuery.next()) { const auto ¤tRecord = d->mSelectTrackQuery.record(); allTracks.push_back(currentRecord.value(0).toULongLong()); } d->mSelectTrackQuery.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 = d->mSelectAlbumIdFromTitleQuery.exec(); if (!queryResult || !d->mSelectAlbumIdFromTitleQuery.isSelect() || !d->mSelectAlbumIdFromTitleQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::internalAlbumIdFromTitleAndArtist" << d->mSelectAlbumIdFromTitleQuery.lastQuery(); qDebug() << "DatabaseInterface::internalAlbumIdFromTitleAndArtist" << d->mSelectAlbumIdFromTitleQuery.boundValues(); qDebug() << "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 = d->mSelectAlbumIdFromTitleWithoutArtistQuery.exec(); if (!queryResult || !d->mSelectAlbumIdFromTitleWithoutArtistQuery.isSelect() || !d->mSelectAlbumIdFromTitleWithoutArtistQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::internalAlbumIdFromTitleAndArtist" << d->mSelectAlbumIdFromTitleWithoutArtistQuery.lastQuery(); qDebug() << "DatabaseInterface::internalAlbumIdFromTitleAndArtist" << d->mSelectAlbumIdFromTitleWithoutArtistQuery.boundValues(); qDebug() << "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 = d->mSelectTrackFromIdQuery.exec(); if (!queryResult || !d->mSelectTrackFromIdQuery.isSelect() || !d->mSelectTrackFromIdQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::internalTrackFromDatabaseId" << d->mSelectAlbumQuery.lastQuery(); qDebug() << "DatabaseInterface::internalTrackFromDatabaseId" << d->mSelectAlbumQuery.boundValues(); qDebug() << "DatabaseInterface::internalTrackFromDatabaseId" << d->mSelectAlbumQuery.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 = d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery.exec(); if (!queryResult || !d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery.isSelect() || !d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::trackIdFromTitleAlbumArtist" << d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery.lastQuery(); qDebug() << "DatabaseInterface::trackIdFromTitleAlbumArtist" << d->mSelectTrackIdFromTitleArtistAlbumTrackDiscNumberQuery.boundValues(); qDebug() << "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 trackNumber, int discNumber) { 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(":trackNumber"), trackNumber); d->mSelectTrackIdFromTitleAlbumTrackDiscNumberQuery.bindValue(QStringLiteral(":discNumber"), discNumber); auto queryResult = d->mSelectTrackIdFromTitleAlbumTrackDiscNumberQuery.exec(); if (!queryResult || !d->mSelectTrackIdFromTitleAlbumTrackDiscNumberQuery.isSelect() || !d->mSelectTrackIdFromTitleAlbumTrackDiscNumberQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::trackIdFromTitleAlbumArtist" << d->mSelectTrackIdFromTitleAlbumTrackDiscNumberQuery.lastQuery(); qDebug() << "DatabaseInterface::trackIdFromTitleAlbumArtist" << d->mSelectTrackIdFromTitleAlbumTrackDiscNumberQuery.boundValues(); qDebug() << "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); auto queryResult = d->mSelectTracksMapping.exec(); if (!queryResult || !d->mSelectTracksMapping.isSelect() || !d->mSelectTracksMapping.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::internalTrackIdFromFileName" << d->mSelectTracksMapping.lastQuery(); qDebug() << "DatabaseInterface::internalTrackIdFromFileName" << d->mSelectTracksMapping.boundValues(); qDebug() << "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 = d->mSelectTracksFromArtist.exec(); if (!result || !d->mSelectTracksFromArtist.isSelect() || !d->mSelectTracksFromArtist.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::tracksFromAuthor" << d->mSelectTracksFromArtist.lastQuery(); qDebug() << "DatabaseInterface::tracksFromAuthor" << d->mSelectTracksFromArtist.boundValues(); qDebug() << "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 = d->mSelectAlbumIdsFromArtist.exec(); if (!result || !d->mSelectAlbumIdsFromArtist.isSelect() || !d->mSelectAlbumIdsFromArtist.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::tracksFromAuthor" << d->mSelectAlbumIdsFromArtist.lastQuery(); qDebug() << "DatabaseInterface::tracksFromAuthor" << d->mSelectAlbumIdsFromArtist.boundValues(); qDebug() << "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::ArtistDataType DatabaseInterface::internalOneArtistPartialData(qulonglong databaseId) { auto result = ArtistDataType{}; d->mSelectArtistQuery.bindValue(QStringLiteral(":artistId"), databaseId); if (!internalGenericPartialData(d->mSelectArtistQuery)) { return result; } if (d->mSelectArtistQuery.next()) { const auto ¤tRecord = d->mSelectArtistQuery.record(); result[DataType::key_type::DatabaseIdRole] = currentRecord.value(0); result[DataType::key_type::TitleRole] = currentRecord.value(1); result[DataType::key_type::GenreRole] = QVariant::fromValue(currentRecord.value(2).toString().split(QStringLiteral(", "))); + result[DataType::key_type::ElementTypeRole] = ElisaUtils::Artist; } d->mSelectArtistQuery.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(3); result[DataType::key_type::ImageUrlRole] = currentRecord.value(5); result[DataType::key_type::ArtistRole] = currentRecord.value(3); result[DataType::key_type::AllArtistsRole] = QVariant::fromValue(currentRecord.value(9).toString().split(QStringLiteral(", "))); result[DataType::key_type::HighestTrackRating] = currentRecord.value(10); result[DataType::key_type::IsSingleDiscAlbumRole] = currentRecord.value(8); result[DataType::key_type::GenreRole] = QVariant::fromValue(currentRecord.value(11).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::GenreDataType DatabaseInterface::internalOneGenrePartialData(qulonglong databaseId) { auto result = GenreDataType{}; d->mSelectGenreQuery.bindValue(QStringLiteral(":genreId"), databaseId); if (!internalGenericPartialData(d->mSelectGenreQuery)) { return result; } if (d->mSelectGenreQuery.next()) { const auto ¤tRecord = d->mSelectGenreQuery.record(); result[DataType::key_type::DatabaseIdRole] = currentRecord.value(0); result[DataType::key_type::TitleRole] = currentRecord.value(1); + result[DataType::key_type::ElementTypeRole] = ElisaUtils::Genre; } d->mSelectGenreQuery.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::ArtistDataType DatabaseInterface::internalOneComposerPartialData(qulonglong databaseId) { auto result = ArtistDataType{}; d->mSelectComposerQuery.bindValue(QStringLiteral(":composerId"), databaseId); if (!internalGenericPartialData(d->mSelectComposerQuery)) { return result; } if (d->mSelectComposerQuery.next()) { const auto ¤tRecord = d->mSelectComposerQuery.record(); result[DataType::key_type::DatabaseIdRole] = currentRecord.value(0); result[DataType::key_type::TitleRole] = currentRecord.value(1); + result[DataType::key_type::ElementTypeRole] = ElisaUtils::Composer; } d->mSelectComposerQuery.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; } DatabaseInterface::ArtistDataType DatabaseInterface::internalOneLyricistPartialData(qulonglong databaseId) { auto result = ArtistDataType{}; d->mSelectLyricistQuery.bindValue(QStringLiteral(":lyricistId"), databaseId); if (!internalGenericPartialData(d->mSelectLyricistQuery)) { return result; } if (d->mSelectLyricistQuery.next()) { const auto ¤tRecord = d->mSelectLyricistQuery.record(); result[DataType::key_type::DatabaseIdRole] = currentRecord.value(0); result[DataType::key_type::TitleRole] = currentRecord.value(1); + result[DataType::key_type::ElementTypeRole] = ElisaUtils::Lyricist; } d->mSelectLyricistQuery.finish(); return result; } bool DatabaseInterface::prepareQuery(QSqlQuery &query, const QString &queryText) const { query.setForwardOnly(true); return query.prepare(queryText); } 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 = d->mUpdateAlbumArtistQuery.exec(); if (!queryResult || !d->mUpdateAlbumArtistQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::updateAlbumArtist" << d->mUpdateAlbumArtistQuery.lastQuery(); qDebug() << "DatabaseInterface::updateAlbumArtist" << d->mUpdateAlbumArtistQuery.boundValues(); qDebug() << "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 = d->mUpdateAlbumArtistInTracksQuery.exec(); if (!queryResult || !d->mUpdateAlbumArtistInTracksQuery.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::updateAlbumArtist" << d->mUpdateAlbumArtistInTracksQuery.lastQuery(); qDebug() << "DatabaseInterface::updateAlbumArtist" << d->mUpdateAlbumArtistInTracksQuery.boundValues(); qDebug() << "DatabaseInterface::updateAlbumArtist" << d->mUpdateAlbumArtistInTracksQuery.lastError(); d->mUpdateAlbumArtistInTracksQuery.finish(); return; } d->mUpdateAlbumArtistInTracksQuery.finish(); } void DatabaseInterface::updateTrackStatistics(qulonglong databaseId, const QDateTime &time) { d->mUpdateTrackStatistics.bindValue(QStringLiteral(":trackId"), databaseId); d->mUpdateTrackStatistics.bindValue(QStringLiteral(":playDate"), time.toMSecsSinceEpoch()); auto queryResult = d->mUpdateTrackStatistics.exec(); if (!queryResult || !d->mUpdateTrackStatistics.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::updateTrackStatistics" << d->mUpdateTrackStatistics.lastQuery(); qDebug() << "DatabaseInterface::updateTrackStatistics" << d->mUpdateTrackStatistics.boundValues(); qDebug() << "DatabaseInterface::updateTrackStatistics" << d->mUpdateTrackStatistics.lastError(); d->mUpdateTrackStatistics.finish(); return; } d->mUpdateTrackStatistics.finish(); d->mUpdateTrackFirstPlayStatistics.bindValue(QStringLiteral(":trackId"), databaseId); d->mUpdateTrackFirstPlayStatistics.bindValue(QStringLiteral(":playDate"), time.toMSecsSinceEpoch()); queryResult = d->mUpdateTrackFirstPlayStatistics.exec(); if (!queryResult || !d->mUpdateTrackFirstPlayStatistics.isActive()) { Q_EMIT databaseError(); qDebug() << "DatabaseInterface::updateTrackStatistics" << d->mUpdateTrackFirstPlayStatistics.lastQuery(); qDebug() << "DatabaseInterface::updateTrackStatistics" << d->mUpdateTrackFirstPlayStatistics.boundValues(); qDebug() << "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 da8132cd..a3f3251e 100644 --- a/src/databaseinterface.h +++ b/src/databaseinterface.h @@ -1,526 +1,527 @@ /* * 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, }; 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(); } 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(); } 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(); } 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(); } }; 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(); DataType oneData(ElisaUtils::PlayListEntryType aType, qulonglong databaseId); 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(const QString &musicSource, QHash allFiles); public Q_SLOTS: void insertTracksList(const QList &tracks, const QHash &covers, const QString &musicSource); void removeTracksList(const QList &removedTracks); void modifyTracksList(const QList &modifiedTracks, const QHash &covers, const QString &musicSource); void removeAllTracksFromSource(const QString &sourceName); void askRestoredTracks(const QString &musicSource); void trackHasStartedPlaying(const QUrl &fileName, const QDateTime &time); 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 trackNumber, int discNumber); 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); qulonglong insertMusicSource(const QString &name); void insertTrackOrigin(const QUrl &fileNameURI, const QDateTime &fileModifiedTime, qulonglong discoverId); void updateTrackOrigin(qulonglong trackId, const QUrl &fileName, const QDateTime &fileModifiedTime); int computeTrackPriority(qulonglong trackId, const QUrl &fileName); qulonglong internalInsertTrack(const MusicAudioTrack &oneModifiedTrack, const QHash &covers, qulonglong originTrackId, TrackFileInsertType insertType); MusicAudioTrack buildTrackFromDatabaseRecord(const QSqlRecord &trackRecord) const; TrackDataType buildTrackDataFromDatabaseRecord(const QSqlRecord &trackRecord) const; void internalRemoveTracksList(const QList &removedTracks); void internalRemoveTracksList(const QHash &removedTracks, qulonglong sourceId); void internalRemoveTracksWithoutMapping(); QUrl internalAlbumArtUriFromAlbumId(qulonglong albumId); bool isValidArtist(qulonglong albumId); qulonglong insertComposer(const QString &name); qulonglong insertLyricist(const QString &name); qulonglong internalSourceIdFromName(const QString &sourceName); QHash internalAllFileNameFromSource(qulonglong sourceId); bool internalGenericPartialData(QSqlQuery &query); ListArtistDataType internalAllArtistsPartialData(QSqlQuery &artistsQuery); ArtistDataType internalOneArtistPartialData(qulonglong databaseId); ListAlbumDataType internalAllAlbumsPartialData(QSqlQuery &query); AlbumDataType internalOneAlbumPartialData(qulonglong databaseId); ListTrackDataType internalAllTracksPartialData(); ListTrackDataType internalRecentlyPlayedTracksData(int count); ListTrackDataType internalFrequentlyPlayedTracksData(int count); TrackDataType internalOneTrackPartialData(qulonglong databaseId); ListGenreDataType internalAllGenresPartialData(); GenreDataType internalOneGenrePartialData(qulonglong databaseId); ListArtistDataType internalAllComposersPartialData(); ArtistDataType internalOneComposerPartialData(qulonglong databaseId); ListArtistDataType internalAllLyricistsPartialData(); ArtistDataType internalOneLyricistPartialData(qulonglong databaseId); bool prepareQuery(QSqlQuery &query, const QString &queryText) const; void updateAlbumArtist(qulonglong albumId, const QString &title, const QString &albumPath, const QString &artistName); void updateTrackStatistics(qulonglong databaseId, const QDateTime &time); 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/mediaplaylist.h b/src/mediaplaylist.h index 98576290..7edd6a50 100644 --- a/src/mediaplaylist.h +++ b/src/mediaplaylist.h @@ -1,358 +1,359 @@ /* * 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 . */ #ifndef MEDIAPLAYLIST_H #define MEDIAPLAYLIST_H #include "elisaLib_export.h" #include "musicaudiotrack.h" #include "elisautils.h" #include "databaseinterface.h" #include #include #include #include #include class MediaPlayListPrivate; class MusicListenersManager; class MediaPlayListEntry; class QDebug; class ELISALIB_EXPORT MediaPlayList : public QAbstractListModel { Q_OBJECT Q_PROPERTY(QVariantMap persistentState READ persistentState WRITE setPersistentState NOTIFY persistentStateChanged) Q_PROPERTY(MusicListenersManager* musicListenersManager READ musicListenersManager WRITE setMusicListenersManager NOTIFY musicListenersManagerChanged) Q_PROPERTY(int tracksCount READ tracksCount NOTIFY tracksCountChanged) Q_PROPERTY(QPersistentModelIndex currentTrack READ currentTrack NOTIFY currentTrackChanged) Q_PROPERTY(int currentTrackRow READ currentTrackRow NOTIFY currentTrackRowChanged) Q_PROPERTY(bool randomPlay READ randomPlay WRITE setRandomPlay NOTIFY randomPlayChanged) Q_PROPERTY(bool repeatPlay READ repeatPlay WRITE setRepeatPlay NOTIFY repeatPlayChanged) public: enum ColumnsRoles { TitleRole = DatabaseInterface::TitleRole, 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, IsValidRole, TrackDataRole, CountRole, IsPlayingRole, HasAlbumHeader, }; Q_ENUM(ColumnsRoles) enum PlayState { NotPlaying, IsPlaying, IsPaused, }; Q_ENUM(PlayState) using ListTrackDataType = DatabaseInterface::ListTrackDataType; using TrackDataType = DatabaseInterface::TrackDataType; explicit MediaPlayList(QObject *parent = nullptr); ~MediaPlayList() 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; Q_INVOKABLE bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override; Q_INVOKABLE bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) override; Q_INVOKABLE void move(int from, int to, int n); Q_INVOKABLE void clearPlayList(); Q_INVOKABLE bool savePlaylist(const QUrl &fileName); QVariantMap persistentState() const; MusicListenersManager* musicListenersManager() const; int tracksCount() const; QPersistentModelIndex currentTrack() const; int currentTrackRow() const; bool randomPlay() const; bool repeatPlay() const; Q_SIGNALS: void newTrackByNameInList(const QString &title, const QString &artist, const QString &album, int trackNumber, int discNumber); void newEntryInList(qulonglong newDatabaseId, const QString &entryTitle, ElisaUtils::PlayListEntryType databaseIdType); void persistentStateChanged(); void musicListenersManagerChanged(); void tracksCountChanged(); void currentTrackChanged(QPersistentModelIndex currentTrack); void currentTrackRowChanged(); void randomPlayChanged(); void repeatPlayChanged(); void playListFinished(); void playListLoaded(); void playListLoadFailed(); void ensurePlay(); public Q_SLOTS: void setPersistentState(const QVariantMap &persistentState); void removeSelection(QList selection); void tracksListAdded(qulonglong newDatabaseId, const QString &entryTitle, ElisaUtils::PlayListEntryType databaseIdType, const MediaPlayList::ListTrackDataType &tracks); void trackChanged(const MediaPlayList::TrackDataType &track); void trackRemoved(qulonglong trackId); void setMusicListenersManager(MusicListenersManager* musicListenersManager); void setRandomPlay(bool value); void setRepeatPlay(bool value); void skipNextTrack(); void skipPreviousTrack(); void seedRandomGenerator(uint seed); void switchTo(int row); void loadPlaylist(const QUrl &fileName); void enqueue(const ElisaUtils::EntryData &newEntry, ElisaUtils::PlayListEntryType databaseIdType); void enqueue(const ElisaUtils::EntryDataList &newEntries, ElisaUtils::PlayListEntryType databaseIdType); void enqueue(qulonglong newEntryDatabaseId, const QString &newEntryTitle, ElisaUtils::PlayListEntryType databaseIdType, ElisaUtils::PlayListEnqueueMode enqueueMode, ElisaUtils::PlayListEnqueueTriggerPlay triggerPlay); void enqueue(const ElisaUtils::EntryData &newEntry, ElisaUtils::PlayListEntryType databaseIdType, ElisaUtils::PlayListEnqueueMode enqueueMode, ElisaUtils::PlayListEnqueueTriggerPlay triggerPlay); void enqueue(const ElisaUtils::EntryDataList &newEntries, ElisaUtils::PlayListEntryType databaseIdType, ElisaUtils::PlayListEnqueueMode enqueueMode, ElisaUtils::PlayListEnqueueTriggerPlay triggerPlay); void replaceAndPlay(const ElisaUtils::EntryData &newEntry, ElisaUtils::PlayListEntryType databaseIdType); void enqueueRestoredEntry(const MediaPlayListEntry &newEntry); void trackInError(const QUrl &sourceInError, QMediaPlayer::Error playerError); private Q_SLOTS: void loadPlayListLoaded(); void loadPlayListLoadFailed(); private: bool rowHasHeader(int row) const; void resetCurrentTrack(); void notifyCurrentTrackChanged(); void restorePlayListPosition(); void restoreRandomPlay(); void restoreRepeatPlay(); void enqueueArtist(const QString &artistName); void enqueueFilesList(const ElisaUtils::EntryDataList &newEntries); void enqueueTracksListById(const ElisaUtils::EntryDataList &newEntries); void enqueueOneEntry(const ElisaUtils::EntryData &entryData, ElisaUtils::PlayListEntryType type); void enqueueMultipleEntries(const ElisaUtils::EntryDataList &entriesData, ElisaUtils::PlayListEntryType type); std::unique_ptr d; }; class MediaPlayListEntry { public: MediaPlayListEntry() = default; explicit MediaPlayListEntry(qulonglong id) : mId(id), mIsValid(true) { } MediaPlayListEntry(QString title, QString artist, QString album, int trackNumber, int discNumber) : mTitle(std::move(title)), mAlbum(std::move(album)), mArtist(std::move(artist)), mTrackNumber(trackNumber), mDiscNumber(discNumber) { } explicit MediaPlayListEntry(const MusicAudioTrack &track) : mTitle(track.title()), mAlbum(track.albumName()), mTrackNumber(track.trackNumber()), mDiscNumber(track.discNumber()), mId(track.databaseId()), mIsValid(true) { } explicit MediaPlayListEntry(const MediaPlayList::TrackDataType &track) : mTitle(track[DatabaseInterface::TitleRole]), mAlbum(track[DatabaseInterface::AlbumRole]), mTrackNumber(track[DatabaseInterface::TrackNumberRole]), mDiscNumber(track[DatabaseInterface::DiscNumberRole]), mId(track[DatabaseInterface::DatabaseIdRole].toULongLong()), mIsValid(true) { } explicit MediaPlayListEntry(QString artist) : mArtist(std::move(artist)), mEntryType(ElisaUtils::Artist) { } explicit MediaPlayListEntry(QUrl fileName) : mTrackUrl(std::move(fileName)) { } explicit MediaPlayListEntry(qulonglong id, const QString &entryTitle, ElisaUtils::PlayListEntryType type) : mTitle(entryTitle), mId(id), mIsValid(type == ElisaUtils::Track), mEntryType(type) { } QVariant mTitle; QVariant mAlbum; QVariant mArtist; QVariant mTrackUrl; QVariant mTrackNumber = -1; QVariant mDiscNumber = -1; qulonglong mId = 0; bool mIsValid = false; ElisaUtils::PlayListEntryType mEntryType = ElisaUtils::PlayListEntryType::Unknown; MediaPlayList::PlayState mIsPlaying = MediaPlayList::NotPlaying; }; QDebug operator<<(const QDebug &stream, const MediaPlayListEntry &data); #endif // MEDIAPLAYLIST_H diff --git a/src/models/datamodel.cpp b/src/models/datamodel.cpp index e5d5bab7..f8c22f96 100644 --- a/src/models/datamodel.cpp +++ b/src/models/datamodel.cpp @@ -1,641 +1,642 @@ /* * 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 "datamodel.h" #include "modeldataloader.h" #include "musiclistenersmanager.h" #include #include #include #include #include #include class DataModelPrivate { public: DataModel::ListTrackDataType mAllTrackData; DataModel::ListAlbumDataType mAllAlbumData; DataModel::ListArtistDataType mAllArtistData; DataModel::ListGenreDataType mAllGenreData; ModelDataLoader mDataLoader; ElisaUtils::PlayListEntryType mModelType = ElisaUtils::Unknown; QString mAlbumTitle; QString mAlbumArtist; QString mGenre; }; DataModel::DataModel(QObject *parent) : QAbstractListModel(parent), d(std::make_unique()) { } DataModel::~DataModel() = default; int DataModel::rowCount(const QModelIndex &parent) const { auto dataCount = 0; if (parent.isValid()) { return dataCount; } dataCount = d->mAllTrackData.size() + d->mAllAlbumData.size() + d->mAllArtistData.size() + d->mAllGenreData.size(); return dataCount; } QHash DataModel::roleNames() const { auto roles = QAbstractListModel::roleNames(); roles[static_cast(DatabaseInterface::ColumnsRoles::TitleRole)] = "title"; roles[static_cast(DatabaseInterface::ColumnsRoles::SecondaryTextRole)] = "secondaryText"; 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::ArtistRole)] = "artist"; roles[static_cast(DatabaseInterface::ColumnsRoles::AllArtistsRole)] = "allArtists"; roles[static_cast(DatabaseInterface::ColumnsRoles::HighestTrackRating)] = "highestTrackRating"; roles[static_cast(DatabaseInterface::ColumnsRoles::GenreRole)] = "genre"; roles[static_cast(DatabaseInterface::ColumnsRoles::AlbumRole)] = "album"; roles[static_cast(DatabaseInterface::ColumnsRoles::AlbumArtistRole)] = "albumArtist"; roles[static_cast(DatabaseInterface::ColumnsRoles::DurationRole)] = "duration"; roles[static_cast(DatabaseInterface::ColumnsRoles::TrackNumberRole)] = "trackNumber"; roles[static_cast(DatabaseInterface::ColumnsRoles::DiscNumberRole)] = "discNumber"; roles[static_cast(DatabaseInterface::ColumnsRoles::RatingRole)] = "rating"; roles[static_cast(DatabaseInterface::ColumnsRoles::IsSingleDiscAlbumRole)] = "isSingleDiscAlbum"; return roles; } Qt::ItemFlags DataModel::flags(const QModelIndex &index) const { if (!index.isValid()) { return Qt::NoItemFlags; } return Qt::ItemIsSelectable | Qt::ItemIsEnabled; } QVariant DataModel::data(const QModelIndex &index, int role) const { auto result = QVariant(); const auto dataCount = d->mAllTrackData.size() + d->mAllAlbumData.size() + d->mAllArtistData.size() + d->mAllGenreData.size(); Q_ASSERT(index.isValid()); Q_ASSERT(index.column() == 0); Q_ASSERT(index.row() >= 0 && index.row() < dataCount); Q_ASSERT(!index.parent().isValid()); Q_ASSERT(index.model() == this); Q_ASSERT(index.internalId() == 0); switch(role) { case Qt::DisplayRole: switch(d->mModelType) { case ElisaUtils::Track: result = d->mAllTrackData[index.row()][TrackDataType::key_type::TitleRole]; break; case ElisaUtils::Album: result = d->mAllAlbumData[index.row()][AlbumDataType::key_type::TitleRole]; break; case ElisaUtils::Artist: result = d->mAllArtistData[index.row()][ArtistDataType::key_type::TitleRole]; break; case ElisaUtils::Genre: result = d->mAllGenreData[index.row()][GenreDataType::key_type::TitleRole]; break; case ElisaUtils::Lyricist: case ElisaUtils::Composer: case ElisaUtils::FileName: case ElisaUtils::Unknown: break; } break; case DatabaseInterface::ColumnsRoles::DurationRole: { if (d->mModelType == ElisaUtils::Track) { auto trackDuration = d->mAllTrackData[index.row()][TrackDataType::key_type::DurationRole].toTime(); if (trackDuration.hour() == 0) { result = trackDuration.toString(QStringLiteral("mm:ss")); } else { result = trackDuration.toString(); } } break; } default: switch(d->mModelType) { case ElisaUtils::Track: result = d->mAllTrackData[index.row()][static_cast(role)]; break; case ElisaUtils::Album: result = d->mAllAlbumData[index.row()][static_cast(role)]; break; case ElisaUtils::Artist: result = d->mAllArtistData[index.row()][static_cast(role)]; break; case ElisaUtils::Genre: result = d->mAllGenreData[index.row()][static_cast(role)]; break; case ElisaUtils::Lyricist: case ElisaUtils::Composer: case ElisaUtils::FileName: case ElisaUtils::Unknown: break; } } return result; } QModelIndex DataModel::index(int row, int column, const QModelIndex &parent) const { auto result = QModelIndex(); if (column != 0) { return result; } if (parent.isValid()) { return result; } result = createIndex(row, column); return result; } QModelIndex DataModel::parent(const QModelIndex &child) const { Q_UNUSED(child) auto result = QModelIndex(); return result; } QString DataModel::title() const { return d->mAlbumTitle; } QString DataModel::author() const { return d->mAlbumArtist; } void DataModel::initialize(MusicListenersManager *manager, ElisaUtils::PlayListEntryType modelType) { d->mModelType = modelType; if (!manager) { return; } manager->connectModel(&d->mDataLoader); connectModel(manager); connect(this, &DataModel::needData, &d->mDataLoader, &ModelDataLoader::loadData); Q_EMIT needData(d->mModelType); } void DataModel::initializeByAlbumTitleAndArtist(MusicListenersManager *manager, ElisaUtils::PlayListEntryType modelType, const QString &albumTitle, const QString &albumArtist) { d->mModelType = modelType; d->mAlbumTitle = albumTitle; d->mAlbumArtist = albumArtist; if (!manager) { return; } manager->connectModel(&d->mDataLoader); connectModel(manager); connect(this, &DataModel::needData, &d->mDataLoader, &ModelDataLoader::loadData); Q_EMIT needData(d->mModelType); } void DataModel::initializeByGenre(MusicListenersManager *manager, ElisaUtils::PlayListEntryType modelType, const QString &genre) { d->mModelType = modelType; d->mGenre = genre; if (!manager) { return; } manager->connectModel(&d->mDataLoader); connectModel(manager); connect(this, &DataModel::needDataByGenre, &d->mDataLoader, &ModelDataLoader::loadDataByGenre); Q_EMIT needDataByGenre(d->mModelType, genre); } void DataModel::initializeByArtist(MusicListenersManager *manager, ElisaUtils::PlayListEntryType modelType, const QString &artist) { d->mModelType = modelType; d->mAlbumArtist = artist; if (!manager) { return; } manager->connectModel(&d->mDataLoader); connectModel(manager); connect(this, &DataModel::needDataByArtist, &d->mDataLoader, &ModelDataLoader::loadDataByArtist); Q_EMIT needDataByArtist(d->mModelType, artist); } void DataModel::initializeByGenreAndArtist(MusicListenersManager *manager, ElisaUtils::PlayListEntryType modelType, const QString &genre, const QString &artist) { d->mModelType = modelType; d->mGenre = genre; d->mAlbumArtist = artist; if (!manager) { return; } manager->connectModel(&d->mDataLoader); connectModel(manager); connect(this, &DataModel::needDataByGenreAndArtist, &d->mDataLoader, &ModelDataLoader::loadDataByGenreAndArtist); Q_EMIT needDataByGenreAndArtist(d->mModelType, genre, artist); } void DataModel::initializeRecentlyPlayed(MusicListenersManager *manager, ElisaUtils::PlayListEntryType modelType) { d->mModelType = modelType; if (!manager) { return; } manager->connectModel(&d->mDataLoader); connectModel(manager); connect(this, &DataModel::needRecentlyPlayedData, &d->mDataLoader, &ModelDataLoader::loadRecentlyPlayedData); Q_EMIT needRecentlyPlayedData(d->mModelType); } void DataModel::initializeFrequentlyPlayed(MusicListenersManager *manager, ElisaUtils::PlayListEntryType modelType) { d->mModelType = modelType; if (!manager) { return; } manager->connectModel(&d->mDataLoader); connectModel(manager); connect(this, &DataModel::needFrequentlyPlayedData, &d->mDataLoader, &ModelDataLoader::loadFrequentlyPlayedData); Q_EMIT needFrequentlyPlayedData(d->mModelType); } int DataModel::trackIndexFromId(qulonglong id) const { int result; for (result = 0; result < d->mAllTrackData.size(); ++result) { if (d->mAllTrackData[result].databaseId() == id) { return result; } } result = -1; return result; } void DataModel::connectModel(MusicListenersManager *manager) { connect(manager->viewDatabase(), &DatabaseInterface::genresAdded, this, &DataModel::genresAdded); connect(manager->viewDatabase(), &DatabaseInterface::albumsAdded, this, &DataModel::albumsAdded); connect(manager->viewDatabase(), &DatabaseInterface::albumModified, this, &DataModel::albumModified); connect(manager->viewDatabase(), &DatabaseInterface::albumRemoved, this, &DataModel::albumRemoved); connect(manager->viewDatabase(), &DatabaseInterface::tracksAdded, this, &DataModel::tracksAdded); connect(manager->viewDatabase(), &DatabaseInterface::trackModified, this, &DataModel::trackModified); connect(manager->viewDatabase(), &DatabaseInterface::trackRemoved, this, &DataModel::trackRemoved); connect(manager->viewDatabase(), &DatabaseInterface::artistsAdded, this, &DataModel::artistsAdded); connect(manager->viewDatabase(), &DatabaseInterface::artistRemoved, this, &DataModel::artistRemoved); connect(&d->mDataLoader, &ModelDataLoader::allTracksData, this, &DataModel::tracksAdded); connect(&d->mDataLoader, &ModelDataLoader::allAlbumsData, this, &DataModel::albumsAdded); connect(&d->mDataLoader, &ModelDataLoader::allArtistsData, this, &DataModel::artistsAdded); connect(&d->mDataLoader, &ModelDataLoader::allGenresData, this, &DataModel::genresAdded); } void DataModel::tracksAdded(ListTrackDataType newData) { if (newData.isEmpty() || d->mModelType != ElisaUtils::Track) { return; } if (!d->mAlbumTitle.isEmpty() && !d->mAlbumArtist.isEmpty()) { for (const auto &newTrack : newData) { if (newTrack.album() != d->mAlbumTitle) { continue; } if (newTrack.albumArtist() != d->mAlbumArtist) { continue; } auto trackIndex = trackIndexFromId(newTrack.databaseId()); if (trackIndex != -1) { continue; } bool trackInserted = false; for (int trackIndex = 0; trackIndex < d->mAllTrackData.count(); ++trackIndex) { const auto &oneTrack = d->mAllTrackData[trackIndex]; if (oneTrack.discNumber() == newTrack.discNumber() && oneTrack.trackNumber() > newTrack.trackNumber()) { beginInsertRows({}, trackIndex, trackIndex); d->mAllTrackData.insert(trackIndex, newTrack); endInsertRows(); trackInserted = true; break; } } if (!trackInserted) { beginInsertRows({}, d->mAllTrackData.count(), d->mAllTrackData.count()); d->mAllTrackData.insert(d->mAllTrackData.count(), newTrack); endInsertRows(); } } } else { if (d->mAllTrackData.isEmpty()) { beginInsertRows({}, 0, newData.size() - 1); d->mAllTrackData.swap(newData); endInsertRows(); } else { beginInsertRows({}, d->mAllTrackData.size(), d->mAllTrackData.size() + newData.size() - 1); d->mAllTrackData.append(newData); endInsertRows(); } } } void DataModel::trackModified(const TrackDataType &modifiedTrack) { if (d->mModelType != ElisaUtils::Track) { return; } if (!d->mAlbumTitle.isEmpty() && !d->mAlbumArtist.isEmpty()) { if (modifiedTrack.album() != d->mAlbumTitle) { return; } auto trackIndex = trackIndexFromId(modifiedTrack.databaseId()); if (trackIndex == -1) { return; } d->mAllTrackData[trackIndex] = modifiedTrack; Q_EMIT dataChanged(index(trackIndex, 0), index(trackIndex, 0)); } else { auto itTrack = std::find_if(d->mAllTrackData.begin(), d->mAllTrackData.end(), [modifiedTrack](auto track) { return track.databaseId() == modifiedTrack.databaseId(); }); if (itTrack == d->mAllTrackData.end()) { return; } auto position = itTrack - d->mAllTrackData.begin(); d->mAllTrackData[position] = modifiedTrack; Q_EMIT dataChanged(index(position, 0), index(position, 0)); } } void DataModel::trackRemoved(qulonglong removedTrackId) { if (d->mModelType != ElisaUtils::Track) { return; } if (!d->mAlbumTitle.isEmpty() && !d->mAlbumArtist.isEmpty()) { auto trackIndex = trackIndexFromId(removedTrackId); if (trackIndex == -1) { return; } beginRemoveRows({}, trackIndex, trackIndex); d->mAllTrackData.removeAt(trackIndex); endRemoveRows(); } else { auto itTrack = std::find_if(d->mAllTrackData.begin(), d->mAllTrackData.end(), [removedTrackId](auto track) {return track.databaseId() == removedTrackId;}); if (itTrack == d->mAllTrackData.end()) { return; } auto position = itTrack - d->mAllTrackData.begin(); beginRemoveRows({}, position, position); d->mAllTrackData.erase(itTrack); endRemoveRows(); } } void DataModel::genresAdded(DataModel::ListGenreDataType newData) { if (newData.isEmpty() || d->mModelType != ElisaUtils::Genre) { return; } if (d->mAllGenreData.isEmpty()) { beginInsertRows({}, d->mAllGenreData.size(), newData.size() - 1); d->mAllGenreData.swap(newData); endInsertRows(); } else { beginInsertRows({}, d->mAllGenreData.size(), d->mAllGenreData.size() + newData.size() - 1); d->mAllGenreData.append(newData); endInsertRows(); } } void DataModel::artistsAdded(DataModel::ListArtistDataType newData) { if (newData.isEmpty() || d->mModelType != ElisaUtils::Artist) { return; } if (d->mAllArtistData.isEmpty()) { beginInsertRows({}, d->mAllArtistData.size(), newData.size() - 1); d->mAllArtistData.swap(newData); endInsertRows(); } else { beginInsertRows({}, d->mAllArtistData.size(), d->mAllArtistData.size() + newData.size() - 1); d->mAllArtistData.append(newData); endInsertRows(); } } void DataModel::artistRemoved(qulonglong removedDatabaseId) { if (d->mModelType != ElisaUtils::Artist) { return; } auto removedDataIterator = d->mAllArtistData.end(); removedDataIterator = std::find_if(d->mAllArtistData.begin(), d->mAllArtistData.end(), [removedDatabaseId](auto album) {return album.databaseId() == removedDatabaseId;}); if (removedDataIterator == d->mAllArtistData.end()) { return; } int dataIndex = removedDataIterator - d->mAllArtistData.begin(); beginRemoveRows({}, dataIndex, dataIndex); d->mAllArtistData.erase(removedDataIterator); endRemoveRows(); } void DataModel::albumsAdded(DataModel::ListAlbumDataType newData) { if (newData.isEmpty() || d->mModelType != ElisaUtils::Album) { return; } if (d->mAllAlbumData.isEmpty()) { beginInsertRows({}, d->mAllAlbumData.size(), newData.size() - 1); d->mAllAlbumData.swap(newData); endInsertRows(); } else { beginInsertRows({}, d->mAllAlbumData.size(), d->mAllAlbumData.size() + newData.size() - 1); d->mAllAlbumData.append(newData); endInsertRows(); } } void DataModel::albumRemoved(qulonglong removedDatabaseId) { if (d->mModelType != ElisaUtils::Album) { return; } auto removedDataIterator = d->mAllAlbumData.end(); removedDataIterator = std::find_if(d->mAllAlbumData.begin(), d->mAllAlbumData.end(), [removedDatabaseId](auto album) {return album.databaseId() == removedDatabaseId;}); if (removedDataIterator == d->mAllAlbumData.end()) { return; } int dataIndex = removedDataIterator - d->mAllAlbumData.begin(); beginRemoveRows({}, dataIndex, dataIndex); d->mAllAlbumData.erase(removedDataIterator); endRemoveRows(); } void DataModel::albumModified(const DataModel::AlbumDataType &modifiedAlbum) { if (d->mModelType != ElisaUtils::Album) { return; } auto modifiedAlbumIterator = std::find_if(d->mAllAlbumData.begin(), d->mAllAlbumData.end(), [modifiedAlbum](auto album) { return album.databaseId() == modifiedAlbum.databaseId(); }); if (modifiedAlbumIterator == d->mAllAlbumData.end()) { return; } auto albumIndex = modifiedAlbumIterator - d->mAllAlbumData.begin(); Q_EMIT dataChanged(index(albumIndex, 0), index(albumIndex, 0)); } #include "moc_datamodel.cpp" diff --git a/src/models/trackmetadatamodel.cpp b/src/models/trackmetadatamodel.cpp index 60ffebe6..67dd1f4f 100644 --- a/src/models/trackmetadatamodel.cpp +++ b/src/models/trackmetadatamodel.cpp @@ -1,308 +1,310 @@ /* * 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 TrackMetadataModel::TrackMetadataModel(QObject *parent) : QAbstractListModel(parent) { } 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:"); break; case DatabaseInterface::DurationRole: result = i18nc("Duration label for track metadata view", "Duration:"); break; case DatabaseInterface::ArtistRole: result = i18nc("Track artist for track metadata view", "Artist:"); break; case DatabaseInterface::AlbumRole: result = i18nc("Album name for track metadata view", "Album:"); break; case DatabaseInterface::AlbumArtistRole: result = i18nc("Album artist for track metadata view", "Album Artist:"); break; case DatabaseInterface::TrackNumberRole: result = i18nc("Track number for track metadata view", "Track Number:"); break; case DatabaseInterface::DiscNumberRole: result = i18nc("Disc number for track metadata view", "Disc Number:"); break; case DatabaseInterface::RatingRole: result = i18nc("Rating label for information panel", "Rating:"); break; case DatabaseInterface::GenreRole: result = i18nc("Genre label for track metadata view", "Genre:"); break; case DatabaseInterface::LyricistRole: result = i18nc("Lyricist label for track metadata view", "Lyricist:"); break; case DatabaseInterface::ComposerRole: result = i18nc("Composer name for track metadata view", "Composer:"); break; case DatabaseInterface::CommentRole: result = i18nc("Comment label for track metadata view", "Comment:"); break; case DatabaseInterface::YearRole: result = i18nc("Year label for track metadata view", "Year:"); break; case DatabaseInterface::ChannelsRole: result = i18nc("Channels label for track metadata view", "Channels:"); break; case DatabaseInterface::BitRateRole: 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:"); break; case DatabaseInterface::LastPlayDate: 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:"); 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::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); } bool TrackMetadataModel::insertRows(int row, int count, const QModelIndex &parent) { beginInsertRows(parent, row, row + count - 1); endInsertRows(); return true; } bool TrackMetadataModel::removeRows(int row, int count, const QModelIndex &parent) { beginRemoveRows(parent, row, row + count - 1); endRemoveRows(); return true; } const QUrl &TrackMetadataModel::coverUrl() const { return mCoverImage; } void TrackMetadataModel::trackData(const TrackMetadataModel::TrackDataType &trackData) { beginResetModel(); if (mTrackData.isValid()) { 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]; } } endResetModel(); mCoverImage = trackData[DatabaseInterface::ImageUrlRole].toUrl(); Q_EMIT coverUrlChanged(); } void TrackMetadataModel::initializeByTrackId(MusicListenersManager *manager, qulonglong databaseId) { manager->connectModel(&mDataLoader); connect(this, &TrackMetadataModel::needDataByDatabaseId, &mDataLoader, &ModelDataLoader::loadDataByDatabaseId); connect(&mDataLoader, &ModelDataLoader::allTrackData, this, &TrackMetadataModel::trackData); Q_EMIT needDataByDatabaseId(ElisaUtils::Track, databaseId); } void TrackMetadataModel::initializeByTrackFileName(MusicListenersManager *manager, const QUrl &fileName) { manager->connectModel(&mDataLoader); connect(this, &TrackMetadataModel::needDataByFileName, &mDataLoader, &ModelDataLoader::loadDataByFileName); connect(&mDataLoader, &ModelDataLoader::allTrackData, this, &TrackMetadataModel::trackData); Q_EMIT needDataByFileName(ElisaUtils::FileName, fileName); } #include "moc_trackmetadatamodel.cpp" diff --git a/src/qml/AlbumView.qml b/src/qml/AlbumView.qml index 4e217a30..d81c4548 100644 --- a/src/qml/AlbumView.qml +++ b/src/qml/AlbumView.qml @@ -1,106 +1,106 @@ /* * 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.10 import QtQuick.Controls 2.3 import org.kde.elisa 1.0 FocusScope { id: viewHeader property alias mainTitle: albumGridView.mainTitle property alias secondaryTitle: albumGridView.secondaryTitle property alias image: albumGridView.image DataModel { id: realModel } SingleAlbumProxyModel { id: proxyModel sourceModel: realModel onEntriesToEnqueue: elisa.mediaPlayList.enqueue(newEntries, databaseIdType, enqueueMode, triggerPlay) } ListBrowserView { id: albumGridView anchors.fill: parent contentModel: proxyModel isSubPage: true enableSorting: false delegate: MediaAlbumTrackDelegate { id: entry width: albumGridView.delegateWidth height: ((true && !true) ? elisaTheme.delegateHeight*2 : elisaTheme.delegateHeight) focus: true databaseId: model.databaseId title: model.title artist: model.artist album: (model.album !== undefined && model.album !== '' ? model.album : '') albumArtist: model.albumArtist duration: model.duration imageUrl: (model.imageUrl !== undefined && model.imageUrl !== '' ? model.imageUrl : '') trackNumber: model.trackNumber discNumber: model.discNumber rating: model.rating isFirstTrackOfDisc: true isSingleDiscAlbum: true isAlternateColor: (index % 2) === 1 mediaTrack.onEnqueue: elisa.mediaPlayList.enqueue(databaseId, name, ElisaUtils.Track, ElisaUtils.AppendPlayList, ElisaUtils.DoNotTriggerPlay) mediaTrack.onReplaceAndPlay: elisa.mediaPlayList.enqueue(databaseId, name, ElisaUtils.Track, ElisaUtils.ReplacePlayList, ElisaUtils.TriggerPlay) mediaTrack.onClicked: albumGridView.currentIndex = index } allowArtistNavigation: true onShowArtist: { - viewManager.openOneArtist(name, elisaTheme.artistIcon, 0) + viewManager.openChildView(name, '', elisaTheme.artistIcon, 0, ElisaUtils.Artist) } onGoBack: viewManager.goBack() } Connections { target: elisa onMusicManagerChanged: realModel.initializeByAlbumTitleAndArtist(elisa.musicManager, ElisaUtils.Track, mainTitle, secondaryTitle) } Component.onCompleted: { if (elisa.musicManager) { realModel.initializeByAlbumTitleAndArtist(elisa.musicManager, ElisaUtils.Track, mainTitle, secondaryTitle) } } } diff --git a/src/qml/AlbumsView.qml b/src/qml/AlbumsView.qml index 5c83d07c..0c1bfa7f 100644 --- a/src/qml/AlbumsView.qml +++ b/src/qml/AlbumsView.qml @@ -1,79 +1,79 @@ /* * 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.10 import QtQuick.Controls 2.3 import org.kde.elisa 1.0 FocusScope { id: viewHeader property alias mainTitle: gridView.mainTitle property alias image: gridView.image property var modelType property alias defaultIcon: gridView.defaultIcon property alias showRating: gridView.showRating property alias delegateDisplaySecondaryText: gridView.delegateDisplaySecondaryText focus: true DataModel { id: realModel } AllAlbumsProxyModel { id: proxyModel sourceModel: realModel onEntriesToEnqueue: elisa.mediaPlayList.enqueue(newEntries, databaseIdType, enqueueMode, triggerPlay) } GridBrowserView { id: gridView focus: true anchors.fill: parent contentModel: proxyModel onEnqueue: elisa.mediaPlayList.enqueue(databaseId, name, modelType, ElisaUtils.AppendPlayList, ElisaUtils.DoNotTriggerPlay) onReplaceAndPlay: elisa.mediaPlayList.enqueue(databaseId, name, modelType, ElisaUtils.ReplacePlayList, ElisaUtils.TriggerPlay) - onOpen: viewManager.openOneAlbum(innerMainTitle, innerSecondaryTitle, innerImage, databaseId) + onOpen: viewManager.openChildView(innerMainTitle, innerSecondaryTitle, innerImage, databaseId, dataType) onGoBack: viewManager.goBack() } Connections { target: elisa onMusicManagerChanged: realModel.initialize(elisa.musicManager, modelType) } Component.onCompleted: { if (elisa.musicManager) { realModel.initialize(elisa.musicManager, modelType) } } } diff --git a/src/qml/ArtistsView.qml b/src/qml/ArtistsView.qml index 8a957d94..e4fba614 100644 --- a/src/qml/ArtistsView.qml +++ b/src/qml/ArtistsView.qml @@ -1,80 +1,79 @@ /* * 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.10 import QtQuick.Controls 2.3 import org.kde.elisa 1.0 FocusScope { id: viewHeader property alias mainTitle: gridView.mainTitle property alias image: gridView.image property var modelType property alias defaultIcon: gridView.defaultIcon property alias showRating: gridView.showRating property alias delegateDisplaySecondaryText: gridView.delegateDisplaySecondaryText focus: true DataModel { id: realModel } AllArtistsProxyModel { id: proxyModel sourceModel: realModel onEntriesToEnqueue: elisa.mediaPlayList.enqueue(newEntries, databaseIdType, enqueueMode, triggerPlay) } GridBrowserView { id: gridView focus: true anchors.fill: parent contentModel: proxyModel onEnqueue: elisa.mediaPlayList.enqueue(databaseId, name, modelType, ElisaUtils.AppendPlayList, ElisaUtils.DoNotTriggerPlay) onReplaceAndPlay: elisa.mediaPlayList.enqueue(databaseId, name, modelType, ElisaUtils.ReplacePlayList, ElisaUtils.TriggerPlay) - onOpen: viewManager.openOneArtist(innerMainTitle, innerImage, 0) - + onOpen: viewManager.openChildView(innerMainTitle, innerSecondaryTitle, innerImage, databaseId, dataType) onGoBack: viewManager.goBack() } Connections { target: elisa onMusicManagerChanged: realModel.initialize(elisa.musicManager, modelType) } Component.onCompleted: { if (elisa.musicManager) { realModel.initialize(elisa.musicManager, modelType) } } } diff --git a/src/qml/GenresView.qml b/src/qml/GenresView.qml index ff154d54..e4fba614 100644 --- a/src/qml/GenresView.qml +++ b/src/qml/GenresView.qml @@ -1,79 +1,79 @@ /* * 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.10 import QtQuick.Controls 2.3 import org.kde.elisa 1.0 FocusScope { id: viewHeader property alias mainTitle: gridView.mainTitle property alias image: gridView.image property var modelType property alias defaultIcon: gridView.defaultIcon property alias showRating: gridView.showRating property alias delegateDisplaySecondaryText: gridView.delegateDisplaySecondaryText focus: true DataModel { id: realModel } AllArtistsProxyModel { id: proxyModel sourceModel: realModel onEntriesToEnqueue: elisa.mediaPlayList.enqueue(newEntries, databaseIdType, enqueueMode, triggerPlay) } GridBrowserView { id: gridView focus: true anchors.fill: parent contentModel: proxyModel onEnqueue: elisa.mediaPlayList.enqueue(databaseId, name, modelType, ElisaUtils.AppendPlayList, ElisaUtils.DoNotTriggerPlay) onReplaceAndPlay: elisa.mediaPlayList.enqueue(databaseId, name, modelType, ElisaUtils.ReplacePlayList, ElisaUtils.TriggerPlay) - onOpen: viewManager.openAllArtistsFromGenre(innerMainTitle) + onOpen: viewManager.openChildView(innerMainTitle, innerSecondaryTitle, innerImage, databaseId, dataType) onGoBack: viewManager.goBack() } Connections { target: elisa onMusicManagerChanged: realModel.initialize(elisa.musicManager, modelType) } Component.onCompleted: { if (elisa.musicManager) { realModel.initialize(elisa.musicManager, modelType) } } } diff --git a/src/qml/GridBrowserView.qml b/src/qml/GridBrowserView.qml index a90fc507..4740283f 100644 --- a/src/qml/GridBrowserView.qml +++ b/src/qml/GridBrowserView.qml @@ -1,165 +1,165 @@ /* * 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 . */ import QtQuick 2.7 import QtQuick.Controls 2.2 import QtQuick.Window 2.2 import QtQml.Models 2.1 import QtQuick.Layouts 1.2 import QtGraphicalEffects 1.0 import org.kde.elisa 1.0 FocusScope { id: gridView property bool isSubPage: false property string mainTitle property string secondaryTitle property url image property alias contentModel: contentDirectoryView.model property alias showRating: navigationBar.showRating property bool delegateDisplaySecondaryText: true property alias expandedFilterView: navigationBar.expandedFilterView property var stackView property url defaultIcon - signal enqueue(var databaseId, var name) - signal replaceAndPlay(var databaseId, var name) - signal open(var innerMainTitle, var innerSecondaryTitle, var innerImage, var databaseId) + signal enqueue(int databaseId, string name) + signal replaceAndPlay(int databaseId, string name) + signal open(string innerMainTitle, string innerSecondaryTitle, url innerImage, int databaseId, var dataType) signal goBack() SystemPalette { id: myPalette colorGroup: SystemPalette.Active } Theme { id: elisaTheme } ColumnLayout { anchors.fill: parent spacing: 0 NavigationActionBar { id: navigationBar mainTitle: gridView.mainTitle secondaryTitle: gridView.secondaryTitle image: gridView.image enableGoBack: isSubPage sortOrder: if (contentModel) {contentModel.sortedAscending} else true height: elisaTheme.navigationBarHeight Layout.preferredHeight: height Layout.minimumHeight: height Layout.maximumHeight: height Layout.fillWidth: true Loader { active: contentModel !== undefined sourceComponent: Binding { target: contentModel property: 'filterText' value: navigationBar.filterText } } Loader { active: contentModel sourceComponent: Binding { target: contentModel property: 'filterRating' value: navigationBar.filterRating } } onEnqueue: contentModel.enqueueToPlayList() onReplaceAndPlay:contentModel.replaceAndPlayOfPlayList() onGoBack: gridView.goBack() onSort: contentModel.sortModel(order) } Rectangle { color: myPalette.base Layout.fillHeight: true Layout.fillWidth: true clip: true GridView { id: contentDirectoryView anchors.topMargin: 20 focus: true anchors.fill: parent ScrollBar.vertical: ScrollBar { id: scrollBar } boundsBehavior: Flickable.StopAtBounds TextMetrics { id: secondaryLabelSize text: 'example' } ScrollHelper { id: scrollHelper flickable: contentDirectoryView anchors.fill: contentDirectoryView } cellWidth: elisaTheme.gridDelegateWidth cellHeight: (delegateDisplaySecondaryText ? elisaTheme.gridDelegateHeight : elisaTheme.gridDelegateHeight - secondaryLabelSize.height) delegate: GridBrowserDelegate { width: contentDirectoryView.cellWidth height: contentDirectoryView.cellHeight focus: true isPartial: false mainText: model.display secondaryText: if (gridView.delegateDisplaySecondaryText) {model.secondaryText} else {""} imageUrl: (model && model.imageUrl && model.imageUrl.toString() !== "" ? model.imageUrl : defaultIcon) shadowForImage: (model && model.imageUrl && model.imageUrl.toString() !== "" ? true : false) databaseId: model.databaseId delegateDisplaySecondaryText: gridView.delegateDisplaySecondaryText onEnqueue: gridView.enqueue(databaseId, name) onReplaceAndPlay: gridView.replaceAndPlay(databaseId, name) onOpen: gridView.open(model.display, model.secondaryText, (model && model.imageUrl && model.imageUrl.toString() !== "" ? model.imageUrl : defaultIcon), - model.databaseId) + model.databaseId, model.dataType) onSelected: { forceActiveFocus() contentDirectoryView.currentIndex = model.index } } } } } } diff --git a/src/qml/OneArtistView.qml b/src/qml/OneArtistView.qml index 1dae69ca..a9d57911 100644 --- a/src/qml/OneArtistView.qml +++ b/src/qml/OneArtistView.qml @@ -1,91 +1,91 @@ /* * 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.10 import QtQuick.Controls 2.3 import org.kde.elisa 1.0 FocusScope { id: viewHeader property alias mainTitle: gridView.mainTitle property alias secondaryTitle: gridView.secondaryTitle property alias image: gridView.image property alias defaultIcon: gridView.defaultIcon property alias showRating: gridView.showRating property alias delegateDisplaySecondaryText: gridView.delegateDisplaySecondaryText property string genreFilterText property string artistFilter DataModel { id: realModel } AllAlbumsProxyModel { id: proxyModel sourceModel: realModel onEntriesToEnqueue: elisa.mediaPlayList.enqueue(newEntries, databaseIdType, enqueueMode, triggerPlay) } GridBrowserView { id: gridView focus: true anchors.fill: parent contentModel: proxyModel isSubPage: true onEnqueue: elisa.mediaPlayList.enqueue(databaseId, name, ElisaUtils.Album, ElisaUtils.AppendPlayList, ElisaUtils.DoNotTriggerPlay) onReplaceAndPlay: elisa.mediaPlayList.enqueue(databaseId, name, ElisaUtils.Album, ElisaUtils.ReplacePlayList, ElisaUtils.TriggerPlay) - onOpen: viewManager.openOneAlbum(innerMainTitle, innerSecondaryTitle, innerImage, databaseId) + onOpen: viewManager.openChildView(innerMainTitle, innerSecondaryTitle, innerImage, databaseId, dataType) onGoBack: viewManager.goBack() } Connections { target: elisa onMusicManagerChanged: { if (genreFilterText) { realModel.initializeByGenreAndArtist(elisa.musicManager, ElisaUtils.Album, genreFilterText, artistFilter) } else { realModel.initializeByArtist(elisa.musicManager, ElisaUtils.Album, artistFilter) } } } Component.onCompleted: { if (elisa.musicManager) { if (genreFilterText) { realModel.initializeByGenreAndArtist(elisa.musicManager, ElisaUtils.Album, genreFilterText, artistFilter) } else { realModel.initializeByArtist(elisa.musicManager, ElisaUtils.Album, artistFilter) } } } } diff --git a/src/qml/OneGenreView.qml b/src/qml/OneGenreView.qml index 3db6f3ba..8b637c55 100644 --- a/src/qml/OneGenreView.qml +++ b/src/qml/OneGenreView.qml @@ -1,80 +1,80 @@ /* * 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.10 import QtQuick.Controls 2.3 import org.kde.elisa 1.0 FocusScope { id: viewHeader property alias mainTitle: gridView.mainTitle property alias secondaryTitle: gridView.secondaryTitle property alias image: gridView.image property alias defaultIcon: gridView.defaultIcon property alias showRating: gridView.showRating property alias delegateDisplaySecondaryText: gridView.delegateDisplaySecondaryText property string genreFilterText DataModel { id: realModel } AllArtistsProxyModel { id: proxyModel sourceModel: realModel onEntriesToEnqueue: elisa.mediaPlayList.enqueue(newEntries, databaseIdType, enqueueMode, triggerPlay) } GridBrowserView { id: gridView contentModel: proxyModel focus: true anchors.fill: parent isSubPage: true onEnqueue: elisa.mediaPlayList.enqueue(databaseId, name, ElisaUtils.Artist, ElisaUtils.AppendPlayList, ElisaUtils.DoNotTriggerPlay) onReplaceAndPlay: elisa.mediaPlayList.enqueue(databaseId, name, ElisaUtils.Artist, ElisaUtils.ReplacePlayList, ElisaUtils.TriggerPlay) - onOpen: viewManager.openOneArtist(innerMainTitle, innerImage, 0) + onOpen: viewManager.openChildView(innerMainTitle, innerSecondaryTitle, innerImage, databaseId, dataType) onGoBack: viewManager.goBack() } Connections { target: elisa onMusicManagerChanged: realModel.initializeByGenre(elisa.musicManager, ElisaUtils.Artist, genreFilterText) } Component.onCompleted: { if (elisa.musicManager) { realModel.initializeByGenre(elisa.musicManager, ElisaUtils.Artist, genreFilterText) } } } diff --git a/src/viewmanager.cpp b/src/viewmanager.cpp index 0a428af0..c5a19d2b 100644 --- a/src/viewmanager.cpp +++ b/src/viewmanager.cpp @@ -1,257 +1,279 @@ /* * 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 "viewmanager.h" ViewManager::ViewManager(QObject *parent) : QObject(parent) { } void ViewManager::closeAllViews() { mCurrentView = ViewsType::NoViews; mTargetView = ViewsType::NoViews; Q_EMIT switchOffAllViews(); } +void ViewManager::openChildView(const QString &innerMainTitle, const QString &innerSecondaryTitle, + const QUrl &innerImage, qulonglong databaseId, + ElisaUtils::PlayListEntryType dataType) +{ + switch(dataType) + { + case ElisaUtils::Album: + openOneAlbum(innerMainTitle, innerSecondaryTitle, innerImage, databaseId); + break; + case ElisaUtils::Artist: + openOneArtist(innerMainTitle, innerImage, databaseId); + break; + case ElisaUtils::Genre: + openAllArtistsFromGenre(innerMainTitle); + break; + case ElisaUtils::Track: + case ElisaUtils::FileName: + case ElisaUtils::Unknown: + break; + } +} + void ViewManager::openRecentlyPlayedTracks(const QString &mainTitle, const QUrl &imageUrl) { mTargetView = ViewsType::RecentlyPlayedTracks; if (mCurrentView != mTargetView) { Q_EMIT switchRecentlyPlayedTracksView(mainTitle, imageUrl, ElisaUtils::Track); } } void ViewManager::openFrequentlyPlayedTracks(const QString &mainTitle, const QUrl &imageUrl) { mTargetView = ViewsType::FrequentlyPlayedTracks; if (mCurrentView != mTargetView) { Q_EMIT switchFrequentlyPlayedTracksView(mainTitle, imageUrl, ElisaUtils::Track); } } void ViewManager::openAllAlbums(const QString &mainTitle, const QUrl &imageUrl) { mTargetView = ViewsType::AllAlbums; if (mCurrentView != mTargetView) { Q_EMIT switchAllAlbumsView(mainTitle, imageUrl, ElisaUtils::Album, QUrl(QStringLiteral("image://icon/media-optical-audio")), true, true); } } void ViewManager::openOneAlbum(const QString &albumTitle, const QString &albumAuthor, const QUrl &albumCover, qulonglong albumDatabaseId) { mTargetAlbumTitle = albumTitle; mTargetAlbumAuthor = albumAuthor; mTargetDatabaseId = albumDatabaseId; mTargetImageUrl = albumCover; if (mCurrentView == ViewsType::AllAlbums) { mTargetView = ViewsType::OneAlbum; Q_EMIT switchOneAlbumView(mTargetAlbumTitle, mTargetImageUrl, mTargetAlbumAuthor, mTargetDatabaseId); } else if (mCurrentView == ViewsType::OneArtist) { mTargetView = ViewsType::OneAlbumFromArtist; Q_EMIT switchOneAlbumView(mTargetAlbumTitle, mTargetImageUrl, mTargetAlbumAuthor, mTargetDatabaseId); } else if (mCurrentView == ViewsType::OneArtistFromGenre) { mTargetView = ViewsType::OneAlbumFromArtistAndGenre; Q_EMIT switchOneAlbumView(mTargetAlbumTitle, mTargetImageUrl, mTargetAlbumAuthor, mTargetDatabaseId); } else { switchAllAlbumsView({}, {}, ElisaUtils::Album, QUrl(QStringLiteral("image://icon/media-optical-audio")), true, true); } } void ViewManager::openAllArtists(const QString &mainTitle, const QUrl &imageUrl) { mTargetView = ViewsType::AllArtists; if (mCurrentView != mTargetView) { Q_EMIT switchAllArtistsView(mainTitle, imageUrl, ElisaUtils::Artist, QUrl(QStringLiteral("image://icon/view-media-artist")), false, false); } } void ViewManager::openOneArtist(const QString &artistName, const QUrl &artistImageUrl, qulonglong artistDatabaseId) { mTargetArtistName = artistName; mTargetDatabaseId = artistDatabaseId; mTargetImageUrl = artistImageUrl; if (mCurrentView == ViewsType::AllArtistsFromGenre) { mTargetView = ViewsType::OneArtistFromGenre; } else { mTargetView = ViewsType::OneArtist; } if (mCurrentView == ViewsType::AllArtists && mTargetView == ViewsType::OneArtist) { Q_EMIT switchOneArtistView(mTargetArtistName, mTargetImageUrl, {}, mTargetDatabaseId); } else if (mCurrentView == ViewsType::OneArtist && mCurrentArtistName != mTargetArtistName && mTargetView == ViewsType::OneArtist) { Q_EMIT popOneView(); Q_EMIT switchOneArtistView(mTargetArtistName, mTargetImageUrl, {}, mTargetDatabaseId); } else if (mCurrentView == ViewsType::OneAlbumFromArtist && mCurrentArtistName != mTargetArtistName && mTargetView == ViewsType::OneArtist) { Q_EMIT popOneView(); Q_EMIT popOneView(); Q_EMIT switchOneArtistView(mTargetArtistName, mTargetImageUrl, {}, mTargetDatabaseId); } else if (mCurrentView == ViewsType::AllArtistsFromGenre && mTargetView == ViewsType::OneArtistFromGenre) { Q_EMIT switchOneArtistFromGenreView(mTargetArtistName, {}, mTargetImageUrl, ElisaUtils::Album, QUrl(QStringLiteral("image://icon/media-optical-audio")), true, true, mTargetDatabaseId, mTargetGenreName); } else { Q_EMIT switchAllArtistsView({}, {}, ElisaUtils::Artist, QUrl(QStringLiteral("image://icon/view-media-artist")), false, false); } } void ViewManager::openAllTracks(const QString &mainTitle, const QUrl &imageUrl) { mTargetView = ViewsType::AllTracks; if (mCurrentView != mTargetView) { Q_EMIT switchAllTracksView(mainTitle, imageUrl, ElisaUtils::Track); } } void ViewManager::openAllGenres(const QString &mainTitle, const QUrl &imageUrl) { mTargetView = ViewsType::AllGenres; if (mCurrentView != mTargetView) { Q_EMIT switchAllGenresView(mainTitle, imageUrl, ElisaUtils::Genre, QUrl(QStringLiteral("image://icon/view-media-genre")), false, false); } } void ViewManager::openAllArtistsFromGenre(const QString &genreName) { mTargetView = ViewsType::AllArtistsFromGenre; mTargetGenreName = genreName; if (mCurrentView == ViewsType::AllGenres) { Q_EMIT switchAllArtistsFromGenreView(mTargetGenreName, {}, QUrl(QStringLiteral("image://icon/view-media-artist")), ElisaUtils::Artist, QUrl(QStringLiteral("image://icon/view-media-artist")), false, false); } else { Q_EMIT switchAllGenresView({}, {}, ElisaUtils::Genre, QUrl(QStringLiteral("image://icon/view-media-genre")), false, false); } } void ViewManager::openFilesBrowser(const QString &mainTitle, const QUrl &imageUrl) { mTargetView = ViewsType::FilesBrowser; if (mCurrentView != mTargetView) { Q_EMIT switchFilesBrowserView(mainTitle, imageUrl); } } void ViewManager::recentlyPlayedTracksIsLoaded() { mCurrentView = ViewsType::RecentlyPlayedTracks; } void ViewManager::frequentlyPlayedTracksIsLoaded() { mCurrentView = ViewsType::FrequentlyPlayedTracks; } void ViewManager::allAlbumsViewIsLoaded() { mCurrentView = ViewsType::AllAlbums; if (mTargetView == ViewsType::OneAlbum) { Q_EMIT switchOneAlbumView(mTargetAlbumTitle, mTargetImageUrl, mTargetArtistName, mTargetDatabaseId); } } void ViewManager::oneAlbumViewIsLoaded() { mCurrentAlbumTitle = mTargetAlbumTitle; mCurrentAlbumAuthor = mTargetAlbumAuthor; if (mTargetView == ViewsType::OneAlbum) { mCurrentView = ViewsType::OneAlbum; } else if (mTargetView == ViewsType::OneAlbumFromArtist) { mCurrentView = ViewsType::OneAlbumFromArtist; } else if (mTargetView == ViewsType::OneAlbumFromArtistAndGenre) { mCurrentView = ViewsType::OneAlbumFromArtistAndGenre; } } void ViewManager::allArtistsViewIsLoaded() { mCurrentView = ViewsType::AllArtists; if (mTargetView == ViewsType::OneArtist) { Q_EMIT switchOneArtistView(mTargetArtistName, mTargetImageUrl, {}, mTargetDatabaseId); } } void ViewManager::oneArtistViewIsLoaded() { mCurrentArtistName = mTargetArtistName; if (mTargetView == ViewsType::OneArtist) { mCurrentView = ViewsType::OneArtist; } else { mCurrentGenreName = mTargetGenreName; mCurrentView = ViewsType::OneArtistFromGenre; } } void ViewManager::allTracksViewIsLoaded() { mCurrentView = ViewsType::AllTracks; } void ViewManager::allGenresViewIsLoaded() { mCurrentView = ViewsType::AllGenres; } void ViewManager::allArtistsFromGenreViewIsLoaded() { mCurrentGenreName = mTargetGenreName; mCurrentView = ViewsType::AllArtistsFromGenre; } void ViewManager::filesBrowserViewIsLoaded() { mCurrentView = ViewsType::FilesBrowser; } void ViewManager::goBack() { Q_EMIT popOneView(); if (mCurrentView == ViewsType::OneAlbum) { mCurrentView = ViewsType::AllAlbums; } else if (mCurrentView == ViewsType::OneArtist) { mCurrentView = ViewsType::AllArtists; } else if (mCurrentView == ViewsType::OneAlbumFromArtist) { mCurrentView = ViewsType::OneArtist; } else if (mCurrentView == ViewsType::AllArtistsFromGenre) { mCurrentView = ViewsType::AllGenres; } else if (mCurrentView == ViewsType::OneArtistFromGenre) { mCurrentView = ViewsType::AllArtistsFromGenre; } else if (mCurrentView == ViewsType::OneAlbumFromArtistAndGenre) { mCurrentView = ViewsType::OneArtistFromGenre; } } #include "moc_viewmanager.cpp" diff --git a/src/viewmanager.h b/src/viewmanager.h index 6d6f8ddc..2d09d647 100644 --- a/src/viewmanager.h +++ b/src/viewmanager.h @@ -1,161 +1,165 @@ /* * 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 VIEWMANAGER_H #define VIEWMANAGER_H #include "elisaLib_export.h" #include "elisautils.h" #include #include class ELISALIB_EXPORT ViewManager : public QObject { Q_OBJECT public: enum ViewsType { NoViews, AllAlbums, OneAlbum, AllArtists, OneArtist, OneAlbumFromArtist, AllTracks, AllGenres, AllArtistsFromGenre, OneArtistFromGenre, OneAlbumFromArtistAndGenre, FrequentlyPlayedTracks, RecentlyPlayedTracks, FilesBrowser }; Q_ENUM(ViewsType) explicit ViewManager(QObject *parent = nullptr); Q_SIGNALS: void switchRecentlyPlayedTracksView(const QString &mainTitle, const QUrl &imageUrl, ElisaUtils::PlayListEntryType dataType); void switchFrequentlyPlayedTracksView(const QString &mainTitle, const QUrl &imageUrl, ElisaUtils::PlayListEntryType dataType); void switchAllAlbumsView(const QString &mainTitle, const QUrl &imageUrl, ElisaUtils::PlayListEntryType dataType, const QUrl &viewDefaultIcon, bool viewShowRating, bool viewDelegateDisplaySecondaryText); void switchOneAlbumView(const QString &mainTitle, const QUrl &imageUrl, const QString &secondaryTitle, qulonglong databaseId); void switchAllArtistsView(const QString &mainTitle, const QUrl &imageUrl, ElisaUtils::PlayListEntryType dataType, const QUrl &viewDefaultIcon, bool viewShowRating, bool viewDelegateDisplaySecondaryText); void switchOneArtistView(const QString &mainTitle, const QUrl &imageUrl, const QString &secondaryTitle, qulonglong databaseId); void switchAllTracksView(const QString &mainTitle, const QUrl &imageUrl, ElisaUtils::PlayListEntryType dataType); void switchAllGenresView(const QString &mainTitle, const QUrl &imageUrl, ElisaUtils::PlayListEntryType dataType, const QUrl &viewDefaultIcon, bool viewShowRating, bool viewDelegateDisplaySecondaryText); void switchAllArtistsFromGenreView(const QString &mainTitle, const QString &secondaryTitle, const QUrl &imageUrl, ElisaUtils::PlayListEntryType dataType, const QUrl &viewDefaultIcon, bool viewShowRating, bool viewDelegateDisplaySecondaryText); void switchOneArtistFromGenreView(const QString &mainTitle, const QString &secondaryTitle, const QUrl &imageUrl, ElisaUtils::PlayListEntryType dataType, const QUrl &viewDefaultIcon, bool viewShowRating, bool viewDelegateDisplaySecondaryText, qulonglong databaseId, const QString &genreName); void switchFilesBrowserView(const QString &mainTitle, const QUrl &imageUrl); void switchOffAllViews(); void popOneView(); public Q_SLOTS: void closeAllViews(); + void openChildView(const QString &innerMainTitle, const QString & innerSecondaryTitle, + const QUrl &innerImage, qulonglong databaseId, + ElisaUtils::PlayListEntryType dataType); + void openRecentlyPlayedTracks(const QString &mainTitle, const QUrl &imageUrl); void openFrequentlyPlayedTracks(const QString &mainTitle, const QUrl &imageUrl); void openAllAlbums(const QString &mainTitle, const QUrl &imageUrl); - void openOneAlbum(const QString &albumTitle, const QString &albumAuthor, - const QUrl &albumCover, qulonglong albumDatabaseId); - void openAllArtists(const QString &mainTitle, const QUrl &imageUrl); - void openOneArtist(const QString &artistName, const QUrl &artistImageUrl, qulonglong artistDatabaseId); - void openAllTracks(const QString &mainTitle, const QUrl &imageUrl); void openAllGenres(const QString &mainTitle, const QUrl &imageUrl); - void openAllArtistsFromGenre(const QString &genreName); - void openFilesBrowser(const QString &mainTitle, const QUrl &imageUrl); void recentlyPlayedTracksIsLoaded(); void frequentlyPlayedTracksIsLoaded(); void allAlbumsViewIsLoaded(); void oneAlbumViewIsLoaded(); void allArtistsViewIsLoaded(); void oneArtistViewIsLoaded(); void allTracksViewIsLoaded(); void allGenresViewIsLoaded(); void allArtistsFromGenreViewIsLoaded(); void filesBrowserViewIsLoaded(); void goBack(); private: + void openOneAlbum(const QString &albumTitle, const QString &albumAuthor, + const QUrl &albumCover, qulonglong albumDatabaseId); + + void openOneArtist(const QString &artistName, const QUrl &artistImageUrl, qulonglong artistDatabaseId); + + void openAllArtistsFromGenre(const QString &genreName); + ViewsType mCurrentView = ViewsType::NoViews; QString mCurrentAlbumTitle; QString mCurrentAlbumAuthor; QString mCurrentArtistName; QString mCurrentGenreName; ViewsType mTargetView = ViewsType::NoViews; QString mTargetAlbumTitle; QString mTargetAlbumAuthor; QString mTargetArtistName; QString mTargetGenreName; QUrl mTargetImageUrl; qulonglong mTargetDatabaseId = 0; }; #endif // VIEWMANAGER_H