Merge pull request #5039 from CEikermann/patch-1
[vuplus_xbmc] / xbmc / storage / MediaManager.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "system.h"
22 #include "MediaManager.h"
23 #include "guilib/LocalizeStrings.h"
24 #include "URL.h"
25 #include "utils/URIUtils.h"
26 #ifdef TARGET_WINDOWS
27 #include "WIN32Util.h"
28 #include "utils/CharsetConverter.h"
29 #endif
30 #include "guilib/GUIWindowManager.h"
31 #ifdef HAS_DVD_DRIVE
32 #ifndef TARGET_WINDOWS
33 // TODO: switch all ports to use auto sources
34 #include "DetectDVDType.h"
35 #include "filesystem/iso9660.h"
36 #endif
37 #endif
38 #include "Autorun.h"
39 #include "GUIUserMessages.h"
40 #include "settings/MediaSourceSettings.h"
41 #include "settings/Settings.h"
42 #include "utils/XBMCTinyXML.h"
43 #include "threads/SingleLock.h"
44 #include "utils/log.h"
45 #include "dialogs/GUIDialogKaiToast.h"
46 #include "utils/JobManager.h"
47 #include "utils/StringUtils.h"
48 #include "AutorunMediaJob.h"
49
50 #include "FileItem.h"
51 #include "filesystem/File.h"
52 #include "filesystem/DirectoryFactory.h"
53 #include "filesystem/Directory.h"
54
55 #include "cores/dvdplayer/DVDInputStreams/DVDInputStreamNavigator.h"
56
57 #if defined(TARGET_DARWIN)
58 #include "osx/DarwinStorageProvider.h"
59 #elif defined(TARGET_ANDROID)
60 #include "android/AndroidStorageProvider.h"
61 #elif defined(TARGET_FREEBSD)
62 #include "linux/LinuxStorageProvider.h"
63 #elif defined(TARGET_POSIX)
64 #include "linux/LinuxStorageProvider.h"
65 #include <sys/ioctl.h>
66 #include <linux/cdrom.h>
67 #elif TARGET_WINDOWS
68 #include "windows/Win32StorageProvider.h"
69 #endif
70
71 using namespace std;
72 using namespace XFILE;
73
74 const char MEDIA_SOURCES_XML[] = { "special://profile/mediasources.xml" };
75
76 class CMediaManager g_mediaManager;
77
78 CMediaManager::CMediaManager()
79 {
80   m_bhasoptical = false;
81   m_platformStorage = NULL;
82 }
83
84 void CMediaManager::Stop()
85 {
86   m_platformStorage->Stop();
87
88   delete m_platformStorage;
89   m_platformStorage = NULL;
90 }
91
92 void CMediaManager::Initialize()
93 {
94   if (!m_platformStorage)
95   {
96     #if defined(TARGET_DARWIN)
97       m_platformStorage = new CDarwinStorageProvider();
98     #elif defined(TARGET_ANDROID)
99       m_platformStorage = new CAndroidStorageProvider();
100     #elif defined(TARGET_POSIX)
101       m_platformStorage = new CLinuxStorageProvider();
102     #elif TARGET_WINDOWS
103       m_platformStorage = new CWin32StorageProvider();
104     #endif
105   }
106 #ifdef HAS_DVD_DRIVE
107   m_strFirstAvailDrive = m_platformStorage->GetFirstOpticalDeviceFileName();
108 #endif
109   m_platformStorage->Initialize();
110 }
111
112 bool CMediaManager::LoadSources()
113 {
114   // clear our location list
115   m_locations.clear();
116
117   // load xml file...
118   CXBMCTinyXML xmlDoc;
119   if ( !xmlDoc.LoadFile( MEDIA_SOURCES_XML ) )
120     return false;
121
122   TiXmlElement* pRootElement = xmlDoc.RootElement();
123   if ( !pRootElement || strcmpi(pRootElement->Value(), "mediasources") != 0)
124   {
125     CLog::Log(LOGERROR, "Error loading %s, Line %d (%s)", MEDIA_SOURCES_XML, xmlDoc.ErrorRow(), xmlDoc.ErrorDesc());
126     return false;
127   }
128
129   // load the <network> block
130   TiXmlNode *pNetwork = pRootElement->FirstChild("network");
131   if (pNetwork)
132   {
133     TiXmlElement *pLocation = pNetwork->FirstChildElement("location");
134     while (pLocation)
135     {
136       CNetworkLocation location;
137       pLocation->Attribute("id", &location.id);
138       if (pLocation->FirstChild())
139       {
140         location.path = pLocation->FirstChild()->Value();
141         m_locations.push_back(location);
142       }
143       pLocation = pLocation->NextSiblingElement("location");
144     }
145   }
146   return true;
147 }
148
149 bool CMediaManager::SaveSources()
150 {
151   CXBMCTinyXML xmlDoc;
152   TiXmlElement xmlRootElement("mediasources");
153   TiXmlNode *pRoot = xmlDoc.InsertEndChild(xmlRootElement);
154   if (!pRoot) return false;
155
156   TiXmlElement networkNode("network");
157   TiXmlNode *pNetworkNode = pRoot->InsertEndChild(networkNode);
158   if (pNetworkNode)
159   {
160     for (vector<CNetworkLocation>::iterator it = m_locations.begin(); it != m_locations.end(); it++)
161     {
162       TiXmlElement locationNode("location");
163       locationNode.SetAttribute("id", (*it).id);
164       TiXmlText value((*it).path);
165       locationNode.InsertEndChild(value);
166       pNetworkNode->InsertEndChild(locationNode);
167     }
168   }
169   return xmlDoc.SaveFile(MEDIA_SOURCES_XML);
170 }
171
172 void CMediaManager::GetLocalDrives(VECSOURCES &localDrives, bool includeQ)
173 {
174   CSingleLock lock(m_CritSecStorageProvider);
175   m_platformStorage->GetLocalDrives(localDrives);
176 }
177
178 void CMediaManager::GetRemovableDrives(VECSOURCES &removableDrives)
179 {
180   CSingleLock lock(m_CritSecStorageProvider);
181   m_platformStorage->GetRemovableDrives(removableDrives);
182 }
183
184 void CMediaManager::GetNetworkLocations(VECSOURCES &locations, bool autolocations)
185 {
186   // Load our xml file
187   LoadSources();
188   for (unsigned int i = 0; i < m_locations.size(); i++)
189   {
190     CMediaSource share;
191     share.strPath = m_locations[i].path;
192     CURL url(share.strPath);
193     share.strName = url.GetWithoutUserDetails();
194     locations.push_back(share);
195   }
196   if (autolocations)
197   {
198     CMediaSource share;
199     share.m_ignore = true;
200 #ifdef HAS_FILESYSTEM_SMB
201     share.strPath = "smb://";
202     share.strName = g_localizeStrings.Get(20171);
203     locations.push_back(share);
204 #endif
205
206 #ifdef HAS_FILESYSTEM_NFS
207     share.strPath = "nfs://";
208     share.strName = g_localizeStrings.Get(20259);
209     locations.push_back(share);
210 #endif// HAS_FILESYSTEM_NFS
211
212 #ifdef HAS_UPNP
213     share.strPath = "upnp://";
214     share.strName = "UPnP Devices";
215     locations.push_back(share);
216 #endif
217     
218 #ifdef HAS_ZEROCONF
219     share.strPath = "zeroconf://";
220     share.strName = "Zeroconf Browser";
221     locations.push_back(share);
222 #endif
223   }
224 }
225
226 bool CMediaManager::AddNetworkLocation(const CStdString &path)
227 {
228   CNetworkLocation location;
229   location.path = path;
230   location.id = (int)m_locations.size();
231   m_locations.push_back(location);
232   return SaveSources();
233 }
234
235 bool CMediaManager::HasLocation(const CStdString& path) const
236 {
237   for (unsigned int i=0;i<m_locations.size();++i)
238   {
239     if (URIUtils::CompareWithoutSlashAtEnd(m_locations[i].path, path))
240       return true;
241   }
242
243   return false;
244 }
245
246
247 bool CMediaManager::RemoveLocation(const CStdString& path)
248 {
249   for (unsigned int i=0;i<m_locations.size();++i)
250   {
251     if (URIUtils::CompareWithoutSlashAtEnd(m_locations[i].path, path))
252     {
253       // prompt for sources, remove, cancel,
254       m_locations.erase(m_locations.begin()+i);
255       return SaveSources();
256     }
257   }
258
259   return false;
260 }
261
262 bool CMediaManager::SetLocationPath(const CStdString& oldPath, const CStdString& newPath)
263 {
264   for (unsigned int i=0;i<m_locations.size();++i)
265   {
266     if (URIUtils::CompareWithoutSlashAtEnd(m_locations[i].path, oldPath))
267     {
268       m_locations[i].path = newPath;
269       return SaveSources();
270     }
271   }
272
273   return false;
274 }
275
276 void CMediaManager::AddAutoSource(const CMediaSource &share, bool bAutorun)
277 {
278   CMediaSourceSettings::Get().AddShare("files", share);
279   CMediaSourceSettings::Get().AddShare("video", share);
280   CMediaSourceSettings::Get().AddShare("pictures", share);
281   CMediaSourceSettings::Get().AddShare("music", share);
282   CMediaSourceSettings::Get().AddShare("programs", share);
283   CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_SOURCES);
284   g_windowManager.SendThreadMessage( msg );
285
286 #ifdef HAS_DVD_DRIVE
287   if(bAutorun)
288     MEDIA_DETECT::CAutorun::ExecuteAutorun(share.strPath);
289 #endif
290 }
291
292 void CMediaManager::RemoveAutoSource(const CMediaSource &share)
293 {
294   CMediaSourceSettings::Get().DeleteSource("files", share.strName, share.strPath, true);
295   CMediaSourceSettings::Get().DeleteSource("video", share.strName, share.strPath, true);
296   CMediaSourceSettings::Get().DeleteSource("pictures", share.strName, share.strPath, true);
297   CMediaSourceSettings::Get().DeleteSource("music", share.strName, share.strPath, true);
298   CMediaSourceSettings::Get().DeleteSource("programs", share.strName, share.strPath, true);
299   CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_SOURCES);
300   g_windowManager.SendThreadMessage( msg );
301
302 #ifdef HAS_DVD_DRIVE
303   // delete cached CdInfo if any
304   RemoveCdInfo(TranslateDevicePath(share.strPath, true));
305 #endif
306 }
307
308 /////////////////////////////////////////////////////////////
309 // AutoSource status functions:
310 // - TODO: translate cdda://<device>/
311
312 CStdString CMediaManager::TranslateDevicePath(const CStdString& devicePath, bool bReturnAsDevice)
313 {
314   CSingleLock waitLock(m_muAutoSource);
315   CStdString strDevice = devicePath;
316   // fallback for cdda://local/ and empty devicePath
317 #ifdef HAS_DVD_DRIVE
318   if(devicePath.empty() || StringUtils::StartsWith(devicePath, "cdda://local"))
319     strDevice = m_strFirstAvailDrive;
320 #endif
321
322 #ifdef TARGET_WINDOWS
323   if(!m_bhasoptical)
324     return "";
325
326   if(bReturnAsDevice == false)
327     StringUtils::Replace(strDevice, "\\\\.\\","");
328   else if(!strDevice.empty() && strDevice[1]==':')
329     strDevice = StringUtils::Format("\\\\.\\%c:", strDevice[0]);
330
331   URIUtils::RemoveSlashAtEnd(strDevice);
332 #endif
333   return strDevice;
334 }
335
336 bool CMediaManager::IsDiscInDrive(const CStdString& devicePath)
337 {
338 #ifdef HAS_DVD_DRIVE
339 #ifdef TARGET_WINDOWS
340   if(!m_bhasoptical)
341     return false;
342
343   CStdString strDevice = TranslateDevicePath(devicePath, true);
344   std::map<CStdString,CCdInfo*>::iterator it;
345   CSingleLock waitLock(m_muAutoSource);
346   it = m_mapCdInfo.find(strDevice);
347   if(it != m_mapCdInfo.end())
348     return true;
349   else
350     return false;
351 #else
352   if(URIUtils::IsDVD(devicePath) || devicePath.empty())
353     return MEDIA_DETECT::CDetectDVDMedia::IsDiscInDrive();   // TODO: switch all ports to use auto sources
354   else
355     return true; // Assume other paths to be mounted already
356 #endif
357 #else
358   return false;
359 #endif
360 }
361
362 bool CMediaManager::IsAudio(const CStdString& devicePath)
363 {
364 #ifdef HAS_DVD_DRIVE
365 #ifdef TARGET_WINDOWS
366   if(!m_bhasoptical)
367     return false;
368
369   CCdInfo* pCdInfo = GetCdInfo(devicePath);
370   if(pCdInfo != NULL && pCdInfo->IsAudio(1))
371     return true;
372
373   return false;
374 #else
375   // TODO: switch all ports to use auto sources
376   MEDIA_DETECT::CCdInfo* pInfo = MEDIA_DETECT::CDetectDVDMedia::GetCdInfo();
377   if (pInfo != NULL && pInfo->IsAudio(1))
378     return true;
379 #endif
380 #endif
381   return false;
382 }
383
384 bool CMediaManager::HasOpticalDrive()
385 {
386 #ifdef HAS_DVD_DRIVE
387   if (!m_strFirstAvailDrive.empty())
388     return true;
389 #endif
390   return false;
391 }
392
393 DWORD CMediaManager::GetDriveStatus(const CStdString& devicePath)
394 {
395 #ifdef HAS_DVD_DRIVE
396 #ifdef TARGET_WINDOWS
397   if(!m_bhasoptical)
398     return DRIVE_NOT_READY;
399
400   CStdString strDevice = TranslateDevicePath(devicePath, true);
401   DWORD dwRet = DRIVE_NOT_READY;
402   int status = CWIN32Util::GetDriveStatus(strDevice);
403
404   switch(status)
405   {
406   case -1: // error
407     dwRet = DRIVE_NOT_READY;
408     break;
409   case 0: // no media
410     dwRet = DRIVE_CLOSED_NO_MEDIA;
411     break;
412   case 1: // tray open
413     dwRet = DRIVE_OPEN;
414     break;
415   case 2: // media accessible
416     dwRet = DRIVE_CLOSED_MEDIA_PRESENT;
417     break;
418   }
419   return dwRet;
420 #else
421   return MEDIA_DETECT::CDetectDVDMedia::DriveReady();
422 #endif
423 #else
424   return DRIVE_NOT_READY;
425 #endif
426 }
427
428 #ifdef HAS_DVD_DRIVE
429 CCdInfo* CMediaManager::GetCdInfo(const CStdString& devicePath)
430 {
431 #ifdef TARGET_WINDOWS
432   if(!m_bhasoptical)
433     return NULL;
434   
435   CStdString strDevice = TranslateDevicePath(devicePath, true);
436   std::map<CStdString,CCdInfo*>::iterator it;
437   {
438     CSingleLock waitLock(m_muAutoSource);
439     it = m_mapCdInfo.find(strDevice);
440     if(it != m_mapCdInfo.end())
441       return it->second;
442   }
443
444   CCdInfo* pCdInfo=NULL;
445   CCdIoSupport cdio;
446   pCdInfo = cdio.GetCdInfo((char*)strDevice.c_str());
447   if(pCdInfo!=NULL)
448   {
449     CSingleLock waitLock(m_muAutoSource);
450     m_mapCdInfo.insert(std::pair<CStdString,CCdInfo*>(strDevice,pCdInfo));
451   }
452
453   return pCdInfo;
454 #else
455   return MEDIA_DETECT::CDetectDVDMedia::GetCdInfo();
456 #endif
457 }
458
459 bool CMediaManager::RemoveCdInfo(const CStdString& devicePath)
460 {
461   if(!m_bhasoptical)
462     return false;
463
464   CStdString strDevice = TranslateDevicePath(devicePath, true);
465
466   std::map<CStdString,CCdInfo*>::iterator it;
467   CSingleLock waitLock(m_muAutoSource);
468   it = m_mapCdInfo.find(strDevice);
469   if(it != m_mapCdInfo.end())
470   {
471     if(it->second != NULL)
472       delete it->second;
473
474     m_mapCdInfo.erase(it);
475     return true;
476   }
477   return false;
478 }
479
480 CStdString CMediaManager::GetDiskLabel(const CStdString& devicePath)
481 {
482 #ifdef TARGET_WINDOWS
483   if(!m_bhasoptical)
484     return "";
485
486   CStdString strDevice = TranslateDevicePath(devicePath);
487   WCHAR cVolumenName[128];
488   WCHAR cFSName[128];
489   URIUtils::AddSlashAtEnd(strDevice);
490   if(GetVolumeInformationW(CStdStringW(strDevice).c_str(), cVolumenName, 127, NULL, NULL, NULL, cFSName, 127)==0)
491     return "";
492   g_charsetConverter.wToUTF8(cVolumenName, strDevice);
493   return StringUtils::TrimRight(strDevice, " ");
494 #else
495   return MEDIA_DETECT::CDetectDVDMedia::GetDVDLabel();
496 #endif
497 }
498
499 CStdString CMediaManager::GetDiskUniqueId(const CStdString& devicePath)
500 {
501   CStdString mediaPath;
502
503   CCdInfo* pInfo = g_mediaManager.GetCdInfo(devicePath);
504   if (pInfo == NULL)
505     return "";
506
507   if (mediaPath.empty() && pInfo->IsAudio(1))
508     mediaPath = "cdda://local/";
509
510   if (mediaPath.empty() && (pInfo->IsISOUDF(1) || pInfo->IsISOHFS(1) || pInfo->IsIso9660(1) || pInfo->IsIso9660Interactive(1)))
511     mediaPath = "iso9660://";
512
513   if (mediaPath.empty())
514     mediaPath = devicePath;
515
516 #ifdef TARGET_WINDOWS
517   if (mediaPath.empty() || mediaPath == "iso9660://")
518   {
519     mediaPath = g_mediaManager.TranslateDevicePath("");
520     URIUtils::AddSlashAtEnd(mediaPath);
521   }
522 #endif
523
524   // Try finding VIDEO_TS/VIDEO_TS.IFO - this indicates a DVD disc is inserted 
525   CStdString pathVideoTS = URIUtils::AddFileToFolder(mediaPath, "VIDEO_TS"); 
526   if(!CFile::Exists(URIUtils::AddFileToFolder(pathVideoTS, "VIDEO_TS.IFO"))) 
527     return ""; // return empty
528
529   // correct the filename if needed 
530   if (StringUtils::StartsWith(pathVideoTS, "dvd://") ||
531       StringUtils::StartsWith(pathVideoTS, "iso9660://"))
532     pathVideoTS = g_mediaManager.TranslateDevicePath(""); 
533
534   CLog::Log(LOGDEBUG, "GetDiskUniqueId: Trying to retrieve ID for path %s", pathVideoTS.c_str());
535
536
537   CDVDInputStreamNavigator dvdNavigator(NULL);
538   dvdNavigator.Open(pathVideoTS, "");
539   CStdString labelString;
540   dvdNavigator.GetDVDTitleString(labelString);
541   CStdString serialString;
542   dvdNavigator.GetDVDSerialString(serialString);
543
544   CStdString strID = StringUtils::Format("removable://%s_%s", labelString.c_str(), serialString.c_str());
545   CLog::Log(LOGDEBUG, "GetDiskUniqueId: Got ID %s for DVD disk", strID.c_str());
546
547   return strID;
548 }
549
550 CStdString CMediaManager::GetDiscPath()
551 {
552 #ifdef TARGET_WINDOWS
553   return g_mediaManager.TranslateDevicePath("");
554 #else
555
556   CSingleLock lock(m_CritSecStorageProvider);
557   VECSOURCES drives;
558   m_platformStorage->GetRemovableDrives(drives);
559   for(unsigned i = 0; i < drives.size(); ++i)
560   {
561     if(drives[i].m_iDriveType == CMediaSource::SOURCE_TYPE_DVD)
562       return drives[i].strPath;
563   }
564
565   // iso9660://, cdda://local/ or D:\ depending on disc type
566   return MEDIA_DETECT::CDetectDVDMedia::GetDVDPath();
567 #endif
568 }
569 #endif
570
571 void CMediaManager::SetHasOpticalDrive(bool bstatus)
572 {
573   CSingleLock waitLock(m_muAutoSource);
574   m_bhasoptical = bstatus;
575 }
576
577 bool CMediaManager::Eject(CStdString mountpath)
578 {
579   CSingleLock lock(m_CritSecStorageProvider);
580   return m_platformStorage->Eject(mountpath);
581 }
582
583 void CMediaManager::EjectTray( const bool bEject, const char cDriveLetter )
584 {
585 #ifdef HAS_DVD_DRIVE
586 #ifdef TARGET_WINDOWS
587   CWIN32Util::EjectTray(cDriveLetter);
588 #else
589   boost::shared_ptr<CLibcdio> c_cdio = CLibcdio::GetInstance();
590   char* dvdDevice = c_cdio->GetDeviceFileName();
591   m_isoReader.Reset();
592   int nRetries=3;
593   while (nRetries-- > 0)
594   {
595     CdIo_t* cdio = c_cdio->cdio_open(dvdDevice, DRIVER_UNKNOWN);
596     if (cdio)
597     {
598       c_cdio->cdio_eject_media(&cdio);
599       c_cdio->cdio_destroy(cdio);
600     }
601     else
602       break;
603   }
604 #endif
605 #endif
606 }
607
608 void CMediaManager::CloseTray(const char cDriveLetter)
609 {
610 #ifdef HAS_DVD_DRIVE
611 #if defined(TARGET_DARWIN)
612   // FIXME...
613 #elif defined(TARGET_FREEBSD)
614   // NYI
615 #elif defined(TARGET_POSIX)
616   char* dvdDevice = CLibcdio::GetInstance()->GetDeviceFileName();
617   if (strlen(dvdDevice) != 0)
618   {
619     int fd = open(dvdDevice, O_RDONLY | O_NONBLOCK);
620     if (fd >= 0)
621     {
622       ioctl(fd, CDROMCLOSETRAY, 0);
623       close(fd);
624     }
625   }
626 #elif defined(TARGET_WINDOWS)
627   CWIN32Util::CloseTray(cDriveLetter);
628 #endif
629 #endif
630 }
631
632 void CMediaManager::ToggleTray(const char cDriveLetter)
633 {
634 #ifdef HAS_DVD_DRIVE
635 #if defined(TARGET_WINDOWS)
636   CWIN32Util::ToggleTray(cDriveLetter);
637 #else
638   if (GetDriveStatus() == TRAY_OPEN || GetDriveStatus() == DRIVE_OPEN)
639     CloseTray();
640   else
641     EjectTray();
642 #endif
643 #endif
644 }
645
646 void CMediaManager::ProcessEvents()
647 {
648   CSingleLock lock(m_CritSecStorageProvider);
649   if (m_platformStorage->PumpDriveChangeEvents(this))
650   {
651 #if defined(HAS_DVD_DRIVE) && defined(TARGET_DARWIN_OSX)
652     // darwins GetFirstOpticalDeviceFileName only gives us something
653     // when a disc is inserted
654     // so we have to refresh m_strFirstAvailDrive when this happens after Initialize
655     // was called (e.x. the disc was inserted after the start of xbmc)
656     // else TranslateDevicePath wouldn't give the correct device
657     m_strFirstAvailDrive = m_platformStorage->GetFirstOpticalDeviceFileName();
658 #endif
659     
660     CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0,GUI_MSG_UPDATE_SOURCES);
661     g_windowManager.SendThreadMessage(msg);
662   }
663 }
664
665 std::vector<CStdString> CMediaManager::GetDiskUsage()
666 {
667   CSingleLock lock(m_CritSecStorageProvider);
668   return m_platformStorage->GetDiskUsage();
669 }
670
671 void CMediaManager::OnStorageAdded(const CStdString &label, const CStdString &path)
672 {
673 #ifdef HAS_DVD_DRIVE
674   if (CSettings::Get().GetInt("audiocds.autoaction") != AUTOCD_NONE || CSettings::Get().GetBool("dvds.autorun"))
675     if (CSettings::Get().GetInt("audiocds.autoaction") == AUTOCD_RIP)
676       CJobManager::GetInstance().AddJob(new CAutorunMediaJob(label, path), this, CJob::PRIORITY_LOW);
677     else
678       CJobManager::GetInstance().AddJob(new CAutorunMediaJob(label, path), this, CJob::PRIORITY_HIGH);
679   else
680     CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, g_localizeStrings.Get(13021), label, TOAST_DISPLAY_TIME, false);
681 #endif
682 }
683
684 void CMediaManager::OnStorageSafelyRemoved(const CStdString &label)
685 {
686   CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, g_localizeStrings.Get(13023), label, TOAST_DISPLAY_TIME, false);
687 }
688
689 void CMediaManager::OnStorageUnsafelyRemoved(const CStdString &label)
690 {
691   CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Warning, g_localizeStrings.Get(13022), label);
692 }