diff --git a/src/databaseinterface.h b/src/databaseinterface.h index b166c25b..42e1a522 100644 --- a/src/databaseinterface.h +++ b/src/databaseinterface.h @@ -1,584 +1,590 @@ /* * Copyright 2016-2017 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef DATABASEINTERFACE_H #define DATABASEINTERFACE_H #include "elisaLib_export.h" #include "datatype.h" #include "elisautils.h" #include #include #include #include #include #include #include #include #include class DatabaseInterfacePrivate; class QMutex; class QSqlRecord; class QSqlQuery; class MusicAudioTrack; class ELISALIB_EXPORT DatabaseInterface : public QObject { Q_OBJECT public: enum ColumnsRoles { TitleRole = Qt::UserRole + 1, SecondaryTextRole, ImageUrlRole, ShadowForImageRole, ChildModelRole, DurationRole, StringDurationRole, MilliSecondsDurationRole, ArtistRole, AllArtistsRole, HighestTrackRating, AlbumRole, AlbumArtistRole, TrackNumberRole, DiscNumberRole, RatingRole, GenreRole, LyricistRole, ComposerRole, CommentRole, YearRole, ChannelsRole, BitRateRole, SampleRateRole, ResourceRole, IdRole, DatabaseIdRole, IsSingleDiscAlbumRole, ContainerDataRole, IsPartialDataRole, AlbumIdRole, HasEmbeddedCover, FileModificationTime, FirstPlayDate, LastPlayDate, PlayCounter, PlayFrequency, ElementTypeRole, + LyricsRole, }; Q_ENUM(ColumnsRoles) private: using DataType = QMap; public: class TrackDataType : public DataType { public: using DataType::DataType; bool isValid() const { return !isEmpty(); } qulonglong databaseId() const { return operator[](key_type::DatabaseIdRole).toULongLong(); } QString title() const { return operator[](key_type::TitleRole).toString(); } QString artist() const { return operator[](key_type::ArtistRole).toString(); } qulonglong albumId() const { return operator[](key_type::AlbumIdRole).toULongLong(); } QString album() const { return operator[](key_type::AlbumRole).toString(); } QString albumArtist() const { return operator[](key_type::AlbumArtistRole).toString(); } int trackNumber() const { return operator[](key_type::TrackNumberRole).toInt(); } int discNumber() const { return operator[](key_type::DiscNumberRole).toInt(); } QTime duration() const { return operator[](key_type::DurationRole).toTime(); } QUrl resourceURI() const { return operator[](key_type::ResourceRole).toUrl(); } QUrl albumCover() const { return operator[](key_type::ImageUrlRole).toUrl(); } bool isSingleDiscAlbum() const { return operator[](key_type::IsSingleDiscAlbumRole).toBool(); } int rating() const { return operator[](key_type::RatingRole).toInt(); } QString genre() const { return operator[](key_type::GenreRole).toString(); } QString composer() const { return operator[](key_type::ComposerRole).toString(); } QString lyricist() const { return operator[](key_type::LyricistRole).toString(); } + QString lyrics() const + { + return operator[](key_type::LyricsRole).toString(); + } + QString comment() const { return operator[](key_type::CommentRole).toString(); } int year() const { return operator[](key_type::YearRole).toInt(); } int channels() const { return operator[](key_type::ChannelsRole).toInt(); } int bitRate() const { return operator[](key_type::BitRateRole).toInt(); } int sampleRate() const { return operator[](key_type::SampleRateRole).toInt(); } bool hasEmbeddedCover() const { return operator[](key_type::HasEmbeddedCover).toBool(); } QDateTime fileModificationTime() const { return operator[](key_type::FileModificationTime).toDateTime(); } }; using ListTrackDataType = QList; class AlbumDataType : public DataType { public: using DataType::DataType; qulonglong databaseId() const { return operator[](key_type::DatabaseIdRole).toULongLong(); } QString title() const { return operator[](key_type::TitleRole).toString(); } QString artist() const { return operator[](key_type::ArtistRole).toString(); } bool isValidArtist() const { const auto &artistData = operator[](key_type::ArtistRole); return artistData.isValid() && !artistData.toString().isEmpty(); } QStringList genres() const { return operator[](key_type::GenreRole).toStringList(); } QUrl albumArtURI() const { return operator[](key_type::ImageUrlRole).toUrl(); } bool isSingleDiscAlbum() const { return operator[](key_type::IsSingleDiscAlbumRole).toBool(); } bool isValid() const { return !isEmpty(); } }; using ListAlbumDataType = QList; class ArtistDataType : public DataType { public: using DataType::DataType; qulonglong databaseId() const { return operator[](key_type::DatabaseIdRole).toULongLong(); } }; using ListArtistDataType = QList; class GenreDataType : public DataType { public: using DataType::DataType; qulonglong databaseId() const { return operator[](key_type::DatabaseIdRole).toULongLong(); } QString title() const { return operator[](key_type::TitleRole).toString(); } }; using ListGenreDataType = QList; enum PropertyType { DatabaseId, DisplayRole, SecondaryRole, }; Q_ENUM(PropertyType) enum AlbumDiscsCount { SingleDiscAlbum, MultipleDiscsAlbum, }; Q_ENUM(AlbumDiscsCount) explicit DatabaseInterface(QObject *parent = nullptr); ~DatabaseInterface() override; Q_INVOKABLE void init(const QString &dbName, const QString &databaseFileName = {}); qulonglong albumIdFromTitleAndArtist(const QString &title, const QString &artist); ListTrackDataType allTracksData(); ListTrackDataType recentlyPlayedTracksData(int count); ListTrackDataType frequentlyPlayedTracksData(int count); ListAlbumDataType allAlbumsData(); ListAlbumDataType allAlbumsDataByGenreAndArtist(const QString &genre, const QString &artist); ListAlbumDataType allAlbumsDataByArtist(const QString &artist); AlbumDataType albumDataFromDatabaseId(qulonglong id); ListTrackDataType albumData(qulonglong databaseId); ListArtistDataType allArtistsData(); ListArtistDataType allArtistsDataByGenre(const QString &genre); ListGenreDataType allGenresData(); bool internalArtistMatchGenre(qulonglong databaseId, const QString &genre); ListTrackDataType tracksDataFromAuthor(const QString &artistName); TrackDataType trackDataFromDatabaseId(qulonglong id); qulonglong trackIdFromTitleAlbumTrackDiscNumber(const QString &title, const QString &artist, const QString &album, int trackNumber, int discNumber); qulonglong trackIdFromFileName(const QUrl &fileName); void applicationAboutToQuit(); Q_SIGNALS: void artistsAdded(const DatabaseInterface::ListArtistDataType &newArtists); void composersAdded(const DatabaseInterface::ListArtistDataType &newComposers); void lyricistsAdded(const DatabaseInterface::ListArtistDataType &newLyricists); void albumsAdded(const DatabaseInterface::ListAlbumDataType &newAlbums); void tracksAdded(const DatabaseInterface::ListTrackDataType &allTracks); void genresAdded(const DatabaseInterface::ListGenreDataType &allGenres); void artistRemoved(qulonglong removedArtistId); void albumRemoved(qulonglong removedAlbumId); void trackRemoved(qulonglong id); void albumModified(const DatabaseInterface::AlbumDataType &modifiedAlbum, qulonglong modifiedAlbumId); void trackModified(const DatabaseInterface::TrackDataType &modifiedTrack); void requestsInitDone(); void databaseError(); void restoredTracks(QHash allFiles); void cleanedDatabase(); void finishInsertingTracksList(); void finishRemovingTracksList(); public Q_SLOTS: void insertTracksList(const QList &tracks, const QHash &covers); void removeTracksList(const QList &removedTracks); void askRestoredTracks(); void trackHasStartedPlaying(const QUrl &fileName, const QDateTime &time); void clearData(); private: enum class TrackFileInsertType { NewTrackFileInsert, ModifiedTrackFileInsert, }; void initChangesTrackers(); void recordModifiedTrack(qulonglong trackId); void recordModifiedAlbum(qulonglong albumId); bool startTransaction() const; bool finishTransaction() const; bool rollBackTransaction() const; QList fetchTrackIds(qulonglong albumId); qulonglong internalAlbumIdFromTitleAndArtist(const QString &title, const QString &artist); MusicAudioTrack internalTrackFromDatabaseId(qulonglong id); qulonglong internalTrackIdFromTitleAlbumTracDiscNumber(const QString &title, const QString &artist, const QString &album, int trackNumber, int discNumber); qulonglong getDuplicateTrackIdFromTitleAlbumTrackDiscNumber(const QString &title, const QString &trackArtist, const QString &album, const QString &albumArtist, const QString &trackPath, int priority); qulonglong internalTrackIdFromFileName(const QUrl &fileName); ListTrackDataType internalTracksFromAuthor(const QString &artistName); QList internalAlbumIdsFromAuthor(const QString &artistName); void initDatabase(); void initRequest(); qulonglong insertAlbum(const QString &title, const QString &albumArtist, const QString &trackArtist, const QString &trackPath, const QUrl &albumArtURI); bool updateAlbumFromId(qulonglong albumId, const QUrl &albumArtUri, const MusicAudioTrack ¤tTrack, const QString &albumPath); qulonglong insertArtist(const QString &name); qulonglong internalArtistIdFromName(const QString &name); qulonglong insertGenre(const QString &name); void removeTrackInDatabase(qulonglong trackId); void updateTrackInDatabase(const MusicAudioTrack &oneTrack, const QString &albumPath); void removeAlbumInDatabase(qulonglong albumId); void removeArtistInDatabase(qulonglong artistId); void reloadExistingDatabase(); qulonglong initialId(DataUtils::DataType aType); qulonglong genericInitialId(QSqlQuery &request); void insertTrackOrigin(const QUrl &fileNameURI, const QDateTime &fileModifiedTime, const QDateTime &importDate); void updateTrackOrigin(const QUrl &fileName, const QDateTime &fileModifiedTime); qulonglong internalInsertTrack(const MusicAudioTrack &oneModifiedTrack, const QHash &covers, bool &isInserted); MusicAudioTrack buildTrackFromDatabaseRecord(const QSqlRecord &trackRecord) const; TrackDataType buildTrackDataFromDatabaseRecord(const QSqlRecord &trackRecord) const; void internalRemoveTracksList(const QList &removedTracks); void internalRemoveTracksList(const QHash &removedTracks, qulonglong sourceId); QUrl internalAlbumArtUriFromAlbumId(qulonglong albumId); bool isValidArtist(qulonglong albumId); qulonglong insertComposer(const QString &name); qulonglong insertLyricist(const QString &name); QHash internalAllFileName(); bool internalGenericPartialData(QSqlQuery &query); ListArtistDataType internalAllArtistsPartialData(QSqlQuery &artistsQuery); ListAlbumDataType internalAllAlbumsPartialData(QSqlQuery &query); AlbumDataType internalOneAlbumPartialData(qulonglong databaseId); ListTrackDataType internalAllTracksPartialData(); ListTrackDataType internalRecentlyPlayedTracksData(int count); ListTrackDataType internalFrequentlyPlayedTracksData(int count); TrackDataType internalOneTrackPartialData(qulonglong databaseId); ListGenreDataType internalAllGenresPartialData(); ListArtistDataType internalAllComposersPartialData(); ListArtistDataType internalAllLyricistsPartialData(); bool prepareQuery(QSqlQuery &query, const QString &queryText) const; bool execQuery(QSqlQuery &query); void updateAlbumArtist(qulonglong albumId, const QString &title, const QString &albumPath, const QString &artistName); void updateTrackStatistics(const QUrl &fileName, const QDateTime &time); void createDatabaseV9(); void upgradeDatabaseV9(); void upgradeDatabaseV11(); void upgradeDatabaseV12(); void checkDatabaseSchema(); void checkAlbumsTableSchema(); void checkArtistsTableSchema(); void checkComposerTableSchema(); void checkGenreTableSchema(); void checkLyricistTableSchema(); void checkTracksTableSchema(); void checkTracksDataTableSchema(); void genericCheckTable(const QString &tableName, const QStringList &expectedColumns); void resetDatabase(); std::unique_ptr d; }; Q_DECLARE_METATYPE(DatabaseInterface::TrackDataType) Q_DECLARE_METATYPE(DatabaseInterface::AlbumDataType) Q_DECLARE_METATYPE(DatabaseInterface::ArtistDataType) Q_DECLARE_METATYPE(DatabaseInterface::GenreDataType) Q_DECLARE_METATYPE(DatabaseInterface::ListTrackDataType) Q_DECLARE_METATYPE(DatabaseInterface::ListAlbumDataType) Q_DECLARE_METATYPE(DatabaseInterface::ListArtistDataType) Q_DECLARE_METATYPE(DatabaseInterface::ListGenreDataType) #endif // DATABASEINTERFACE_H diff --git a/src/filescanner.cpp b/src/filescanner.cpp index d7d9f599..57ddaafe 100644 --- a/src/filescanner.cpp +++ b/src/filescanner.cpp @@ -1,232 +1,237 @@ /* * Copyright 2018 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "filescanner.h" #include "config-upnp-qt.h" #if defined KF5FileMetaData_FOUND && KF5FileMetaData_FOUND #include #include #include #include #include #if defined KF5Baloo_FOUND && KF5Baloo_FOUND #include #endif #endif #include class FileScannerPrivate { public: #if defined KF5FileMetaData_FOUND && KF5FileMetaData_FOUND KFileMetaData::ExtractorCollection mAllExtractors; KFileMetaData::PropertyMap mAllProperties; #endif }; FileScanner::FileScanner() : d(std::make_unique()) { } FileScanner::~FileScanner() = default; MusicAudioTrack FileScanner::scanOneFile(const QUrl &scanFile, const QMimeDatabase &mimeDatabase) { #if defined KF5FileMetaData_FOUND && KF5FileMetaData_FOUND MusicAudioTrack newTrack; auto localFileName = scanFile.toLocalFile(); QFileInfo scanFileInfo(localFileName); newTrack.setFileModificationTime(scanFileInfo.fileTime(QFile::FileModificationTime)); newTrack.setResourceURI(scanFile); const auto &fileMimeType = mimeDatabase.mimeTypeForFile(localFileName); if (!fileMimeType.name().startsWith(QStringLiteral("audio/"))) { return newTrack; } QString mimetype = fileMimeType.name(); QList exList = d->mAllExtractors.fetchExtractors(mimetype); if (exList.isEmpty()) { return newTrack; } KFileMetaData::Extractor* ex = exList.first(); KFileMetaData::SimpleExtractionResult result(localFileName, mimetype, KFileMetaData::ExtractionResult::ExtractMetaData); ex->extract(&result); d->mAllProperties = result.properties(); scanProperties(localFileName, newTrack); return newTrack; #else Q_UNUSED(scanFile) Q_UNUSED(mimeDatabase) return {}; #endif } void FileScanner::scanProperties(const Baloo::File &match, MusicAudioTrack &trackData) { #if defined KF5Baloo_FOUND && KF5Baloo_FOUND d->mAllProperties = match.properties(); scanProperties(match.path(), trackData); #else Q_UNUSED(match) Q_UNUSED(trackData) #endif } void FileScanner::scanProperties(const QString &localFileName, MusicAudioTrack &trackData) { #if defined KF5FileMetaData_FOUND && KF5FileMetaData_FOUND auto titleProperty = d->mAllProperties.find(KFileMetaData::Property::Title); auto durationProperty = d->mAllProperties.find(KFileMetaData::Property::Duration); auto artistProperty = d->mAllProperties.find(KFileMetaData::Property::Artist); auto albumProperty = d->mAllProperties.find(KFileMetaData::Property::Album); auto albumArtistProperty = d->mAllProperties.find(KFileMetaData::Property::AlbumArtist); auto trackNumberProperty = d->mAllProperties.find(KFileMetaData::Property::TrackNumber); auto discNumberProperty = d->mAllProperties.find(KFileMetaData::Property::DiscNumber); auto genreProperty = d->mAllProperties.find(KFileMetaData::Property::Genre); auto yearProperty = d->mAllProperties.find(KFileMetaData::Property::ReleaseYear); auto composerProperty = d->mAllProperties.find(KFileMetaData::Property::Composer); auto lyricistProperty = d->mAllProperties.find(KFileMetaData::Property::Lyricist); + auto lyricsProperty = d->mAllProperties.find(KFileMetaData::Property::Lyrics); auto channelsProperty = d->mAllProperties.find(KFileMetaData::Property::Channels); auto bitRateProperty = d->mAllProperties.find(KFileMetaData::Property::BitRate); auto sampleRateProperty = d->mAllProperties.find(KFileMetaData::Property::SampleRate); auto commentProperty = d->mAllProperties.find(KFileMetaData::Property::Comment); auto ratingProperty = d->mAllProperties.find(KFileMetaData::Property::Rating); #if !defined Q_OS_ANDROID auto fileData = KFileMetaData::UserMetaData(localFileName); #endif if (albumProperty != d->mAllProperties.end()) { trackData.setAlbumName(albumProperty->toString()); } if (artistProperty != d->mAllProperties.end()) { trackData.setArtist(artistProperty->toStringList().join(QStringLiteral(", "))); } if (durationProperty != d->mAllProperties.end()) { trackData.setDuration(QTime::fromMSecsSinceStartOfDay(int(1000 * durationProperty->toDouble()))); } if (titleProperty != d->mAllProperties.end()) { trackData.setTitle(titleProperty->toString()); } if (trackNumberProperty != d->mAllProperties.end()) { trackData.setTrackNumber(trackNumberProperty->toInt()); } if (discNumberProperty != d->mAllProperties.end()) { trackData.setDiscNumber(discNumberProperty->toInt()); } if (albumArtistProperty != d->mAllProperties.end()) { trackData.setAlbumArtist(albumArtistProperty->toStringList().join(QStringLiteral(", "))); } if (yearProperty != d->mAllProperties.end()) { trackData.setYear(yearProperty->toInt()); } if (channelsProperty != d->mAllProperties.end()) { trackData.setChannels(channelsProperty->toInt()); } if (bitRateProperty != d->mAllProperties.end()) { trackData.setBitRate(bitRateProperty->toInt()); } if (sampleRateProperty != d->mAllProperties.end()) { trackData.setSampleRate(sampleRateProperty->toInt()); } if (genreProperty != d->mAllProperties.end()) { trackData.setGenre(genreProperty->toStringList().join(QStringLiteral(", "))); } if (composerProperty != d->mAllProperties.end()) { trackData.setComposer(composerProperty->toStringList().join(QStringLiteral(", "))); } if (lyricistProperty != d->mAllProperties.end()) { trackData.setLyricist(lyricistProperty->toStringList().join(QStringLiteral(", "))); } + if (lyricsProperty != d->mAllProperties.end()) { + trackData.setLyrics(lyricsProperty->toString()); + } + if (trackData.artist().isEmpty()) { trackData.setArtist(trackData.albumArtist()); } #if !defined Q_OS_ANDROID QString comment = fileData.userComment(); if (!comment.isEmpty()) { trackData.setComment(comment); } else if (commentProperty != d->mAllProperties.end()) { trackData.setComment(commentProperty->toString()); } int rating = fileData.rating(); if (rating > 0) { trackData.setRating(rating); } else if (ratingProperty != d->mAllProperties.end()) { trackData.setRating(ratingProperty->toInt()); } else { trackData.setRating(0); } #else if (ratingProperty != d->mAllProperties.end()) { trackData.setRating(ratingProperty->toInt()); } else { trackData.setRating(0); } if (commentProperty != d->mAllProperties.end()) { trackData.setComment(commentProperty->toString()); } #endif if (!trackData.duration().isValid()) { return; } trackData.setValid(true); #else Q_UNUSED(localFileName) Q_UNUSED(trackData) #endif } diff --git a/src/filescanner.h b/src/filescanner.h index 39191224..dd455c8d 100644 --- a/src/filescanner.h +++ b/src/filescanner.h @@ -1,63 +1,65 @@ /* * Copyright 2018 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef FILESCANNER_H #define FILESCANNER_H +#include "elisaLib_export.h" + #include "musicaudiotrack.h" #include #include #include #include namespace KFileMetaData { class ExtractorCollection; } namespace Baloo { class File; } class FileScannerPrivate; -class FileScanner +class ELISALIB_EXPORT FileScanner { public: FileScanner(); virtual ~FileScanner(); MusicAudioTrack scanOneFile(const QUrl &scanFile, const QMimeDatabase &mimeDatabase); void scanProperties(const Baloo::File &match, MusicAudioTrack &trackData); void scanProperties(const QString &localFileName, MusicAudioTrack &trackData); private: std::unique_ptr d; }; #endif // FILESCANNER_H diff --git a/src/musicaudiotrack.cpp b/src/musicaudiotrack.cpp index ef50b6cf..505cb4fb 100644 --- a/src/musicaudiotrack.cpp +++ b/src/musicaudiotrack.cpp @@ -1,590 +1,605 @@ /* * Copyright 2016-2017 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "musicaudiotrack.h" #include #include #include #include class MusicAudioTrackPrivate : public QSharedData { public: MusicAudioTrackPrivate() = default; MusicAudioTrackPrivate(bool aValid, QString aId, QString aParentId, QString aTitle, QString aArtist, QString aAlbumName, QString aAlbumArtist, int aTrackNumber, int aDiscNumber, QTime aDuration, QUrl aResourceURI, QDateTime fileModificationTime, QUrl aAlbumCover, int rating, bool aIsSingleDiscAlbum, QString aGenre, QString aComposer, QString aLyricist, bool aHasEmbeddedCover) : QSharedData(), mId(std::move(aId)), mParentId(std::move(aParentId)), mTitle(std::move(aTitle)), mArtist(std::move(aArtist)), mAlbumName(std::move(aAlbumName)), mAlbumArtist(std::move(aAlbumArtist)), mGenre(std::move(aGenre)), mComposer(std::move(aComposer)), mLyricist(std::move(aLyricist)), - mResourceURI(std::move(aResourceURI)), mAlbumCover(std::move(aAlbumCover)), + mLyrics(), mResourceURI(std::move(aResourceURI)), mAlbumCover(std::move(aAlbumCover)), mFileModificationTime(std::move(fileModificationTime)), mDuration(aDuration), mTrackNumber(aTrackNumber), mDiscNumber(aDiscNumber), mRating(rating), mIsValid(aValid), mIsSingleDiscAlbum(aIsSingleDiscAlbum), mHasBooleanCover(aHasEmbeddedCover), mTrackNumberIsValid(true), mDiscNumberIsValid(true) { } QString mId; QString mParentId; QString mTitle; QString mArtist; QString mAlbumName; QString mAlbumArtist; QString mGenre; QString mComposer; QString mLyricist; + QString mLyrics; + QString mComment; QUrl mResourceURI; QUrl mAlbumCover; qulonglong mDatabaseId = 0; qulonglong mAlbumId = 0; QDateTime mFileModificationTime; QTime mDuration; int mTrackNumber = -1; int mDiscNumber = -1; int mChannels = -1; int mBitRate = -1; int mSampleRate = -1; int mYear = 0; int mRating = -1; bool mIsValid = false; bool mIsSingleDiscAlbum = true; bool mHasBooleanCover = false; bool mTrackNumberIsValid = false; bool mDiscNumberIsValid = false; bool mChannelsIsValid = false; bool mBitRateIsValid = false; bool mSampleRateIsValid = false; }; MusicAudioTrack::MusicAudioTrack() : d(new MusicAudioTrackPrivate()) { } MusicAudioTrack::MusicAudioTrack(bool aValid, QString aId, QString aParentId, QString aTitle, QString aArtist, QString aAlbumName, QString aAlbumArtist, int aTrackNumber, int aDiscNumber, QTime aDuration, QUrl aResourceURI, const QDateTime &fileModificationTime, QUrl aAlbumCover, int rating, bool aIsSingleDiscAlbum, QString aGenre, QString aComposer, QString aLyricist, bool aHasEmbeddedCover) : d(new MusicAudioTrackPrivate(aValid, std::move(aId), std::move(aParentId), std::move(aTitle), std::move(aArtist), std::move(aAlbumName), std::move(aAlbumArtist), aTrackNumber, aDiscNumber, aDuration, std::move(aResourceURI), fileModificationTime, std::move(aAlbumCover), rating, aIsSingleDiscAlbum, std::move(aGenre), std::move(aComposer), std::move(aLyricist), aHasEmbeddedCover)) { } MusicAudioTrack::MusicAudioTrack(MusicAudioTrack &&other) noexcept = default; MusicAudioTrack::MusicAudioTrack(const MusicAudioTrack &other) = default; MusicAudioTrack::~MusicAudioTrack() = default; MusicAudioTrack& MusicAudioTrack::operator=(MusicAudioTrack &&other) noexcept = default; MusicAudioTrack& MusicAudioTrack::operator=(const MusicAudioTrack &other) = default; bool MusicAudioTrack::operator <(const MusicAudioTrack &other) const { return d->mDiscNumber < other.d->mDiscNumber || (d->mDiscNumber == other.d->mDiscNumber && d->mTrackNumber < other.d->mTrackNumber); } bool MusicAudioTrack::operator ==(const MusicAudioTrack &other) const { return d->mTitle == other.d->mTitle && d->mArtist == other.d->mArtist && d->mAlbumName == other.d->mAlbumName && d->mAlbumArtist == other.d->mAlbumArtist && d->mTrackNumber == other.d->mTrackNumber && d->mDiscNumber == other.d->mDiscNumber && d->mDuration == other.d->mDuration && d->mResourceURI == other.d->mResourceURI && d->mFileModificationTime == other.d->mFileModificationTime && d->mAlbumCover == other.d->mAlbumCover && d->mRating == other.d->mRating && d->mGenre == other.d->mGenre && d->mComposer == other.d->mComposer && - d->mLyricist == other.d->mLyricist && d->mComment == other.d->mComment && + d->mLyricist == other.d->mLyricist && d->mLyrics == other.d->mLyrics && + d->mComment == other.d->mComment && d->mYear == other.d->mYear && d->mChannels == other.d->mChannels && d->mBitRate == other.d->mBitRate && d->mSampleRate == other.d->mSampleRate; } bool MusicAudioTrack::operator !=(const MusicAudioTrack &other) const { return d->mTitle != other.d->mTitle || d->mArtist != other.d->mArtist || d->mAlbumName != other.d->mAlbumName || d->mAlbumArtist != other.d->mAlbumArtist || d->mTrackNumber != other.d->mTrackNumber || d->mDiscNumber != other.d->mDiscNumber || d->mDuration != other.d->mDuration || d->mResourceURI != other.d->mResourceURI || d->mFileModificationTime != other.d->mFileModificationTime || d->mAlbumCover != other.d->mAlbumCover || d->mRating != other.d->mRating || d->mGenre != other.d->mGenre || d->mComposer != other.d->mComposer || - d->mLyricist != other.d->mLyricist || d->mComment != other.d->mComment || + d->mLyricist != other.d->mLyricist || d->mLyrics != other.d->mLyrics || + d->mComment != other.d->mComment || d->mYear != other.d->mYear || d->mChannels != other.d->mChannels || d->mBitRate != other.d->mBitRate || d->mSampleRate != other.d->mSampleRate; } MusicAudioTrack MusicAudioTrack::trackFromData(const DatabaseInterface::TrackDataType &data) { auto result = MusicAudioTrack{}; result.setDatabaseId(data.databaseId()); result.setTitle(data.title()); result.setArtist(data.artist()); result.setAlbumName(data.album()); result.setAlbumArtist(data.albumArtist()); result.setGenre(data.genre()); result.setComposer(data.composer()); result.setLyricist(data.lyricist()); + result.setLyrics(data.lyrics()); result.setComment(data.comment()); result.setAlbumCover(data.albumCover()); result.setTrackNumber(data.trackNumber()); result.setDiscNumber(data.discNumber()); result.setYear(data.year()); result.setChannels(data.channels()); result.setBitRate(data.bitRate()); result.setSampleRate(data.sampleRate()); result.setResourceURI(data.resourceURI()); result.setRating(data.rating()); result.setDuration(data[MusicAudioTrack::TrackDataType::key_type::DurationRole].toTime()); result.setFileModificationTime(data.fileModificationTime()); return result; } void MusicAudioTrack::setValid(bool value) { d->mIsValid = value; } bool MusicAudioTrack::isValid() const { return d->mIsValid; } void MusicAudioTrack::setDatabaseId(qulonglong value) { d->mDatabaseId = value; } qulonglong MusicAudioTrack::databaseId() const { return d->mDatabaseId; } void MusicAudioTrack::setAlbumId(qulonglong value) { d->mAlbumId = value; } qulonglong MusicAudioTrack::albumId() const { return d->mAlbumId; } void MusicAudioTrack::setId(const QString &value) { d->mId = value; } QString MusicAudioTrack::id() const { return d->mId; } void MusicAudioTrack::setParentId(const QString &value) { d->mParentId = value; } QString MusicAudioTrack::parentId() const { return d->mParentId; } void MusicAudioTrack::setTitle(const QString &value) { d->mTitle = value; } QString MusicAudioTrack::title() const { return d->mTitle; } void MusicAudioTrack::setArtist(const QString &value) { d->mArtist = value; } QString MusicAudioTrack::artist() const { return d->mArtist; } void MusicAudioTrack::setAlbumName(const QString &value) { d->mAlbumName = value; } QString MusicAudioTrack::albumName() const { return d->mAlbumName; } void MusicAudioTrack::setAlbumArtist(const QString &value) { d->mAlbumArtist = value; } QString MusicAudioTrack::albumArtist() const { return (d->mAlbumArtist.isEmpty() ? d->mArtist : d->mAlbumArtist); } bool MusicAudioTrack::isValidAlbumArtist() const { return !d->mAlbumArtist.isEmpty(); } void MusicAudioTrack::setAlbumCover(const QUrl &value) { d->mAlbumCover = value; } QUrl MusicAudioTrack::albumCover() const { if (d->mAlbumCover.isValid() || !hasEmbeddedCover()) { return d->mAlbumCover; } else { return QUrl(QStringLiteral("image://cover/") + d->mResourceURI.toLocalFile()); } } void MusicAudioTrack::setGenre(const QString &value) { d->mGenre = value; } QString MusicAudioTrack::genre() const { return d->mGenre; } void MusicAudioTrack::setComposer(const QString &value) { d->mComposer = value; } QString MusicAudioTrack::composer() const { return d->mComposer; } void MusicAudioTrack::setLyricist(const QString &value) { d->mLyricist = value; } QString MusicAudioTrack::lyricist() const { return d->mLyricist; } +void MusicAudioTrack::setLyrics(const QString &value) +{ + d->mLyrics = value; +} + +QString MusicAudioTrack::lyrics() const +{ + return d->mLyrics; +} + void MusicAudioTrack::setComment(const QString &value) { d->mComment = value; } QString MusicAudioTrack::comment() const { return d->mComment; } void MusicAudioTrack::setTrackNumber(int value) { d->mTrackNumber = value; d->mTrackNumberIsValid = true; } int MusicAudioTrack::trackNumber() const { return d->mTrackNumber; } bool MusicAudioTrack::trackNumberIsValid() const { return d->mTrackNumberIsValid; } void MusicAudioTrack::setDiscNumber(int value) { d->mDiscNumber = value; d->mDiscNumberIsValid = true; } int MusicAudioTrack::discNumber() const { return d->mDiscNumber; } bool MusicAudioTrack::discNumberIsValid() const { return d->mDiscNumberIsValid; } void MusicAudioTrack::setYear(int value) { d->mYear = value; } int MusicAudioTrack::year() const { return d->mYear; } void MusicAudioTrack::setChannels(int value) { d->mChannels = value; d->mChannelsIsValid = true; } int MusicAudioTrack::channels() const { return d->mChannels; } bool MusicAudioTrack::channelsIsValid() const { return d->mChannelsIsValid; } void MusicAudioTrack::setBitRate(int value) { d->mBitRate = value; d->mBitRateIsValid = true; } int MusicAudioTrack::bitRate() const { return d->mBitRate; } bool MusicAudioTrack::bitRateIsValid() const { return d->mBitRateIsValid; } void MusicAudioTrack::setSampleRate(int value) { d->mSampleRate = value; d->mSampleRateIsValid = true; } int MusicAudioTrack::sampleRate() const { return d->mSampleRate; } bool MusicAudioTrack::sampleRateIsValid() const { return d->mSampleRateIsValid; } void MusicAudioTrack::setDuration(QTime value) { d->mDuration = value; } QTime MusicAudioTrack::duration() const { return d->mDuration; } void MusicAudioTrack::setFileModificationTime(const QDateTime &value) { d->mFileModificationTime = value; } const QDateTime &MusicAudioTrack::fileModificationTime() const { return d->mFileModificationTime; } void MusicAudioTrack::setResourceURI(const QUrl &value) { d->mResourceURI = value; } const QUrl &MusicAudioTrack::resourceURI() const { return d->mResourceURI; } void MusicAudioTrack::setRating(int value) { d->mRating = value; } int MusicAudioTrack::rating() const { return d->mRating; } void MusicAudioTrack::setIsSingleDiscAlbum(bool value) { d->mIsSingleDiscAlbum = value; } bool MusicAudioTrack::isSingleDiscAlbum() const { return d->mIsSingleDiscAlbum; } void MusicAudioTrack::setHasEmbeddedCover(bool value) { d->mHasBooleanCover = value; } bool MusicAudioTrack::hasEmbeddedCover() const { return d->mHasBooleanCover; } MusicAudioTrack::TrackDataType MusicAudioTrack::toTrackData() const { auto result = MusicAudioTrack::TrackDataType{}; result[MusicAudioTrack::TrackDataType::key_type::DatabaseIdRole] = databaseId(); if (!title().isEmpty()) { result[MusicAudioTrack::TrackDataType::key_type::TitleRole] = title(); } if (!artist().isEmpty()) { result[MusicAudioTrack::TrackDataType::key_type::ArtistRole] = artist(); } if (!albumName().isEmpty()) { result[MusicAudioTrack::TrackDataType::key_type::AlbumRole] = albumName(); } if (!albumArtist().isEmpty()) { result[MusicAudioTrack::TrackDataType::key_type::AlbumArtistRole] = albumArtist(); } if (!genre().isEmpty()) { result[MusicAudioTrack::TrackDataType::key_type::GenreRole] = genre(); } if (!composer().isEmpty()) { result[MusicAudioTrack::TrackDataType::key_type::ComposerRole] = composer(); } if (!lyricist().isEmpty()) { result[MusicAudioTrack::TrackDataType::key_type::LyricistRole] = lyricist(); } if (!comment().isEmpty()) { result[MusicAudioTrack::TrackDataType::key_type::CommentRole] = comment(); } if (!albumCover().isEmpty()) { result[MusicAudioTrack::TrackDataType::key_type::ImageUrlRole] = albumCover(); } if (trackNumber() != -1) { result[MusicAudioTrack::TrackDataType::key_type::TrackNumberRole] = trackNumber(); } if (discNumber()) { result[MusicAudioTrack::TrackDataType::key_type::DiscNumberRole] = discNumber(); } if (year()) { result[MusicAudioTrack::TrackDataType::key_type::YearRole] = year(); } if (channels()) { result[MusicAudioTrack::TrackDataType::key_type::ChannelsRole] = channels(); } if (bitRate()) { result[MusicAudioTrack::TrackDataType::key_type::BitRateRole] = bitRate(); } if (sampleRate()) { result[MusicAudioTrack::TrackDataType::key_type::SampleRateRole] = sampleRate(); } if (!resourceURI().isEmpty()) { result[MusicAudioTrack::TrackDataType::key_type::ResourceRole] = resourceURI(); } if (rating()) { result[MusicAudioTrack::TrackDataType::key_type::RatingRole] = rating(); } if (duration().isValid()) { result[MusicAudioTrack::TrackDataType::key_type::DurationRole] = duration(); } return result; } ELISALIB_EXPORT QDebug operator<<(QDebug stream, const MusicAudioTrack &data) { stream << data.title() << data.artist() << data.albumName() << data.albumArtist() << data.duration() << data.resourceURI(); return stream; } diff --git a/src/musicaudiotrack.h b/src/musicaudiotrack.h index 26c1c8c5..f351da09 100644 --- a/src/musicaudiotrack.h +++ b/src/musicaudiotrack.h @@ -1,198 +1,202 @@ /* * Copyright 2016-2017 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef MUSICAUDIOTRACK_H #define MUSICAUDIOTRACK_H #include "elisaLib_export.h" #include "databaseinterface.h" #include #include #include #include #include #include class MusicAudioTrackPrivate; class QDebug; class ELISALIB_EXPORT MusicAudioTrack { public: using TrackDataType = DatabaseInterface::TrackDataType; MusicAudioTrack(); MusicAudioTrack(bool aValid, QString aId, QString aParentId, QString aTitle, QString aArtist, QString aAlbumName, QString aAlbumArtist, int aTrackNumber, int aDiscNumber, QTime aDuration, QUrl aResourceURI, const QDateTime &fileModificationTime, QUrl aAlbumCover, int rating, bool aIsSingleDiscAlbum, QString aGenre, QString aComposer, QString aLyricist, bool aHasEmbeddedCover); MusicAudioTrack(MusicAudioTrack &&other) noexcept; MusicAudioTrack(const MusicAudioTrack &other); ~MusicAudioTrack(); MusicAudioTrack& operator=(MusicAudioTrack &&other) noexcept; MusicAudioTrack& operator=(const MusicAudioTrack &other); bool operator <(const MusicAudioTrack &other) const; bool operator ==(const MusicAudioTrack &other) const; bool operator !=(const MusicAudioTrack &other) const; static MusicAudioTrack trackFromData(const DatabaseInterface::TrackDataType &data); void setValid(bool value); bool isValid() const; void setDatabaseId(qulonglong value); qulonglong databaseId() const; void setAlbumId(qulonglong value); qulonglong albumId() const; void setId(const QString &value); QString id() const; void setParentId(const QString &value); QString parentId() const; void setTitle(const QString &value); QString title() const; void setArtist(const QString &value); QString artist() const; void setAlbumName(const QString &value); QString albumName() const; void setAlbumArtist(const QString &value); QString albumArtist() const; void setGenre(const QString &value); QString genre() const; void setComposer(const QString &value); QString composer() const; void setLyricist(const QString &value); QString lyricist() const; + void setLyrics(const QString &value); + + QString lyrics() const; + void setComment(const QString &value); QString comment() const; bool isValidAlbumArtist() const; void setAlbumCover(const QUrl &value); QUrl albumCover() const; void setTrackNumber(int value); int trackNumber() const; bool trackNumberIsValid() const; void setDiscNumber(int value); int discNumber() const; bool discNumberIsValid() const; void setYear(int value); int year() const; void setChannels(int value); int channels() const; bool channelsIsValid() const; void setBitRate(int value); int bitRate() const; bool bitRateIsValid() const; void setSampleRate(int value); int sampleRate() const; bool sampleRateIsValid() const; void setDuration(QTime value); QTime duration() const; void setFileModificationTime(const QDateTime &value); const QDateTime &fileModificationTime() const; void setResourceURI(const QUrl &value); const QUrl& resourceURI() const; void setRating(int value); int rating() const; void setIsSingleDiscAlbum(bool value); bool isSingleDiscAlbum() const; void setHasEmbeddedCover(bool value); bool hasEmbeddedCover() const; TrackDataType toTrackData() const; private: QSharedDataPointer d; }; ELISALIB_EXPORT QDebug operator<<(QDebug stream, const MusicAudioTrack &data); Q_DECLARE_TYPEINFO(MusicAudioTrack, Q_MOVABLE_TYPE); Q_DECLARE_METATYPE(MusicAudioTrack) #endif // MUSICAUDIOTRACK_H