1 /* This file is part of Clementine.
2    Copyright 2009-2012, David Sansome <me@davidsansome.com>
3    Copyright 2010-2011, Paweł Bara <keirangtp@gmail.com>
4    Copyright 2010, 2012, 2014, John Maguire <john.maguire@gmail.com>
5    Copyright 2011-2012, 2014, Arnaud Bienner <arnaud.bienner@gmail.com>
6    Copyright 2011, Angus Gratton <gus@projectgus.com>
7    Copyright 2012, Kacper "mattrick" Banasik <mattrick@jabster.pl>
8    Copyright 2013, Martin Brodbeck <martin@brodbeck-online.de>
9    Copyright 2013, Joel Bradshaw <cincodenada@gmail.com>
10    Copyright 2013, Uwe Klotz <uwe.klotz@gmail.com>
11    Copyright 2013, Mateusz Kowalczyk <fuuzetsu@fuuzetsu.co.uk>
12    Copyright 2014, Andreas <asfa194@gmail.com>
13    Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
14 
15    Clementine is free software: you can redistribute it and/or modify
16    it under the terms of the GNU General Public License as published by
17    the Free Software Foundation, either version 3 of the License, or
18    (at your option) any later version.
19 
20    Clementine is distributed in the hope that it will be useful,
21    but WITHOUT ANY WARRANTY; without even the implied warranty of
22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23    GNU General Public License for more details.
24 
25    You should have received a copy of the GNU General Public License
26    along with Clementine.  If not, see <http://www.gnu.org/licenses/>.
27 */
28 
29 #ifndef CORE_SONG_H_
30 #define CORE_SONG_H_
31 
32 #include <QImage>
33 #include <QMetaType>
34 #include <QSharedDataPointer>
35 #include <QVariantMap>
36 
37 #include "config.h"
38 #include "engines/engine_fwd.h"
39 
40 namespace pb {
41 namespace tagreader {
42 class SongMetadata;
43 }  // namespace tagreader
44 }  // namespace pb
45 
46 class QSqlQuery;
47 class QUrl;
48 
49 #ifdef HAVE_LIBGPOD
50 struct _Itdb_Track;
51 #endif
52 
53 #ifdef HAVE_LIBMTP
54 struct LIBMTP_track_struct;
55 #endif
56 
57 #ifdef HAVE_LIBLASTFM
58 namespace lastfm {
59 class Track;
60 }
61 #endif
62 
63 class SqlRow;
64 
65 class Song {
66  public:
67   Song();
68   Song(const Song& other);
69   ~Song();
70 
71   static const QStringList kColumns;
72   static const QString kColumnSpec;
73   static const QString kBindSpec;
74   static const QString kUpdateSpec;
75 
76   static const QStringList kIntColumns;
77   static const QStringList kFloatColumns;
78   static const QStringList kDateColumns;
79 
80   static const QStringList kFtsColumns;
81   static const QString kFtsColumnSpec;
82   static const QString kFtsBindSpec;
83   static const QString kFtsUpdateSpec;
84 
85   static const QString kManuallyUnsetCover;
86   static const QString kEmbeddedCover;
87 
88   static QString JoinSpec(const QString& table);
89 
90   // Don't change these values - they're stored in the database, and defined
91   // in the tag reader protobuf.
92   // If a new lossless file is added, also add it to IsFileLossless().
93   enum FileType {
94     Type_Unknown = 0,
95     Type_Asf = 1,
96     Type_Flac = 2,
97     Type_Mp4 = 3,
98     Type_Mpc = 4,
99     Type_Mpeg = 5,
100     Type_OggFlac = 6,
101     Type_OggSpeex = 7,
102     Type_OggVorbis = 8,
103     Type_Aiff = 9,
104     Type_Wav = 10,
105     Type_TrueAudio = 11,
106     Type_Cdda = 12,
107     Type_OggOpus = 13,
108     Type_WavPack = 14,
109     Type_Spc = 15,
110     Type_VGM = 16,
111     Type_APE = 17,
112     Type_Stream = 99,
113   };
114   static QString TextForFiletype(FileType type);
TextForFiletype()115   QString TextForFiletype() const { return TextForFiletype(filetype()); }
116   bool IsFileLossless() const;
117 
118   // Sort songs alphabetically using their pretty title
119   static void SortSongsListAlphabetically(QList<Song>* songs);
120 
121   // Constructors
122   void Init(const QString& title, const QString& artist, const QString& album,
123             qint64 length_nanosec);
124   void Init(const QString& title, const QString& artist, const QString& album,
125             qint64 beginning, qint64 end);
126   void InitFromProtobuf(const pb::tagreader::SongMetadata& pb);
127   void InitFromQuery(const SqlRow& query, bool reliable_metadata, int col = 0);
128   void InitFromFilePartial(
129       const QString& filename);  // Just store the filename: incomplete but fast
130   void InitArtManual();  // Check if there is already a art in the cache and
131                          // store the filename in art_manual
132 #ifdef HAVE_LIBLASTFM
133   void InitFromLastFM(const lastfm::Track& track);
134 #endif
135 
136   void MergeFromSimpleMetaBundle(const Engine::SimpleMetaBundle& bundle);
137 
138 #ifdef HAVE_LIBGPOD
139   void InitFromItdb(const _Itdb_Track* track, const QString& prefix);
140   void ToItdb(_Itdb_Track* track) const;
141 #endif
142 
143 #ifdef HAVE_LIBMTP
144   void InitFromMTP(const LIBMTP_track_struct* track, const QString& host);
145   void ToMTP(LIBMTP_track_struct* track) const;
146 #endif
147 
148   // Copies important statistics from the other song to this one, overwriting
149   // any data that already exists.  Useful when you want updated tags from disk
150   // but you want to keep user stats.
151   void MergeUserSetData(const Song& other);
152 
153   static QString Decode(const QString& tag, const QTextCodec* codec = nullptr);
154 
155   // Save
156   void BindToQuery(QSqlQuery* query) const;
157   void BindToFtsQuery(QSqlQuery* query) const;
158 #ifdef HAVE_LIBLASTFM
159   void ToLastFM(lastfm::Track* track, bool prefer_album_artist) const;
160 #endif
161   void ToXesam(QVariantMap* map) const;
162   void ToProtobuf(pb::tagreader::SongMetadata* pb) const;
163 
164   // Simple accessors
165   bool is_valid() const;
166   bool is_unavailable() const;
167   int id() const;
168 
169   const QString& title() const;
170   const QString& album() const;
171   const QString& effective_album() const;
172   const QString& artist() const;
173   const QString& albumartist() const;
174   const QString& effective_albumartist() const;
175   // Playlist views are special because you don't want to fill in album artists
176   // automatically for
177   // compilations, but you do for normal albums:
178   const QString& playlist_albumartist() const;
179   const QString& composer() const;
180   const QString& performer() const;
181   const QString& grouping() const;
182   const QString& lyrics() const;
183   int track() const;
184   int disc() const;
185   float bpm() const;
186   int year() const;
187   int originalyear() const;
188   int effective_originalyear() const;
189   const QString& genre() const;
190   const QString& comment() const;
191   bool is_compilation() const;
192   float rating() const;
193   int playcount() const;
194   int skipcount() const;
195   int lastplayed() const;
196   int score() const;
197   int album_id() const;
198 
199   const QString& cue_path() const;
200   bool has_cue() const;
201 
202   qint64 beginning_nanosec() const;
203   qint64 end_nanosec() const;
204 
205   qint64 length_nanosec() const;
206 
207   int bitrate() const;
208   int samplerate() const;
209 
210   int directory_id() const;
211   const QUrl& url() const;
212   const QString& basefilename() const;
213   uint mtime() const;
214   uint ctime() const;
215   int filesize() const;
216   FileType filetype() const;
217   bool is_stream() const;
218   bool is_cdda() const;
219   // Guess if it is a library song using fields set. Might not be 100% reliable.
220   bool is_library_song() const;
221 
222   const QString& art_automatic() const;
223   const QString& art_manual() const;
224 
225   const QString& etag() const;
226 
227   // Returns true if this Song had it's cover manually unset by user.
228   bool has_manually_unset_cover() const;
229   // This method represents an explicit request to unset this song's
230   // cover.
231   void manually_unset_cover();
232 
233   // Returns true if this song (it's media file) has an embedded cover.
234   bool has_embedded_cover() const;
235   // Sets a flag saying that this song (it's media file) has an embedded
236   // cover.
237   void set_embedded_cover();
238 
239   const QImage& image() const;
240 
241   // Pretty accessors
242   QString PrettyRating() const;
243   QString PrettyTitle() const;
244   QString PrettyTitleWithArtist() const;
245   QString PrettyLength() const;
246   QString PrettyYear() const;
247 
248   QString TitleWithCompilationArtist() const;
249 
250   // Setters
251   bool IsEditable() const;
252 
253   void set_id(int id);
254   void set_valid(bool v);
255   void set_title(const QString& v);
256 
257   void set_album(const QString& v);
258   void set_artist(const QString& v);
259   void set_albumartist(const QString& v);
260   void set_composer(const QString& v);
261   void set_performer(const QString& v);
262   void set_grouping(const QString& v);
263   void set_lyrics(const QString& v);
264   void set_track(int v);
265   void set_disc(int v);
266   void set_bpm(float v);
267   void set_year(int v);
268   void set_originalyear(int v);
269   void set_genre(const QString& v);
270   void set_genre_id3(int id);
271   void set_comment(const QString& v);
272   void set_compilation(bool v);
273   void set_sampler(bool v);
274   void set_album_id(int v);
275   void set_beginning_nanosec(qint64 v);
276   void set_end_nanosec(qint64 v);
277   void set_length_nanosec(qint64 v);
278   void set_bitrate(int v);
279   void set_samplerate(int v);
280   void set_mtime(int v);
281   void set_ctime(int v);
282   void set_filesize(int v);
283   void set_filetype(FileType v);
284   void set_art_automatic(const QString& v);
285   void set_art_manual(const QString& v);
286   void set_image(const QImage& i);
287   void set_forced_compilation_on(bool v);
288   void set_forced_compilation_off(bool v);
289   void set_rating(float v);
290   void set_playcount(int v);
291   void set_skipcount(int v);
292   void set_lastplayed(int v);
293   void set_score(int v);
294   void set_cue_path(const QString& v);
295   void set_unavailable(bool v);
296   void set_etag(const QString& etag);
297 
298   // Setters that should only be used by tests
299   void set_url(const QUrl& v);
300   void set_basefilename(const QString& v);
301   void set_directory_id(int v);
302 
303   // Comparison functions
304   bool IsMetadataEqual(const Song& other) const;
305   bool IsOnSameAlbum(const Song& other) const;
306   bool IsSimilar(const Song& other) const;
307 
308   bool operator==(const Song& other) const;
309 
310   // Two songs that are on the same album will have the same AlbumKey.  It is
311   // more efficient to use IsOnSameAlbum, but this function can be used when
312   // you need to hash the key to do fast lookups.
313   QString AlbumKey() const;
314 
315   Song& operator=(const Song& other);
316 
317  private:
318   struct Private;
319   QSharedDataPointer<Private> d;
320 };
321 Q_DECLARE_METATYPE(Song)
322 
323 typedef QList<Song> SongList;
324 Q_DECLARE_METATYPE(QList<Song>)
325 
326 uint qHash(const Song& song);
327 // Hash function using field checked in IsSimilar function
328 uint HashSimilar(const Song& song);
329 
330 #endif  // CORE_SONG_H_
331