1 /* LocalLibrary.cpp */
2
3 /* Copyright (C) 2011-2020 Michael Lugmair (Lucio Carreras)
4 *
5 * This file is part of sayonara player
6 *
7 * This program 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 * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "LocalLibrary.h"
22 #include "Importer/LibraryImporter.h"
23 #include "Threads/ReloadThread.h"
24
25 #include "Components/LibraryManagement/LibraryManager.h"
26
27 #include "Database/Connector.h"
28 #include "Database/Library.h"
29 #include "Database/LibraryDatabase.h"
30
31 #include "Interfaces/LibraryPlaylistInteractor.h"
32
33 #include "Utils/MetaData/Album.h"
34 #include "Utils/MetaData/Artist.h"
35 #include "Utils/MetaData/MetaDataList.h"
36 #include "Utils/Settings/Settings.h"
37 #include "Utils/Library/LibraryInfo.h"
38 #include "Utils/Logger/Logger.h"
39
40 #include <QTime>
41
42 struct LocalLibrary::Private
43 {
44 LibraryId libraryId;
45 DB::LibraryDatabase* libraryDatabase;
46
47 Library::Manager* libraryManager;
48 Library::ReloadThread* reloadThread = nullptr;
49 Library::Importer* libraryImporter = nullptr;
50
PrivateLocalLibrary::Private51 Private(Library::Manager* libraryManager, LibraryId libraryId) :
52 libraryId(libraryId),
53 libraryDatabase(DB::Connector::instance()->libraryDatabase(libraryId, 0)),
54 libraryManager(libraryManager) {}
55 };
56
LocalLibrary(Library::Manager * libraryManager,LibraryId libraryId,LibraryPlaylistInteractor * playlistInteractor,QObject * parent)57 LocalLibrary::LocalLibrary(Library::Manager* libraryManager, LibraryId libraryId,
58 LibraryPlaylistInteractor* playlistInteractor, QObject* parent) :
59 AbstractLibrary(playlistInteractor, parent)
60 {
61 m = Pimpl::make<Private>(libraryManager, libraryId);
62
63 applyDatabaseFixes();
64
65 connect(libraryManager, &Library::Manager::sigRenamed, this, [&](const auto id) {
66 if(id == m->libraryId)
67 {
68 emit sigRenamed(info().name());
69 }
70 });
71
72 connect(libraryManager, &Library::Manager::sigPathChanged, this, [&](const auto id) {
73 if(id == m->libraryId)
74 {
75 emit sigPathChanged(info().path());
76 }
77 });
78
79 ListenSettingNoCall(Set::Lib_SearchMode, LocalLibrary::searchModeChanged);
80 ListenSettingNoCall(Set::Lib_ShowAlbumArtists, LocalLibrary::showAlbumArtistsChanged);
81 }
82
83 LocalLibrary::~LocalLibrary() = default;
84
applyDatabaseFixes()85 void LocalLibrary::applyDatabaseFixes() {}
86
reloadLibrary(bool clearFirst,Library::ReloadQuality quality)87 void LocalLibrary::reloadLibrary(bool clearFirst, Library::ReloadQuality quality)
88 {
89 if(isReloading())
90 {
91 return;
92 }
93
94 if(!m->reloadThread)
95 {
96 initReloadThread();
97 }
98
99 if(clearFirst)
100 {
101 deleteAllTracks();
102 }
103
104 const auto info = this->info();
105 m->reloadThread->setLibrary(info.id(), info.path());
106 m->reloadThread->setQuality(quality);
107 m->reloadThread->start();
108 }
109
reloadThreadFinished()110 void LocalLibrary::reloadThreadFinished()
111 {
112 load();
113
114 emit sigReloadingLibrary(QString(), -1);
115 emit sigReloadingLibraryFinished();
116 }
117
searchModeChanged()118 void LocalLibrary::searchModeChanged()
119 {
120 spLog(Log::Debug, this) << "Updating cissearch... " << GetSetting(Set::Lib_SearchMode);
121
122 m->libraryDatabase->updateSearchMode();
123
124 spLog(Log::Debug, this) << "Updating cissearch finished" << GetSetting(Set::Lib_SearchMode);
125 }
126
showAlbumArtistsChanged()127 void LocalLibrary::showAlbumArtistsChanged()
128 {
129 const auto showAlbumArtists = GetSetting(Set::Lib_ShowAlbumArtists);
130
131 const auto libraryDatabases = DB::Connector::instance()->libraryDatabases();
132 for(auto* libraryDatabase : libraryDatabases)
133 {
134 if(libraryDatabase->databaseId() == 0)
135 {
136 const auto field = (showAlbumArtists)
137 ? DB::LibraryDatabase::ArtistIDField::AlbumArtistID
138 : DB::LibraryDatabase::ArtistIDField::ArtistID;
139
140 libraryDatabase->changeArtistIdField(field);
141 }
142 }
143
144 refreshCurrentView();
145 }
146
importStatusChanged(Library::Importer::ImportStatus status)147 void LocalLibrary::importStatusChanged(Library::Importer::ImportStatus status)
148 {
149 if(status == Library::Importer::ImportStatus::Imported)
150 {
151 refreshCurrentView();
152 }
153 }
154
reloadThreadNewBlock()155 void LocalLibrary::reloadThreadNewBlock()
156 {
157 m->reloadThread->pause();
158 refreshCurrentView();
159 m->reloadThread->goon();
160 }
161
getAllArtists(ArtistList & artists) const162 void LocalLibrary::getAllArtists(ArtistList& artists) const
163 {
164 m->libraryDatabase->getAllArtists(artists, false);
165 }
166
getAllArtistsBySearchstring(Library::Filter filter,ArtistList & artists) const167 void LocalLibrary::getAllArtistsBySearchstring(Library::Filter filter, ArtistList& artists) const
168 {
169 m->libraryDatabase->getAllArtistsBySearchString(filter, artists);
170 }
171
getAllAlbums(AlbumList & albums) const172 void LocalLibrary::getAllAlbums(AlbumList& albums) const
173 {
174 m->libraryDatabase->getAllAlbums(albums, false);
175 }
176
getAllAlbumsByArtist(IdList artistIds,AlbumList & albums,Library::Filter filter) const177 void LocalLibrary::getAllAlbumsByArtist(IdList artistIds, AlbumList& albums, Library::Filter filter) const
178 {
179 m->libraryDatabase->getAllAlbumsByArtist(artistIds, albums, filter);
180 }
181
getAllAlbumsBySearchstring(Library::Filter filter,AlbumList & albums) const182 void LocalLibrary::getAllAlbumsBySearchstring(Library::Filter filter, AlbumList& albums) const
183 {
184 m->libraryDatabase->getAllAlbumsBySearchString(filter, albums);
185 }
186
getTrackCount() const187 int LocalLibrary::getTrackCount() const
188 {
189 return m->libraryDatabase->getNumTracks();
190 }
191
getAllTracks(MetaDataList & tracks) const192 void LocalLibrary::getAllTracks(MetaDataList& tracks) const
193 {
194 m->libraryDatabase->getAllTracks(tracks);
195 }
196
getAllTracks(const QStringList & paths,MetaDataList & tracks) const197 void LocalLibrary::getAllTracks(const QStringList& paths, MetaDataList& tracks) const
198 {
199 m->libraryDatabase->getMultipleTracksByPath(paths, tracks);
200 }
201
getAllTracksByArtist(IdList artistIds,MetaDataList & tracks,Library::Filter filter) const202 void LocalLibrary::getAllTracksByArtist(IdList artistIds, MetaDataList& tracks, Library::Filter filter) const
203 {
204 m->libraryDatabase->getAllTracksByArtist(artistIds, tracks, filter);
205 }
206
getAllTracksByAlbum(IdList albumIds,MetaDataList & tracks,Library::Filter filter) const207 void LocalLibrary::getAllTracksByAlbum(IdList albumIds, MetaDataList& tracks, Library::Filter filter) const
208 {
209 m->libraryDatabase->getAllTracksByAlbum(albumIds, tracks, filter, -1);
210 }
211
getAllTracksBySearchstring(Library::Filter filter,MetaDataList & tracks) const212 void LocalLibrary::getAllTracksBySearchstring(Library::Filter filter, MetaDataList& tracks) const
213 {
214 m->libraryDatabase->getAllTracksBySearchString(filter, tracks);
215 }
216
getAllTracksByPath(const QStringList & paths,MetaDataList & tracks) const217 void LocalLibrary::getAllTracksByPath(const QStringList& paths, MetaDataList& tracks) const
218 {
219 m->libraryDatabase->getAllTracksByPaths(paths, tracks);
220 }
221
getTrackById(TrackID trackId,MetaData & track) const222 void LocalLibrary::getTrackById(TrackID trackId, MetaData& track) const
223 {
224 const auto tmpTrack = m->libraryDatabase->getTrackById(trackId);
225 track = (tmpTrack.libraryId() == m->libraryId)
226 ? tmpTrack
227 : MetaData();
228 }
229
getAlbumById(AlbumId albumId,Album & album) const230 void LocalLibrary::getAlbumById(AlbumId albumId, Album& album) const
231 {
232 m->libraryDatabase->getAlbumByID(albumId, album);
233 }
234
getArtistById(ArtistId artistId,Artist & artist) const235 void LocalLibrary::getArtistById(ArtistId artistId, Artist& artist) const
236 {
237 m->libraryDatabase->getArtistByID(artistId, artist);
238 }
239
initReloadThread()240 void LocalLibrary::initReloadThread()
241 {
242 if(!m->reloadThread)
243 {
244 m->reloadThread = new Library::ReloadThread(this);
245
246 connect(m->reloadThread, &Library::ReloadThread::sigReloadingLibrary,
247 this, &LocalLibrary::sigReloadingLibrary);
248
249 connect(m->reloadThread, &Library::ReloadThread::sigNewBlockSaved,
250 this, &LocalLibrary::reloadThreadNewBlock);
251
252 connect(m->reloadThread, &Library::ReloadThread::finished,
253 this, &LocalLibrary::reloadThreadFinished);
254 }
255 }
256
deleteTracks(const MetaDataList & tracks,Library::TrackDeletionMode mode)257 void LocalLibrary::deleteTracks(const MetaDataList& tracks, Library::TrackDeletionMode mode)
258 {
259 m->libraryDatabase->deleteTracks(tracks);
260 AbstractLibrary::deleteTracks(tracks, mode);
261 }
262
refreshArtists()263 void LocalLibrary::refreshArtists() {}
264
refreshAlbums()265 void LocalLibrary::refreshAlbums() {}
266
refreshTracks()267 void LocalLibrary::refreshTracks() {}
268
importFiles(const QStringList & files)269 void LocalLibrary::importFiles(const QStringList& files)
270 {
271 importFilesTo(files, QString());
272 }
273
importFilesTo(const QStringList & files,const QString & targetDirectory)274 void LocalLibrary::importFilesTo(const QStringList& files, const QString& targetDirectory)
275 {
276 if(!files.isEmpty())
277 {
278 if(!m->libraryImporter)
279 {
280 m->libraryImporter = new Library::Importer(this);
281 connect(m->libraryImporter, &Library::Importer::sigStatusChanged, this, &LocalLibrary::importStatusChanged);
282 }
283
284 m->libraryImporter->importFiles(files, targetDirectory);
285
286 emit sigImportDialogRequested(targetDirectory);
287 }
288 }
289
setLibraryPath(const QString & library_path)290 bool LocalLibrary::setLibraryPath(const QString& library_path)
291 {
292 return m->libraryManager->changeLibraryPath(m->libraryId, library_path);
293 }
294
setLibraryName(const QString & library_name)295 bool LocalLibrary::setLibraryName(const QString& library_name)
296 {
297 return m->libraryManager->renameLibrary(m->libraryId, library_name);
298 }
299
info() const300 Library::Info LocalLibrary::info() const
301 {
302 return m->libraryManager->libraryInfo(m->libraryId);
303 }
304
importer()305 Library::Importer* LocalLibrary::importer()
306 {
307 if(!m->libraryImporter)
308 {
309 m->libraryImporter = new Library::Importer(this);
310 connect(m->libraryImporter, &Library::Importer::sigStatusChanged, this, &LocalLibrary::importStatusChanged);
311 }
312
313 return m->libraryImporter;
314 }
315
isReloading() const316 bool LocalLibrary::isReloading() const
317 {
318 return (m->reloadThread != nullptr && m->reloadThread->isRunning());
319 }
320