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