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 */