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