1 /* 2 * Strawberry Music Player 3 * This file was part of Clementine. 4 * Copyright 2010, David Sansome <me@davidsansome.com> 5 * Copyright 2018-2021, Jonas Kvinge <jonas@jkvinge.net> 6 * 7 * Strawberry is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation, either version 3 of the License, or 10 * (at your option) any later version. 11 * 12 * Strawberry is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with Strawberry. If not, see <http://www.gnu.org/licenses/>. 19 * 20 */ 21 22 #ifndef SONG_H 23 #define SONG_H 24 25 #include "config.h" 26 27 #include <QtGlobal> 28 #include <QSharedData> 29 #include <QSharedDataPointer> 30 #include <QMetaType> 31 #include <QList> 32 #include <QSet> 33 #include <QMap> 34 #include <QVariant> 35 #include <QString> 36 #include <QStringList> 37 #include <QRegularExpression> 38 #include <QUrl> 39 #include <QFileInfo> 40 #include <QImage> 41 #include <QIcon> 42 43 class SqlQuery; 44 45 namespace Engine { 46 struct SimpleMetaBundle; 47 } // namespace Engine 48 49 namespace spb { 50 namespace tagreader { 51 class SongMetadata; 52 } // namespace tagreader 53 } // namespace spb 54 55 #ifdef HAVE_LIBGPOD 56 struct _Itdb_Track; 57 #endif 58 59 #ifdef HAVE_LIBMTP 60 struct LIBMTP_track_struct; 61 #endif 62 63 class SqlRow; 64 65 class Song { 66 67 public: 68 69 enum Source { 70 Source_Unknown = 0, 71 Source_LocalFile = 1, 72 Source_Collection = 2, 73 Source_CDDA = 3, 74 Source_Device = 4, 75 Source_Stream = 5, 76 Source_Tidal = 6, 77 Source_Subsonic = 7, 78 Source_Qobuz = 8, 79 Source_SomaFM = 9, 80 Source_RadioParadise = 10 81 }; 82 83 // Don't change these values - they're stored in the database, and defined in the tag reader protobuf. 84 // If a new lossless file is added, also add it to IsFileLossless(). 85 86 enum FileType { 87 FileType_Unknown = 0, 88 FileType_WAV = 1, 89 FileType_FLAC = 2, 90 FileType_WavPack = 3, 91 FileType_OggFlac = 4, 92 FileType_OggVorbis = 5, 93 FileType_OggOpus = 6, 94 FileType_OggSpeex = 7, 95 FileType_MPEG = 8, 96 FileType_MP4 = 9, 97 FileType_ASF = 10, 98 FileType_AIFF = 11, 99 FileType_MPC = 12, 100 FileType_TrueAudio = 13, 101 FileType_DSF = 14, 102 FileType_DSDIFF = 15, 103 FileType_PCM = 16, 104 FileType_APE = 17, 105 FileType_MOD = 18, 106 FileType_S3M = 19, 107 FileType_XM = 20, 108 FileType_IT = 21, 109 FileType_CDDA = 90, 110 FileType_Stream = 91, 111 }; 112 113 Song(Song::Source source = Song::Source_Unknown); 114 Song(const Song &other); 115 ~Song(); 116 117 static const QStringList kColumns; 118 static const QString kColumnSpec; 119 static const QString kBindSpec; 120 static const QString kUpdateSpec; 121 122 static const QStringList kFtsColumns; 123 static const QString kFtsColumnSpec; 124 static const QString kFtsBindSpec; 125 static const QString kFtsUpdateSpec; 126 127 static const QString kManuallyUnsetCover; 128 static const QString kEmbeddedCover; 129 130 static const QRegularExpression kAlbumRemoveDisc; 131 static const QRegularExpression kAlbumRemoveMisc; 132 static const QRegularExpression kTitleRemoveMisc; 133 134 static const QString kVariousArtists; 135 136 static const QStringList kArticles; 137 138 static const QStringList kAcceptedExtensions; 139 140 static QString JoinSpec(const QString &table); 141 142 static Source SourceFromURL(const QUrl &url); 143 static QString TextForSource(Source source); 144 static QString DescriptionForSource(Source source); 145 static Song::Source SourceFromText(const QString &source); 146 static QIcon IconForSource(Source source); 147 static QString TextForFiletype(FileType filetype); 148 static QString ExtensionForFiletype(FileType filetype); 149 static QIcon IconForFiletype(FileType filetype); 150 TextForSource()151 QString TextForSource() const { return TextForSource(source()); } DescriptionForSource()152 QString DescriptionForSource() const { return DescriptionForSource(source()); } IconForSource()153 QIcon IconForSource() const { return IconForSource(source()); } TextForFiletype()154 QString TextForFiletype() const { return TextForFiletype(filetype()); } IconForFiletype()155 QIcon IconForFiletype() const { return IconForFiletype(filetype()); } 156 157 bool IsFileLossless() const; 158 static FileType FiletypeByMimetype(const QString &mimetype); 159 static FileType FiletypeByDescription(const QString &text); 160 static FileType FiletypeByExtension(const QString &ext); 161 static QString ImageCacheDir(const Song::Source source); 162 163 // Sort songs alphabetically using their pretty title 164 static int CompareSongsName(const Song &song1, const Song &song2); 165 static void SortSongsListAlphabetically(QList<Song> *songs); 166 167 // Constructors 168 void Init(const QString &title, const QString &artist, const QString &album, qint64 length_nanosec); 169 void Init(const QString &title, const QString &artist, const QString &album, qint64 beginning, qint64 end); 170 void InitFromProtobuf(const spb::tagreader::SongMetadata &pb); 171 void InitFromQuery(const SqlRow &query, bool reliable_metadata, int col = 0); 172 void InitFromFilePartial(const QString &filename, const QFileInfo &fileinfo); 173 void InitArtManual(); 174 void InitArtAutomatic(); 175 176 bool MergeFromSimpleMetaBundle(const Engine::SimpleMetaBundle &bundle); 177 178 #ifdef HAVE_LIBGPOD 179 void InitFromItdb(_Itdb_Track *track, const QString &prefix); 180 void ToItdb(_Itdb_Track *track) const; 181 #endif 182 183 #ifdef HAVE_LIBMTP 184 void InitFromMTP(const LIBMTP_track_struct *track, const QString &host); 185 void ToMTP(LIBMTP_track_struct *track) const; 186 #endif 187 188 // Copies important statistics from the other song to this one, overwriting any data that already exists. 189 // Useful when you want updated tags from disk but you want to keep user stats. 190 void MergeUserSetData(const Song &other); 191 192 // Save 193 void BindToQuery(SqlQuery *query) const; 194 void BindToFtsQuery(SqlQuery *query) const; 195 void ToXesam(QVariantMap *map) const; 196 void ToProtobuf(spb::tagreader::SongMetadata *pb) const; 197 198 // Simple accessors 199 bool is_valid() const; 200 bool is_unavailable() const; 201 int id() const; 202 203 const QString &title() const; 204 const QString &title_sortable() const; 205 const QString &album() const; 206 const QString &album_sortable() const; 207 const QString &artist() const; 208 const QString &artist_sortable() const; 209 const QString &albumartist() const; 210 const QString &albumartist_sortable() const; 211 int track() const; 212 int disc() const; 213 int year() const; 214 int originalyear() const; 215 const QString &genre() const; 216 bool compilation() const; 217 const QString &composer() const; 218 const QString &performer() const; 219 const QString &grouping() const; 220 const QString &comment() const; 221 const QString &lyrics() const; 222 223 QString artist_id() const; 224 QString album_id() const; 225 QString song_id() const; 226 227 qint64 beginning_nanosec() const; 228 qint64 end_nanosec() const; 229 qint64 length_nanosec() const; 230 231 int bitrate() const; 232 int samplerate() const; 233 int bitdepth() const; 234 235 Source source() const; 236 int directory_id() const; 237 const QUrl &url() const; 238 const QString &basefilename() const; 239 FileType filetype() const; 240 int filesize() const; 241 qint64 mtime() const; 242 qint64 ctime() const; 243 244 QString fingerprint() const; 245 246 int playcount() const; 247 int skipcount() const; 248 qint64 lastplayed() const; 249 qint64 lastseen() const; 250 251 bool compilation_detected() const; 252 bool compilation_off() const; 253 bool compilation_on() const; 254 255 const QUrl &art_automatic() const; 256 const QUrl &art_manual() const; 257 258 const QString &cue_path() const; 259 bool has_cue() const; 260 261 double rating() const; 262 263 const QString &effective_album() const; 264 int effective_originalyear() const; 265 const QString &effective_albumartist() const; 266 const QString &effective_albumartist_sortable() const; 267 268 bool is_collection_song() const; 269 bool is_stream() const; 270 bool is_radio() const; 271 bool is_cdda() const; 272 bool is_metadata_good() const; 273 bool art_automatic_is_valid() const; 274 bool art_manual_is_valid() const; 275 bool has_valid_art() const; 276 bool is_compilation() const; 277 bool stream_url_can_expire() const; 278 bool is_module_music() const; 279 280 // Playlist views are special because you don't want to fill in album artists automatically for compilations, but you do for normal albums: 281 const QString &playlist_albumartist() const; 282 const QString &playlist_albumartist_sortable() const; 283 284 // Returns true if this Song had it's cover manually unset by user. 285 bool has_manually_unset_cover() const; 286 // This method represents an explicit request to unset this song's cover. 287 void set_manually_unset_cover(); 288 289 // Returns true if this song (it's media file) has an embedded cover. 290 bool has_embedded_cover() const; 291 // Sets a flag saying that this song (it's media file) has an embedded cover. 292 void set_embedded_cover(); 293 294 void clear_art_automatic(); 295 void clear_art_manual(); 296 297 static bool save_embedded_cover_supported(const FileType filetype); save_embedded_cover_supported()298 bool save_embedded_cover_supported() const { return url().isLocalFile() && save_embedded_cover_supported(filetype()) && !has_cue(); }; 299 300 const QUrl &stream_url() const; 301 const QUrl &effective_stream_url() const; 302 const QImage &image() const; 303 bool init_from_file() const; 304 305 // Pretty accessors 306 QString PrettyTitle() const; 307 QString PrettyTitleWithArtist() const; 308 QString PrettyLength() const; 309 QString PrettyYear() const; 310 QString PrettyOriginalYear() const; 311 312 QString TitleWithCompilationArtist() const; 313 314 QString SampleRateBitDepthToText() const; 315 316 QString PrettyRating() const; 317 318 // Setters 319 bool IsEditable() const; 320 321 void set_id(int id); 322 void set_valid(bool v); 323 324 void set_title(const QString &v); 325 void set_album(const QString &v); 326 void set_artist(const QString &v); 327 void set_albumartist(const QString &v); 328 void set_track(int v); 329 void set_disc(int v); 330 void set_year(int v); 331 void set_originalyear(int v); 332 void set_genre(const QString &v); 333 void set_compilation(bool v); 334 void set_composer(const QString &v); 335 void set_performer(const QString &v); 336 void set_grouping(const QString &v); 337 void set_comment(const QString &v); 338 void set_lyrics(const QString &v); 339 340 void set_artist_id(const QString &v); 341 void set_album_id(const QString &v); 342 void set_song_id(const QString &v); 343 344 void set_beginning_nanosec(qint64 v); 345 void set_end_nanosec(qint64 v); 346 void set_length_nanosec(qint64 v); 347 348 void set_bitrate(int v); 349 void set_samplerate(int v); 350 void set_bitdepth(int v); 351 352 void set_source(Source v); 353 void set_directory_id(int v); 354 void set_url(const QUrl &v); 355 void set_basefilename(const QString &v); 356 void set_filetype(FileType v); 357 void set_filesize(int v); 358 void set_mtime(qint64 v); 359 void set_ctime(qint64 v); 360 void set_unavailable(bool v); 361 362 void set_fingerprint(const QString &v); 363 364 void set_playcount(int v); 365 void set_skipcount(int v); 366 void set_lastplayed(qint64 v); 367 void set_lastseen(qint64 v); 368 369 void set_compilation_detected(bool v); 370 void set_compilation_on(bool v); 371 void set_compilation_off(bool v); 372 373 void set_art_automatic(const QUrl &v); 374 void set_art_manual(const QUrl &v); 375 376 void set_cue_path(const QString &v); 377 378 void set_rating(const double v); 379 380 void set_stream_url(const QUrl &v); 381 void set_image(const QImage &i); 382 383 // Comparison functions 384 bool IsMetadataEqual(const Song &other) const; 385 bool IsMetadataAndMoreEqual(const Song &other) const; 386 bool IsOnSameAlbum(const Song &other) const; 387 bool IsSimilar(const Song &other) const; 388 389 bool operator==(const Song &other) const; 390 bool operator!=(const Song &other) const; 391 392 // Two songs that are on the same album will have the same AlbumKey. 393 // It is more efficient to use IsOnSameAlbum, but this function can be used when you need to hash the key to do fast lookups. 394 QString AlbumKey() const; 395 396 Song &operator=(const Song &other); 397 398 private: 399 struct Private; 400 401 static QString sortable(const QString &v); 402 403 QSharedDataPointer<Private> d; 404 }; 405 406 typedef QList<Song> SongList; 407 typedef QMap<QString, Song> SongMap; 408 409 Q_DECLARE_METATYPE(Song) 410 Q_DECLARE_METATYPE(SongList) 411 Q_DECLARE_METATYPE(SongMap) 412 413 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 414 size_t qHash(const Song &song); 415 #else 416 uint qHash(const Song &song); 417 #endif 418 // Hash function using field checked in IsSimilar function 419 size_t HashSimilar(const Song &song); 420 421 #endif // SONG_H 422