1 /* This file is part of Clementine.
2    Copyright 2010, David Sansome <me@davidsansome.com>
3 
4    Clementine is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8 
9    Clementine is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with Clementine.  If not, see <http://www.gnu.org/licenses/>.
16 */
17 
18 #ifndef LIBRARYBACKEND_H
19 #define LIBRARYBACKEND_H
20 
21 #include <QObject>
22 #include <QSet>
23 #include <QUrl>
24 #include <QFileInfo>
25 
26 #include "directory.h"
27 #include "libraryquery.h"
28 #include "core/song.h"
29 
30 class Database;
31 
32 namespace smart_playlists {
33 class Search;
34 }
35 
36 class LibraryBackendInterface : public QObject {
37   Q_OBJECT
38 
39  public:
QObject(parent)40   LibraryBackendInterface(QObject* parent = nullptr) : QObject(parent) {}
~LibraryBackendInterface()41   virtual ~LibraryBackendInterface() {}
42 
43   struct Album {
AlbumAlbum44     Album() {}
AlbumAlbum45     Album(const QString& _artist, const QString& _album_artist,
46           const QString& _album_name, const QString& _art_automatic,
47           const QString& _art_manual, const QUrl& _first_url)
48         : artist(_artist),
49           album_artist(_album_artist),
50           album_name(_album_name),
51           art_automatic(_art_automatic),
52           art_manual(_art_manual),
53           first_url(_first_url) {}
54 
effective_albumartistAlbum55     const QString& effective_albumartist() const {
56       return album_artist.isEmpty() ? artist : album_artist;
57     }
58 
59     QString artist;
60     QString album_artist;
61     QString album_name;
62 
63     QString art_automatic;
64     QString art_manual;
65     QUrl first_url;
66   };
67   typedef QList<Album> AlbumList;
68 
69   virtual QString songs_table() const = 0;
70 
71   // Get a list of directories in the library.  Emits DirectoriesDiscovered.
72   virtual void LoadDirectoriesAsync() = 0;
73 
74   // Counts the songs in the library.  Emits TotalSongCountUpdated
75   virtual void UpdateTotalSongCountAsync() = 0;
76 
77   virtual SongList FindSongsInDirectory(int id) = 0;
78   virtual SubdirectoryList SubdirsInDirectory(int id) = 0;
79   virtual DirectoryList GetAllDirectories() = 0;
80   virtual void ChangeDirPath(int id, const QString& old_path,
81                              const QString& new_path) = 0;
82 
83   virtual QStringList GetAllArtists(
84       const QueryOptions& opt = QueryOptions()) = 0;
85   virtual QStringList GetAllArtistsWithAlbums(
86       const QueryOptions& opt = QueryOptions()) = 0;
87   virtual SongList GetSongsByAlbum(
88       const QString& album, const QueryOptions& opt = QueryOptions()) = 0;
89   virtual SongList GetSongs(const QString& artist, const QString& album,
90                             const QueryOptions& opt = QueryOptions()) = 0;
91 
92   virtual SongList GetCompilationSongs(
93       const QString& album, const QueryOptions& opt = QueryOptions()) = 0;
94 
95   virtual AlbumList GetAllAlbums(const QueryOptions& opt = QueryOptions()) = 0;
96   virtual AlbumList GetAlbumsByArtist(
97       const QString& artist, const QueryOptions& opt = QueryOptions()) = 0;
98   virtual AlbumList GetCompilationAlbums(
99       const QueryOptions& opt = QueryOptions()) = 0;
100 
101   virtual void UpdateManualAlbumArtAsync(const QString& artist,
102                                          const QString& albumartist,
103                                          const QString& album,
104                                          const QString& art) = 0;
105   virtual Album GetAlbumArt(const QString& artist, const QString& albumartist,
106                             const QString& album) = 0;
107 
108   virtual Song GetSongById(int id) = 0;
109 
110   // Returns all sections of a song with the given filename. If there's just one
111   // section
112   // the resulting list will have it's size equal to 1.
113   virtual SongList GetSongsByUrl(const QUrl& url) = 0;
114   // Returns a section of a song with the given filename and beginning. If the
115   // section
116   // is not present in library, returns invalid song.
117   // Using default beginning value is suitable when searching for single-section
118   // songs.
119   virtual Song GetSongByUrl(const QUrl& url, qint64 beginning = 0) = 0;
120 
121   virtual void AddDirectory(const QString& path) = 0;
122   virtual void RemoveDirectory(const Directory& dir) = 0;
123 
124   virtual bool ExecQuery(LibraryQuery* q) = 0;
125 };
126 
127 class LibraryBackend : public LibraryBackendInterface {
128   Q_OBJECT
129 
130  public:
131   static const char* kSettingsGroup;
132 
133   Q_INVOKABLE LibraryBackend(QObject* parent = nullptr);
134   void Init(Database* db, const QString& songs_table, const QString& dirs_table,
135             const QString& subdirs_table, const QString& fts_table);
136 
db()137   Database* db() const { return db_; }
138 
songs_table()139   QString songs_table() const { return songs_table_; }
dirs_table()140   QString dirs_table() const { return dirs_table_; }
subdirs_table()141   QString subdirs_table() const { return subdirs_table_; }
142 
143   // Get a list of directories in the library.  Emits DirectoriesDiscovered.
144   void LoadDirectoriesAsync();
145 
146   // Counts the songs in the library.  Emits TotalSongCountUpdated
147   void UpdateTotalSongCountAsync();
148 
149   SongList FindSongsInDirectory(int id);
150   SubdirectoryList SubdirsInDirectory(int id);
151   DirectoryList GetAllDirectories();
152   void ChangeDirPath(int id, const QString& old_path, const QString& new_path);
153 
154   QStringList GetAll(const QString& column,
155                      const QueryOptions& opt = QueryOptions());
156   QStringList GetAllArtists(const QueryOptions& opt = QueryOptions());
157   QStringList GetAllArtistsWithAlbums(const QueryOptions& opt = QueryOptions());
158   SongList GetSongsByAlbum(const QString& album,
159                            const QueryOptions& opt = QueryOptions());
160   SongList GetSongs(const QString& artist, const QString& album,
161                     const QueryOptions& opt = QueryOptions());
162 
163   SongList GetCompilationSongs(const QString& album,
164                                const QueryOptions& opt = QueryOptions());
165 
166   AlbumList GetAllAlbums(const QueryOptions& opt = QueryOptions());
167   AlbumList GetAlbumsByArtist(const QString& artist,
168                               const QueryOptions& opt = QueryOptions());
169   AlbumList GetAlbumsByAlbumArtist(const QString& albumartist,
170                                    const QueryOptions& opt = QueryOptions());
171   AlbumList GetCompilationAlbums(const QueryOptions& opt = QueryOptions());
172 
173   void UpdateManualAlbumArtAsync(const QString& artist,
174                                  const QString& albumartist,
175                                  const QString& album, const QString& art);
176   Album GetAlbumArt(const QString& artist, const QString& albumartist,
177                     const QString& album);
178 
179   Song GetSongById(int id);
180   SongList GetSongsById(const QList<int>& ids);
181   SongList GetSongsById(const QStringList& ids);
182   SongList GetSongsByForeignId(const QStringList& ids, const QString& table,
183                                const QString& column);
184 
185   SongList GetSongsByUrl(const QUrl& url);
186   Song GetSongByUrl(const QUrl& url, qint64 beginning = 0);
187 
188   void AddDirectory(const QString& path);
189   void RemoveDirectory(const Directory& dir);
190 
191   bool ExecQuery(LibraryQuery* q);
192   SongList ExecLibraryQuery(LibraryQuery* query);
193   SongList FindSongs(const smart_playlists::Search& search);
194   SongList GetAllSongs();
195 
196   void IncrementPlayCountAsync(int id);
197   void IncrementSkipCountAsync(int id, float progress);
198   void ResetStatisticsAsync(int id);
199   void UpdateSongRatingAsync(int id, float rating);
200   void UpdateSongsRatingAsync(const QList<int>& ids, float rating);
201 
202   void DeleteAll();
203 
204  public slots:
205   void LoadDirectories();
206   void UpdateTotalSongCount();
207   void AddOrUpdateSongs(const SongList& songs);
208   void UpdateMTimesOnly(const SongList& songs);
209   void DeleteSongs(const SongList& songs);
210   void MarkSongsUnavailable(const SongList& songs, bool unavailable = true);
211   void AddOrUpdateSubdirs(const SubdirectoryList& subdirs);
212   void UpdateCompilations();
213   void UpdateManualAlbumArt(const QString& artist, const QString& albumartist,
214                             const QString& album, const QString& art);
215   void ForceCompilation(const QString& album, const QList<QString>& artists,
216                         bool on);
217   void IncrementPlayCount(int id);
218   void IncrementSkipCount(int id, float progress);
219   void ResetStatistics(int id);
220   void UpdateSongRating(int id, float rating);
221   void UpdateSongsRating(const QList<int>& id_list, float rating);
222   // Tells the library model that a song path has changed
223   void SongPathChanged(const Song& song, const QFileInfo& new_file);
224 
225 signals:
226   void DirectoryDiscovered(const Directory& dir,
227                            const SubdirectoryList& subdirs);
228   void DirectoryDeleted(const Directory& dir);
229 
230   void SongsDiscovered(const SongList& songs);
231   void SongsDeleted(const SongList& songs);
232   void SongsStatisticsChanged(const SongList& songs);
233   void SongsRatingChanged(const SongList& songs);
234   void DatabaseReset();
235 
236   void TotalSongCountUpdated(int total);
237 
238  private:
239   struct CompilationInfo {
CompilationInfoCompilationInfo240     CompilationInfo() : has_samplers(0), has_not_samplers(0) {}
241 
242     QList<QUrl> urls;
243     QStringList artists;
244 
245     int has_samplers;
246     int has_not_samplers;
247   };
248 
249   static const char* kNewScoreSql;
250 
251   void UpdateCompilations(const QSqlDatabase& db, SongList& deleted_songs,
252                           SongList& added_songs, const QUrl& url,
253                           const bool sampler);
254   AlbumList GetAlbums(const QString& artist, const QString& album_artist,
255                       bool compilation = false,
256                       const QueryOptions& opt = QueryOptions());
257   SubdirectoryList SubdirsInDirectory(int id, QSqlDatabase& db);
258 
259   Song GetSongById(int id, QSqlDatabase& db);
260   SongList GetSongsById(const QStringList& ids, QSqlDatabase& db);
261 
262  private:
263   Database* db_;
264   QString songs_table_;
265   QString dirs_table_;
266   QString subdirs_table_;
267   QString fts_table_;
268   bool save_statistics_in_file_;
269   bool save_ratings_in_file_;
270 };
271 
272 #endif  // LIBRARYBACKEND_H
273