summaryrefslogtreecommitdiffstats
path: root/xbmc/music/MusicLibraryQueue.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/music/MusicLibraryQueue.cpp')
-rw-r--r--xbmc/music/MusicLibraryQueue.cpp301
1 files changed, 301 insertions, 0 deletions
diff --git a/xbmc/music/MusicLibraryQueue.cpp b/xbmc/music/MusicLibraryQueue.cpp
new file mode 100644
index 0000000..f16272f
--- /dev/null
+++ b/xbmc/music/MusicLibraryQueue.cpp
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2017-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "MusicLibraryQueue.h"
+
+#include "GUIUserMessages.h"
+#include "ServiceBroker.h"
+#include "Util.h"
+#include "dialogs/GUIDialogProgress.h"
+#include "guilib/GUIComponent.h"
+#include "guilib/GUIWindowManager.h"
+#include "music/infoscanner/MusicInfoScanner.h"
+#include "music/jobs/MusicLibraryCleaningJob.h"
+#include "music/jobs/MusicLibraryExportJob.h"
+#include "music/jobs/MusicLibraryImportJob.h"
+#include "music/jobs/MusicLibraryJob.h"
+#include "music/jobs/MusicLibraryScanningJob.h"
+#include "settings/Settings.h"
+#include "settings/SettingsComponent.h"
+#include "utils/Variant.h"
+
+#include <mutex>
+#include <utility>
+
+CMusicLibraryQueue::CMusicLibraryQueue()
+ : CJobQueue(false, 1, CJob::PRIORITY_LOW),
+ m_jobs()
+{ }
+
+CMusicLibraryQueue::~CMusicLibraryQueue()
+{
+ std::unique_lock<CCriticalSection> lock(m_critical);
+ m_jobs.clear();
+}
+
+CMusicLibraryQueue& CMusicLibraryQueue::GetInstance()
+{
+ static CMusicLibraryQueue s_instance;
+ return s_instance;
+}
+
+void CMusicLibraryQueue::ExportLibrary(const CLibExportSettings& settings, bool showDialog /* = false */)
+{
+ CGUIDialogProgress* progress = NULL;
+ if (showDialog)
+ {
+ progress = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogProgress>(WINDOW_DIALOG_PROGRESS);
+ if (progress)
+ {
+ progress->SetHeading(CVariant{ 20196 }); //"Export music library"
+ progress->SetText(CVariant{ 650 }); //"Exporting"
+ progress->SetPercentage(0);
+ progress->Open();
+ progress->ShowProgressBar(true);
+ }
+ }
+
+ CMusicLibraryExportJob* exportJob = new CMusicLibraryExportJob(settings, progress);
+ if (showDialog)
+ {
+ AddJob(exportJob);
+
+ // Wait for export to complete or be canceled, but render every 10ms so that the
+ // pointer movements work on dialog even when export is reporting progress infrequently
+ if (progress)
+ progress->Wait();
+ }
+ else
+ {
+ m_modal = true;
+ exportJob->DoWork();
+
+ delete exportJob;
+ m_modal = false;
+ Refresh();
+ }
+}
+
+void CMusicLibraryQueue::ImportLibrary(const std::string& xmlFile, bool showDialog /* = false */)
+{
+ CGUIDialogProgress* progress = nullptr;
+ if (showDialog)
+ {
+ progress = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogProgress>(WINDOW_DIALOG_PROGRESS);
+ if (progress)
+ {
+ progress->SetHeading(CVariant{ 20197 }); //"Import music library"
+ progress->SetText(CVariant{ 649 }); //"Importing"
+ progress->SetLine(1, CVariant{ 330 }); //"This could take some time"
+ progress->SetLine(2, CVariant{ "" });
+ progress->SetPercentage(0);
+ progress->Open();
+ progress->ShowProgressBar(true);
+ }
+ }
+
+ CMusicLibraryImportJob* importJob = new CMusicLibraryImportJob(xmlFile, progress);
+ if (showDialog)
+ {
+ AddJob(importJob);
+
+ // Wait for import to complete or be canceled, but render every 10ms so that the
+ // pointer movements work on dialog even when import is reporting progress infrequently
+ if (progress)
+ progress->Wait();
+ }
+ else
+ {
+ m_modal = true;
+ importJob->DoWork();
+
+ delete importJob;
+ m_modal = false;
+ Refresh();
+ }
+}
+
+void CMusicLibraryQueue::ScanLibrary(const std::string& strDirectory,
+ int flags /* = 0 */,
+ bool showProgress /* = true */)
+{
+ if (flags == MUSIC_INFO::CMusicInfoScanner::SCAN_NORMAL)
+ {
+ if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(
+ CSettings::SETTING_MUSICLIBRARY_DOWNLOADINFO))
+ flags |= MUSIC_INFO::CMusicInfoScanner::SCAN_ONLINE;
+ }
+
+ if (!showProgress || CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(
+ CSettings::SETTING_MUSICLIBRARY_BACKGROUNDUPDATE))
+ flags |= MUSIC_INFO::CMusicInfoScanner::SCAN_BACKGROUND;
+
+ AddJob(new CMusicLibraryScanningJob(strDirectory, flags, showProgress));
+}
+
+void CMusicLibraryQueue::StartAlbumScan(const std::string & strDirectory, bool refresh)
+{
+ int flags = MUSIC_INFO::CMusicInfoScanner::SCAN_ALBUMS;
+ if (refresh)
+ flags |= MUSIC_INFO::CMusicInfoScanner::SCAN_RESCAN;
+ AddJob(new CMusicLibraryScanningJob(strDirectory, flags, true));
+}
+
+void CMusicLibraryQueue::StartArtistScan(const std::string& strDirectory, bool refresh)
+{
+ int flags = MUSIC_INFO::CMusicInfoScanner::SCAN_ARTISTS;
+ if (refresh)
+ flags |= MUSIC_INFO::CMusicInfoScanner::SCAN_RESCAN;
+ AddJob(new CMusicLibraryScanningJob(strDirectory, flags, true));
+}
+
+bool CMusicLibraryQueue::IsScanningLibrary() const
+{
+ // check if the library is being cleaned synchronously
+ if (m_cleaning)
+ return true;
+
+ // check if the library is being scanned asynchronously
+ MusicLibraryJobMap::const_iterator scanningJobs = m_jobs.find("MusicLibraryScanningJob");
+ if (scanningJobs != m_jobs.end() && !scanningJobs->second.empty())
+ return true;
+
+ // check if the library is being cleaned asynchronously
+ MusicLibraryJobMap::const_iterator cleaningJobs = m_jobs.find("MusicLibraryCleaningJob");
+ if (cleaningJobs != m_jobs.end() && !cleaningJobs->second.empty())
+ return true;
+
+ return false;
+}
+
+void CMusicLibraryQueue::StopLibraryScanning()
+{
+ std::unique_lock<CCriticalSection> lock(m_critical);
+ MusicLibraryJobMap::const_iterator scanningJobs = m_jobs.find("MusicLibraryScanningJob");
+ if (scanningJobs == m_jobs.end())
+ return;
+
+ // get a copy of the scanning jobs because CancelJob() will modify m_scanningJobs
+ MusicLibraryJobs tmpScanningJobs(scanningJobs->second.begin(), scanningJobs->second.end());
+
+ // cancel all scanning jobs
+ for (const auto& job : tmpScanningJobs)
+ CancelJob(job);
+ Refresh();
+}
+
+void CMusicLibraryQueue::CleanLibrary(bool showDialog /* = false */)
+{
+ CGUIDialogProgress* progress = NULL;
+ if (showDialog)
+ {
+ progress = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogProgress>(WINDOW_DIALOG_PROGRESS);
+ if (progress)
+ {
+ progress->SetHeading(CVariant{ 700 });
+ progress->SetPercentage(0);
+ progress->Open();
+ progress->ShowProgressBar(true);
+ }
+ }
+
+ CMusicLibraryCleaningJob* cleaningJob = new CMusicLibraryCleaningJob(progress);
+ AddJob(cleaningJob);
+
+ // Wait for cleaning to complete or be canceled, but render every 20ms so that the
+ // pointer movements work on dialog even when cleaning is reporting progress infrequently
+ if (progress)
+ progress->Wait(20);
+}
+
+void CMusicLibraryQueue::AddJob(CMusicLibraryJob *job)
+{
+ if (job == NULL)
+ return;
+
+ std::unique_lock<CCriticalSection> lock(m_critical);
+ if (!CJobQueue::AddJob(job))
+ return;
+
+ // add the job to our list of queued/running jobs
+ std::string jobType = job->GetType();
+ MusicLibraryJobMap::iterator jobsIt = m_jobs.find(jobType);
+ if (jobsIt == m_jobs.end())
+ {
+ MusicLibraryJobs jobs;
+ jobs.insert(job);
+ m_jobs.insert(std::make_pair(jobType, jobs));
+ }
+ else
+ jobsIt->second.insert(job);
+}
+
+void CMusicLibraryQueue::CancelJob(CMusicLibraryJob *job)
+{
+ if (job == NULL)
+ return;
+
+ std::unique_lock<CCriticalSection> lock(m_critical);
+ // remember the job type needed later because the job might be deleted
+ // in the call to CJobQueue::CancelJob()
+ std::string jobType;
+ if (job->GetType() != NULL)
+ jobType = job->GetType();
+
+ // check if the job supports cancellation and cancel it
+ if (job->CanBeCancelled())
+ job->Cancel();
+
+ // remove the job from the job queue
+ CJobQueue::CancelJob(job);
+
+ // remove the job from our list of queued/running jobs
+ MusicLibraryJobMap::iterator jobsIt = m_jobs.find(jobType);
+ if (jobsIt != m_jobs.end())
+ jobsIt->second.erase(job);
+}
+
+void CMusicLibraryQueue::CancelAllJobs()
+{
+ std::unique_lock<CCriticalSection> lock(m_critical);
+ CJobQueue::CancelJobs();
+
+ // remove all scanning jobs
+ m_jobs.clear();
+}
+
+bool CMusicLibraryQueue::IsRunning() const
+{
+ return CJobQueue::IsProcessing() || m_modal;
+}
+
+void CMusicLibraryQueue::Refresh()
+{
+ CUtil::DeleteMusicDatabaseDirectoryCache();
+ CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE);
+ CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);
+}
+
+void CMusicLibraryQueue::OnJobComplete(unsigned int jobID, bool success, CJob *job)
+{
+ if (success)
+ {
+ if (QueueEmpty())
+ Refresh();
+ }
+
+ {
+ std::unique_lock<CCriticalSection> lock(m_critical);
+ // remove the job from our list of queued/running jobs
+ MusicLibraryJobMap::iterator jobsIt = m_jobs.find(job->GetType());
+ if (jobsIt != m_jobs.end())
+ jobsIt->second.erase(static_cast<CMusicLibraryJob*>(job));
+ }
+
+ return CJobQueue::OnJobComplete(jobID, success, job);
+}