diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
commit | c04dcc2e7d834218ef2d4194331e383402495ae1 (patch) | |
tree | 7333e38d10d75386e60f336b80c2443c1166031d /xbmc/video/dialogs/GUIDialogSubtitles.cpp | |
parent | Initial commit. (diff) | |
download | kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.tar.xz kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.zip |
Adding upstream version 2:20.4+dfsg.upstream/2%20.4+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'xbmc/video/dialogs/GUIDialogSubtitles.cpp')
-rw-r--r-- | xbmc/video/dialogs/GUIDialogSubtitles.cpp | 703 |
1 files changed, 703 insertions, 0 deletions
diff --git a/xbmc/video/dialogs/GUIDialogSubtitles.cpp b/xbmc/video/dialogs/GUIDialogSubtitles.cpp new file mode 100644 index 0000000..600c6da --- /dev/null +++ b/xbmc/video/dialogs/GUIDialogSubtitles.cpp @@ -0,0 +1,703 @@ +/* + * Copyright (C) 2005-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 "GUIDialogSubtitles.h" + +#include "FileItem.h" +#include "LangInfo.h" +#include "ServiceBroker.h" +#include "URL.h" +#include "Util.h" +#include "addons/AddonManager.h" +#include "addons/addoninfo/AddonInfo.h" +#include "addons/addoninfo/AddonType.h" +#include "addons/gui/GUIDialogAddonSettings.h" +#include "application/Application.h" +#include "application/ApplicationComponents.h" +#include "application/ApplicationPlayer.h" +#include "cores/IPlayer.h" +#include "dialogs/GUIDialogContextMenu.h" +#include "dialogs/GUIDialogKaiToast.h" +#include "filesystem/AddonsDirectory.h" +#include "filesystem/Directory.h" +#include "filesystem/File.h" +#include "filesystem/SpecialProtocol.h" +#include "filesystem/StackDirectory.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUIKeyboardFactory.h" +#include "guilib/GUIWindowManager.h" +#include "guilib/LocalizeStrings.h" +#include "input/actions/ActionIDs.h" +#include "settings/Settings.h" +#include "settings/SettingsComponent.h" +#include "settings/lib/Setting.h" +#include "utils/JobManager.h" +#include "utils/LangCodeExpander.h" +#include "utils/StringUtils.h" +#include "utils/URIUtils.h" +#include "utils/Variant.h" +#include "utils/log.h" +#include "video/VideoDatabase.h" + +#include <mutex> + +using namespace ADDON; +using namespace XFILE; + +namespace +{ +constexpr int CONTROL_NAMELABEL = 100; +constexpr int CONTROL_NAMELOGO = 110; +constexpr int CONTROL_SUBLIST = 120; +constexpr int CONTROL_SUBSEXIST = 130; +constexpr int CONTROL_SUBSTATUS = 140; +constexpr int CONTROL_SERVICELIST = 150; +constexpr int CONTROL_MANUALSEARCH = 160; + +enum class SUBTITLE_SERVICE_CONTEXT_BUTTONS +{ + ADDON_SETTINGS, + ADDON_DISABLE +}; +} // namespace + +/*! \brief simple job to retrieve a directory and store a string (language) + */ +class CSubtitlesJob: public CJob +{ +public: + CSubtitlesJob(const CURL &url, const std::string &language) : m_url(url), m_language(language) + { + m_items = new CFileItemList; + } + ~CSubtitlesJob() override + { + delete m_items; + } + bool DoWork() override + { + CDirectory::GetDirectory(m_url.Get(), *m_items, "", DIR_FLAG_DEFAULTS); + return true; + } + bool operator==(const CJob *job) const override + { + if (strcmp(job->GetType(),GetType()) == 0) + { + const CSubtitlesJob* rjob = dynamic_cast<const CSubtitlesJob*>(job); + if (rjob) + { + return m_url.Get() == rjob->m_url.Get() && + m_language == rjob->m_language; + } + } + return false; + } + const CFileItemList *GetItems() const { return m_items; } + const CURL &GetURL() const { return m_url; } + const std::string &GetLanguage() const { return m_language; } +private: + CURL m_url; + CFileItemList *m_items; + std::string m_language; +}; + +CGUIDialogSubtitles::CGUIDialogSubtitles(void) + : CGUIDialog(WINDOW_DIALOG_SUBTITLES, "DialogSubtitles.xml") + , m_subtitles(new CFileItemList) + , m_serviceItems(new CFileItemList) +{ + m_loadType = KEEP_IN_MEMORY; +} + +CGUIDialogSubtitles::~CGUIDialogSubtitles(void) +{ + CancelJobs(); + delete m_subtitles; + delete m_serviceItems; +} + +bool CGUIDialogSubtitles::OnMessage(CGUIMessage& message) +{ + if (message.GetMessage() == GUI_MSG_CLICKED) + { + int iControl = message.GetSenderId(); + bool selectAction = (message.GetParam1() == ACTION_SELECT_ITEM || + message.GetParam1() == ACTION_MOUSE_LEFT_CLICK); + + bool contextMenuAction = (message.GetParam1() == ACTION_CONTEXT_MENU || + message.GetParam1() == ACTION_MOUSE_RIGHT_CLICK); + + if (selectAction && iControl == CONTROL_SUBLIST) + { + CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_SUBLIST); + OnMessage(msg); + + int item = msg.GetParam1(); + if (item >= 0 && item < m_subtitles->Size()) + Download(*m_subtitles->Get(item)); + return true; + } + else if (selectAction && iControl == CONTROL_SERVICELIST) + { + CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_SERVICELIST); + OnMessage(msg); + + int item = msg.GetParam1(); + if (item >= 0 && item < m_serviceItems->Size()) + { + SetService(m_serviceItems->Get(item)->GetProperty("Addon.ID").asString()); + Search(); + } + return true; + } + else if (contextMenuAction && iControl == CONTROL_SERVICELIST) + { + CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_SERVICELIST); + OnMessage(msg); + + const int itemIdx = msg.GetParam1(); + if (itemIdx >= 0 && itemIdx < m_serviceItems->Size()) + { + OnSubtitleServiceContextMenu(itemIdx); + } + } + else if (iControl == CONTROL_MANUALSEARCH) + { + //manual search + if (CGUIKeyboardFactory::ShowAndGetInput(m_strManualSearch, CVariant{g_localizeStrings.Get(24121)}, true)) + { + Search(m_strManualSearch); + return true; + } + } + } + else if (message.GetMessage() == GUI_MSG_WINDOW_DEINIT) + { + auto& components = CServiceBroker::GetAppComponents(); + const auto appPlayer = components.GetComponent<CApplicationPlayer>(); + // Resume the video if the user has requested it + if (appPlayer->IsPaused() && m_pausedOnRun) + appPlayer->Pause(); + + CGUIDialog::OnMessage(message); + + ClearSubtitles(); + ClearServices(); + return true; + } + return CGUIDialog::OnMessage(message); +} + +void CGUIDialogSubtitles::OnInitWindow() +{ + // Pause the video if the user has requested it + m_pausedOnRun = false; + auto& components = CServiceBroker::GetAppComponents(); + const auto appPlayer = components.GetComponent<CApplicationPlayer>(); + if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool( + CSettings::SETTING_SUBTITLES_PAUSEONSEARCH) && + !appPlayer->IsPaused()) + { + appPlayer->Pause(); + m_pausedOnRun = true; + } + + FillServices(); + CGUIWindow::OnInitWindow(); + Search(); +} + +void CGUIDialogSubtitles::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions) +{ + if (m_bInvalidated) + { + // take copies of our variables to ensure we don't hold the lock for long. + std::string status; + CFileItemList subs; + { + std::unique_lock<CCriticalSection> lock(m_critsection); + status = m_status; + subs.Assign(*m_subtitles); + } + SET_CONTROL_LABEL(CONTROL_SUBSTATUS, status); + + if (m_updateSubsList) + { + CGUIMessage message(GUI_MSG_LABEL_BIND, GetID(), CONTROL_SUBLIST, 0, 0, &subs); + OnMessage(message); + if (!subs.IsEmpty()) + { + // focus subtitles list + CGUIMessage msg(GUI_MSG_SETFOCUS, GetID(), CONTROL_SUBLIST); + OnMessage(msg); + } + m_updateSubsList = false; + } + + int control = GetFocusedControlID(); + // nothing has focus + if (!control) + { + CGUIMessage msg(GUI_MSG_SETFOCUS, GetID(), m_subtitles->IsEmpty() ? + CONTROL_SERVICELIST : CONTROL_SUBLIST); + OnMessage(msg); + } + // subs list is focused but we have no subs + else if (control == CONTROL_SUBLIST && m_subtitles->IsEmpty()) + { + CGUIMessage msg(GUI_MSG_SETFOCUS, GetID(), CONTROL_SERVICELIST); + OnMessage(msg); + } + } + CGUIDialog::Process(currentTime, dirtyregions); +} + +void CGUIDialogSubtitles::FillServices() +{ + ClearServices(); + + VECADDONS addons; + CServiceBroker::GetAddonMgr().GetAddons(addons, AddonType::SUBTITLE_MODULE); + + if (addons.empty()) + { + UpdateStatus(NO_SERVICES); + return; + } + + std::string defaultService; + const CFileItem &item = g_application.CurrentUnstackedItem(); + if (item.GetVideoContentType() == VideoDbContentType::TVSHOWS || + item.GetVideoContentType() == VideoDbContentType::EPISODES) + // Set default service for tv shows + defaultService = CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_SUBTITLES_TV); + else + // Set default service for filemode and movies + defaultService = CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_SUBTITLES_MOVIE); + + std::string service = addons.front()->ID(); + for (VECADDONS::const_iterator addonIt = addons.begin(); addonIt != addons.end(); ++addonIt) + { + CFileItemPtr item(CAddonsDirectory::FileItemFromAddon(*addonIt, "plugin://" + (*addonIt)->ID(), false)); + m_serviceItems->Add(item); + if ((*addonIt)->ID() == defaultService) + service = (*addonIt)->ID(); + } + + // Bind our services to the UI + CGUIMessage msg(GUI_MSG_LABEL_BIND, GetID(), CONTROL_SERVICELIST, 0, 0, m_serviceItems); + OnMessage(msg); + + SetService(service); +} + +bool CGUIDialogSubtitles::SetService(const std::string &service) +{ + if (service != m_currentService) + { + m_currentService = service; + CLog::Log(LOGDEBUG, "New Service [{}] ", m_currentService); + + CFileItemPtr currentService = GetService(); + // highlight this item in the skin + for (int i = 0; i < m_serviceItems->Size(); i++) + { + CFileItemPtr pItem = m_serviceItems->Get(i); + pItem->Select(pItem == currentService); + } + + SET_CONTROL_LABEL(CONTROL_NAMELABEL, currentService->GetLabel()); + + if (currentService->HasAddonInfo()) + { + std::string icon = URIUtils::AddFileToFolder(currentService->GetAddonInfo()->Path(), "logo.png"); + SET_CONTROL_FILENAME(CONTROL_NAMELOGO, icon); + } + + const auto& components = CServiceBroker::GetAppComponents(); + const auto appPlayer = components.GetComponent<CApplicationPlayer>(); + if (appPlayer->GetSubtitleCount() == 0) + SET_CONTROL_HIDDEN(CONTROL_SUBSEXIST); + else + SET_CONTROL_VISIBLE(CONTROL_SUBSEXIST); + + return true; + } + return false; +} + +const CFileItemPtr CGUIDialogSubtitles::GetService() const +{ + for (int i = 0; i < m_serviceItems->Size(); i++) + { + if (m_serviceItems->Get(i)->GetProperty("Addon.ID") == m_currentService) + return m_serviceItems->Get(i); + } + return CFileItemPtr(); +} + +void CGUIDialogSubtitles::Search(const std::string &search/*=""*/) +{ + if (m_currentService.empty()) + return; // no services available + + UpdateStatus(SEARCHING); + ClearSubtitles(); + + CURL url("plugin://" + m_currentService + "/"); + if (!search.empty()) + { + url.SetOption("action", "manualsearch"); + url.SetOption("searchstring", search); + } + else + url.SetOption("action", "search"); + + const std::shared_ptr<CSettings> settings = CServiceBroker::GetSettingsComponent()->GetSettings(); + SettingConstPtr setting = settings->GetSetting(CSettings::SETTING_SUBTITLES_LANGUAGES); + if (setting) + url.SetOption("languages", setting->ToString()); + + // Check for stacking + if (g_application.CurrentFileItem().IsStack()) + url.SetOption("stack", "1"); + + std::string preferredLanguage = settings->GetString(CSettings::SETTING_LOCALE_SUBTITLELANGUAGE); + + if (StringUtils::EqualsNoCase(preferredLanguage, "original")) + { + AudioStreamInfo info; + std::string strLanguage; + + const auto& components = CServiceBroker::GetAppComponents(); + const auto appPlayer = components.GetComponent<CApplicationPlayer>(); + appPlayer->GetAudioStreamInfo(CURRENT_STREAM, info); + + if (!g_LangCodeExpander.Lookup(info.language, strLanguage)) + strLanguage = "Unknown"; + + preferredLanguage = strLanguage; + } + else if (StringUtils::EqualsNoCase(preferredLanguage, "default")) + preferredLanguage = g_langInfo.GetEnglishLanguageName(); + + url.SetOption("preferredlanguage", preferredLanguage); + + AddJob(new CSubtitlesJob(url, "")); +} + +void CGUIDialogSubtitles::OnJobComplete(unsigned int jobID, bool success, CJob *job) +{ + const CURL &url = static_cast<CSubtitlesJob*>(job)->GetURL(); + const CFileItemList *items = static_cast<CSubtitlesJob*>(job)->GetItems(); + const std::string &language = static_cast<CSubtitlesJob*>(job)->GetLanguage(); + if (url.GetOption("action") == "search" || url.GetOption("action") == "manualsearch") + OnSearchComplete(items); + else + OnDownloadComplete(items, language); + CJobQueue::OnJobComplete(jobID, success, job); +} + +void CGUIDialogSubtitles::OnSearchComplete(const CFileItemList *items) +{ + std::unique_lock<CCriticalSection> lock(m_critsection); + m_subtitles->Assign(*items); + UpdateStatus(SEARCH_COMPLETE); + m_updateSubsList = true; + MarkDirtyRegion(); + + const auto& components = CServiceBroker::GetAppComponents(); + const auto appPlayer = components.GetComponent<CApplicationPlayer>(); + if (!items->IsEmpty() && appPlayer->GetSubtitleCount() == 0 && + m_LastAutoDownloaded != g_application.CurrentFile() && + CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool( + CSettings::SETTING_SUBTITLES_DOWNLOADFIRST)) + { + CFileItemPtr item = items->Get(0); + CLog::Log(LOGDEBUG, "{} - Automatically download first subtitle: {}", __FUNCTION__, + item->GetLabel2()); + m_LastAutoDownloaded = g_application.CurrentFile(); + Download(*item); + } + + SetInvalid(); +} + +void CGUIDialogSubtitles::OnSubtitleServiceContextMenu(int itemIdx) +{ + const auto service = m_serviceItems->Get(itemIdx); + + CContextButtons buttons; + // Subtitle addon settings + buttons.Add(static_cast<int>(SUBTITLE_SERVICE_CONTEXT_BUTTONS::ADDON_SETTINGS), + g_localizeStrings.Get(21417)); + // Disable addon + buttons.Add(static_cast<int>(SUBTITLE_SERVICE_CONTEXT_BUTTONS::ADDON_DISABLE), + g_localizeStrings.Get(24021)); + + auto idx = static_cast<SUBTITLE_SERVICE_CONTEXT_BUTTONS>(CGUIDialogContextMenu::Show(buttons)); + switch (idx) + { + case SUBTITLE_SERVICE_CONTEXT_BUTTONS::ADDON_SETTINGS: + { + AddonPtr addon; + if (CServiceBroker::GetAddonMgr().GetAddon(service->GetProperty("Addon.ID").asString(), addon, + AddonType::SUBTITLE_MODULE, + OnlyEnabled::CHOICE_YES)) + { + CGUIDialogAddonSettings::ShowForAddon(addon); + } + else + { + CLog::Log(LOGERROR, "{} - Could not open settings for addon: {}", __FUNCTION__, + service->GetProperty("Addon.ID").asString()); + } + break; + } + case SUBTITLE_SERVICE_CONTEXT_BUTTONS::ADDON_DISABLE: + { + CServiceBroker::GetAddonMgr().DisableAddon(service->GetProperty("Addon.ID").asString(), + AddonDisabledReason::USER); + const bool currentActiveServiceWasDisabled = + m_currentService == service->GetProperty("Addon.ID").asString(); + FillServices(); + // restart search if the current active service was disabled + if (currentActiveServiceWasDisabled && !m_serviceItems->IsEmpty()) + { + Search(); + } + // if no more services are available make sure the subtitle list is cleaned up + else if (m_serviceItems->IsEmpty()) + { + ClearSubtitles(); + } + break; + } + default: + break; + } +} + +void CGUIDialogSubtitles::UpdateStatus(STATUS status) +{ + std::unique_lock<CCriticalSection> lock(m_critsection); + std::string label; + switch (status) + { + case NO_SERVICES: + label = g_localizeStrings.Get(24114); + break; + case SEARCHING: + label = g_localizeStrings.Get(24107); + break; + case SEARCH_COMPLETE: + if (!m_subtitles->IsEmpty()) + label = StringUtils::Format(g_localizeStrings.Get(24108), m_subtitles->Size()); + else + label = g_localizeStrings.Get(24109); + break; + case DOWNLOADING: + label = g_localizeStrings.Get(24110); + break; + default: + break; + } + if (label != m_status) + { + m_status = label; + SetInvalid(); + } +} + +void CGUIDialogSubtitles::Download(const CFileItem &subtitle) +{ + UpdateStatus(DOWNLOADING); + + // subtitle URL should be of the form plugin://<addonid>/?param=foo¶m=bar + // we just append (if not already present) the action=download parameter. + CURL url(subtitle.GetURL()); + if (url.GetOption("action").empty()) + url.SetOption("action", "download"); + + AddJob(new CSubtitlesJob(url, subtitle.GetLabel())); +} + +void CGUIDialogSubtitles::OnDownloadComplete(const CFileItemList *items, const std::string &language) +{ + if (items->IsEmpty()) + { + CFileItemPtr service = GetService(); + if (service) + CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error, service->GetLabel(), g_localizeStrings.Get(24113)); + UpdateStatus(SEARCH_COMPLETE); + return; + } + + SUBTITLE_STORAGEMODE storageMode = (SUBTITLE_STORAGEMODE) CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_SUBTITLES_STORAGEMODE); + + // Get (unstacked) path + std::string strCurrentFile = g_application.CurrentUnstackedItem().GetDynPath(); + + std::string strDownloadPath = "special://temp"; + std::string strDestPath; + std::vector<std::string> vecFiles; + + std::string strCurrentFilePath; + if (StringUtils::StartsWith(strCurrentFilePath, "http://")) + { + strCurrentFile = "TempSubtitle"; + vecFiles.push_back(strCurrentFile); + } + else + { + std::string subPath = CSpecialProtocol::TranslatePath("special://subtitles"); + if (!subPath.empty()) + strDownloadPath = subPath; + + /** Get item's folder for sub storage, special case for RAR/ZIP items + * @todo We need some way to avoid special casing this all over the place + * for rar/zip (perhaps modify GetDirectory?) + */ + if (URIUtils::IsInRAR(strCurrentFile) || URIUtils::IsInZIP(strCurrentFile)) + strCurrentFilePath = URIUtils::GetDirectory(CURL(strCurrentFile).GetHostName()); + else + strCurrentFilePath = URIUtils::GetDirectory(strCurrentFile); + + // Handle stacks + if (g_application.CurrentFileItem().IsStack() && items->Size() > 1) + { + CStackDirectory::GetPaths(g_application.CurrentFileItem().GetPath(), vecFiles); + // Make sure (stack) size is the same as the size of the items handed to us, else fallback to single item + if (items->Size() != (int) vecFiles.size()) + { + vecFiles.clear(); + vecFiles.push_back(strCurrentFile); + } + } + else + { + vecFiles.push_back(strCurrentFile); + } + + if (storageMode == SUBTITLE_STORAGEMODE_MOVIEPATH && + CUtil::SupportsWriteFileOperations(strCurrentFilePath)) + { + strDestPath = strCurrentFilePath; + } + } + + // Use fallback? + if (strDestPath.empty()) + strDestPath = strDownloadPath; + + // Extract the language and appropriate extension + std::string strSubLang; + g_LangCodeExpander.ConvertToISO6391(language, strSubLang); + + // Iterate over all items to transfer + for (unsigned int i = 0; i < vecFiles.size() && i < (unsigned int) items->Size(); i++) + { + std::string strUrl = items->Get(i)->GetPath(); + std::string strFileName = URIUtils::GetFileName(vecFiles[i]); + URIUtils::RemoveExtension(strFileName); + + // construct subtitle path + std::string strSubExt = URIUtils::GetExtension(strUrl); + std::string strSubName = StringUtils::Format("{}.{}{}", strFileName, strSubLang, strSubExt); + + // Handle URL encoding: + std::string strDownloadFile = URIUtils::ChangeBasePath(strCurrentFilePath, strSubName, strDownloadPath); + std::string strDestFile = strDownloadFile; + + if (!CFile::Copy(strUrl, strDownloadFile)) + { + CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error, strSubName, g_localizeStrings.Get(24113)); + CLog::Log(LOGERROR, "{} - Saving of subtitle {} to {} failed", __FUNCTION__, strUrl, + strDownloadFile); + } + else + { + if (strDestPath != strDownloadPath) + { + // Handle URL encoding: + std::string strTryDestFile = URIUtils::ChangeBasePath(strCurrentFilePath, strSubName, strDestPath); + + /* Copy the file from temp to our final destination, if that fails fallback to download path + * (ie. special://subtitles or use special://temp). Note that after the first item strDownloadPath equals strDestpath + * so that all remaining items (including the .idx below) are copied directly to their final destination and thus all + * items end up in the same folder + */ + CLog::Log(LOGDEBUG, "{} - Saving subtitle {} to {}", __FUNCTION__, strDownloadFile, + strTryDestFile); + if (CFile::Copy(strDownloadFile, strTryDestFile)) + { + CFile::Delete(strDownloadFile); + strDestFile = strTryDestFile; + strDownloadPath = strDestPath; // Update download path so all the other items get directly downloaded to our final destination + } + else + { + CLog::Log(LOGWARNING, "{} - Saving of subtitle {} to {} failed. Falling back to {}", + __FUNCTION__, strDownloadFile, strTryDestFile, strDownloadPath); + strDestPath = strDownloadPath; // Copy failed, use fallback for the rest of the items + } + } + else + { + CLog::Log(LOGDEBUG, "{} - Saved subtitle {} to {}", __FUNCTION__, strUrl, strDownloadFile); + } + + // for ".sub" subtitles we check if ".idx" counterpart exists and copy that as well + if (StringUtils::EqualsNoCase(strSubExt, ".sub")) + { + strUrl = URIUtils::ReplaceExtension(strUrl, ".idx"); + if(CFile::Exists(strUrl)) + { + std::string strSubNameIdx = StringUtils::Format("{}.{}.idx", strFileName, strSubLang); + // Handle URL encoding: + strDestFile = URIUtils::ChangeBasePath(strCurrentFilePath, strSubNameIdx, strDestPath); + CFile::Copy(strUrl, strDestFile); + } + } + + // Set sub for currently playing (stack) item + if (vecFiles[i] == strCurrentFile) + SetSubtitles(strDestFile); + } + } + + // Notify window manager that a subtitle was downloaded + CGUIMessage msg(GUI_MSG_SUBTITLE_DOWNLOADED, 0, 0); + CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg); + + // Close the window + Close(); +} + +void CGUIDialogSubtitles::ClearSubtitles() +{ + CGUIMessage msg(GUI_MSG_LABEL_RESET, GetID(), CONTROL_SUBLIST); + OnMessage(msg); + std::unique_lock<CCriticalSection> lock(m_critsection); + m_subtitles->Clear(); +} + +void CGUIDialogSubtitles::ClearServices() +{ + CGUIMessage msg(GUI_MSG_LABEL_RESET, GetID(), CONTROL_SERVICELIST); + OnMessage(msg); + m_serviceItems->Clear(); + m_currentService.clear(); +} + +void CGUIDialogSubtitles::SetSubtitles(const std::string &subtitle) +{ + auto& components = CServiceBroker::GetAppComponents(); + const auto appPlayer = components.GetComponent<CApplicationPlayer>(); + appPlayer->AddSubtitle(subtitle); +} |