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.
9 #include "MediaManager.h"
12 #include "ServiceBroker.h"
14 #include "guilib/GUIComponent.h"
15 #include "guilib/LocalizeStrings.h"
16 #include "utils/URIUtils.h"
20 #include "platform/win32/WIN32Util.h"
21 #include "utils/CharsetConverter.h"
23 #include "guilib/GUIWindowManager.h"
24 #ifdef HAS_OPTICAL_DRIVE
25 #ifndef TARGET_WINDOWS
26 //! @todo switch all ports to use auto sources
29 #include "DetectDVDType.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"
53 #ifdef HAS_OPTICAL_DRIVE
54 using namespace MEDIA_DETECT
;
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();
82 m_platformStorage
->Initialize();
85 bool CMediaManager::LoadSources()
87 // clear our location list
92 if ( !xmlDoc
.LoadFile( MEDIA_SOURCES_XML
) )
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(),
103 // load the <network> block
104 auto* pNetwork
= pRootElement
->FirstChildElement("network");
107 auto* pLocation
= pNetwork
->FirstChildElement("location");
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");
124 bool CMediaManager::SaveSources()
127 auto* xmlRootElement
= doc
.NewElement("mediasources");
128 auto* rootNode
= doc
.InsertFirstChild(xmlRootElement
);
133 auto* networkElement
= doc
.NewElement("network");
134 auto* networkNode
= rootNode
->InsertEndChild(networkElement
);
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
++)
167 share
.strPath
= m_locations
[i
].path
;
168 CURL
url(share
.strPath
);
169 share
.strName
= url
.GetWithoutUserDetails();
170 locations
.push_back(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
);
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
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
);
199 share
.strPath
= "zeroconf://";
200 share
.strName
= g_localizeStrings
.Get(20262);
201 locations
.push_back(share
);
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
))
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();
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();
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");
312 CLog::LogF(LOGERROR
, "Invalid type {} provided", type
);
317 CMediaSource
CMediaManager::ComputeRootAddonTypeSource(const std::string
& type
,
318 const std::string
& label
,
319 const std::string
& thumb
) const
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;
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();
340 gui
->GetWindowManager().SendThreadMessage( msg
);
342 #ifdef HAS_OPTICAL_DRIVE
344 MEDIA_DETECT::CAutorun::ExecuteAutorun(share
.strPath
);
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));
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
;
379 #ifdef TARGET_WINDOWS
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
);
393 bool CMediaManager::IsDiscInDrive(const std::string
& devicePath
)
395 #ifdef HAS_OPTICAL_DRIVE
396 #ifdef TARGET_WINDOWS
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())
409 if(URIUtils::IsDVD(devicePath
) || devicePath
.empty())
410 return MEDIA_DETECT::CDetectDVDMedia::IsDiscInDrive(); //! @todo switch all ports to use auto sources
412 return true; // Assume other paths to be mounted already
419 bool CMediaManager::IsAudio(const std::string
& devicePath
)
421 #ifdef HAS_OPTICAL_DRIVE
422 #ifdef TARGET_WINDOWS
426 CCdInfo
* pCdInfo
= GetCdInfo(devicePath
);
427 if(pCdInfo
!= NULL
&& pCdInfo
->IsAudio(1))
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))
441 bool CMediaManager::HasOpticalDrive()
443 #ifdef HAS_OPTICAL_DRIVE
444 if (!m_strFirstAvailDrive
.empty())
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
);
460 return MEDIA_DETECT::CDetectDVDMedia::GetDriveState();
463 return DriveState::NOT_READY
;
467 #ifdef HAS_OPTICAL_DRIVE
468 CCdInfo
* CMediaManager::GetCdInfo(const std::string
& devicePath
)
470 #ifdef TARGET_WINDOWS
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())
483 CCdInfo
* pCdInfo
=NULL
;
485 pCdInfo
= cdio
.GetCdInfo((char*)strDevice
.c_str());
488 std::unique_lock
<CCriticalSection
> waitLock(m_muAutoSource
);
489 m_mapCdInfo
.insert(std::pair
<std::string
,CCdInfo
*>(strDevice
,pCdInfo
));
494 return MEDIA_DETECT::CDetectDVDMedia::GetCdInfo();
498 bool CMediaManager::RemoveCdInfo(const std::string
& devicePath
)
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
)
513 m_mapCdInfo
.erase(it
);
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)
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
)
539 UTILS::DISCS::DiscInfo info
;
540 info
= GetDiscInfo(mediaPath
);
541 if (!info
.name
.empty())
543 m_mapDiscInfo
[mediaPath
] = info
;
547 std::string strDevice
= TranslateDevicePath(devicePath
);
548 WCHAR cVolumenName
[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)
555 g_charsetConverter
.wToUTF8(cVolumenName
, strDevice
);
556 info
.name
= StringUtils::TrimRight(strDevice
, " ");
557 if (!info
.name
.empty())
558 m_mapDiscInfo
[mediaPath
] = info
;
562 return MEDIA_DETECT::CDetectDVDMedia::GetDVDLabel();
566 std::string
CMediaManager::GetDiskUniqueId(const std::string
& devicePath
)
568 std::string mediaPath
;
570 CCdInfo
* pInfo
= CServiceBroker::GetMediaManager().GetCdInfo(devicePath
);
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
);
590 UTILS::DISCS::DiscInfo info
= GetDiscInfo(mediaPath
);
593 CLog::Log(LOGDEBUG
, "GetDiskUniqueId: Retrieving ID for path {} failed, ID is empty.",
594 CURL::GetRedacted(mediaPath
));
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
));
605 std::string
CMediaManager::GetDiscPath()
607 #ifdef TARGET_WINDOWS
608 return CServiceBroker::GetMediaManager().TranslateDevicePath("");
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();
626 std::shared_ptr
<IDiscDriveHandler
> CMediaManager::GetDiscDriveHandler()
628 return m_platformDiscDriveHander
;
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(""));
654 void CMediaManager::CloseTray(const char cDriveLetter
)
656 #ifdef HAS_OPTICAL_DRIVE
657 if (m_platformDiscDriveHander
)
659 m_platformDiscDriveHander
->ToggleDriveTray(TranslateDevicePath(""));
664 void CMediaManager::ToggleTray(const char cDriveLetter
)
666 #ifdef HAS_OPTICAL_DRIVE
667 if (m_platformDiscDriveHander
)
669 m_platformDiscDriveHander
->ToggleDriveTray(TranslateDevicePath(""));
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();
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,
712 if (device
.type
== MEDIA_DETECT::STORAGE::Type::OPTICAL
)
714 if (MEDIA_DETECT::CAutorun::ExecuteAutorun(device
.path
))
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
);
727 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info
, g_localizeStrings
.Get(13021),
728 device
.label
, TOAST_DISPLAY_TIME
, false);
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),
745 UTILS::DISCS::DiscInfo
CMediaManager::GetDiscInfo(const std::string
& mediaPath
)
747 UTILS::DISCS::DiscInfo info
;
749 if (mediaPath
.empty())
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
);
768 // check for Blu-ray discs
769 if (CFileUtils::Exists(URIUtils::AddFileToFolder(mediaPath
, "BDMV", "index.bdmv")))
771 info
= UTILS::DISCS::ProbeBlurayDiscInfo(mediaPath
);
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",
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();
821 KODI::MESSAGING::HELPERS::ShowOKDialogText(strLine1
, strLine2
);