PageRenderTime 47ms CodeModel.GetById 6ms app.highlight 35ms RepoModel.GetById 1ms app.codeStats 1ms

/xbmc/Autorun.cpp

http://github.com/xbmc/xbmc
C++ | 531 lines | 393 code | 61 blank | 77 comment | 113 complexity | a254ef9c448bfbd19e53ec7d3d85e79f MD5 | raw file
  1/*
  2 *  Copyright (C) 2005-2018 Team Kodi
  3 *  This file is part of Kodi - https://kodi.tv
  4 *
  5 *  SPDX-License-Identifier: GPL-2.0-or-later
  6 *  See LICENSES/README.md for more information.
  7 */
  8
  9#include "Autorun.h"
 10
 11#include <stdlib.h>
 12
 13#include "Application.h"
 14#include "GUIPassword.h"
 15#include "GUIUserMessages.h"
 16#include "PlayListPlayer.h"
 17#include "ServiceBroker.h"
 18#include "cores/playercorefactory/PlayerCoreFactory.h"
 19#include "filesystem/StackDirectory.h"
 20#include "filesystem/Directory.h"
 21#include "filesystem/DirectoryFactory.h"
 22#include "filesystem/File.h"
 23#include "messaging/ApplicationMessenger.h"
 24#include "messaging/helpers/DialogHelper.h"
 25#include "profiles/ProfileManager.h"
 26#include "settings/Settings.h"
 27#include "settings/SettingsComponent.h"
 28#include "settings/lib/Setting.h"
 29#include "settings/lib/SettingDefinitions.h"
 30#include "playlists/PlayList.h"
 31#include "guilib/GUIComponent.h"
 32#include "guilib/GUIWindowManager.h"
 33#include "guilib/LocalizeStrings.h"
 34#include "storage/MediaManager.h"
 35#include "video/VideoDatabase.h"
 36#include "utils/StringUtils.h"
 37#include "utils/URIUtils.h"
 38#include "utils/log.h"
 39#include "utils/Variant.h"
 40
 41#ifdef HAS_CDDA_RIPPER
 42#include "cdrip/CDDARipper.h"
 43#endif
 44
 45using namespace XFILE;
 46using namespace PLAYLIST;
 47using namespace MEDIA_DETECT;
 48using namespace KODI::MESSAGING;
 49
 50using KODI::MESSAGING::HELPERS::DialogResponse;
 51
 52CAutorun::CAutorun()
 53{
 54  m_bEnable = true;
 55}
 56
 57CAutorun::~CAutorun() = default;
 58
 59void CAutorun::ExecuteAutorun(const std::string& path, bool bypassSettings, bool ignoreplaying, bool startFromBeginning )
 60{
 61  if (!ignoreplaying)
 62  {
 63    if (g_application.GetAppPlayer().IsPlayingAudio() ||
 64        g_application.GetAppPlayer().IsPlayingVideo() ||
 65        CServiceBroker::GetGUI()->GetWindowManager().HasModalDialog(true))
 66    {
 67      return;
 68    }
 69  }
 70
 71  if (CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_LOGIN_SCREEN)
 72    return;
 73
 74  CCdInfo* pInfo = CServiceBroker::GetMediaManager().GetCdInfo(path);
 75
 76  if ( pInfo == NULL )
 77    return ;
 78
 79  g_application.ResetScreenSaver();
 80  g_application.WakeUpScreenSaverAndDPMS();  // turn off the screensaver if it's active
 81
 82#ifdef HAS_CDDA_RIPPER
 83  if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_AUDIOCDS_AUTOACTION) == AUTOCD_RIP &&
 84      pInfo->IsAudio(1) && !CServiceBroker::GetSettingsComponent()->GetProfileManager()->GetCurrentProfile().musicLocked())
 85  {
 86    CCDDARipper::GetInstance().RipCD();
 87  }
 88  else
 89#endif
 90
 91  PlayDisc(path, bypassSettings, startFromBeginning);
 92}
 93
 94bool CAutorun::PlayDisc(const std::string& path, bool bypassSettings, bool startFromBeginning)
 95{
 96  if ( !bypassSettings && CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_AUDIOCDS_AUTOACTION) != AUTOCD_PLAY && !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_DVDS_AUTORUN))
 97    return false;
 98
 99  int nSize = CServiceBroker::GetPlaylistPlayer().GetPlaylist( PLAYLIST_MUSIC ).size();
