/* * Copyright (C) 2016-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 "PVRGUIActionsDatabase.h" #include "FileItem.h" #include "ServiceBroker.h" #include "dialogs/GUIDialogProgress.h" #include "dialogs/GUIDialogSelect.h" #include "dialogs/GUIDialogYesNo.h" #include "guilib/GUIComponent.h" #include "guilib/GUIWindowManager.h" #include "guilib/LocalizeStrings.h" #include "guilib/WindowIDs.h" #include "messaging/ApplicationMessenger.h" #include "pvr/PVRDatabase.h" #include "pvr/PVRManager.h" #include "pvr/PVRPlaybackState.h" #include "pvr/epg/EpgContainer.h" #include "pvr/epg/EpgDatabase.h" #include "pvr/guilib/PVRGUIActionsParentalControl.h" #include "pvr/recordings/PVRRecordings.h" #include "pvr/recordings/PVRRecordingsPath.h" #include "utils/StringUtils.h" #include "utils/Variant.h" #include "utils/log.h" #include "video/VideoDatabase.h" #include #include using namespace PVR; namespace { class CPVRGUIDatabaseResetComponentsSelector { public: CPVRGUIDatabaseResetComponentsSelector() = default; virtual ~CPVRGUIDatabaseResetComponentsSelector() = default; bool Select() { CGUIDialogSelect* pDlgSelect = CServiceBroker::GetGUI()->GetWindowManager().GetWindow( WINDOW_DIALOG_SELECT); if (!pDlgSelect) { CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_SELECT!"); return false; } CFileItemList options; const std::shared_ptr itemAll = std::make_shared(StringUtils::Format(g_localizeStrings.Get(593))); // All itemAll->SetPath("all"); options.Add(itemAll); // if channels are cleared, groups, EPG data and providers must also be cleared const std::shared_ptr itemChannels = std::make_shared(StringUtils::Format("{}, {}, {}, {}", g_localizeStrings.Get(19019), // Channels g_localizeStrings.Get(19146), // Groups g_localizeStrings.Get(19069), // Guide g_localizeStrings.Get(19334))); // Providers itemChannels->SetPath("channels"); itemChannels->Select(true); // preselect this item in dialog options.Add(itemChannels); const std::shared_ptr itemGroups = std::make_shared(g_localizeStrings.Get(19146)); // Groups itemGroups->SetPath("groups"); options.Add(itemGroups); const std::shared_ptr itemGuide = std::make_shared(g_localizeStrings.Get(19069)); // Guide itemGuide->SetPath("guide"); options.Add(itemGuide); const std::shared_ptr itemProviders = std::make_shared(g_localizeStrings.Get(19334)); // Providers itemProviders->SetPath("providers"); options.Add(itemProviders); const std::shared_ptr itemReminders = std::make_shared(g_localizeStrings.Get(19215)); // Reminders itemReminders->SetPath("reminders"); options.Add(itemReminders); const std::shared_ptr itemRecordings = std::make_shared(g_localizeStrings.Get(19017)); // Recordings itemRecordings->SetPath("recordings"); options.Add(itemRecordings); const std::shared_ptr itemClients = std::make_shared(g_localizeStrings.Get(24019)); // PVR clients itemClients->SetPath("clients"); options.Add(itemClients); pDlgSelect->Reset(); pDlgSelect->SetHeading(CVariant{g_localizeStrings.Get(19185)}); // "Clear data" pDlgSelect->SetItems(options); pDlgSelect->SetMultiSelection(true); pDlgSelect->Open(); if (!pDlgSelect->IsConfirmed()) return false; for (int i : pDlgSelect->GetSelectedItems()) { const std::string path = options.Get(i)->GetPath(); m_bResetChannels |= (path == "channels" || path == "all"); m_bResetGroups |= (path == "groups" || path == "all"); m_bResetGuide |= (path == "guide" || path == "all"); m_bResetProviders |= (path == "providers" || path == "all"); m_bResetReminders |= (path == "reminders" || path == "all"); m_bResetRecordings |= (path == "recordings" || path == "all"); m_bResetClients |= (path == "clients" || path == "all"); } m_bResetGroups |= m_bResetChannels; m_bResetGuide |= m_bResetChannels; m_bResetProviders |= m_bResetChannels; return (m_bResetChannels || m_bResetGroups || m_bResetGuide || m_bResetProviders || m_bResetReminders || m_bResetRecordings || m_bResetClients); } bool IsResetChannelsSelected() const { return m_bResetChannels; } bool IsResetGroupsSelected() const { return m_bResetGroups; } bool IsResetGuideSelected() const { return m_bResetGuide; } bool IsResetProvidersSelected() const { return m_bResetProviders; } bool IsResetRemindersSelected() const { return m_bResetReminders; } bool IsResetRecordingsSelected() const { return m_bResetRecordings; } bool IsResetClientsSelected() const { return m_bResetClients; } private: bool m_bResetChannels = false; bool m_bResetGroups = false; bool m_bResetGuide = false; bool m_bResetProviders = false; bool m_bResetReminders = false; bool m_bResetRecordings = false; bool m_bResetClients = false; }; } // unnamed namespace bool CPVRGUIActionsDatabase::ResetDatabase(bool bResetEPGOnly) { CGUIDialogProgress* pDlgProgress = CServiceBroker::GetGUI()->GetWindowManager().GetWindow( WINDOW_DIALOG_PROGRESS); if (!pDlgProgress) { CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_PROGRESS!"); return false; } bool bResetChannels = false; bool bResetGroups = false; bool bResetGuide = false; bool bResetProviders = false; bool bResetReminders = false; bool bResetRecordings = false; bool bResetClients = false; if (bResetEPGOnly) { if (!CGUIDialogYesNo::ShowAndGetInput( CVariant{19098}, // "Warning!" CVariant{19188})) // "All guide data will be cleared. Are you sure?" return false; bResetGuide = true; } else { if (CServiceBroker::GetPVRManager().Get().CheckParentalPIN() != ParentalCheckResult::SUCCESS) return false; CPVRGUIDatabaseResetComponentsSelector selector; if (!selector.Select()) return false; if (!CGUIDialogYesNo::ShowAndGetInput( CVariant{19098}, // "Warning!" CVariant{19186})) // "All selected data will be cleared. ... Are you sure?" return false; bResetChannels = selector.IsResetChannelsSelected(); bResetGroups = selector.IsResetGroupsSelected(); bResetGuide = selector.IsResetGuideSelected(); bResetProviders = selector.IsResetProvidersSelected(); bResetReminders = selector.IsResetRemindersSelected(); bResetRecordings = selector.IsResetRecordingsSelected(); bResetClients = selector.IsResetClientsSelected(); } CDateTime::ResetTimezoneBias(); CLog::LogFC(LOGDEBUG, LOGPVR, "PVR clearing {} database", bResetEPGOnly ? "EPG" : "PVR and EPG"); pDlgProgress->SetHeading(CVariant{313}); // "Cleaning database" pDlgProgress->SetLine(0, CVariant{g_localizeStrings.Get(19187)}); // "Clearing all related data." pDlgProgress->SetLine(1, CVariant{""}); pDlgProgress->SetLine(2, CVariant{""}); pDlgProgress->Open(); pDlgProgress->Progress(); if (CServiceBroker::GetPVRManager().PlaybackState()->IsPlaying()) { CLog::Log(LOGINFO, "PVR is stopping playback for {} database reset", bResetEPGOnly ? "EPG" : "PVR and EPG"); CServiceBroker::GetAppMessenger()->SendMsg(TMSG_MEDIA_STOP); } const std::shared_ptr pvrDatabase(CServiceBroker::GetPVRManager().GetTVDatabase()); const std::shared_ptr epgDatabase( CServiceBroker::GetPVRManager().EpgContainer().GetEpgDatabase()); // increase db open refcounts, so they don't get closed during following pvr manager shutdown pvrDatabase->Open(); epgDatabase->Open(); // stop pvr manager; close both pvr and epg databases CServiceBroker::GetPVRManager().Stop(); const int iProgressStepPercentage = 100 / ((2 * bResetChannels) + bResetGroups + bResetGuide + bResetProviders + bResetReminders + bResetRecordings + bResetClients + 1); int iProgressStepsDone = 0; if (bResetProviders) { pDlgProgress->SetPercentage(iProgressStepPercentage * ++iProgressStepsDone); pDlgProgress->Progress(); // delete all providers pvrDatabase->DeleteProviders(); } if (bResetGuide) { pDlgProgress->SetPercentage(iProgressStepPercentage * ++iProgressStepsDone); pDlgProgress->Progress(); // reset channel's EPG pointers pvrDatabase->ResetEPG(); // delete all entries from the EPG database epgDatabase->DeleteEpg(); } if (bResetGroups) { pDlgProgress->SetPercentage(iProgressStepPercentage * ++iProgressStepsDone); pDlgProgress->Progress(); // delete all channel groups (including data only available locally, like user defined groups) pvrDatabase->DeleteChannelGroups(); } if (bResetChannels) { pDlgProgress->SetPercentage(iProgressStepPercentage * ++iProgressStepsDone); pDlgProgress->Progress(); // delete all channels (including data only available locally, like user set icons) pvrDatabase->DeleteChannels(); } if (bResetReminders) { pDlgProgress->SetPercentage(iProgressStepPercentage * ++iProgressStepsDone); pDlgProgress->Progress(); // delete all timers data (e.g. all reminders, which are only stored locally) pvrDatabase->DeleteTimers(); } if (bResetClients) { pDlgProgress->SetPercentage(iProgressStepPercentage * ++iProgressStepsDone); pDlgProgress->Progress(); // delete all clients data (e.g priorities, which are only stored locally) pvrDatabase->DeleteClients(); } if (bResetChannels || bResetRecordings) { CVideoDatabase videoDatabase; if (videoDatabase.Open()) { if (bResetChannels) { pDlgProgress->SetPercentage(iProgressStepPercentage * ++iProgressStepsDone); pDlgProgress->Progress(); // delete all channel's entries (e.g. settings, bookmarks, stream details) videoDatabase.EraseAllForPath("pvr://channels/"); } if (bResetRecordings) { pDlgProgress->SetPercentage(iProgressStepPercentage * ++iProgressStepsDone); pDlgProgress->Progress(); // delete all recording's entries (e.g. settings, bookmarks, stream details) videoDatabase.EraseAllForPath(CPVRRecordingsPath::PATH_RECORDINGS); } videoDatabase.Close(); } } // decrease db open refcounts; this actually closes dbs because refcounts drops to zero pvrDatabase->Close(); epgDatabase->Close(); CLog::LogFC(LOGDEBUG, LOGPVR, "{} database cleared", bResetEPGOnly ? "EPG" : "PVR and EPG"); CLog::Log(LOGINFO, "Restarting the PVR Manager after {} database reset", bResetEPGOnly ? "EPG" : "PVR and EPG"); CServiceBroker::GetPVRManager().Start(); pDlgProgress->SetPercentage(100); pDlgProgress->Close(); return true; }