/xbmc/Autorun.cpp
http://github.com/xbmc/xbmc · C++ · 531 lines · 393 code · 61 blank · 77 comment · 113 complexity · a254ef9c448bfbd19e53ec7d3d85e79f MD5 · raw file
- /*
- * 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 "Autorun.h"
- #include <stdlib.h>
- #include "Application.h"
- #include "GUIPassword.h"
- #include "GUIUserMessages.h"
- #include "PlayListPlayer.h"
- #include "ServiceBroker.h"
- #include "cores/playercorefactory/PlayerCoreFactory.h"
- #include "filesystem/StackDirectory.h"
- #include "filesystem/Directory.h"
- #include "filesystem/DirectoryFactory.h"
- #include "filesystem/File.h"
- #include "messaging/ApplicationMessenger.h"
- #include "messaging/helpers/DialogHelper.h"
- #include "profiles/ProfileManager.h"
- #include "settings/Settings.h"
- #include "settings/SettingsComponent.h"
- #include "settings/lib/Setting.h"
- #include "settings/lib/SettingDefinitions.h"
- #include "playlists/PlayList.h"
- #include "guilib/GUIComponent.h"
- #include "guilib/GUIWindowManager.h"
- #include "guilib/LocalizeStrings.h"
- #include "storage/MediaManager.h"
- #include "video/VideoDatabase.h"
- #include "utils/StringUtils.h"
- #include "utils/URIUtils.h"
- #include "utils/log.h"
- #include "utils/Variant.h"
- #ifdef HAS_CDDA_RIPPER
- #include "cdrip/CDDARipper.h"
- #endif
- using namespace XFILE;
- using namespace PLAYLIST;
- using namespace MEDIA_DETECT;
- using namespace KODI::MESSAGING;
- using KODI::MESSAGING::HELPERS::DialogResponse;
- CAutorun::CAutorun()
- {
- m_bEnable = true;
- }
- CAutorun::~CAutorun() = default;
- void CAutorun::ExecuteAutorun(const std::string& path, bool bypassSettings, bool ignoreplaying, bool startFromBeginning )
- {
- if (!ignoreplaying)
- {
- if (g_application.GetAppPlayer().IsPlayingAudio() ||
- g_application.GetAppPlayer().IsPlayingVideo() ||
- CServiceBroker::GetGUI()->GetWindowManager().HasModalDialog(true))
- {
- return;
- }
- }
- if (CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_LOGIN_SCREEN)
- return;
- CCdInfo* pInfo = CServiceBroker::GetMediaManager().GetCdInfo(path);
- if ( pInfo == NULL )
- return ;
- g_application.ResetScreenSaver();
- g_application.WakeUpScreenSaverAndDPMS(); // turn off the screensaver if it's active
- #ifdef HAS_CDDA_RIPPER
- if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_AUDIOCDS_AUTOACTION) == AUTOCD_RIP &&
- pInfo->IsAudio(1) && !CServiceBroker::GetSettingsComponent()->GetProfileManager()->GetCurrentProfile().musicLocked())
- {
- CCDDARipper::GetInstance().RipCD();
- }
- else
- #endif
- PlayDisc(path, bypassSettings, startFromBeginning);
- }
- bool CAutorun::PlayDisc(const std::string& path, bool bypassSettings, bool startFromBeginning)
- {
- if ( !bypassSettings && CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_AUDIOCDS_AUTOACTION) != AUTOCD_PLAY && !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_DVDS_AUTORUN))
- return false;
- int nSize = CServiceBroker::GetPlaylistPlayer().GetPlaylist( PLAYLIST_MUSIC ).size();
- int nAddedToPlaylist = 0;
- std::string mediaPath;
- CCdInfo* pInfo = CServiceBroker::GetMediaManager().GetCdInfo(path);
- if (pInfo == NULL)
- return false;
- if (mediaPath.empty() && pInfo->IsAudio(1))
- mediaPath = "cdda://local/";
- if (mediaPath.empty() && (pInfo->IsISOUDF(1) || pInfo->IsISOHFS(1) || pInfo->IsIso9660(1) || pInfo->IsIso9660Interactive(1)))
- mediaPath = "iso9660://";
- if (mediaPath.empty())
- mediaPath = path;
- if (mediaPath.empty() || mediaPath == "iso9660://")
- mediaPath = CServiceBroker::GetMediaManager().GetDiscPath();
- const CURL pathToUrl(mediaPath);
- std::unique_ptr<IDirectory> pDir ( CDirectoryFactory::Create( pathToUrl ));
- bool bPlaying = RunDisc(pDir.get(), mediaPath, nAddedToPlaylist, true, bypassSettings, startFromBeginning);
- if ( !bPlaying && nAddedToPlaylist > 0 )
- {
- CGUIMessage msg( GUI_MSG_PLAYLIST_CHANGED, 0, 0 );
- CServiceBroker::GetGUI()->GetWindowManager().SendMessage( msg );
- CServiceBroker::GetPlaylistPlayer().SetCurrentPlaylist(PLAYLIST_MUSIC);
- // Start playing the items we inserted
- return CServiceBroker::GetPlaylistPlayer().Play(nSize, "");
- }
- return bPlaying;
- }
- /**
- * This method tries to determine what type of disc is located in the given drive and starts to play the content appropriately.
- */
- bool CAutorun::RunDisc(IDirectory* pDir, const std::string& strDrive, int& nAddedToPlaylist, bool bRoot, bool bypassSettings /* = false */, bool startFromBeginning /* = false */)
- {
- bool bPlaying(false);
- CFileItemList vecItems;
- const CURL pathToUrl(strDrive);
- if ( !pDir->GetDirectory( pathToUrl, vecItems ) )
- {
- return false;
- }
- // Sorting necessary for easier HDDVD handling
- vecItems.Sort(SortByLabel, SortOrderAscending);
- bool bAllowVideo = true;
- // bool bAllowPictures = true;
- bool bAllowMusic = true;
- if (!g_passwordManager.IsMasterLockUnlocked(false))
- {
- const std::shared_ptr<CProfileManager> profileManager = CServiceBroker::GetSettingsComponent()->GetProfileManager();
- bAllowVideo = !profileManager->GetCurrentProfile().videoLocked();
- // bAllowPictures = !profileManager->GetCurrentProfile().picturesLocked();
- bAllowMusic = !profileManager->GetCurrentProfile().musicLocked();
- }
- // is this a root folder we have to check the content to determine a disc type
- if (bRoot)
- {
- std::string hddvdname = "";
- CFileItemPtr phddvdItem;
- bool bAutorunDVDs = CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_DVDS_AUTORUN);
- // check root folders next, for normal structured dvd's
- for (const auto& pItem : vecItems)
- {
- // is the current item a (non system) folder?
- if (pItem->m_bIsFolder && pItem->GetPath() != "." && pItem->GetPath() != "..")
- {
- std::string name = pItem->GetPath();
- URIUtils::RemoveSlashAtEnd(name);
- name = URIUtils::GetFileName(name);
- // Check if the current foldername indicates a DVD structure (name is "VIDEO_TS")
- if (StringUtils::EqualsNoCase(name, "VIDEO_TS") && bAllowVideo
- && (bypassSettings || bAutorunDVDs))
- {
- std::string path = URIUtils::AddFileToFolder(pItem->GetPath(), "VIDEO_TS.IFO");
- if(!CFile::Exists(path))
- path = URIUtils::AddFileToFolder(pItem->GetPath(), "video_ts.ifo");
- CFileItemPtr item(new CFileItem(path, false));
- item->SetLabel(CServiceBroker::GetMediaManager().GetDiskLabel(strDrive));
- item->GetVideoInfoTag()->m_strFileNameAndPath =
- CServiceBroker::GetMediaManager().GetDiskUniqueId(strDrive);
- if (!startFromBeginning && !item->GetVideoInfoTag()->m_strFileNameAndPath.empty())
- item->m_lStartOffset = STARTOFFSET_RESUME;
- CServiceBroker::GetPlaylistPlayer().ClearPlaylist(PLAYLIST_VIDEO);
- CServiceBroker::GetPlaylistPlayer().SetShuffle (PLAYLIST_VIDEO, false);
- CServiceBroker::GetPlaylistPlayer().Add(PLAYLIST_VIDEO, item);
- CServiceBroker::GetPlaylistPlayer().SetCurrentPlaylist(PLAYLIST_VIDEO);
- CServiceBroker::GetPlaylistPlayer().Play(0, "");
- return true;
- }
- // Check if the current foldername indicates a Blu-Ray structure (default is "BDMV").
- // A BR should also include an "AACS" folder for encryption, Sony-BRs can also include update folders for PS3 (PS3_UPDATE / PS3_VPRM).
- //! @todo for the time being, the DVD autorun settings are used to determine if the BR should be started automatically.
- if (StringUtils::EqualsNoCase(name, "BDMV") && bAllowVideo
- && (bypassSettings || bAutorunDVDs))
- {
- CFileItemPtr item(new CFileItem(URIUtils::AddFileToFolder(pItem->GetPath(), "index.bdmv"), false));
- item->SetLabel(CServiceBroker::GetMediaManager().GetDiskLabel(strDrive));
- item->GetVideoInfoTag()->m_strFileNameAndPath =
- CServiceBroker::GetMediaManager().GetDiskUniqueId(strDrive);
- if (!startFromBeginning && !item->GetVideoInfoTag()->m_strFileNameAndPath.empty())
- item->m_lStartOffset = STARTOFFSET_RESUME;
- CServiceBroker::GetPlaylistPlayer().ClearPlaylist(PLAYLIST_VIDEO);
- CServiceBroker::GetPlaylistPlayer().SetShuffle (PLAYLIST_VIDEO, false);
- CServiceBroker::GetPlaylistPlayer().Add(PLAYLIST_VIDEO, item);
- CServiceBroker::GetPlaylistPlayer().SetCurrentPlaylist(PLAYLIST_VIDEO);
- CServiceBroker::GetPlaylistPlayer().Play(0, "");
- return true;
- }
- // Check if the current foldername indicates a HD DVD structure (default is "HVDVD_TS").
- // Most HD DVD will also include an "ADV_OBJ" folder for advanced content. This folder should be handled first.
- //! @todo for the time being, the DVD autorun settings are used to determine if the HD DVD should be started automatically.
- CFileItemList items, sitems;
- // Advanced Content HD DVD (most discs?)
- if (StringUtils::EqualsNoCase(name, "ADV_OBJ"))
- {
- CLog::Log(LOGINFO,"HD DVD: Checking for playlist.");
- // find playlist file
- CDirectory::GetDirectory(pItem->GetPath(), items, "*.xpl", DIR_FLAG_DEFAULTS);
- if (items.Size())
- {
- // HD DVD Standard says the highest numbered playlist has to be handled first.
- CLog::Log(LOGINFO,"HD DVD: Playlist found. Set filetypes to *.xpl for external player.");
- items.Sort(SortByLabel, SortOrderDescending);
- phddvdItem = pItem;
- hddvdname = URIUtils::GetFileName(items[0]->GetPath());
- CLog::Log(LOGINFO,"HD DVD: %s", items[0]->GetPath().c_str());
- }
- }
- // Standard Content HD DVD (few discs?)
- if (StringUtils::EqualsNoCase(name, "HVDVD_TS") && bAllowVideo
- && (bypassSettings || bAutorunDVDs))
- {
- if (hddvdname == "")
- {
- CLog::Log(LOGINFO,"HD DVD: Checking for ifo.");
- // find Video Manager or Title Set Information
- CDirectory::GetDirectory(pItem->GetPath(), items, "HV*.ifo", DIR_FLAG_DEFAULTS);
- if (items.Size())
- {
- // HD DVD Standard says the lowest numbered ifo has to be handled first.
- CLog::Log(LOGINFO,"HD DVD: IFO found. Set filename to HV* and filetypes to *.ifo for external player.");
- items.Sort(SortByLabel, SortOrderAscending);
- phddvdItem = pItem;
- hddvdname = URIUtils::GetFileName(items[0]->GetPath());
- CLog::Log(LOGINFO,"HD DVD: %s",items[0]->GetPath().c_str());
- }
- }
- // Find and sort *.evo files for internal playback.
- // While this algorithm works for all of my HD DVDs, it may fail on other discs. If there are very large extras which are
- // alphabetically before the main movie they will be sorted to the top of the playlist and get played first.
- CDirectory::GetDirectory(pItem->GetPath(), items, "*.evo", DIR_FLAG_DEFAULTS);
- if (items.Size())
- {
- // Sort *.evo files in alphabetical order.
- items.Sort(SortByLabel, SortOrderAscending);
- int64_t asize = 0;
- int ecount = 0;
- // calculate average size of elements above 1gb
- for (int j = 0; j < items.Size(); j++)
- if (items[j]->m_dwSize > 1000000000)
- {
- ecount++;
- asize = asize + items[j]->m_dwSize;
- }
- if (ecount > 0)
- asize = asize / ecount;
- // Put largest files in alphabetical order to top of new list.
- for (int j = 0; j < items.Size(); j++)
- if (items[j]->m_dwSize >= asize)
- sitems.Add (items[j]);
- // Sort *.evo files by size.
- items.Sort(SortBySize, SortOrderDescending);
- // Add other files with descending size to bottom of new list.
- for (int j = 0; j < items.Size(); j++)
- if (items[j]->m_dwSize < asize)
- sitems.Add (items[j]);
- // Replace list with optimized list.
- items.Clear();
- items.Copy (sitems);
- sitems.Clear();
- }
- if (hddvdname != "")
- {
- CFileItem item(URIUtils::AddFileToFolder(phddvdItem->GetPath(), hddvdname), false);
- item.SetLabel(CServiceBroker::GetMediaManager().GetDiskLabel(strDrive));
- item.GetVideoInfoTag()->m_strFileNameAndPath =
- CServiceBroker::GetMediaManager().GetDiskUniqueId(strDrive);
- if (!startFromBeginning && !item.GetVideoInfoTag()->m_strFileNameAndPath.empty())
- item.m_lStartOffset = STARTOFFSET_RESUME;
- // get playername
- std::string hdVideoPlayer = CServiceBroker::GetPlayerCoreFactory().GetDefaultPlayer(item);
- // Single *.xpl or *.ifo files require an external player to handle playback.
- // If no matching rule was found, VideoPlayer will be default player.
- if (hdVideoPlayer != "VideoPlayer")
- {
- CLog::Log(LOGINFO,"HD DVD: External singlefile playback initiated: %s",hddvdname.c_str());
- g_application.PlayFile(item, hdVideoPlayer, false);
- return true;
- } else
- CLog::Log(LOGINFO,"HD DVD: No external player found. Fallback to internal one.");
- }
- // internal *.evo playback.
- CLog::Log(LOGINFO,"HD DVD: Internal multifile playback initiated.");
- CServiceBroker::GetPlaylistPlayer().ClearPlaylist(PLAYLIST_VIDEO);
- CServiceBroker::GetPlaylistPlayer().SetShuffle (PLAYLIST_VIDEO, false);
- CServiceBroker::GetPlaylistPlayer().Add(PLAYLIST_VIDEO, items);
- CServiceBroker::GetPlaylistPlayer().SetCurrentPlaylist(PLAYLIST_VIDEO);
- CServiceBroker::GetPlaylistPlayer().Play(0, "");
- return true;
- }
- // Video CDs can have multiple file formats. First we need to determine which one is used on the CD
- std::string strExt;
- if (StringUtils::EqualsNoCase(name, "MPEGAV"))
- strExt = ".dat";
- if (StringUtils::EqualsNoCase(name, "MPEG2"))
- strExt = ".mpg";
- // If a file format was extracted we are sure this is a VCD. Autoplay if settings indicate we should.
- if (!strExt.empty() && bAllowVideo
- && (bypassSettings || bAutorunDVDs))
- {
- CFileItemList items;
- CDirectory::GetDirectory(pItem->GetPath(), items, strExt, DIR_FLAG_DEFAULTS);
- if (items.Size())
- {
- items.Sort(SortByLabel, SortOrderAscending);
- CServiceBroker::GetPlaylistPlayer().ClearPlaylist(PLAYLIST_VIDEO);
- CServiceBroker::GetPlaylistPlayer().Add(PLAYLIST_VIDEO, items);
- CServiceBroker::GetPlaylistPlayer().SetCurrentPlaylist(PLAYLIST_VIDEO);
- CServiceBroker::GetPlaylistPlayer().Play(0, "");
- return true;
- }
- }
- /* Probably want this if/when we add some automedia action dialog...
- else if (pItem->GetPath().Find("PICTURES") != -1 && bAllowPictures
- && (bypassSettings))
- {
- bPlaying = true;
- std::string strExec = StringUtils::Format("RecursiveSlideShow(%s)", pItem->GetPath().c_str());
- CBuiltins::Execute(strExec);
- return true;
- }
- */
- }
- }
- }
- // check video first
- if (!nAddedToPlaylist && !bPlaying && (bypassSettings || CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_DVDS_AUTORUN)))
- {
- // stack video files
- CFileItemList tempItems;
- tempItems.Append(vecItems);
- if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_MYVIDEOS_STACKVIDEOS))
- tempItems.Stack();
- CFileItemList itemlist;
- for (int i = 0; i < tempItems.Size(); i++)
- {
- CFileItemPtr pItem = tempItems[i];
- if (!pItem->m_bIsFolder && pItem->IsVideo())
- {
- bPlaying = true;
- if (pItem->IsStack())
- {
- //! @todo remove this once the app/player is capable of handling stacks immediately
- CStackDirectory dir;
- CFileItemList items;
- dir.GetDirectory(pItem->GetURL(), items);
- itemlist.Append(items);
- }
- else
- itemlist.Add(pItem);
- }
- }
- if (itemlist.Size())
- {
- if (!bAllowVideo)
- {
- if (!bypassSettings)
- return false;
- if (!g_passwordManager.IsMasterLockUnlocked(true))
- return false;
- }
- CServiceBroker::GetPlaylistPlayer().ClearPlaylist(PLAYLIST_VIDEO);
- CServiceBroker::GetPlaylistPlayer().Add(PLAYLIST_VIDEO, itemlist);
- CServiceBroker::GetPlaylistPlayer().SetCurrentPlaylist(PLAYLIST_VIDEO);
- CServiceBroker::GetPlaylistPlayer().Play(0, "");
- }
- }
- // then music
- if (!bPlaying && (bypassSettings || CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_AUDIOCDS_AUTOACTION) == AUTOCD_PLAY) && bAllowMusic)
- {
- for (int i = 0; i < vecItems.Size(); i++)
- {
- CFileItemPtr pItem = vecItems[i];
- if (!pItem->m_bIsFolder && pItem->IsAudio())
- {
- nAddedToPlaylist++;
- CServiceBroker::GetPlaylistPlayer().Add(PLAYLIST_MUSIC, pItem);
- }
- }
- }
- /* Probably want this if/when we add some automedia action dialog...
- // and finally pictures
- if (!nAddedToPlaylist && !bPlaying && bypassSettings && bAllowPictures)
- {
- for (int i = 0; i < vecItems.Size(); i++)
- {
- CFileItemPtr pItem = vecItems[i];
- if (!pItem->m_bIsFolder && pItem->IsPicture())
- {
- bPlaying = true;
- std::string strExec = StringUtils::Format("RecursiveSlideShow(%s)", strDrive.c_str());
- CBuiltins::Execute(strExec);
- break;
- }
- }
- }
- */
- // check subdirs if we are not playing yet
- if (!bPlaying)
- {
- for (int i = 0; i < vecItems.Size(); i++)
- {
- CFileItemPtr pItem = vecItems[i];
- if (pItem->m_bIsFolder)
- {
- if (pItem->GetPath() != "." && pItem->GetPath() != ".." )
- {
- if (RunDisc(pDir, pItem->GetPath(), nAddedToPlaylist, false, bypassSettings, startFromBeginning))
- {
- bPlaying = true;
- break;
- }
- }
- } // if (non system) folder
- } // for all items in directory
- } // if root folder
- return bPlaying;
- }
- void CAutorun::HandleAutorun()
- {
- #ifndef TARGET_WINDOWS
- if (!m_bEnable)
- {
- CDetectDVDMedia::m_evAutorun.Reset();
- return ;
- }
- if (CDetectDVDMedia::m_evAutorun.WaitMSec(0))
- {
- ExecuteAutorun();
- CDetectDVDMedia::m_evAutorun.Reset();
- }
- #endif
- }
- void CAutorun::Enable()
- {
- m_bEnable = true;
- }
- void CAutorun::Disable()
- {
- m_bEnable = false;
- }
- bool CAutorun::IsEnabled() const
- {
- return m_bEnable;
- }
- bool CAutorun::PlayDiscAskResume(const std::string& path)
- {
- return PlayDisc(path, true, !CanResumePlayDVD(path) ||
- HELPERS::ShowYesNoDialogText(CVariant{341}, CVariant{""}, CVariant{13404}, CVariant{12021}) ==
- DialogResponse::YES);
- }
- bool CAutorun::CanResumePlayDVD(const std::string& path)
- {
- std::string strUniqueId = CServiceBroker::GetMediaManager().GetDiskUniqueId(path);
- if (!strUniqueId.empty())
- {
- CVideoDatabase dbs;
- dbs.Open();
- CBookmark bookmark;
- if (dbs.GetResumeBookMark(strUniqueId, bookmark))
- return true;
- }
- return false;
- }
- void CAutorun::SettingOptionAudioCdActionsFiller(SettingConstPtr setting, std::vector<IntegerSettingOption> &list, int ¤t, void *data)
- {
- list.emplace_back(g_localizeStrings.Get(16018), AUTOCD_NONE);
- list.emplace_back(g_localizeStrings.Get(14098), AUTOCD_PLAY);
- #ifdef HAS_CDDA_RIPPER
- list.emplace_back(g_localizeStrings.Get(14096), AUTOCD_RIP);
- #endif
- }