100  int nAddedToPlaylist = 0;
101
102  std::string mediaPath;
103
104  CCdInfo* pInfo = CServiceBroker::GetMediaManager().GetCdInfo(path);
105  if (pInfo == NULL)
106    return false;
107
108  if (mediaPath.empty() && pInfo->IsAudio(1))
109    mediaPath = "cdda://local/";
110
111  if (mediaPath.empty() && (pInfo->IsISOUDF(1) || pInfo->IsISOHFS(1) || pInfo->IsIso9660(1) || pInfo->IsIso9660Interactive(1)))
112    mediaPath = "iso9660://";
113
114  if (mediaPath.empty())
115    mediaPath = path;
116
117  if (mediaPath.empty() || mediaPath == "iso9660://")
118    mediaPath = CServiceBroker::GetMediaManager().GetDiscPath();
119
120  const CURL pathToUrl(mediaPath);
121  std::unique_ptr<IDirectory> pDir ( CDirectoryFactory::Create( pathToUrl ));
122  bool bPlaying = RunDisc(pDir.get(), mediaPath, nAddedToPlaylist, true, bypassSettings, startFromBeginning);
123
124  if ( !bPlaying && nAddedToPlaylist > 0 )
125  {
126    CGUIMessage msg( GUI_MSG_PLAYLIST_CHANGED, 0, 0 );
127    CServiceBroker::GetGUI()->GetWindowManager().SendMessage( msg );
128    CServiceBroker::GetPlaylistPlayer().SetCurrentPlaylist(PLAYLIST_MUSIC);
129    // Start playing the items we inserted
130    return CServiceBroker::GetPlaylistPlayer().Play(nSize, "");
131  }
132
133  return bPlaying;
134}
135
136/**
137 * This method tries to determine what type of disc is located in the given drive and starts to play the content appropriately.
138 */
139bool CAutorun::RunDisc(IDirectory* pDir, const std::string& strDrive, int& nAddedToPlaylist, bool bRoot, bool bypassSettings /* = false */, bool startFromBeginning /* = false */)
140{
141  bool bPlaying(false);
142  CFileItemList vecItems;
143
144  const CURL pathToUrl(strDrive);
145  if ( !pDir->GetDirectory( pathToUrl, vecItems ) )
146  {
147    return false;
148  }
149
150  // Sorting necessary for easier HDDVD handling
151  vecItems.Sort(SortByLabel, SortOrderAscending);
152
153  bool bAllowVideo = true;
154//  bool bAllowPictures = true;
155  bool bAllowMusic = true;
156  if (!g_passwordManager.IsMasterLockUnlocked(false))
157  {
158    const std::shared_ptr<CProfileManager> profileManager = CServiceBroker::GetSettingsComponent()->GetProfileManager();
159
160    bAllowVideo = !profileManager->GetCurrentProfile().videoLocked();
161//    bAllowPictures = !profileManager->GetCurrentProfile().picturesLocked();
162    bAllowMusic = !profileManager->GetCurrentProfile().musicLocked();
163  }
164
165  // is this a root folder we have to check the content to determine a disc type
166  if (bRoot)
167  {
168    std::string hddvdname = "";
169    CFileItemPtr phddvdItem;
170    bool bAutorunDVDs = CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_DVDS_AUTORUN);
171
172    // check root folders next, for normal structured dvd's
173    for (const auto& pItem : vecItems)
174    {
175      // is the current item a (non system) folder?
176      if (pItem->m_bIsFolder && pItem->GetPath() != "." && pItem->GetPath() != "..")
177      {
178        std::string name = pItem->GetPath();
179        URIUtils::RemoveSlashAtEnd(name);
180        name = URIUtils::GetFileName(name);
181
182        // Check if the current foldername indicates a DVD structure (name is "VIDEO_TS")
183        if (StringUtils::EqualsNoCase(name, "VIDEO_TS") && bAllowVideo
184        && (bypassSettings || bAutorunDVDs))
185        {
186          std::string path = URIUtils::AddFileToFolder(pItem->GetPath(), "VIDEO_TS.IFO");
187          if(!CFile::Exists(path))
188            path = URIUtils::AddFileToFolder(pItem->GetPath(), "video_ts.ifo");
189          CFileItemPtr item(new CFileItem(path, false));
190          item->SetLabel(CServiceBroker::GetMediaManager().GetDiskLabel(strDrive));
191          item->GetVideoInfoTag()->m_strFileNameAndPath =
192              CServiceBroker::GetMediaManager().GetDiskUniqueId(strDrive);
193
194          if (!startFromBeginning && !item->GetVideoInfoTag()->m_strFileNameAndPath.empty())
195            item->m_lStartOffset = STARTOFFSET_RESUME;
196
197          CServiceBroker::GetPlaylistPlayer().ClearPlaylist(PLAYLIST_VIDEO);
198          CServiceBroker::GetPlaylistPlayer().SetShuffle (PLAYLIST_VIDEO, false);
199          CServiceBroker::GetPlaylistPlayer().Add(PLAYLIST_VIDEO, item);
200          CServiceBroker::GetPlaylistPlayer().SetCurrentPlaylist(PLAYLIST_VIDEO);
201          CServiceBroker::GetPlaylistPlayer().Play(0, "");
202          return true;
203        }
204
205        // Check if the current foldername indicates a Blu-Ray structure (default is "BDMV").
206        // A BR should also include an "AACS" folder for encryption, Sony-BRs can also include update folders for PS3 (PS3_UPDATE / PS3_VPRM).
207        //! @todo for the time being, the DVD autorun settings are used to determine if the BR should be started automatically.
208        if (StringUtils::EqualsNoCase(name, "BDMV") && bAllowVideo
209        && (bypassSettings || bAutorunDVDs))
210        {
211          CFileItemPtr item(new CFileItem(URIUtils::AddFileToFolder(pItem->GetPath(), "index.bdmv"), false));
212          item->SetLabel(CServiceBroker::GetMediaManager().GetDiskLabel(strDrive));
213          item->GetVideoInfoTag()->m_strFileNameAndPath =
214              CServiceBroker::GetMediaManager().GetDiskUniqueId(strDrive);
215
216          if (!startFromBeginning && !item->GetVideoInfoTag()->m_strFileNameAndPath.empty())
217            item->m_lStartOffset = STARTOFFSET_RESUME;
218
219          CServiceBroker::GetPlaylistPlayer().ClearPlaylist(PLAYLIST_VIDEO);
220          CServiceBroker::GetPlaylistPlayer().SetShuffle (PLAYLIST_VIDEO, false);
221          CServiceBroker::GetPlaylistPlayer().Add(PLAYLIST_VIDEO, item);
222          CServiceBroker::GetPlaylistPlayer().SetCurrentPlaylist(PLAYLIST_VIDEO);
223          CServiceBroker::GetPlaylistPlayer().Play(0, "");
224          return true;
225        }
226
227        // Check if the current foldername indicates a HD DVD structure (default is "HVDVD_TS").
228        // Most HD DVD will also include an "ADV_OBJ" folder for advanced content. This folder should be handled first.
229        //! @todo for the time being, the DVD autorun settings are used to determine if the HD DVD should be started automatically.
230        CFileItemList items, sitems;
231
232        // Advanced Content HD DVD (most discs?)
233        if (StringUtils::EqualsNoCase(name, "ADV_OBJ"))
234        {
235          CLog::Log(LOGINFO,"HD DVD: Checking for playlist.");
236          // find playlist file
237          CDirectory::GetDirectory(pItem->GetPath(), items, "*.xpl", DIR_FLAG_DEFAULTS);
238          if (items.Size())
239          {
240            // HD DVD Standard says the highest numbered playlist has to be handled first.
241            CLog::Log(LOGINFO,"HD DVD: Playlist found. Set filetypes to *.xpl for external player.");
242            items.Sort(SortByLabel, SortOrderDescending);
243            phddvdItem = pItem;
244            hddvdname = URIUtils::GetFileName(items[0]->GetPath());
245            CLog::Log(LOGINFO,"HD DVD: %s", items[0]->GetPath().c_str());
246          }
247        }
248
249        // Standard Content HD DVD (few discs?)
250        if (StringUtils::EqualsNoCase(name, "HVDVD_TS") && bAllowVideo
251        && (bypassSettings || bAutorunDVDs))
252        {
253          if (hddvdname == "")
254          {
255            CLog::Log(LOGINFO,"HD DVD: Checking for ifo.");
256            // find Video Manager or Title Set Information
257            CDirectory::GetDirectory(pItem->GetPath(), items, "HV*.ifo", DIR_FLAG_DEFAULTS);
258            if (items.Size())
259            {
260              // HD DVD Standard says the lowest numbered ifo has to be handled first.
261              CLog::Log(LOGINFO,"HD DVD: IFO found. Set filename to HV* and filetypes to *.ifo for external player.");
262              items.Sort(SortByLabel, SortOrderAscending);
263              phddvdItem = pItem;
264              hddvdname = URIUtils::GetFileName(items[0]->GetPath());
265              CLog::Log(LOGINFO,"HD DVD: %s",items[0]->GetPath().c_str());
266            }
267          }
268          // Find and sort *.evo files for internal playback.
269          // While this algorithm works for all of my HD DVDs, it may fail on other discs. If there are very large extras which are
270          // alphabetically before the main movie they will be sorted to the top of the playlist and get played first.
271          CDirectory::GetDirectory(pItem->GetPath(), items, "*.evo", DIR_FLAG_DEFAULTS);
272          if (items.Size())
273          {
274            // Sort *.evo files in alphabetical order.
275            items.Sort(SortByLabel, SortOrderAscending);
276            int64_t asize = 0;
277            int ecount = 0;
278            // calculate average size of elements above 1gb
279            for (int j = 0; j < items.Size(); j++)
280              if (items[j]->m_dwSize > 1000000000)
281              {
282                ecount++;
283                asize = asize + items[j]->m_dwSize;
284              }
285            if (ecount > 0)
286              asize = asize / ecount;
287            // Put largest files in alphabetical order to top of new list.
288            for (int j = 0; j < items.Size(); j++)
289              if (items[j]->m_dwSize >= asize)
290                sitems.Add (items[j]);
291            // Sort *.evo files by size.
292            items.Sort(SortBySize, SortOrderDescending);
293            // Add other files with descending size to bottom of new list.
294            for (int j = 0; j < items.Size(); j++)
295              if (items[j]->m_dwSize < asize)
296                sitems.Add (items[j]);
297            // Replace list with optimized list.
298            items.Clear();
299            items.Copy (sitems);
300            sitems.Clear();
301          }
302          if (hddvdname != "")
303          {
304            CFileItem item(URIUtils::AddFileToFolder(phddvdItem->GetPath(), hddvdname), false);
305            item.SetLabel(CServiceBroker::GetMediaManager().GetDiskLabel(strDrive));
306            item.GetVideoInfoTag()->m_strFileNameAndPath =
307                CServiceBroker::GetMediaManager().GetDiskUniqueId(strDrive);
308
309            if (!startFromBeginning && !item.GetVideoInfoTag()->m_strFileNameAndPath.empty())
310            item.m_lStartOffset = STARTOFFSET_RESUME;
311
312            // get playername
313            std::string hdVideoPlayer = CServiceBroker::GetPlayerCoreFactory().GetDefaultPlayer(item);
314
315            // Single *.xpl or *.ifo files require an external player to handle playback.
316            // If no matching rule was found, VideoPlayer will be default player.
317            if (hdVideoPlayer != "VideoPlayer")
318            {
319              CLog::Log(LOGINFO,"HD DVD: External singlefile playback initiated: %s",hddvdname.c_str());
320              g_application.PlayFile(item, hdVideoPlayer, false);
321              return true;
322            } else
323              CLog::Log(LOGINFO,"HD DVD: No external player found. Fallback to internal one.");
324          }
325
326          //  internal *.evo playback.
327          CLog::Log(LOGINFO,"HD DVD: Internal multifile playback initiated.");
328          CServiceBroker::GetPlaylistPlayer().ClearPlaylist(PLAYLIST_VIDEO);
329          CServiceBroker::GetPlaylistPlayer().SetShuffle (PLAYLIST_VIDEO, false);
330          CServiceBroker::GetPlaylistPlayer().Add(PLAYLIST_VIDEO, items);
331          CServiceBroker::GetPlaylistPlayer().SetCurrentPlaylist(PLAYLIST_VIDEO);
332          CServiceBroker::GetPlaylistPlayer().Play(0, "");
333          return true;
334        }
335
336        // Video CDs can have multiple file formats. First we need to determine which one is used on the CD
337        std::string strExt;
338        if (StringUtils::EqualsNoCase(name, "MPEGAV"))
339          strExt = ".dat";
340        if (StringUtils::EqualsNoCase(name, "MPEG2"))
341          strExt = ".mpg";
342
343        // If a file format was extracted we are sure this is a VCD. Autoplay if settings indicate we should.
344        if (!strExt.empty() && bAllowVideo
345             && (bypassSettings || bAutorunDVDs))
346        {
347          CFileItemList items;
348          CDirectory::GetDirectory(pItem->GetPath(), items, strExt, DIR_FLAG_DEFAULTS);
349          if (items.Size())
350          {
351            items.Sort(SortByLabel, SortOrderAscending);
352            CServiceBroker::GetPlaylistPlayer().ClearPlaylist(PLAYLIST_VIDEO);
353            CServiceBroker::GetPlaylistPlayer().Add(PLAYLIST_VIDEO, items);
354            CServiceBroker::GetPlaylistPlayer().SetCurrentPlaylist(PLAYLIST_VIDEO);
355            CServiceBroker::GetPlaylistPlayer().Play(0, "");
356            return true;
357          }
358        }
359        /* Probably want this if/when we add some automedia action dialog...
360        else if (pItem->GetPath().Find("PICTURES") != -1 && bAllowPictures
361              && (bypassSettings))
362        {
363          bPlaying = true;
364          std::string strExec = StringUtils::Format("RecursiveSlideShow(%s)", pItem->GetPath().c_str());
365          CBuiltins::Execute(strExec);
366          return true;
367        }
368        */
369      }
370    }
371  }
372
373  // check video first
374  if (!nAddedToPlaylist && !bPlaying && (bypassSettings || CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_DVDS_AUTORUN)))
375  {
376    // stack video files
377    CFileItemList tempItems;
378    tempItems.Append(vecItems);
379    if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_MYVIDEOS_STACKVIDEOS))
380      tempItems.Stack();
381    CFileItemList itemlist;
382
383    for (int i = 0; i < tempItems.Size(); i++)
384    {
385      CFileItemPtr pItem = tempItems[i];
386      if (!pItem->m_bIsFolder && pItem->IsVideo())
387      {
388        bPlaying = true;
389        if (pItem->IsStack())
390        {
391          //! @todo remove this once the app/player is capable of handling stacks immediately
392          CStackDirectory dir;
393          CFileItemList items;
394          dir.GetDirectory(pItem->GetURL(), items);
395          itemlist.Append(items);
396        }
397        else
398          itemlist.Add(pItem);
399      }
400    }
401    if (itemlist.Size())
402    {
403      if (!bAllowVideo)
404      {
405        if (!bypassSettings)
406          return false;
407
408        if (!g_passwordManager.IsMasterLockUnlocked(true))
409          return false;
410      }
411      CServiceBroker::GetPlaylistPlayer().ClearPlaylist(PLAYLIST_VIDEO);
412      CServiceBroker::GetPlaylistPlayer().Add(PLAYLIST_VIDEO, itemlist);
413      CServiceBroker::GetPlaylistPlayer().SetCurrentPlaylist(PLAYLIST_VIDEO);
414      CServiceBroker::GetPlaylistPlayer().Play(0, "");
415    }
416  }
417  // then music
418  if (!bPlaying && (bypassSettings || CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_AUDIOCDS_AUTOACTION) == AUTOCD_PLAY) && bAllowMusic)
419  {
420    for (int i = 0; i < vecItems.Size(); i++)
421    {
422      CFileItemPtr pItem = vecItems[i];
423      if (!pItem->m_bIsFolder && pItem->IsAudio())
424      {
425        nAddedToPlaylist++;
426        CServiceBroker::GetPlaylistPlayer().Add(PLAYLIST_MUSIC, pItem);
427      }
428    }
429  }
430  /* Probably want this if/when we add some automedia action dialog...
431  // and finally pictures
432  if (!nAddedToPlaylist && !bPlaying && bypassSettings && bAllowPictures)
433  {
434    for (int i = 0; i < vecItems.Size(); i++)
435    {
436      CFileItemPtr pItem = vecItems[i];
437      if (!pItem->m_bIsFolder && pItem->IsPicture())
438      {
439        bPlaying = true;
440        std::string strExec = StringUtils::Format("RecursiveSlideShow(%s)", strDrive.c_str());
441        CBuiltins::Execute(strExec);
442        break;
443      }
444    }
445  }
446  */
447
448  // check subdirs if we are not playing yet
449  if (!bPlaying)
450  {
451    for (int i = 0; i < vecItems.Size(); i++)
452    {
453      CFileItemPtr  pItem = vecItems[i];
454      if (pItem->m_bIsFolder)
455      {
456        if (pItem->GetPath() != "." && pItem->GetPath() != ".." )
457        {
458          if (RunDisc(pDir, pItem->GetPath(), nAddedToPlaylist, false, bypassSettings, startFromBeginning))
459          {
460            bPlaying = true;
461            break;
462          }
463        }
464      } // if (non system) folder
465    } // for all items in directory
466  } // if root folder
467
468  return bPlaying;
469}
470
471void CAutorun::HandleAutorun()
472{
473#ifndef TARGET_WINDOWS
474  if (!m_bEnable)
475  {
476    CDetectDVDMedia::m_evAutorun.Reset();
477    return ;
478  }
479
480  if (CDetectDVDMedia::m_evAutorun.WaitMSec(0))
481  {
482    ExecuteAutorun();
483    CDetectDVDMedia::m_evAutorun.Reset();
484  }
485#endif
486}
487
488void CAutorun::Enable()
489{
490  m_bEnable = true;
491}
492
493void CAutorun::Disable()
494{
495  m_bEnable = false;
496}
497
498bool CAutorun::IsEnabled() const
499{
500  return m_bEnable;
501}
502
503bool CAutorun::PlayDiscAskResume(const std::string& path)
504{
505  return PlayDisc(path, true, !CanResumePlayDVD(path) ||
506    HELPERS::ShowYesNoDialogText(CVariant{341}, CVariant{""}, CVariant{13404}, CVariant{12021}) ==
507    DialogResponse::YES);
508}
509
510bool CAutorun::CanResumePlayDVD(const std::string& path)
511{
512  std::string strUniqueId = CServiceBroker::GetMediaManager().GetDiskUniqueId(path);
513  if (!strUniqueId.empty())
514  {
515    CVideoDatabase dbs;
516    dbs.Open();
517    CBookmark bookmark;
518    if (dbs.GetResumeBookMark(strUniqueId, bookmark))
519      return true;
520  }
521  return false;
522}
523
524void CAutorun::SettingOptionAudioCdActionsFiller(SettingConstPtr setting, std::vector<IntegerSettingOption> &list, int &current, void *data)
525{
526  list.emplace_back(g_localizeStrings.Get(16018), AUTOCD_NONE);
527  list.emplace_back(g_localizeStrings.Get(14098), AUTOCD_PLAY);
528#ifdef HAS_CDDA_RIPPER
529  list.emplace_back(g_localizeStrings.Get(14096), AUTOCD_RIP);
530#endif
531}