File indexing completed on 2025-01-19 04:24:24
0001 /**************************************************************************************** 0002 * Copyright (c) 2007 Maximilian Kossick <maximilian.kossick@googlemail.com> * 0003 * Copyright (c) 2007 Alexandre Pereira de Oliveira <aleprj@gmail.com> * 0004 * Copyright (c) 2010 Ralf Engels <ralf-engels@gmx.de> * 0005 * * 0006 * This program is free software; you can redistribute it and/or modify it under * 0007 * the terms of the GNU General Public License as published by the Free Software * 0008 * Foundation; either version 2 of the License, or (at your option) any later * 0009 * version. * 0010 * * 0011 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0012 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0013 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0014 * * 0015 * You should have received a copy of the GNU General Public License along with * 0016 * this program. If not, see <http://www.gnu.org/licenses/>. * 0017 ****************************************************************************************/ 0018 0019 #ifndef SQLMETA_H 0020 #define SQLMETA_H 0021 0022 #include "core/meta/Meta.h" 0023 #include "core/meta/Statistics.h" 0024 #include "core/meta/TrackEditor.h" 0025 #include "core/meta/support/MetaConstants.h" 0026 #include "amarok_sqlcollection_export.h" 0027 #include "FileType.h" 0028 0029 #include <QAtomicInt> 0030 #include <QByteArray> 0031 #include <QMutex> 0032 #include <QReadWriteLock> 0033 #include <QString> 0034 #include <QStringList> 0035 #include <QVariant> 0036 0037 namespace Capabilities { 0038 } 0039 0040 class SqlRegistry; 0041 class TrackUrlsTableCommitter; 0042 class TrackTracksTableCommitter; 0043 class TrackStatisticsTableCommitter; 0044 namespace Collections { 0045 class SqlCollection; 0046 } 0047 0048 class SqlScanResultProcessor; 0049 0050 namespace Meta 0051 { 0052 0053 /** The SqlTrack is a Meta::Track used by the SqlCollection. 0054 The SqlTrack has a couple of functions for writing values and also 0055 some functions for getting e.g. the track id used in the underlying database. 0056 However it is not recommended to interface with the database directly. 0057 0058 The whole class should be thread save. 0059 */ 0060 class AMAROK_SQLCOLLECTION_EXPORT SqlTrack : public Track, public Statistics, public TrackEditor 0061 { 0062 public: 0063 /** Creates a new SqlTrack without. 0064 * Note that the trackId and urlId are empty meaning that this track 0065 * has no database representation until it's written first by setting 0066 * some of the meta information. 0067 * It is advisable to set at least the path. 0068 */ 0069 SqlTrack( Collections::SqlCollection *collection, int deviceId, 0070 const QString &rpath, int directoryId, const QString &uidUrl ); 0071 SqlTrack( Collections::SqlCollection *collection, const QStringList &queryResult ); 0072 ~ SqlTrack() override; 0073 0074 QString name() const override; 0075 QString prettyName() const override; 0076 QUrl playableUrl() const override; 0077 QString prettyUrl() const override; 0078 QString uidUrl() const override; 0079 QString notPlayableReason() const override; 0080 0081 Meta::AlbumPtr album() const override; 0082 Meta::ArtistPtr artist() const override; 0083 Meta::ComposerPtr composer() const override; 0084 Meta::YearPtr year() const override; 0085 Meta::GenrePtr genre() const override; 0086 0087 QString type() const override; 0088 qreal bpm() const override; 0089 QString comment() const override; 0090 qint64 length() const override; 0091 int filesize() const override; 0092 int sampleRate() const override; 0093 int bitrate() const override; 0094 QDateTime createDate() const override; 0095 QDateTime modifyDate() const override; 0096 int trackNumber() const override; 0097 int discNumber() const override; 0098 qreal replayGain( Meta::ReplayGainTag mode ) const override; 0099 0100 bool inCollection() const override; 0101 Collections::Collection* collection() const override; 0102 0103 QString cachedLyrics() const override; 0104 void setCachedLyrics( const QString &lyrics ) override; 0105 0106 bool hasCapabilityInterface( Capabilities::Capability::Type type ) const override; 0107 Capabilities::Capability* createCapabilityInterface( Capabilities::Capability::Type type ) override; 0108 0109 void addLabel( const QString &label ) override; 0110 void addLabel( const Meta::LabelPtr &label ) override; 0111 void removeLabel( const Meta::LabelPtr &label ) override; 0112 Meta::LabelList labels() const override; 0113 0114 TrackEditorPtr editor() override; 0115 StatisticsPtr statistics() override; 0116 0117 // Meta::TrackEditor methods: 0118 void setAlbum( const QString &newAlbum ) override; 0119 void setAlbumArtist( const QString &newAlbumArtist ) override; 0120 void setArtist( const QString &newArtist ) override; 0121 void setComposer( const QString &newComposer ) override; 0122 void setGenre( const QString &newGenre ) override; 0123 void setYear( int newYear ) override; 0124 void setTitle( const QString &newTitle ) override; 0125 void setComment( const QString &newComment ) override; 0126 void setTrackNumber( int newTrackNumber ) override; 0127 void setDiscNumber( int newDiscNumber ) override; 0128 void setBpm( const qreal newBpm ) override; 0129 0130 // Meta::Statistics methods: 0131 double score() const override; 0132 void setScore( double newScore ) override; 0133 0134 int rating() const override; 0135 void setRating( int newRating ) override; 0136 0137 QDateTime firstPlayed() const override; 0138 void setFirstPlayed( const QDateTime &newTime ) override; 0139 0140 QDateTime lastPlayed() const override; 0141 void setLastPlayed( const QDateTime &newTime ) override; 0142 0143 int playCount() const override; 0144 void setPlayCount( const int newCount ) override; 0145 0146 // combined Meta::Statistics and Meta::TrackEditor methods: 0147 void beginUpdate() override; 0148 void endUpdate() override; 0149 0150 // SqlTrack specific methods 0151 /** true if there is a collection, the file exists on disk and is writable */ 0152 bool isEditable() const; 0153 0154 void setUidUrl( const QString &uid ); 0155 void setAlbum( int albumId ); 0156 void setType( Amarok::FileType newType ); 0157 void setLength( qint64 newLength ); 0158 void setSampleRate( int newSampleRate ); 0159 void setUrl( int deviceId, const QString &rpath, int directoryId ); 0160 void setBitrate( int newBitrate ); 0161 void setModifyDate( const QDateTime &newTime ); 0162 void setReplayGain( Meta::ReplayGainTag mode, qreal value ); 0163 0164 /** Enables or disables writing changes to the file. 0165 * This function can be useful when changes are imported from the file. 0166 * In such a case writing the changes back again is stupid. 0167 */ 0168 virtual void setWriteFile( const bool enable ) 0169 { m_writeFile = enable; } 0170 0171 int id() const; 0172 int urlId() const; 0173 Collections::SqlCollection* sqlCollection() const { return m_collection; } 0174 0175 /** Does it's best to remove the track from database. 0176 * Considered that there is no signal that says "I am now removed" 0177 * this function still tries it's best to notify everyone 0178 * That the track is now removed, plus it will also delete it from 0179 * the database. 0180 */ 0181 void remove(); 0182 0183 // SqlDatabase specific values 0184 0185 /** Some numbers used in SqlRegistry. 0186 * Update if getTrackReturnValues is updated. 0187 */ 0188 enum TrackReturnIndex 0189 { 0190 returnIndex_urlId = 0, 0191 returnIndex_urlDeviceId = 1, 0192 returnIndex_urlRPath = 2, 0193 returnIndex_urlUid = 4, 0194 returnIndex_trackId = 5 0195 }; 0196 0197 // SqlDatabase specific values 0198 0199 /** returns a string of all database values that can be fetched for a track */ 0200 static QString getTrackReturnValues(); 0201 /** returns the number of return values in getTrackReturnValues() */ 0202 static int getTrackReturnValueCount(); 0203 /** returns a string of all database joins that are required to fetch all values for a track*/ 0204 static QString getTrackJoinConditions(); 0205 0206 0207 protected: 0208 /** 0209 * Will commit all changes in m_cache if m_batch == 0. Must be called with m_lock 0210 * locked for writing. 0211 * 0212 * commitIfInNonBatchUpdate() will do three things: 0213 * 1. It will update the member variables. 0214 * 2. It will call all write methods 0215 * 3. It will notify all observers and the collection about the changes. 0216 */ 0217 void commitIfInNonBatchUpdate( qint64 field, const QVariant &value ); 0218 void commitIfInNonBatchUpdate(); 0219 0220 void updatePlaylistsToDb( const FieldHash &fields, const QString &oldUid ); 0221 void updateEmbeddedCoversToDb( const FieldHash &fields, const QString &oldUid ); 0222 0223 private: 0224 //helper functions 0225 static QString prettyTitle( const QString &filename ); 0226 0227 Collections::SqlCollection* const m_collection; 0228 0229 QString m_title; 0230 0231 // the url table 0232 int m_urlId; 0233 int m_deviceId; 0234 QString m_rpath; 0235 int m_directoryId; // only set when the urls table needs to be written 0236 QUrl m_url; 0237 QString m_uid; 0238 0239 // the rest 0240 int m_trackId; 0241 int m_statisticsId; 0242 0243 qint64 m_length; 0244 qint64 m_filesize; 0245 int m_trackNumber; 0246 int m_discNumber; 0247 QDateTime m_lastPlayed; 0248 QDateTime m_firstPlayed; 0249 int m_playCount; 0250 int m_bitrate; 0251 int m_sampleRate; 0252 int m_rating; 0253 double m_score; 0254 QString m_comment; 0255 qreal m_bpm; 0256 qreal m_albumGain; 0257 qreal m_albumPeakGain; 0258 qreal m_trackGain; 0259 qreal m_trackPeakGain; 0260 QDateTime m_createDate; 0261 QDateTime m_modifyDate; 0262 0263 Meta::AlbumPtr m_album; 0264 Meta::ArtistPtr m_artist; 0265 Meta::GenrePtr m_genre; 0266 Meta::ComposerPtr m_composer; 0267 Meta::YearPtr m_year; 0268 0269 Amarok::FileType m_filetype; 0270 0271 /** 0272 * Number of current batch operations started by @see beginUpdate() and not 0273 * yet ended by @see endUpdate(). Must only be accessed with m_lock held. 0274 */ 0275 int m_batchUpdate; 0276 bool m_writeFile; 0277 bool m_writeAllStatisticsFields; 0278 FieldHash m_cache; 0279 0280 /** This ReadWriteLock is protecting all internal variables. 0281 It is ensuring that m_cache, m_batchUpdate and the other internal variable are 0282 in a consistent state all the time. 0283 */ 0284 mutable QReadWriteLock m_lock; 0285 0286 mutable bool m_labelsInCache; 0287 mutable Meta::LabelList m_labelsCache; 0288 0289 friend class ::SqlRegistry; // needs to call notifyObservers 0290 friend class ::TrackUrlsTableCommitter; 0291 friend class ::TrackTracksTableCommitter; 0292 friend class ::TrackStatisticsTableCommitter; 0293 }; 0294 0295 class AMAROK_SQLCOLLECTION_EXPORT SqlArtist : public Meta::Artist 0296 { 0297 public: 0298 SqlArtist( Collections::SqlCollection* collection, int id, const QString &name ); 0299 ~SqlArtist() override; 0300 0301 QString name() const override { return m_name; } 0302 0303 virtual void invalidateCache(); 0304 0305 Meta::TrackList tracks() override; 0306 0307 bool hasCapabilityInterface( Capabilities::Capability::Type type ) const override; 0308 0309 Capabilities::Capability* createCapabilityInterface( Capabilities::Capability::Type type ) override; 0310 0311 //SQL specific methods 0312 int id() const { return m_id; } 0313 private: 0314 Collections::SqlCollection* const m_collection; 0315 const int m_id; 0316 const QString m_name; 0317 0318 bool m_tracksLoaded; 0319 Meta::TrackList m_tracks; 0320 QMutex m_mutex; 0321 0322 friend class ::SqlRegistry; // needs to call notifyObservers 0323 friend class Meta::SqlTrack; // needs to call notifyObservers 0324 }; 0325 0326 /** Represents an albums stored in the database. 0327 Note: The album without name is special. It will always be a compilation 0328 and never have a picture. 0329 */ 0330 class AMAROK_SQLCOLLECTION_EXPORT SqlAlbum : public Meta::Album 0331 { 0332 public: 0333 SqlAlbum( Collections::SqlCollection* collection, int id, const QString &name, int artist ); 0334 ~SqlAlbum() override; 0335 0336 QString name() const override { return m_name; } 0337 0338 virtual void invalidateCache(); 0339 0340 Meta::TrackList tracks() override; 0341 0342 bool isCompilation() const override; 0343 bool canUpdateCompilation() const override { return true; } 0344 void setCompilation( bool compilation ) override; 0345 0346 /** Returns true if this album has an artist. 0347 * The following equation is always true: isCompilation() != hasAlbumArtist() 0348 */ 0349 bool hasAlbumArtist() const override; 0350 0351 /** Returns the album artist. 0352 * Note that setting the album artist is not supported. 0353 * A compilation does not have an artist and not only an empty artist. 0354 */ 0355 Meta::ArtistPtr albumArtist() const override; 0356 0357 //updating album images is possible for local tracks, but let's ignore it for now 0358 0359 /** Returns true if the album has a cover image. 0360 * @param size The maximum width or height of the result. 0361 * when size is <= 1, return the full size image 0362 */ 0363 bool hasImage(int size = 0) const override; 0364 bool canUpdateImage() const override { return true; } 0365 0366 /** Returns the album cover image. 0367 * Returns a default image if no specific album image could be found. 0368 * In such a case it will start the cover fetcher. 0369 * 0370 * @param size is the maximum width or height of the resulting image. 0371 * when size is <= 1, return the full size image 0372 */ 0373 QImage image( int size = 0 ) const override; 0374 0375 QUrl imageLocation( int size = 0 ) override; 0376 void setImage( const QImage &image ) override; 0377 void removeImage() override; 0378 void setSuppressImageAutoFetch( const bool suppress ) override { m_suppressAutoFetch = suppress; } 0379 bool suppressImageAutoFetch() const override { return m_suppressAutoFetch; } 0380 0381 bool hasCapabilityInterface( Capabilities::Capability::Type type ) const override; 0382 0383 Capabilities::Capability* createCapabilityInterface( Capabilities::Capability::Type type ) override; 0384 0385 //SQL specific methods 0386 int id() const { return m_id; } 0387 0388 Collections::SqlCollection *sqlCollection() const { return m_collection; } 0389 0390 private: 0391 QByteArray md5sum( const QString& artist, const QString& album, const QString& file ) const; 0392 0393 /** Returns a unique key for the album cover. */ 0394 QByteArray imageKey() const; 0395 0396 /** Returns the path that the large scale image should have on the disk 0397 * Does not check if the file exists. 0398 * Note: not all large images have a disk cache, e.g. if they are set from outside 0399 * or embedded inside an audio file. 0400 * The largeDiskCache is only used for images set via setImage(QImage) 0401 */ 0402 QString largeDiskCachePath() const; 0403 0404 /** Returns the path that the image should have on the disk 0405 * Does not check if the file exists. 0406 * @param size is the maximum width or height of the resulting image. 0407 * size==0 is the large image and the location of this file is completely different. 0408 * there should never be a scaled cached version of the large image. it dose not make 0409 * sense. 0410 */ 0411 QString scaledDiskCachePath( int size ) const; 0412 0413 /** Returns the path to the large image 0414 * Queries the database for the path of the large scale image. 0415 */ 0416 QString largeImagePath(); 0417 0418 /** Updates the database 0419 * Sets the current albums image to the given path. 0420 * The path should point to a valid image. 0421 * Note: setImage will not delete the already set image. 0422 */ 0423 void setImage( const QString &path ); 0424 0425 /** Finds or creates a magic value in the database which tells Amarok not to auto fetch an image since it has been explicitly unset. 0426 */ 0427 int unsetImageId() const; 0428 0429 Collections::SqlCollection* const m_collection; 0430 0431 enum TracksLoadingStatus 0432 { 0433 NotLoaded, 0434 Loading, 0435 Loaded 0436 }; 0437 0438 const QString m_name; 0439 const int m_id; // the id of this album in the database 0440 const int m_artistId; 0441 int m_imageId; 0442 mutable QString m_imagePath; // path read from the database 0443 mutable bool m_hasImage; // true if we have an original image 0444 mutable bool m_hasImageChecked; // true if hasImage was checked 0445 0446 mutable int m_unsetImageId; // this is the id of the unset magic value in the image sql database 0447 static const QString AMAROK_UNSET_MAGIC; 0448 0449 TracksLoadingStatus m_tracksLoaded; 0450 bool m_suppressAutoFetch; 0451 Meta::ArtistPtr m_artist; 0452 Meta::TrackList m_tracks; 0453 mutable QMutex m_mutex; 0454 0455 //TODO: add album artist 0456 0457 friend class ::SqlRegistry; // needs to call notifyObservers 0458 friend class Meta::SqlTrack; // needs to set images directly 0459 friend class ::SqlScanResultProcessor; // needs to set images directly 0460 }; 0461 0462 class AMAROK_SQLCOLLECTION_EXPORT SqlComposer : public Meta::Composer 0463 { 0464 public: 0465 SqlComposer( Collections::SqlCollection* collection, int id, const QString &name ); 0466 0467 QString name() const override { return m_name; } 0468 0469 virtual void invalidateCache(); 0470 0471 Meta::TrackList tracks() override; 0472 0473 //SQL specific methods 0474 int id() const { return m_id; } 0475 0476 private: 0477 Collections::SqlCollection* const m_collection; 0478 0479 const int m_id; 0480 const QString m_name; 0481 0482 bool m_tracksLoaded; 0483 bool m_tracksLoading; 0484 Meta::TrackList m_tracks; 0485 QMutex m_mutex; 0486 0487 friend class ::SqlRegistry; // needs to call notifyObservers 0488 friend class Meta::SqlTrack; // needs to call notifyObservers 0489 }; 0490 0491 class SqlGenre : public Meta::Genre 0492 { 0493 public: 0494 SqlGenre( Collections::SqlCollection* collection, int id, const QString &name ); 0495 0496 QString name() const override { return m_name; } 0497 0498 /** Invalidates the tracks cache */ 0499 /** Invalidates the tracks cache */ 0500 virtual void invalidateCache(); 0501 0502 Meta::TrackList tracks() override; 0503 0504 //SQL specific methods 0505 int id() const { return m_id; } 0506 0507 private: 0508 Collections::SqlCollection* const m_collection; 0509 0510 const int m_id; 0511 const QString m_name; 0512 0513 bool m_tracksLoaded; 0514 Meta::TrackList m_tracks; 0515 QMutex m_mutex; 0516 0517 friend class ::SqlRegistry; // needs to call notifyObservers 0518 friend class Meta::SqlTrack; // needs to call notifyObservers 0519 }; 0520 0521 class AMAROK_SQLCOLLECTION_EXPORT SqlYear : public Meta::Year 0522 { 0523 public: 0524 SqlYear( Collections::SqlCollection* collection, int id, int year ); 0525 0526 QString name() const override { return QString::number(m_year); } 0527 0528 int year() const override { return m_year; } 0529 0530 /** Invalidates the tracks cache */ 0531 virtual void invalidateCache(); 0532 0533 Meta::TrackList tracks() override; 0534 0535 //SQL specific methods 0536 int id() const { return m_id; } 0537 0538 private: 0539 Collections::SqlCollection* const m_collection; 0540 const int m_id; 0541 const int m_year; 0542 0543 0544 bool m_tracksLoaded; 0545 Meta::TrackList m_tracks; 0546 QMutex m_mutex; 0547 0548 friend class ::SqlRegistry; // needs to call notifyObservers 0549 friend class Meta::SqlTrack; // needs to call notifyObservers 0550 }; 0551 0552 class AMAROK_SQLCOLLECTION_EXPORT SqlLabel : public Meta::Label 0553 { 0554 public: 0555 SqlLabel( Collections::SqlCollection *collection, int id, const QString &name ); 0556 0557 QString name() const override { return m_name; } 0558 0559 /** Invalidates the tracks cache */ 0560 virtual void invalidateCache(); 0561 0562 virtual Meta::TrackList tracks(); 0563 0564 //SQL specific methods 0565 int id() const { return m_id; } 0566 0567 private: 0568 Collections::SqlCollection* const m_collection; 0569 const int m_id; 0570 const QString m_name; 0571 0572 bool m_tracksLoaded; 0573 Meta::TrackList m_tracks; 0574 QMutex m_mutex; 0575 0576 friend class ::SqlRegistry; // needs to call notifyObservers 0577 friend class Meta::SqlTrack; // needs to call notifyObservers 0578 }; 0579 0580 typedef AmarokSharedPointer<SqlTrack> SqlTrackPtr; 0581 typedef AmarokSharedPointer<SqlArtist> SqlArtistPtr; 0582 typedef AmarokSharedPointer<SqlAlbum> SqlAlbumPtr; 0583 typedef AmarokSharedPointer<SqlComposer> SqlComposerPtr; 0584 typedef AmarokSharedPointer<SqlGenre> SqlGenrePtr; 0585 typedef AmarokSharedPointer<SqlYear> SqlYearPtr; 0586 0587 } 0588 0589 #endif /* SQLMETA_H */