Merge pull request #25922 from sarbes/shader-cleanup
[xbmc.git] / xbmc / storage / MediaManager.cpp
blobc5da61dd82b19de219a192c19095053881dee521
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "MediaManager.h"
11 #include "FileItem.h"
12 #include "ServiceBroker.h"
13 #include "URL.h"
14 #include "guilib/GUIComponent.h"
15 #include "guilib/LocalizeStrings.h"
16 #include "utils/URIUtils.h"
18 #include <mutex>
19 #ifdef TARGET_WINDOWS
20 #include "platform/win32/WIN32Util.h"
21 #include "utils/CharsetConverter.h"
22 #endif
23 #include "guilib/GUIWindowManager.h"
24 #ifdef HAS_OPTICAL_DRIVE
25 #ifndef TARGET_WINDOWS
26 //! @todo switch all ports to use auto sources
27 #include <map>
28 #include <utility>
29 #include "DetectDVDType.h"
30 #endif
31 #endif
32 #include "Autorun.h"
33 #include "AutorunMediaJob.h"
34 #include "GUIUserMessages.h"
35 #include "addons/VFSEntry.h"
36 #include "dialogs/GUIDialogKaiToast.h"
37 #include "dialogs/GUIDialogPlayEject.h"
38 #include "messaging/helpers/DialogOKHelper.h"
39 #include "settings/AdvancedSettings.h"
40 #include "settings/MediaSourceSettings.h"
41 #include "settings/Settings.h"
42 #include "settings/SettingsComponent.h"
43 #include "utils/FileUtils.h"
44 #include "utils/JobManager.h"
45 #include "utils/StringUtils.h"
46 #include "utils/XBMCTinyXML2.h"
47 #include "utils/XMLUtils.h"
48 #include "utils/log.h"
50 #include <string>
51 #include <vector>
53 #ifdef HAS_OPTICAL_DRIVE
54 using namespace MEDIA_DETECT;
55 #endif
57 const char MEDIA_SOURCES_XML[] = { "special://profile/mediasources.xml" };
59 CMediaManager::CMediaManager()
61 m_bhasoptical = false;
64 void CMediaManager::Stop()
66 if (m_platformStorage)
67 m_platformStorage->Stop();
69 m_platformStorage.reset();
72 void CMediaManager::Initialize()
74 if (!m_platformStorage)
76 m_platformStorage = IStorageProvider::CreateInstance();
78 #ifdef HAS_OPTICAL_DRIVE
79 m_platformDiscDriveHander = IDiscDriveHandler::CreateInstance();
80 m_strFirstAvailDrive = m_platformStorage->GetFirstOpticalDeviceFileName();
81 #endif
82 m_platformStorage->Initialize();
85 bool CMediaManager::LoadSources()
87 // clear our location list
88 m_locations.clear();
90 // load xml file...
91 CXBMCTinyXML2 xmlDoc;
92 if ( !xmlDoc.LoadFile( MEDIA_SOURCES_XML ) )
93 return false;
95 auto* pRootElement = xmlDoc.RootElement();
96 if (!pRootElement || StringUtils::CompareNoCase(pRootElement->Value(), "mediasources") != 0)
98 CLog::Log(LOGERROR, "Error loading {}, Line {} ({})", MEDIA_SOURCES_XML, xmlDoc.ErrorLineNum(),
99 xmlDoc.ErrorStr());
100 return false;
103 // load the <network> block
104 auto* pNetwork = pRootElement->FirstChildElement("network");
105 if (pNetwork)
107 auto* pLocation = pNetwork->FirstChildElement("location");
108 while (pLocation)
110 CNetworkLocation location;
111 location.id = pLocation->IntAttribute("id");
112 if (pLocation->FirstChild())
114 location.path = pLocation->FirstChild()->Value();
115 m_locations.push_back(location);
117 pLocation = pLocation->NextSiblingElement("location");
120 LoadAddonSources();
121 return true;
124 bool CMediaManager::SaveSources()
126 CXBMCTinyXML2 doc;
127 auto* xmlRootElement = doc.NewElement("mediasources");
128 auto* rootNode = doc.InsertFirstChild(xmlRootElement);
130 if (!rootNode)
131 return false;
133 auto* networkElement = doc.NewElement("network");
134 auto* networkNode = rootNode->InsertEndChild(networkElement);
135 if (networkNode)
137 for (std::vector<CNetworkLocation>::iterator it = m_locations.begin(); it != m_locations.end(); ++it)
139 auto* locationNode = doc.NewElement("location");
140 locationNode->SetAttribute("id", (*it).id);
141 auto* value = doc.NewText((*it).path.c_str());
142 locationNode->InsertEndChild(value);
143 networkNode->InsertEndChild(locationNode);
146 return doc.SaveFile(MEDIA_SOURCES_XML);
149 void CMediaManager::GetLocalDrives(std::vector<CMediaSource>& localDrives, bool includeQ)
151 std::unique_lock<CCriticalSection> lock(m_CritSecStorageProvider);
152 m_platformStorage->GetLocalDrives(localDrives);
155 void CMediaManager::GetRemovableDrives(std::vector<CMediaSource>& removableDrives)
157 std::unique_lock<CCriticalSection> lock(m_CritSecStorageProvider);
158 if (m_platformStorage)
159 m_platformStorage->GetRemovableDrives(removableDrives);
162 void CMediaManager::GetNetworkLocations(std::vector<CMediaSource>& locations, bool autolocations)
164 for (unsigned int i = 0; i < m_locations.size(); i++)
166 CMediaSource share;
167 share.strPath = m_locations[i].path;
168 CURL url(share.strPath);
169 share.strName = url.GetWithoutUserDetails();
170 locations.push_back(share);
172 if (autolocations)
174 CMediaSource share;
175 share.m_ignore = true;
176 #ifdef HAS_FILESYSTEM_SMB
177 share.strPath = "smb://";
178 share.strName = g_localizeStrings.Get(20171);
179 locations.push_back(share);
180 #endif
182 #ifdef HAS_FILESYSTEM_NFS
183 share.strPath = "nfs://";
184 share.strName = g_localizeStrings.Get(20259);
185 locations.push_back(share);
186 #endif// HAS_FILESYSTEM_NFS
188 #ifdef HAS_UPNP
189 if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_SERVICES_UPNP))
191 const std::string& strDevices = g_localizeStrings.Get(33040); //"% Devices"
192 share.strPath = "upnp://";
193 share.strName = StringUtils::Format(strDevices, "UPnP"); //"UPnP Devices"
194 locations.push_back(share);
196 #endif
198 #ifdef HAS_ZEROCONF
199 share.strPath = "zeroconf://";
200 share.strName = g_localizeStrings.Get(20262);
201 locations.push_back(share);
202 #endif
204 if (CServiceBroker::IsAddonInterfaceUp())
206 for (const auto& addon : CServiceBroker::GetVFSAddonCache().GetAddonInstances())
208 const auto& info = addon->GetProtocolInfo();
209 if (!info.type.empty() && info.supportBrowsing)
211 share.strPath = info.type + "://";
212 share.strName = g_localizeStrings.GetAddonString(addon->ID(), info.label);
213 if (share.strName.empty())
214 share.strName = g_localizeStrings.Get(info.label);
215 locations.push_back(share);
222 bool CMediaManager::AddNetworkLocation(const std::string &path)
224 CNetworkLocation location;
225 location.path = path;
226 location.id = (int)m_locations.size();
227 m_locations.push_back(location);
228 return SaveSources();
231 bool CMediaManager::HasLocation(const std::string& path) const
233 for (unsigned int i=0;i<m_locations.size();++i)
235 if (URIUtils::CompareWithoutSlashAtEnd(m_locations[i].path, path))
236 return true;
239 return false;
243 bool CMediaManager::RemoveLocation(const std::string& path)
245 for (unsigned int i=0;i<m_locations.size();++i)
247 if (URIUtils::CompareWithoutSlashAtEnd(m_locations[i].path, path))
249 // prompt for sources, remove, cancel,
250 m_locations.erase(m_locations.begin()+i);
251 return SaveSources();
255 return false;
258 bool CMediaManager::SetLocationPath(const std::string& oldPath, const std::string& newPath)
260 for (unsigned int i=0;i<m_locations.size();++i)
262 if (URIUtils::CompareWithoutSlashAtEnd(m_locations[i].path, oldPath))
264 m_locations[i].path = newPath;
265 return SaveSources();
269 return false;
272 void CMediaManager::LoadAddonSources() const
274 if (CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_bVirtualShares)
276 CMediaSourceSettings::GetInstance().AddShare("video", GetRootAddonTypeSource("video"));
277 CMediaSourceSettings::GetInstance().AddShare("programs", GetRootAddonTypeSource("programs"));
278 CMediaSourceSettings::GetInstance().AddShare("pictures", GetRootAddonTypeSource("pictures"));
279 CMediaSourceSettings::GetInstance().AddShare("music", GetRootAddonTypeSource("music"));
280 CMediaSourceSettings::GetInstance().AddShare("games", GetRootAddonTypeSource("games"));
284 CMediaSource CMediaManager::GetRootAddonTypeSource(const std::string& type) const
286 if (type == "programs" || type == "myprograms")
288 return ComputeRootAddonTypeSource("executable", g_localizeStrings.Get(1043),
289 "DefaultAddonProgram.png");
291 else if (type == "video" || type == "videos")
293 return ComputeRootAddonTypeSource("video", g_localizeStrings.Get(1037),
294 "DefaultAddonVideo.png");
296 else if (type == "music")
298 return ComputeRootAddonTypeSource("audio", g_localizeStrings.Get(1038),
299 "DefaultAddonMusic.png");
301 else if (type == "pictures")
303 return ComputeRootAddonTypeSource("image", g_localizeStrings.Get(1039),
304 "DefaultAddonPicture.png");
306 else if (type == "games")
308 return ComputeRootAddonTypeSource("game", g_localizeStrings.Get(35049), "DefaultAddonGame.png");
310 else
312 CLog::LogF(LOGERROR, "Invalid type {} provided", type);
313 return {};
317 CMediaSource CMediaManager::ComputeRootAddonTypeSource(const std::string& type,
318 const std::string& label,
319 const std::string& thumb) const
321 CMediaSource source;
322 source.strPath = "addons://sources/" + type + "/";
323 source.strName = label;
324 source.m_strThumbnailImage = thumb;
325 source.m_iDriveType = CMediaSource::SOURCE_TYPE_VPATH;
326 source.m_ignore = true;
327 return source;
330 void CMediaManager::AddAutoSource(const CMediaSource &share, bool bAutorun)
332 CMediaSourceSettings::GetInstance().AddShare("files", share);
333 CMediaSourceSettings::GetInstance().AddShare("video", share);
334 CMediaSourceSettings::GetInstance().AddShare("pictures", share);
335 CMediaSourceSettings::GetInstance().AddShare("music", share);
336 CMediaSourceSettings::GetInstance().AddShare("programs", share);
337 CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_SOURCES);
338 CGUIComponent *gui = CServiceBroker::GetGUI();
339 if (gui)
340 gui->GetWindowManager().SendThreadMessage( msg );
342 #ifdef HAS_OPTICAL_DRIVE
343 if(bAutorun)
344 MEDIA_DETECT::CAutorun::ExecuteAutorun(share.strPath);
345 #endif
348 void CMediaManager::RemoveAutoSource(const CMediaSource &share)
350 CMediaSourceSettings::GetInstance().DeleteSource("files", share.strName, share.strPath, true);
351 CMediaSourceSettings::GetInstance().DeleteSource("video", share.strName, share.strPath, true);
352 CMediaSourceSettings::GetInstance().DeleteSource("pictures", share.strName, share.strPath, true);
353 CMediaSourceSettings::GetInstance().DeleteSource("music", share.strName, share.strPath, true);
354 CMediaSourceSettings::GetInstance().DeleteSource("programs", share.strName, share.strPath, true);
355 CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_SOURCES);
356 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage( msg );
358 #ifdef HAS_OPTICAL_DRIVE
359 // delete cached CdInfo if any
360 RemoveCdInfo(TranslateDevicePath(share.strPath, true));
361 RemoveDiscInfo(TranslateDevicePath(share.strPath, true));
362 #endif
365 /////////////////////////////////////////////////////////////
366 // AutoSource status functions:
367 //! @todo translate cdda://<device>/
369 std::string CMediaManager::TranslateDevicePath(const std::string& devicePath, bool bReturnAsDevice)
371 std::unique_lock<CCriticalSection> waitLock(m_muAutoSource);
372 std::string strDevice = devicePath;
373 // fallback for cdda://local/ and empty devicePath
374 #ifdef HAS_OPTICAL_DRIVE
375 if(devicePath.empty() || StringUtils::StartsWith(devicePath, "cdda://local"))
376 strDevice = m_strFirstAvailDrive;
377 #endif
379 #ifdef TARGET_WINDOWS
380 if(!m_bhasoptical)
381 return "";
383 if(bReturnAsDevice == false)
384 StringUtils::Replace(strDevice, "\\\\.\\","");
385 else if(!strDevice.empty() && strDevice[1]==':')
386 strDevice = StringUtils::Format("\\\\.\\{}:", strDevice[0]);
388 URIUtils::RemoveSlashAtEnd(strDevice);
389 #endif
390 return strDevice;
393 bool CMediaManager::IsDiscInDrive(const std::string& devicePath)
395 #ifdef HAS_OPTICAL_DRIVE
396 #ifdef TARGET_WINDOWS
397 if(!m_bhasoptical)
398 return false;
400 std::string strDevice = TranslateDevicePath(devicePath, false);
401 std::map<std::string,CCdInfo*>::iterator it;
402 std::unique_lock<CCriticalSection> waitLock(m_muAutoSource);
403 it = m_mapCdInfo.find(strDevice);
404 if(it != m_mapCdInfo.end())
405 return true;
406 else
407 return false;
408 #else
409 if(URIUtils::IsDVD(devicePath) || devicePath.empty())
410 return MEDIA_DETECT::CDetectDVDMedia::IsDiscInDrive(); //! @todo switch all ports to use auto sources
411 else
412 return true; // Assume other paths to be mounted already
413 #endif
414 #else
415 return false;
416 #endif
419 bool CMediaManager::IsAudio(const std::string& devicePath)
421 #ifdef HAS_OPTICAL_DRIVE
422 #ifdef TARGET_WINDOWS
423 if(!m_bhasoptical)
424 return false;
426 CCdInfo* pCdInfo = GetCdInfo(devicePath);
427 if(pCdInfo != NULL && pCdInfo->IsAudio(1))
428 return true;
430 return false;
431 #else
432 //! @todo switch all ports to use auto sources
433 MEDIA_DETECT::CCdInfo* pInfo = MEDIA_DETECT::CDetectDVDMedia::GetCdInfo();
434 if (pInfo != NULL && pInfo->IsAudio(1))
435 return true;
436 #endif
437 #endif
438 return false;
441 bool CMediaManager::HasOpticalDrive()
443 #ifdef HAS_OPTICAL_DRIVE
444 if (!m_strFirstAvailDrive.empty())
445 return true;
446 #endif
447 return false;
450 DriveState CMediaManager::GetDriveStatus(const std::string& devicePath)
452 #ifdef HAS_OPTICAL_DRIVE
453 #ifdef TARGET_WINDOWS
454 if (!m_bhasoptical || !m_platformDiscDriveHander)
455 return DriveState::NOT_READY;
457 std::string translatedDevicePath = TranslateDevicePath(devicePath, true);
458 return m_platformDiscDriveHander->GetDriveState(translatedDevicePath);
459 #else
460 return MEDIA_DETECT::CDetectDVDMedia::GetDriveState();
461 #endif
462 #else
463 return DriveState::NOT_READY;
464 #endif
467 #ifdef HAS_OPTICAL_DRIVE
468 CCdInfo* CMediaManager::GetCdInfo(const std::string& devicePath)
470 #ifdef TARGET_WINDOWS
471 if(!m_bhasoptical)
472 return NULL;
474 std::string strDevice = TranslateDevicePath(devicePath, false);
475 std::map<std::string,CCdInfo*>::iterator it;
477 std::unique_lock<CCriticalSection> waitLock(m_muAutoSource);
478 it = m_mapCdInfo.find(strDevice);
479 if(it != m_mapCdInfo.end())
480 return it->second;
483 CCdInfo* pCdInfo=NULL;
484 CCdIoSupport cdio;
485 pCdInfo = cdio.GetCdInfo((char*)strDevice.c_str());
486 if(pCdInfo!=NULL)
488 std::unique_lock<CCriticalSection> waitLock(m_muAutoSource);
489 m_mapCdInfo.insert(std::pair<std::string,CCdInfo*>(strDevice,pCdInfo));
492 return pCdInfo;
493 #else
494 return MEDIA_DETECT::CDetectDVDMedia::GetCdInfo();
495 #endif
498 bool CMediaManager::RemoveCdInfo(const std::string& devicePath)
500 if(!m_bhasoptical)
501 return false;
503 std::string strDevice = TranslateDevicePath(devicePath, false);
505 std::map<std::string,CCdInfo*>::iterator it;
506 std::unique_lock<CCriticalSection> waitLock(m_muAutoSource);
507 it = m_mapCdInfo.find(strDevice);
508 if(it != m_mapCdInfo.end())
510 if(it->second != NULL)
511 delete it->second;
513 m_mapCdInfo.erase(it);
514 return true;
516 return false;
519 std::string CMediaManager::GetDiskLabel(const std::string& devicePath)
521 #ifdef TARGET_WINDOWS_STORE
522 return ""; // GetVolumeInformationW nut support in UWP app
523 #elif defined(TARGET_WINDOWS)
524 if(!m_bhasoptical)
525 return "";
527 std::string mediaPath = CServiceBroker::GetMediaManager().TranslateDevicePath(devicePath);
529 auto cached = m_mapDiscInfo.find(mediaPath);
530 if (cached != m_mapDiscInfo.end())
531 return cached->second.name;
533 // try to minimize the chance of a "device not ready" dialog
534 std::string drivePath = CServiceBroker::GetMediaManager().TranslateDevicePath(devicePath, true);
535 if (CServiceBroker::GetMediaManager().GetDriveStatus(drivePath) !=
536 DriveState::CLOSED_MEDIA_PRESENT)
537 return "";
539 UTILS::DISCS::DiscInfo info;
540 info = GetDiscInfo(mediaPath);
541 if (!info.name.empty())
543 m_mapDiscInfo[mediaPath] = info;
544 return info.name;
547 std::string strDevice = TranslateDevicePath(devicePath);
548 WCHAR cVolumenName[128];
549 WCHAR cFSName[128];
550 URIUtils::AddSlashAtEnd(strDevice);
551 std::wstring strDeviceW;
552 g_charsetConverter.utf8ToW(strDevice, strDeviceW);
553 if(GetVolumeInformationW(strDeviceW.c_str(), cVolumenName, 127, NULL, NULL, NULL, cFSName, 127)==0)
554 return "";
555 g_charsetConverter.wToUTF8(cVolumenName, strDevice);
556 info.name = StringUtils::TrimRight(strDevice, " ");
557 if (!info.name.empty())
558 m_mapDiscInfo[mediaPath] = info;
560 return info.name;
561 #else
562 return MEDIA_DETECT::CDetectDVDMedia::GetDVDLabel();
563 #endif
566 std::string CMediaManager::GetDiskUniqueId(const std::string& devicePath)
568 std::string mediaPath;
570 CCdInfo* pInfo = CServiceBroker::GetMediaManager().GetCdInfo(devicePath);
571 if (pInfo == NULL)
572 return "";
574 if (pInfo->IsAudio(1))
575 mediaPath = "cdda://local/";
577 if (mediaPath.empty() && (pInfo->IsISOUDF(1) || pInfo->IsISOHFS(1) || pInfo->IsIso9660(1) || pInfo->IsIso9660Interactive(1)))
578 mediaPath = "iso9660://";
580 if (mediaPath.empty())
581 mediaPath = devicePath;
583 #ifdef TARGET_WINDOWS
584 if (mediaPath.empty() || mediaPath == "iso9660://")
586 mediaPath = CServiceBroker::GetMediaManager().TranslateDevicePath(devicePath);
588 #endif
590 UTILS::DISCS::DiscInfo info = GetDiscInfo(mediaPath);
591 if (info.empty())
593 CLog::Log(LOGDEBUG, "GetDiskUniqueId: Retrieving ID for path {} failed, ID is empty.",
594 CURL::GetRedacted(mediaPath));
595 return "";
598 std::string strID = StringUtils::Format("removable://{}_{}", info.name, info.serial);
599 CLog::Log(LOGDEBUG, "GetDiskUniqueId: Got ID {} for disc with path {}", strID,
600 CURL::GetRedacted(mediaPath));
602 return strID;
605 std::string CMediaManager::GetDiscPath()
607 #ifdef TARGET_WINDOWS
608 return CServiceBroker::GetMediaManager().TranslateDevicePath("");
609 #else
611 std::unique_lock<CCriticalSection> lock(m_CritSecStorageProvider);
612 std::vector<CMediaSource> drives;
613 m_platformStorage->GetRemovableDrives(drives);
614 for(unsigned i = 0; i < drives.size(); ++i)
616 if (drives[i].m_iDriveType == CMediaSource::SOURCE_TYPE_OPTICAL_DISC &&
617 !drives[i].strPath.empty())
618 return drives[i].strPath;
621 // iso9660://, cdda://local/ or D:\ depending on disc type
622 return MEDIA_DETECT::CDetectDVDMedia::GetDVDPath();
623 #endif
626 std::shared_ptr<IDiscDriveHandler> CMediaManager::GetDiscDriveHandler()
628 return m_platformDiscDriveHander;
630 #endif
632 void CMediaManager::SetHasOpticalDrive(bool bstatus)
634 std::unique_lock<CCriticalSection> waitLock(m_muAutoSource);
635 m_bhasoptical = bstatus;
638 bool CMediaManager::Eject(const std::string& mountpath)
640 std::unique_lock<CCriticalSection> lock(m_CritSecStorageProvider);
641 return m_platformStorage->Eject(mountpath);
644 void CMediaManager::EjectTray( const bool bEject, const char cDriveLetter )
646 #ifdef HAS_OPTICAL_DRIVE
647 if (m_platformDiscDriveHander)
649 m_platformDiscDriveHander->EjectDriveTray(TranslateDevicePath(""));
651 #endif
654 void CMediaManager::CloseTray(const char cDriveLetter)
656 #ifdef HAS_OPTICAL_DRIVE
657 if (m_platformDiscDriveHander)
659 m_platformDiscDriveHander->ToggleDriveTray(TranslateDevicePath(""));
661 #endif
664 void CMediaManager::ToggleTray(const char cDriveLetter)
666 #ifdef HAS_OPTICAL_DRIVE
667 if (m_platformDiscDriveHander)
669 m_platformDiscDriveHander->ToggleDriveTray(TranslateDevicePath(""));
671 #endif
674 void CMediaManager::ProcessEvents()
676 std::unique_lock<CCriticalSection> lock(m_CritSecStorageProvider);
677 if (m_platformStorage->PumpDriveChangeEvents(this))
679 #if defined(HAS_OPTICAL_DRIVE) && defined(TARGET_DARWIN_OSX)
680 // darwins GetFirstOpticalDeviceFileName only gives us something
681 // when a disc is inserted
682 // so we have to refresh m_strFirstAvailDrive when this happens after Initialize
683 // was called (e.x. the disc was inserted after the start of xbmc)
684 // else TranslateDevicePath wouldn't give the correct device
685 m_strFirstAvailDrive = m_platformStorage->GetFirstOpticalDeviceFileName();
686 #endif
688 CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0,GUI_MSG_UPDATE_SOURCES);
689 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);
693 std::vector<std::string> CMediaManager::GetDiskUsage()
695 std::unique_lock<CCriticalSection> lock(m_CritSecStorageProvider);
696 return m_platformStorage->GetDiskUsage();
699 void CMediaManager::OnStorageAdded(const MEDIA_DETECT::STORAGE::StorageDevice& device)
701 #ifdef HAS_OPTICAL_DRIVE
702 const std::shared_ptr<CSettings> settings = CServiceBroker::GetSettingsComponent()->GetSettings();
703 if (settings->GetInt(CSettings::SETTING_AUDIOCDS_AUTOACTION) != AUTOCD_NONE || settings->GetBool(CSettings::SETTING_DVDS_AUTORUN))
705 if (settings->GetInt(CSettings::SETTING_AUDIOCDS_AUTOACTION) == AUTOCD_RIP)
707 CServiceBroker::GetJobManager()->AddJob(new CAutorunMediaJob(device.label, device.path), this,
708 CJob::PRIORITY_LOW);
710 else
712 if (device.type == MEDIA_DETECT::STORAGE::Type::OPTICAL)
714 if (MEDIA_DETECT::CAutorun::ExecuteAutorun(device.path))
716 return;
718 CLog::Log(LOGDEBUG, "{}: Could not execute autorun for optical disc with path {}",
719 __FUNCTION__, device.path);
721 CServiceBroker::GetJobManager()->AddJob(new CAutorunMediaJob(device.label, device.path), this,
722 CJob::PRIORITY_HIGH);
725 else
727 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, g_localizeStrings.Get(13021),
728 device.label, TOAST_DISPLAY_TIME, false);
730 #endif
733 void CMediaManager::OnStorageSafelyRemoved(const MEDIA_DETECT::STORAGE::StorageDevice& device)
735 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, g_localizeStrings.Get(13023),
736 device.label, TOAST_DISPLAY_TIME, false);
739 void CMediaManager::OnStorageUnsafelyRemoved(const MEDIA_DETECT::STORAGE::StorageDevice& device)
741 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Warning, g_localizeStrings.Get(13022),
742 device.label);
745 UTILS::DISCS::DiscInfo CMediaManager::GetDiscInfo(const std::string& mediaPath)
747 UTILS::DISCS::DiscInfo info;
749 if (mediaPath.empty())
750 return info;
752 // Try finding VIDEO_TS/VIDEO_TS.IFO - this indicates a DVD disc is inserted
753 std::string pathVideoTS = URIUtils::AddFileToFolder(mediaPath, "VIDEO_TS", "VIDEO_TS.IFO");
754 // correct the filename if needed
755 if (StringUtils::StartsWith(mediaPath, "dvd://") ||
756 StringUtils::StartsWith(mediaPath, "iso9660://"))
758 pathVideoTS = TranslateDevicePath("");
761 // check for DVD discs
762 if (CFileUtils::Exists(pathVideoTS))
764 info = UTILS::DISCS::ProbeDVDDiscInfo(pathVideoTS);
765 if (!info.empty())
766 return info;
768 // check for Blu-ray discs
769 if (CFileUtils::Exists(URIUtils::AddFileToFolder(mediaPath, "BDMV", "index.bdmv")))
771 info = UTILS::DISCS::ProbeBlurayDiscInfo(mediaPath);
774 return info;
777 void CMediaManager::RemoveDiscInfo(const std::string& devicePath)
779 std::string strDevice = TranslateDevicePath(devicePath, false);
781 auto it = m_mapDiscInfo.find(strDevice);
782 if (it != m_mapDiscInfo.end())
783 m_mapDiscInfo.erase(it);
786 bool CMediaManager::playStubFile(const CFileItem& item)
788 // Figure out Lines 1 and 2 of the dialog
789 std::string strLine1, strLine2;
791 // use generic message by default
792 strLine1 = g_localizeStrings.Get(435).c_str();
793 strLine2 = g_localizeStrings.Get(436).c_str();
795 CXBMCTinyXML2 discStubXML;
796 if (discStubXML.LoadFile(item.GetPath()))
798 auto* pRootElement = discStubXML.RootElement();
799 if (!pRootElement || StringUtils::CompareNoCase(pRootElement->Value(), "discstub") != 0)
800 CLog::Log(LOGINFO, "No <discstub> node found for {}. Using default info dialog message",
801 item.GetPath());
802 else
804 XMLUtils::GetString(pRootElement, "title", strLine1);
805 XMLUtils::GetString(pRootElement, "message", strLine2);
806 // no title? use the label of the CFileItem as line 1
807 if (strLine1.empty())
808 strLine1 = item.GetLabel();
812 if (HasOpticalDrive())
814 #ifdef HAS_OPTICAL_DRIVE
815 if (CGUIDialogPlayEject::ShowAndGetInput(strLine1, strLine2))
816 return MEDIA_DETECT::CAutorun::PlayDiscAskResume();
817 #endif
819 else
821 KODI::MESSAGING::HELPERS::ShowOKDialogText(strLine1, strLine2);
823 return true;