Merge pull request #1777 from Montellese/dont_group_in_files_view
[vuplus_xbmc] / xbmc / video / windows / GUIWindowVideoBase.cpp
1 /*
2  *      Copyright (C) 2005-2012 Team XBMC
3  *      http://www.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 "GUIWindowVideoBase.h"
23 #include "Util.h"
24 #include "video/VideoInfoDownloader.h"
25 #include "video/VideoInfoScanner.h"
26 #include "utils/RegExp.h"
27 #include "utils/Variant.h"
28 #include "addons/AddonManager.h"
29 #include "addons/GUIDialogAddonInfo.h"
30 #include "addons/IAddon.h"
31 #include "video/dialogs/GUIDialogVideoInfo.h"
32 #include "GUIWindowVideoNav.h"
33 #include "dialogs/GUIDialogSmartPlaylistEditor.h"
34 #include "dialogs/GUIDialogProgress.h"
35 #include "dialogs/GUIDialogYesNo.h"
36 #include "playlists/PlayListFactory.h"
37 #include "Application.h"
38 #include "NfoFile.h"
39 #include "PlayListPlayer.h"
40 #include "GUIPassword.h"
41 #include "filesystem/ZipManager.h"
42 #include "filesystem/StackDirectory.h"
43 #include "filesystem/MultiPathDirectory.h"
44 #include "video/dialogs/GUIDialogFileStacking.h"
45 #include "dialogs/GUIDialogMediaSource.h"
46 #include "windows/GUIWindowFileManager.h"
47 #include "filesystem/VideoDatabaseDirectory.h"
48 #include "PartyModeManager.h"
49 #include "guilib/GUIWindowManager.h"
50 #include "dialogs/GUIDialogOK.h"
51 #include "dialogs/GUIDialogSelect.h"
52 #include "guilib/GUIKeyboardFactory.h"
53 #include "filesystem/Directory.h"
54 #include "playlists/PlayList.h"
55 #include "settings/Settings.h"
56 #include "settings/AdvancedSettings.h"
57 #include "settings/GUISettings.h"
58 #include "settings/GUIDialogContentSettings.h"
59 #include "guilib/LocalizeStrings.h"
60 #include "utils/StringUtils.h"
61 #include "utils/log.h"
62 #include "utils/FileUtils.h"
63 #include "interfaces/AnnouncementManager.h"
64 #include "pvr/PVRManager.h"
65 #include "pvr/recordings/PVRRecordings.h"
66 #include "utils/URIUtils.h"
67 #include "GUIUserMessages.h"
68 #include "addons/Skin.h"
69 #include "storage/MediaManager.h"
70 #include "Autorun.h"
71 #include "URL.h"
72 #include "utils/EdenVideoArtUpdater.h"
73 #include "GUIInfoManager.h"
74 #include "utils/GroupUtils.h"
75 #include "filesystem/File.h"
76
77 using namespace std;
78 using namespace XFILE;
79 using namespace PLAYLIST;
80 using namespace VIDEODATABASEDIRECTORY;
81 using namespace VIDEO;
82 using namespace ADDON;
83 using namespace PVR;
84
85 #define CONTROL_BTNVIEWASICONS     2
86 #define CONTROL_BTNSORTBY          3
87 #define CONTROL_BTNSORTASC         4
88 #define CONTROL_BTNTYPE            5
89 #define CONTROL_LABELFILES        12
90
91 #define CONTROL_PLAY_DVD           6
92 #define CONTROL_STACK              7
93 #define CONTROL_BTNSCAN            8
94
95 CGUIWindowVideoBase::CGUIWindowVideoBase(int id, const CStdString &xmlFile)
96     : CGUIMediaWindow(id, xmlFile)
97 {
98   m_thumbLoader.SetObserver(this);
99   m_thumbLoader.SetStreamDetailsObserver(this);
100   m_stackingAvailable = true;
101 }
102
103 CGUIWindowVideoBase::~CGUIWindowVideoBase()
104 {
105 }
106
107 bool CGUIWindowVideoBase::OnAction(const CAction &action)
108 {
109   if (action.GetID() == ACTION_SCAN_ITEM)
110     return OnContextButton(m_viewControl.GetSelectedItem(),CONTEXT_BUTTON_SCAN);
111   else if (action.GetID() == ACTION_SHOW_PLAYLIST)
112   {
113     if (g_playlistPlayer.GetCurrentPlaylist() == PLAYLIST_VIDEO ||
114         g_playlistPlayer.GetPlaylist(PLAYLIST_VIDEO).size() > 0)
115     {
116       g_windowManager.ActivateWindow(WINDOW_VIDEO_PLAYLIST);
117       return true;
118     }
119   }
120
121   return CGUIMediaWindow::OnAction(action);
122 }
123
124 bool CGUIWindowVideoBase::OnMessage(CGUIMessage& message)
125 {
126   switch ( message.GetMessage() )
127   {
128   case GUI_MSG_WINDOW_DEINIT:
129     if (m_thumbLoader.IsLoading())
130       m_thumbLoader.StopThread();
131     m_database.Close();
132     break;
133
134   case GUI_MSG_WINDOW_INIT:
135     {
136       m_database.Open();
137
138       m_dlgProgress = (CGUIDialogProgress*)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
139
140       // save current window, unless the current window is the video playlist window
141       if (GetID() != WINDOW_VIDEO_PLAYLIST && g_settings.m_iVideoStartWindow != GetID())
142       {
143         g_settings.m_iVideoStartWindow = GetID();
144         g_settings.Save();
145       }
146
147       return CGUIMediaWindow::OnMessage(message);
148     }
149     break;
150
151   case GUI_MSG_CLICKED:
152     {
153       int iControl = message.GetSenderId();
154       if (iControl == CONTROL_STACK)
155       {
156         g_settings.m_videoStacking = !g_settings.m_videoStacking;
157         g_settings.Save();
158         UpdateButtons();
159         Update( m_vecItems->GetPath() );
160       }
161 #if defined(HAS_DVD_DRIVE)
162       else if (iControl == CONTROL_PLAY_DVD)
163       {
164         // play movie...
165         MEDIA_DETECT::CAutorun::PlayDiscAskResume(g_mediaManager.TranslateDevicePath(""));
166       }
167 #endif
168       else if (iControl == CONTROL_BTNTYPE)
169       {
170         CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_BTNTYPE);
171         g_windowManager.SendMessage(msg);
172
173         int nSelected = msg.GetParam1();
174         int nNewWindow = WINDOW_VIDEO_FILES;
175         switch (nSelected)
176         {
177         case 0:  // Movies
178           nNewWindow = WINDOW_VIDEO_FILES;
179           break;
180         case 1:  // Library
181           nNewWindow = WINDOW_VIDEO_NAV;
182           break;
183         }
184
185         if (nNewWindow != GetID())
186         {
187           g_settings.m_iVideoStartWindow = nNewWindow;
188           g_settings.Save();
189           g_windowManager.ChangeActiveWindow(nNewWindow);
190           CGUIMessage msg2(GUI_MSG_SETFOCUS, nNewWindow, CONTROL_BTNTYPE);
191           g_windowManager.SendMessage(msg2);
192         }
193
194         return true;
195       }
196       else if (m_viewControl.HasControl(iControl))  // list/thumb control
197       {
198         // get selected item
199         int iItem = m_viewControl.GetSelectedItem();
200         int iAction = message.GetParam1();
201
202         // iItem is checked for validity inside these routines
203         if (iAction == ACTION_QUEUE_ITEM || iAction == ACTION_MOUSE_MIDDLE_CLICK)
204         {
205           OnQueueItem(iItem);
206           return true;
207         }
208         else if (iAction == ACTION_SHOW_INFO)
209         {
210           return OnInfo(iItem);
211         }
212         else if (iAction == ACTION_PLAYER_PLAY && !g_application.IsPlayingVideo())
213         {
214           return OnResumeItem(iItem);
215         }
216         else if (iAction == ACTION_DELETE_ITEM)
217         {
218           // is delete allowed?
219           if (g_settings.GetCurrentProfile().canWriteDatabases())
220           {
221             // must be at the title window
222             if (GetID() == WINDOW_VIDEO_NAV)
223               OnDeleteItem(iItem);
224
225             // or be at the files window and have file deletion enabled
226             else if (GetID() == WINDOW_VIDEO_FILES && g_guiSettings.GetBool("filelists.allowfiledeletion"))
227               OnDeleteItem(iItem);
228
229             // or be at the video playlists location
230             else if (m_vecItems->GetPath().Equals("special://videoplaylists/"))
231               OnDeleteItem(iItem);
232             else
233               return false;
234
235             return true;
236           }
237         }
238       }
239     }
240     break;
241   case GUI_MSG_SEARCH:
242     OnSearch();
243     break;
244   }
245   return CGUIMediaWindow::OnMessage(message);
246 }
247
248 void CGUIWindowVideoBase::UpdateButtons()
249 {
250   // Remove labels from the window selection
251   CGUIMessage msg(GUI_MSG_LABEL_RESET, GetID(), CONTROL_BTNTYPE);
252   g_windowManager.SendMessage(msg);
253
254   // Add labels to the window selection
255   CStdString strItem = g_localizeStrings.Get(744); // Files
256   CGUIMessage msg2(GUI_MSG_LABEL_ADD, GetID(), CONTROL_BTNTYPE);
257   msg2.SetLabel(strItem);
258   g_windowManager.SendMessage(msg2);
259
260   strItem = g_localizeStrings.Get(14022); // Library
261   msg2.SetLabel(strItem);
262   g_windowManager.SendMessage(msg2);
263
264   // Select the current window as default item
265   int nWindow = g_settings.m_iVideoStartWindow-WINDOW_VIDEO_FILES;
266   CONTROL_SELECT_ITEM(CONTROL_BTNTYPE, nWindow);
267
268   CONTROL_ENABLE(CONTROL_BTNSCAN);
269
270   SET_CONTROL_LABEL(CONTROL_STACK, 14000);  // Stack
271   SET_CONTROL_SELECTED(GetID(), CONTROL_STACK, g_settings.m_videoStacking);
272   CONTROL_ENABLE_ON_CONDITION(CONTROL_STACK, m_stackingAvailable);
273   
274   CGUIMediaWindow::UpdateButtons();
275 }
276
277 void CGUIWindowVideoBase::OnInfo(CFileItem* pItem, const ADDON::ScraperPtr& scraper)
278 {
279   if (!pItem)
280     return;
281
282   if (pItem->IsParentFolder() || pItem->m_bIsShareOrDrive || pItem->GetPath().Equals("add") ||
283      (pItem->IsPlayList() && !URIUtils::GetExtension(pItem->GetPath()).Equals(".strm")))
284     return;
285
286   // ShowIMDB can kill the item as this window can be closed while we do it,
287   // so take a copy of the item now
288   CFileItem item(*pItem);
289   if (item.IsVideoDb() && item.HasVideoInfoTag())
290   {
291     if (item.GetVideoInfoTag()->m_type == "season")
292     { // clear out the art - we're really grabbing the info on the show here
293       item.ClearArt();
294     }
295     item.SetPath(item.GetVideoInfoTag()->GetPath());
296   }
297   else
298   {
299     if (item.m_bIsFolder && scraper && scraper->Content() != CONTENT_TVSHOWS)
300     {
301       CFileItemList items;
302       CDirectory::GetDirectory(item.GetPath(), items, g_settings.m_videoExtensions);
303       items.Stack();
304
305       // check for media files
306       bool bFoundFile(false);
307       for (int i = 0; i < items.Size(); ++i)
308       {
309         CFileItemPtr item2 = items[i];
310
311         if (item2->IsVideo() && !item2->IsPlayList() &&
312             !CUtil::ExcludeFileOrFolder(item2->GetPath(), g_advancedSettings.m_moviesExcludeFromScanRegExps))
313         {
314           item.SetPath(item2->GetPath());
315           item.m_bIsFolder = false;
316           bFoundFile = true;
317           break;
318         }
319       }
320
321       // no video file in this folder
322       if (!bFoundFile)
323       {
324         CGUIDialogOK::ShowAndGetInput(13346,20349,20022,20022);
325         return;
326       }
327     }
328   }
329
330   // we need to also request any thumbs be applied to the folder item
331   if (pItem->m_bIsFolder)
332     item.SetProperty("set_folder_thumb", pItem->GetPath());
333
334   bool modified = ShowIMDB(&item, scraper);
335   if (modified &&
336      (g_windowManager.GetActiveWindow() == WINDOW_VIDEO_FILES ||
337       g_windowManager.GetActiveWindow() == WINDOW_VIDEO_NAV)) // since we can be called from the music library we need this check
338   {
339     int itemNumber = m_viewControl.GetSelectedItem();
340     Refresh();
341     m_viewControl.SetSelectedItem(itemNumber);
342   }
343 }
344
345 // ShowIMDB is called as follows:
346 // 1.  To lookup info on a file.
347 // 2.  To lookup info on a folder (which may or may not contain a file)
348 // 3.  To lookup info just for fun (no file or folder related)
349
350 // We just need the item object for this.
351 // A "blank" item object is sent for 3.
352 // If a folder is sent, currently it sets strFolder and bFolder
353 // this is only used for setting the folder thumb, however.
354
355 // Steps should be:
356
357 // 1.  Check database to see if we have this information already
358 // 2.  Else, check for a nfoFile to get the URL
359 // 3.  Run a loop to check for refresh
360 // 4.  If no URL is present do a search to get the URL
361 // 4.  Once we have the URL, download the details
362 // 5.  Once we have the details, add to the database if necessary (case 1,2)
363 //     and show the information.
364 // 6.  Check for a refresh, and if so, go to 3.
365
366 bool CGUIWindowVideoBase::ShowIMDB(CFileItem *item, const ScraperPtr &info2)
367 {
368   /*
369   CLog::Log(LOGDEBUG,"CGUIWindowVideoBase::ShowIMDB");
370   CLog::Log(LOGDEBUG,"  strMovie  = [%s]", strMovie.c_str());
371   CLog::Log(LOGDEBUG,"  strFile   = [%s]", strFile.c_str());
372   CLog::Log(LOGDEBUG,"  strFolder = [%s]", strFolder.c_str());
373   CLog::Log(LOGDEBUG,"  bFolder   = [%s]", ((int)bFolder ? "true" : "false"));
374   */
375
376   CGUIDialogProgress* pDlgProgress = (CGUIDialogProgress*)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
377   CGUIDialogSelect* pDlgSelect = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
378   CGUIDialogVideoInfo* pDlgInfo = (CGUIDialogVideoInfo*)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_INFO);
379
380   ScraperPtr info(info2); // use this as nfo might change it..
381
382   if (!pDlgProgress) return false;
383   if (!pDlgSelect) return false;
384   if (!pDlgInfo) return false;
385
386   // 1.  Check for already downloaded information, and if we have it, display our dialog
387   //     Return if no Refresh is needed.
388   bool bHasInfo=false;
389
390   CVideoInfoTag movieDetails;
391   if (info)
392   {
393     m_database.Open(); // since we can be called from the music library
394
395     if (info->Content() == CONTENT_MOVIES)
396     {
397       bHasInfo = m_database.GetMovieInfo(item->GetPath(), movieDetails);
398     }
399     if (info->Content() == CONTENT_TVSHOWS)
400     {
401       if (item->m_bIsFolder)
402       {
403         bHasInfo = m_database.GetTvShowInfo(item->GetPath(), movieDetails);
404       }
405       else
406       {
407         int EpisodeHint=-1;
408         if (item->HasVideoInfoTag())
409           EpisodeHint = item->GetVideoInfoTag()->m_iEpisode;
410         int idEpisode=-1;
411         if ((idEpisode = m_database.GetEpisodeId(item->GetPath(),EpisodeHint)) > -1)
412         {
413           bHasInfo = true;
414           m_database.GetEpisodeInfo(item->GetPath(), movieDetails, idEpisode);
415         }
416         else
417         {
418           // !! WORKAROUND !!
419           // As we cannot add an episode to a non-existing tvshow entry, we have to check the parent directory
420           // to see if it`s already in our video database. If it's not yet part of the database we will exit here.
421           // (Ticket #4764)
422           //
423           // NOTE: This will fail for episodes on multipath shares, as the parent path isn't what is stored in the
424           //       database.  Possible solutions are to store the paths in the db separately and rely on the show
425           //       stacking stuff, or to modify GetTvShowId to do support multipath:// shares
426           CStdString strParentDirectory;
427           URIUtils::GetParentPath(item->GetPath(), strParentDirectory);
428           if (m_database.GetTvShowId(strParentDirectory) < 0)
429           {
430             CLog::Log(LOGERROR,"%s: could not add episode [%s]. tvshow does not exist yet..", __FUNCTION__, item->GetPath().c_str());
431             return false;
432           }
433         }
434       }
435     }
436     if (info->Content() == CONTENT_MUSICVIDEOS)
437     {
438       bHasInfo = m_database.GetMusicVideoInfo(item->GetPath(), movieDetails);
439     }
440     m_database.Close();
441   }
442   else if(item->HasVideoInfoTag())
443   {
444     bHasInfo = true;
445     movieDetails = *item->GetVideoInfoTag();
446   }
447   
448   bool needsRefresh = false;
449   if (bHasInfo)
450   {
451     if (!info || info->Content() == CONTENT_NONE) // disable refresh button
452       movieDetails.m_strIMDBNumber = "xx"+movieDetails.m_strIMDBNumber;
453     *item->GetVideoInfoTag() = movieDetails;
454     pDlgInfo->SetMovie(item);
455     pDlgInfo->DoModal();
456     needsRefresh = pDlgInfo->NeedRefresh();
457     if (!needsRefresh)
458       return pDlgInfo->HasUpdatedThumb();
459   }
460
461   // quietly return if Internet lookups are disabled
462   if (!g_settings.GetCurrentProfile().canWriteDatabases() && !g_passwordManager.bMasterUser)
463     return false;
464
465   if(!info)
466     return false;
467
468   if (g_application.IsVideoScanning())
469   {
470     CGUIDialogOK::ShowAndGetInput(13346,14057,-1,-1);
471     return false;
472   }
473
474   m_database.Open();
475   // 2. Look for a nfo File to get the search URL
476   SScanSettings settings;
477   info = m_database.GetScraperForPath(item->GetPath(),settings);
478
479   if (!info)
480     return false;
481
482   // Get the correct movie title
483   CStdString movieName = item->GetMovieName(settings.parent_name);
484
485   CScraperUrl scrUrl;
486   CVideoInfoScanner scanner;
487   bool hasDetails = false;
488   bool listNeedsUpdating = false;
489   bool ignoreNfo = false;
490   // 3. Run a loop so that if we Refresh we re-run this block
491   do
492   {
493     if (!ignoreNfo)
494     {
495       CNfoFile::NFOResult nfoResult = scanner.CheckForNFOFile(item,settings.parent_name_root,info,scrUrl);
496       if (nfoResult == CNfoFile::ERROR_NFO)
497         ignoreNfo = true;
498       else
499       if (nfoResult != CNfoFile::NO_NFO)
500         hasDetails = true;
501
502       if (needsRefresh)
503       {
504         bHasInfo = true;
505         if (nfoResult == CNfoFile::URL_NFO || nfoResult == CNfoFile::COMBINED_NFO || nfoResult == CNfoFile::FULL_NFO)
506         {
507           if (CGUIDialogYesNo::ShowAndGetInput(13346,20446,20447,20022))
508           {
509             hasDetails = false;
510             ignoreNfo = true;
511             scrUrl.Clear();
512             info = info2;
513           }
514         }
515       }
516     }
517
518     // 4. if we don't have an url, or need to refresh the search
519     //    then do the web search
520     MOVIELIST movielist;
521     if (info->Content() == CONTENT_TVSHOWS && !item->m_bIsFolder)
522       hasDetails = true;
523
524     if (!hasDetails && (scrUrl.m_url.size() == 0 || needsRefresh))
525     {
526       // 4a. show dialog that we're busy querying www.imdb.com
527       CStdString strHeading;
528       strHeading.Format(g_localizeStrings.Get(197),info->Name().c_str());
529       pDlgProgress->SetHeading(strHeading);
530       pDlgProgress->SetLine(0, movieName);
531       pDlgProgress->SetLine(1, "");
532       pDlgProgress->SetLine(2, "");
533       pDlgProgress->StartModal();
534       pDlgProgress->Progress();
535
536       // 4b. do the websearch
537       info->ClearCache();
538       CVideoInfoDownloader imdb(info);
539       int returncode = imdb.FindMovie(movieName, movielist, pDlgProgress);
540       if (returncode > 0)
541       {
542         pDlgProgress->Close();
543         if (movielist.size() > 0)
544         {
545           int iString = 196;
546           if (info->Content() == CONTENT_TVSHOWS)
547             iString = 20356;
548           pDlgSelect->SetHeading(iString);
549           pDlgSelect->Reset();
550           for (unsigned int i = 0; i < movielist.size(); ++i)
551             pDlgSelect->Add(movielist[i].strTitle);
552           pDlgSelect->EnableButton(true, 413); // manual
553           pDlgSelect->DoModal();
554
555           // and wait till user selects one
556           int iSelectedMovie = pDlgSelect->GetSelectedLabel();
557           if (iSelectedMovie >= 0)
558           {
559             scrUrl = movielist[iSelectedMovie];
560             CLog::Log(LOGDEBUG, "%s: user selected movie '%s' with URL '%s'",
561               __FUNCTION__, scrUrl.strTitle.c_str(), scrUrl.m_url[0].m_url.c_str());
562           }
563           else if (!pDlgSelect->IsButtonPressed())
564           {
565             m_database.Close();
566             return listNeedsUpdating; // user backed out
567           }
568         }
569       }
570       else if (returncode == -1 || !CVideoInfoScanner::DownloadFailed(pDlgProgress))
571       {
572         pDlgProgress->Close();
573         return false;
574       }
575     }
576     // 4c. Check if url is still empty - occurs if user has selected to do a manual
577     //     lookup, or if the IMDb lookup failed or was cancelled.
578     if (!hasDetails && scrUrl.m_url.size() == 0)
579     {
580       // Check for cancel of the progress dialog
581       pDlgProgress->Close();
582       if (pDlgProgress->IsCanceled())
583       {
584         m_database.Close();
585         return listNeedsUpdating;
586       }
587
588       // Prompt the user to input the movieName
589       int iString = 16009;
590       if (info->Content() == CONTENT_TVSHOWS)
591         iString = 20357;
592       if (!CGUIKeyboardFactory::ShowAndGetInput(movieName, g_localizeStrings.Get(iString), false))
593       {
594         m_database.Close();
595         return listNeedsUpdating; // user backed out
596       }
597
598       needsRefresh = true;
599     }
600     else
601     {
602       // 5. Download the movie information
603       // show dialog that we're downloading the movie info
604
605       // clear artwork
606       item->SetArt("thumb", "");
607       item->SetArt("fanart", "");
608
609       CFileItemList list;
610       CStdString strPath=item->GetPath();
611       if (item->IsVideoDb())
612       {
613         CFileItemPtr newItem(new CFileItem(*item->GetVideoInfoTag()));
614         list.Add(newItem);
615         strPath = item->GetVideoInfoTag()->m_strPath;
616       }
617       else
618       {
619         CFileItemPtr newItem(new CFileItem(*item));
620         list.Add(newItem);
621       }
622
623       if (item->m_bIsFolder)
624         list.SetPath(URIUtils::GetParentPath(strPath));
625       else
626       {
627         CStdString path;
628         URIUtils::GetDirectory(strPath, path);
629         list.SetPath(path);
630       }
631
632       int iString=198;
633       if (info->Content() == CONTENT_TVSHOWS)
634       {
635         if (item->m_bIsFolder)
636           iString = 20353;
637         else
638           iString = 20361;
639       }
640       if (info->Content() == CONTENT_MUSICVIDEOS)
641         iString = 20394;
642       pDlgProgress->SetHeading(iString);
643       pDlgProgress->SetLine(0, movieName);
644       pDlgProgress->SetLine(1, scrUrl.strTitle);
645       pDlgProgress->SetLine(2, "");
646       pDlgProgress->StartModal();
647       pDlgProgress->Progress();
648       if (bHasInfo)
649       {
650         if (info->Content() == CONTENT_MOVIES)
651           m_database.DeleteMovie(item->GetPath());
652         if (info->Content() == CONTENT_TVSHOWS && !item->m_bIsFolder)
653           m_database.DeleteEpisode(item->GetPath(),movieDetails.m_iDbId);
654         if (info->Content() == CONTENT_MUSICVIDEOS)
655           m_database.DeleteMusicVideo(item->GetPath());
656         if (info->Content() == CONTENT_TVSHOWS && item->m_bIsFolder)
657         {
658           if (pDlgInfo->RefreshAll())
659             m_database.DeleteTvShow(item->GetPath());
660           else
661             m_database.DeleteDetailsForTvShow(item->GetPath());
662         }
663       }
664       if (scanner.RetrieveVideoInfo(list,settings.parent_name_root,info->Content(),!ignoreNfo,&scrUrl,pDlgInfo->RefreshAll(),pDlgProgress))
665       {
666         if (info->Content() == CONTENT_MOVIES)
667           m_database.GetMovieInfo(item->GetPath(),movieDetails);
668         if (info->Content() == CONTENT_MUSICVIDEOS)
669           m_database.GetMusicVideoInfo(item->GetPath(),movieDetails);
670         if (info->Content() == CONTENT_TVSHOWS)
671         {
672           // update tvshow info to get updated episode numbers
673           if (item->m_bIsFolder)
674             m_database.GetTvShowInfo(item->GetPath(),movieDetails);
675           else
676             m_database.GetEpisodeInfo(item->GetPath(),movieDetails);
677         }
678
679         // got all movie details :-)
680         OutputDebugString("got details\n");
681         pDlgProgress->Close();
682
683         // now show the imdb info
684         OutputDebugString("show info\n");
685
686         // remove directory caches and reload images
687         CUtil::DeleteVideoDatabaseDirectoryCache();
688         CGUIMessage reload(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_REFRESH_THUMBS);
689         OnMessage(reload);
690
691         *item->GetVideoInfoTag() = movieDetails;
692         pDlgInfo->SetMovie(item);
693         pDlgInfo->DoModal();
694         item->SetArt("thumb", pDlgInfo->GetThumbnail());
695         needsRefresh = pDlgInfo->NeedRefresh();
696         listNeedsUpdating = true;
697       }
698       else
699       {
700         pDlgProgress->Close();
701         if (pDlgProgress->IsCanceled())
702         {
703           m_database.Close();
704           return listNeedsUpdating; // user cancelled
705         }
706         CGUIDialogOK::ShowAndGetInput(195, movieName, 0, 0);
707         m_database.Close();
708         return listNeedsUpdating;
709       }
710     }
711   // 6. Check for a refresh
712   } while (needsRefresh);
713   m_database.Close();
714   return listNeedsUpdating;
715 }
716
717 void CGUIWindowVideoBase::OnQueueItem(int iItem)
718 {
719   // don't re-queue items from playlist window
720   if ( iItem < 0 || iItem >= m_vecItems->Size() || GetID() == WINDOW_VIDEO_PLAYLIST ) return ;
721
722   // we take a copy so that we can alter the queue state
723   CFileItemPtr item(new CFileItem(*m_vecItems->Get(iItem)));
724   if (item->IsRAR() || item->IsZIP())
725     return;
726
727   //  Allow queuing of unqueueable items
728   //  when we try to queue them directly
729   if (!item->CanQueue())
730     item->SetCanQueue(true);
731
732   CFileItemList queuedItems;
733   AddItemToPlayList(item, queuedItems);
734   // if party mode, add items but DONT start playing
735   if (g_partyModeManager.IsEnabled(PARTYMODECONTEXT_VIDEO))
736   {
737     g_partyModeManager.AddUserSongs(queuedItems, false);
738     return;
739   }
740
741   g_playlistPlayer.Add(PLAYLIST_VIDEO, queuedItems);
742   g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_VIDEO);
743   // video does not auto play on queue like music
744   m_viewControl.SetSelectedItem(iItem + 1);
745 }
746
747 void CGUIWindowVideoBase::AddItemToPlayList(const CFileItemPtr &pItem, CFileItemList &queuedItems)
748 {
749   if (!pItem->CanQueue() || pItem->IsRAR() || pItem->IsZIP() || pItem->IsParentFolder()) // no zip/rar enques thank you!
750     return;
751
752   if (pItem->m_bIsFolder)
753   {
754     if (pItem->IsParentFolder())
755       return;
756
757     // Check if we add a locked share
758     if ( pItem->m_bIsShareOrDrive )
759     {
760       CFileItem item = *pItem;
761       if ( !g_passwordManager.IsItemUnlocked( &item, "video" ) )
762         return;
763     }
764
765     // recursive
766     CFileItemList items;
767     GetDirectory(pItem->GetPath(), items);
768     FormatAndSort(items);
769
770     int watchedMode = g_settings.GetWatchMode(items.GetContent());
771     bool unwatchedOnly = watchedMode == VIDEO_SHOW_UNWATCHED;
772     bool watchedOnly = watchedMode == VIDEO_SHOW_WATCHED;
773     for (int i = 0; i < items.Size(); ++i)
774     {
775       if (items[i]->m_bIsFolder)
776       {
777         CStdString strPath = items[i]->GetPath();
778         URIUtils::RemoveSlashAtEnd(strPath);
779         strPath.ToLower();
780         if (strPath.size() > 6)
781         {
782           CStdString strSub = strPath.substr(strPath.size()-6);
783           if (strPath.Mid(strPath.size()-6).Equals("sample")) // skip sample folders
784             continue;
785         }
786       }
787       else if (items[i]->HasVideoInfoTag() &&
788        ((unwatchedOnly && items[i]->GetVideoInfoTag()->m_playCount > 0) ||
789         (watchedOnly && items[i]->GetVideoInfoTag()->m_playCount <= 0)))
790         continue;
791
792       AddItemToPlayList(items[i], queuedItems);
793     }
794   }
795   else
796   {
797     // just an item
798     if (pItem->IsPlayList())
799     {
800       auto_ptr<CPlayList> pPlayList (CPlayListFactory::Create(*pItem));
801       if (pPlayList.get())
802       {
803         // load it
804         if (!pPlayList->Load(pItem->GetPath()))
805         {
806           CGUIDialogOK::ShowAndGetInput(6, 0, 477, 0);
807           return; //hmmm unable to load playlist?
808         }
809
810         CPlayList playlist = *pPlayList;
811         for (int i = 0; i < (int)playlist.size(); ++i)
812         {
813           AddItemToPlayList(playlist[i], queuedItems);
814         }
815         return;
816       }
817     }
818     else if(pItem->IsInternetStream())
819     { // just queue the internet stream, it will be expanded on play
820       queuedItems.Add(pItem);
821     }
822     else if (pItem->IsPlugin() && pItem->GetProperty("isplayable") == "true")
823     { // a playable python files
824       queuedItems.Add(pItem);
825     }
826     else if (pItem->IsVideoDb())
827     { // this case is needed unless we allow IsVideo() to return true for videodb items,
828       // but then we have issues with playlists of videodb items
829       CFileItemPtr item(new CFileItem(*pItem->GetVideoInfoTag()));
830       queuedItems.Add(item);
831     }
832     else if (!pItem->IsNFO() && pItem->IsVideo())
833     {
834       queuedItems.Add(pItem);
835     }
836   }
837 }
838
839 void CGUIWindowVideoBase::GetResumeItemOffset(const CFileItem *item, int& startoffset, int& partNumber)
840 {
841   // do not resume livetv
842   if (item->IsLiveTV())
843     return;
844
845   startoffset = 0;
846   partNumber = 0;
847
848   if (!item->IsNFO() && !item->IsPlayList())
849   {
850     if (item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_resumePoint.IsSet())
851     {
852       startoffset = (int)(item->GetVideoInfoTag()->m_resumePoint.timeInSeconds*75);
853       partNumber = item->GetVideoInfoTag()->m_resumePoint.partNumber;
854     }
855     else
856     {
857       CBookmark bookmark;
858       CStdString strPath = item->GetPath();
859       if ((item->IsVideoDb() || item->IsDVD()) && item->HasVideoInfoTag())
860         strPath = item->GetVideoInfoTag()->m_strFileNameAndPath;
861
862       CVideoDatabase db;
863       if (!db.Open())
864       {
865         CLog::Log(LOGERROR, "%s - Cannot open VideoDatabase", __FUNCTION__);
866         return;
867       }
868       if (db.GetResumeBookMark(strPath, bookmark))
869       {
870         startoffset = (int)(bookmark.timeInSeconds*75);
871         partNumber = bookmark.partNumber;
872       }
873       db.Close();
874     }
875   }
876 }
877
878 bool CGUIWindowVideoBase::HasResumeItemOffset(const CFileItem *item)
879 {
880   int startoffset = 0, partNumber = 0;
881   GetResumeItemOffset(item, startoffset, partNumber);
882   return startoffset > 0;
883 }
884
885 bool CGUIWindowVideoBase::OnClick(int iItem)
886 {
887   return CGUIMediaWindow::OnClick(iItem);
888 }
889
890 bool CGUIWindowVideoBase::OnSelect(int iItem)
891 {
892   if (iItem < 0 || iItem >= m_vecItems->Size())
893     return false;
894
895   CFileItemPtr item = m_vecItems->Get(iItem);
896
897   CStdString path = item->GetPath();
898   if (!item->m_bIsFolder && path != "add" && path != "addons://more/video" &&
899       path.Left(19) != "newsmartplaylist://" && path.Left(14) != "newplaylist://" && path.Left(9) != "newtag://")
900     return OnFileAction(iItem, g_guiSettings.GetInt("myvideos.selectaction"));
901
902   return CGUIMediaWindow::OnSelect(iItem);
903 }
904
905 bool CGUIWindowVideoBase::OnFileAction(int iItem, int action)
906 {
907   CFileItemPtr item = m_vecItems->Get(iItem);
908
909   // Reset the current start offset. The actual resume
910   // option is set in the switch, based on the action passed.
911   item->m_lStartOffset = 0;
912   
913   switch (action)
914   {
915   case SELECT_ACTION_CHOOSE:
916     {
917       CContextButtons choices;
918
919       if (item->IsVideoDb())
920       {
921         CStdString itemPath(item->GetPath());
922         itemPath = item->GetVideoInfoTag()->m_strFileNameAndPath;
923         if (URIUtils::IsStack(itemPath) && CFileItem(CStackDirectory::GetFirstStackedFile(itemPath),false).IsDVDImage())
924           choices.Add(SELECT_ACTION_PLAYPART, 20324); // Play Part
925       }
926
927       CStdString resumeString = GetResumeString(*item);
928       if (!resumeString.IsEmpty())
929       {
930         choices.Add(SELECT_ACTION_RESUME, resumeString);
931         choices.Add(SELECT_ACTION_PLAY, 12021);   // Start from beginning
932       }
933       else
934         choices.Add(SELECT_ACTION_PLAY, 208);   // Play
935
936       choices.Add(SELECT_ACTION_INFO, 22081); // Info
937       choices.Add(SELECT_ACTION_MORE, 22082); // More
938       int value = CGUIDialogContextMenu::ShowAndGetChoice(choices);
939       if (value < 0)
940         return true;
941
942       return OnFileAction(iItem, value);
943     }
944     break;
945   case SELECT_ACTION_PLAY_OR_RESUME:
946     return OnResumeItem(iItem);
947   case SELECT_ACTION_INFO:
948     if (OnInfo(iItem))
949       return true;
950     break;
951   case SELECT_ACTION_MORE:
952     OnPopupMenu(iItem);
953     return true;
954   case SELECT_ACTION_RESUME:
955     item->m_lStartOffset = STARTOFFSET_RESUME;
956     break;
957   case SELECT_ACTION_PLAYPART:
958     if (!OnPlayStackPart(iItem))
959       return false;
960     break;
961   case SELECT_ACTION_PLAY:
962   default:
963     break;
964   }
965   return OnClick(iItem);
966 }
967
968 bool CGUIWindowVideoBase::OnInfo(int iItem) 
969 {
970   if (iItem < 0 || iItem >= m_vecItems->Size())
971     return false;
972
973   CFileItemPtr item = m_vecItems->Get(iItem);
974
975   if (item->GetPath().Equals("add") || item->IsParentFolder() ||
976      (item->IsPlayList() && !URIUtils::GetExtension(item->GetPath()).Equals(".strm")))
977     return false;
978
979   if (!m_vecItems->IsPlugin() && (item->IsPlugin() || item->IsScript()))
980     return CGUIDialogAddonInfo::ShowForItem(item);
981
982   ADDON::ScraperPtr scraper;
983   if (!m_vecItems->IsPlugin() && !m_vecItems->IsRSS() && !m_vecItems->IsLiveTV())
984   {
985     CStdString strDir;
986     if (item->IsVideoDb()       &&
987         item->HasVideoInfoTag() &&
988         !item->GetVideoInfoTag()->m_strPath.IsEmpty())
989     {
990       strDir = item->GetVideoInfoTag()->m_strPath;
991     }
992     else
993       URIUtils::GetDirectory(item->GetPath(),strDir);
994
995     SScanSettings settings;
996     bool foundDirectly = false;
997     scraper = m_database.GetScraperForPath(strDir, settings, foundDirectly);
998
999     if (!scraper &&
1000         !(m_database.HasMovieInfo(item->GetPath()) ||
1001           m_database.HasTvShowInfo(strDir)           ||
1002           m_database.HasEpisodeInfo(item->GetPath())))
1003     {
1004       return false;
1005     }
1006
1007     if (scraper && scraper->Content() == CONTENT_TVSHOWS && foundDirectly && !settings.parent_name_root) // dont lookup on root tvshow folder
1008       return true;
1009   }
1010
1011   OnInfo(item.get(), scraper);
1012
1013   return true;
1014 }
1015
1016 void CGUIWindowVideoBase::OnRestartItem(int iItem)
1017 {
1018   CGUIMediaWindow::OnClick(iItem);
1019 }
1020
1021 CStdString CGUIWindowVideoBase::GetResumeString(const CFileItem &item)
1022 {
1023   CStdString resumeString;
1024   int startOffset = 0, startPart = 0;
1025   GetResumeItemOffset(&item, startOffset, startPart);
1026   if (startOffset > 0)
1027   {
1028     resumeString.Format(g_localizeStrings.Get(12022).c_str(), StringUtils::SecondsToTimeString(startOffset/75).c_str());
1029     if (startPart > 0)
1030     {
1031       CStdString partString;
1032       partString.Format(g_localizeStrings.Get(23051).c_str(), startPart);
1033       resumeString += " (" + partString + ")";
1034     }
1035   }
1036   return resumeString;
1037 }
1038
1039 bool CGUIWindowVideoBase::ShowResumeMenu(CFileItem &item)
1040 {
1041   if (!item.m_bIsFolder && !item.IsLiveTV())
1042   {
1043     CStdString resumeString = GetResumeString(item);
1044     if (!resumeString.IsEmpty())
1045     { // prompt user whether they wish to resume
1046       CContextButtons choices;
1047       choices.Add(1, resumeString);
1048       choices.Add(2, 12021); // start from the beginning
1049       int retVal = CGUIDialogContextMenu::ShowAndGetChoice(choices);
1050       if (retVal < 0)
1051         return false; // don't do anything
1052       if (retVal == 1)
1053         item.m_lStartOffset = STARTOFFSET_RESUME;
1054     }
1055   }
1056   return true;
1057 }
1058
1059 bool CGUIWindowVideoBase::ShowPlaySelection(CFileItemPtr& item)
1060 {
1061   /* if asked to resume somewhere, we should not show anything */
1062   if (item->m_lStartOffset)
1063     return true;
1064
1065   if (item->IsBDFile())
1066   {
1067     CStdString root = URIUtils::GetParentPath(item->GetPath());
1068     URIUtils::RemoveSlashAtEnd(root);
1069     if(URIUtils::GetFileName(root) == "BDMV")
1070     {
1071       CURL url("bluray://");
1072       url.SetHostName(URIUtils::GetParentPath(root));
1073       return ShowPlaySelection(item, url.Get());
1074     }
1075   }
1076
1077   CStdString ext = URIUtils::GetExtension(item->GetPath());
1078   ext.ToLower();
1079   if (ext == ".iso" ||  ext == ".img")
1080   {
1081     CURL url2("udf://");
1082     url2.SetHostName(item->GetPath());
1083     url2.SetFileName("BDMV/index.bdmv");
1084     if (CFile::Exists(url2.Get()))
1085     {
1086       url2.SetFileName("");
1087
1088       CURL url("bluray://");
1089       url.SetHostName(url2.Get());
1090       return ShowPlaySelection(item, url.Get());
1091     }
1092   }
1093   return true;
1094 }
1095
1096 bool CGUIWindowVideoBase::ShowPlaySelection(CFileItemPtr& item, const CStdString& directory)
1097 {
1098
1099   CFileItemList items;
1100
1101   if (!XFILE::CDirectory::GetDirectory(directory, items, XFILE::CDirectory::CHints(), true))
1102   {
1103     CLog::Log(LOGERROR, "CGUIWindowVideoBase::ShowPlaySelection - Failed to get play directory for %s", directory.c_str());
1104     return true;
1105   }
1106
1107   if (items.Size() == 0)
1108   {
1109     CLog::Log(LOGERROR, "CGUIWindowVideoBase::ShowPlaySelection - Failed to get any items %s", directory.c_str());
1110     return true;
1111   }
1112
1113   CGUIDialogSelect* dialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
1114   while(true)
1115   {
1116     dialog->Reset();
1117     dialog->SetHeading(25006 /* Select playback item */);
1118     dialog->SetItems(&items);
1119     dialog->SetUseDetails(true);
1120     dialog->DoModal();
1121
1122     CFileItemPtr item_new = dialog->GetSelectedItem();
1123     if(!item_new || dialog->GetSelectedLabel() < 0)
1124     {
1125       CLog::Log(LOGDEBUG, "CGUIWindowVideoBase::ShowPlaySelection - User aborted %s", directory.c_str());
1126       break;
1127     }
1128
1129     if(item_new->m_bIsFolder == false)
1130     {
1131       item.reset(new CFileItem(*item));
1132       item->SetPath(item_new->GetPath());
1133       return true;
1134     }
1135
1136     items.Clear();
1137     if(!XFILE::CDirectory::GetDirectory(item_new->GetPath(), items, XFILE::CDirectory::CHints(), true) || items.Size() == 0)
1138     {
1139       CLog::Log(LOGERROR, "CGUIWindowVideoBase::ShowPlaySelection - Failed to get any items %s", item_new->GetPath().c_str());
1140       break;
1141     }
1142   }
1143
1144   return false;
1145 }
1146
1147 bool CGUIWindowVideoBase::OnResumeItem(int iItem)
1148 {
1149   if (iItem < 0 || iItem >= m_vecItems->Size()) return true;
1150   CFileItemPtr item = m_vecItems->Get(iItem);
1151
1152   if (item->m_bIsFolder)
1153   {
1154     // resuming directories isn't supported yet. play.
1155     PlayItem(iItem);
1156     return true;
1157   }
1158
1159   CStdString resumeString = GetResumeString(*item);
1160
1161   if (!resumeString.IsEmpty())
1162   {
1163     CContextButtons choices;
1164     choices.Add(SELECT_ACTION_RESUME, resumeString);
1165     choices.Add(SELECT_ACTION_PLAY, 12021);   // Start from beginning
1166     int value = CGUIDialogContextMenu::ShowAndGetChoice(choices);
1167     if (value < 0)
1168       return true;
1169     return OnFileAction(iItem, value);
1170   }
1171
1172   return OnFileAction(iItem, SELECT_ACTION_PLAY);
1173 }
1174
1175 void CGUIWindowVideoBase::OnStreamDetails(const CStreamDetails &details, const CStdString &strFileName, long lFileId)
1176 {
1177   CVideoDatabase db;
1178   if (db.Open())
1179   {
1180     if (lFileId < 0)
1181       db.SetStreamDetailsForFile(details, strFileName);
1182     else
1183       db.SetStreamDetailsForFileId(details, lFileId);
1184
1185     db.Close();
1186   }
1187 }
1188
1189 void CGUIWindowVideoBase::GetContextButtons(int itemNumber, CContextButtons &buttons)
1190 {
1191   CFileItemPtr item;
1192   if (itemNumber >= 0 && itemNumber < m_vecItems->Size())
1193     item = m_vecItems->Get(itemNumber);
1194
1195   // contextual buttons
1196   if (item && !item->GetProperty("pluginreplacecontextitems").asBoolean())
1197   {
1198     if (!item->IsParentFolder())
1199     {
1200       CStdString path(item->GetPath());
1201       if (item->IsVideoDb() && item->HasVideoInfoTag())
1202         path = item->GetVideoInfoTag()->m_strFileNameAndPath;
1203
1204       if (!item->GetPath().Equals("add") && !item->IsPlugin() &&
1205           !item->IsScript() && !item->IsAddonsPath() && !item->IsLiveTV())
1206       {
1207         if (URIUtils::IsStack(path))
1208         {
1209           vector<int> times;
1210           if (m_database.GetStackTimes(path,times) || CFileItem(CStackDirectory::GetFirstStackedFile(path),false).IsDVDImage())
1211             buttons.Add(CONTEXT_BUTTON_PLAY_PART, 20324);
1212         }
1213
1214         if (!m_vecItems->GetPath().IsEmpty() && !item->GetPath().Left(19).Equals("newsmartplaylist://") && !item->GetPath().Left(9).Equals("newtag://")
1215             && !m_vecItems->IsSourcesPath())
1216         {
1217           buttons.Add(CONTEXT_BUTTON_QUEUE_ITEM, 13347);      // Add to Playlist
1218         }
1219
1220         // allow a folder to be ad-hoc queued and played by the default player
1221         if (item->m_bIsFolder || (item->IsPlayList() &&
1222            !g_advancedSettings.m_playlistAsFolders))
1223         {
1224           buttons.Add(CONTEXT_BUTTON_PLAY_ITEM, 208);
1225         }
1226       }
1227
1228       if (!m_vecItems->IsPlugin() && (item->IsPlugin() || item->IsScript()))
1229         buttons.Add(CONTEXT_BUTTON_INFO,24003); // Add-on info
1230
1231       if (!item->m_bIsFolder && !(item->IsPlayList() && !g_advancedSettings.m_playlistAsFolders))
1232       { // get players
1233         VECPLAYERCORES vecCores;
1234         if (item->IsVideoDb())
1235         {
1236           CFileItem item2(item->GetVideoInfoTag()->m_strFileNameAndPath, false);
1237           CPlayerCoreFactory::GetPlayers(item2, vecCores);
1238         }
1239         else
1240           CPlayerCoreFactory::GetPlayers(*item, vecCores);
1241         if (vecCores.size() > 1)
1242           buttons.Add(CONTEXT_BUTTON_PLAY_WITH, 15213);
1243       }
1244       if (item->IsSmartPlayList())
1245       {
1246         buttons.Add(CONTEXT_BUTTON_PLAY_PARTYMODE, 15216); // Play in Partymode
1247       }
1248
1249       // if autoresume is enabled then add restart video button
1250       // check to see if the Resume Video button is applicable
1251       // only if the video is NOT a DVD (in that case the resume button will be added by CGUIDialogContextMenu::GetContextButtons)
1252       if (!item->IsDVD() && HasResumeItemOffset(item.get()))
1253       {
1254         buttons.Add(CONTEXT_BUTTON_RESUME_ITEM, GetResumeString(*(item.get())));     // Resume Video
1255       }
1256       //if the item isn't a folder or script, is a member of a list rather than a single item
1257       //and we're not on the last element of the list, 
1258       //then add add either 'play from here' or 'play only this' depending on default behaviour
1259       if (!(item->m_bIsFolder || item->IsScript()) && m_vecItems->Size() > 1 && itemNumber < m_vecItems->Size()-1)
1260       {
1261         if (!g_guiSettings.GetBool("videoplayer.autoplaynextitem"))
1262           buttons.Add(CONTEXT_BUTTON_PLAY_AND_QUEUE, 13412);
1263         else
1264           buttons.Add(CONTEXT_BUTTON_PLAY_ONLY_THIS, 13434);
1265       }
1266       if (item->IsSmartPlayList() || m_vecItems->IsSmartPlayList())
1267         buttons.Add(CONTEXT_BUTTON_EDIT_SMART_PLAYLIST, 586);
1268     }
1269   }
1270   CGUIMediaWindow::GetContextButtons(itemNumber, buttons);
1271 }
1272
1273 void CGUIWindowVideoBase::GetNonContextButtons(int itemNumber, CContextButtons &buttons)
1274 {
1275   if (g_playlistPlayer.GetPlaylist(PLAYLIST_VIDEO).size() > 0)
1276     buttons.Add(CONTEXT_BUTTON_NOW_PLAYING, 13350);
1277 }
1278
1279 bool CGUIWindowVideoBase::OnPlayStackPart(int iItem)
1280 {
1281   if (iItem < 0 || iItem >= m_vecItems->Size())
1282     return false;
1283
1284   CFileItemPtr stack = m_vecItems->Get(iItem);
1285   CStdString path(stack->GetPath());
1286   if (stack->IsVideoDb())
1287     path = stack->GetVideoInfoTag()->m_strFileNameAndPath;
1288
1289   if (!URIUtils::IsStack(path))
1290     return false;
1291
1292   CFileItemList parts;
1293   CDirectory::GetDirectory(path,parts);
1294   CGUIDialogFileStacking* dlg = (CGUIDialogFileStacking*)g_windowManager.GetWindow(WINDOW_DIALOG_FILESTACKING);
1295   if (!dlg) return true;
1296   dlg->SetNumberOfFiles(parts.Size());
1297   dlg->DoModal();
1298   int selectedFile = dlg->GetSelectedFile();
1299   if (selectedFile > 0)
1300   {
1301     // ISO stack
1302     if (CFileItem(CStackDirectory::GetFirstStackedFile(path),false).IsDVDImage())
1303     {
1304       CStdString resumeString = CGUIWindowVideoBase::GetResumeString(*(parts[selectedFile - 1].get()));
1305       stack->m_lStartOffset = 0;
1306       if (!resumeString.IsEmpty()) 
1307       {
1308         CContextButtons choices;
1309         choices.Add(SELECT_ACTION_RESUME, resumeString);
1310         choices.Add(SELECT_ACTION_PLAY, 12021);   // Start from beginning
1311         int value = CGUIDialogContextMenu::ShowAndGetChoice(choices);
1312         if (value == SELECT_ACTION_RESUME)
1313           GetResumeItemOffset(parts[selectedFile - 1].get(), stack->m_lStartOffset, stack->m_lStartPartNumber);
1314         else if (value != SELECT_ACTION_PLAY)
1315           return false; // if not selected PLAY, then we changed our mind so return
1316       }
1317       stack->m_lStartPartNumber = selectedFile;
1318     }
1319     // regular stack
1320     else
1321     {
1322       if (selectedFile > 1)
1323       {
1324         vector<int> times;
1325         if (m_database.GetStackTimes(path,times))
1326           stack->m_lStartOffset = times[selectedFile-2]*75; // wtf?
1327       }
1328       else
1329         stack->m_lStartOffset = 0;
1330     }
1331
1332
1333   }
1334
1335   return true;
1336 }
1337
1338 bool CGUIWindowVideoBase::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
1339 {
1340   CFileItemPtr item;
1341   if (itemNumber >= 0 && itemNumber < m_vecItems->Size())
1342     item = m_vecItems->Get(itemNumber);
1343   switch (button)
1344   {
1345   case CONTEXT_BUTTON_SET_CONTENT:
1346     {
1347       OnAssignContent(item->HasVideoInfoTag() && !item->GetVideoInfoTag()->m_strPath.IsEmpty() ? item->GetVideoInfoTag()->m_strPath : item->GetPath());
1348       return true;
1349     }
1350   case CONTEXT_BUTTON_PLAY_PART:
1351     {
1352       if (OnPlayStackPart(itemNumber)) 
1353       {
1354         // call CGUIMediaWindow::OnClick() as otherwise autoresume will kick in
1355         CGUIMediaWindow::OnClick(itemNumber);
1356         return true;
1357       }
1358       else
1359         return false;
1360     }
1361   case CONTEXT_BUTTON_QUEUE_ITEM:
1362     OnQueueItem(itemNumber);
1363     return true;
1364
1365   case CONTEXT_BUTTON_PLAY_ITEM:
1366     PlayItem(itemNumber);
1367     return true;
1368
1369   case CONTEXT_BUTTON_PLAY_WITH:
1370     {
1371       VECPLAYERCORES vecCores;
1372       if (item->IsVideoDb())
1373       {
1374         CFileItem item2(*item->GetVideoInfoTag());
1375         CPlayerCoreFactory::GetPlayers(item2, vecCores);
1376       }
1377       else
1378         CPlayerCoreFactory::GetPlayers(*item, vecCores);
1379       g_application.m_eForcedNextPlayer = CPlayerCoreFactory::SelectPlayerDialog(vecCores);
1380       if (g_application.m_eForcedNextPlayer != EPC_NONE)
1381         OnClick(itemNumber);
1382       return true;
1383     }
1384
1385   case CONTEXT_BUTTON_PLAY_PARTYMODE:
1386     g_partyModeManager.Enable(PARTYMODECONTEXT_VIDEO, m_vecItems->Get(itemNumber)->GetPath());
1387     return true;
1388
1389   case CONTEXT_BUTTON_RESTART_ITEM:
1390     OnRestartItem(itemNumber);
1391     return true;
1392
1393   case CONTEXT_BUTTON_RESUME_ITEM:
1394     return OnFileAction(itemNumber, SELECT_ACTION_RESUME);
1395
1396   case CONTEXT_BUTTON_NOW_PLAYING:
1397     g_windowManager.ActivateWindow(WINDOW_VIDEO_PLAYLIST);
1398     return true;
1399
1400   case CONTEXT_BUTTON_INFO:
1401     OnInfo(itemNumber);
1402     return true;
1403
1404   case CONTEXT_BUTTON_STOP_SCANNING:
1405     {
1406       g_application.StopVideoScan();
1407       return true;
1408     }
1409   case CONTEXT_BUTTON_SCAN:
1410   case CONTEXT_BUTTON_UPDATE_TVSHOW:
1411     {
1412       if( !item)
1413         return false;
1414       ADDON::ScraperPtr info;
1415       SScanSettings settings;
1416       GetScraperForItem(item.get(), info, settings);
1417       CStdString strPath = item->GetPath();
1418       if (item->IsVideoDb() && (!item->m_bIsFolder || item->GetVideoInfoTag()->m_strPath.IsEmpty()))
1419         return false;
1420
1421       if (item->IsVideoDb())
1422         strPath = item->GetVideoInfoTag()->m_strPath;
1423
1424       if (!info || info->Content() == CONTENT_NONE)
1425         return false;
1426
1427       if (item->m_bIsFolder)
1428       {
1429         m_database.SetPathHash(strPath,""); // to force scan
1430         OnScan(strPath, true);
1431       }
1432       else
1433         OnInfo(item.get(),info);
1434
1435       return true;
1436     }
1437   case CONTEXT_BUTTON_DELETE:
1438     OnDeleteItem(itemNumber);
1439     return true;
1440   case CONTEXT_BUTTON_EDIT_SMART_PLAYLIST:
1441     {
1442       CStdString playlist = m_vecItems->Get(itemNumber)->IsSmartPlayList() ? m_vecItems->Get(itemNumber)->GetPath() : m_vecItems->GetPath(); // save path as activatewindow will destroy our items
1443       if (CGUIDialogSmartPlaylistEditor::EditPlaylist(playlist, "video"))
1444         Refresh(true); // need to update
1445       return true;
1446     }
1447   case CONTEXT_BUTTON_RENAME:
1448     OnRenameItem(itemNumber);
1449     return true;
1450   case CONTEXT_BUTTON_MARK_WATCHED:
1451     {
1452       int newSelection = m_viewControl.GetSelectedItem() + 1;
1453       MarkWatched(item,true);
1454       m_viewControl.SetSelectedItem(newSelection);
1455
1456       CUtil::DeleteVideoDatabaseDirectoryCache();
1457       Refresh();
1458       return true;
1459     }
1460   case CONTEXT_BUTTON_MARK_UNWATCHED:
1461     MarkWatched(item,false);
1462     CUtil::DeleteVideoDatabaseDirectoryCache();
1463     Refresh();
1464     return true;
1465   case CONTEXT_BUTTON_PLAY_AND_QUEUE:
1466     return OnPlayAndQueueMedia(item);
1467   case CONTEXT_BUTTON_PLAY_ONLY_THIS:
1468     return OnPlayMedia(itemNumber);
1469   default:
1470     break;
1471   }
1472   return CGUIMediaWindow::OnContextButton(itemNumber, button);
1473 }
1474
1475 bool CGUIWindowVideoBase::OnPlayMedia(int iItem)
1476 {
1477   if ( iItem < 0 || iItem >= (int)m_vecItems->Size() )
1478     return false;
1479
1480   CFileItemPtr pItem = m_vecItems->Get(iItem);
1481
1482   // party mode
1483   if (g_partyModeManager.IsEnabled(PARTYMODECONTEXT_VIDEO))
1484   {
1485     CPlayList playlistTemp;
1486     playlistTemp.Add(pItem);
1487     g_partyModeManager.AddUserSongs(playlistTemp, true);
1488     return true;
1489   }
1490
1491   // Reset Playlistplayer, playback started now does
1492   // not use the playlistplayer.
1493   g_playlistPlayer.Reset();
1494   g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_NONE);
1495
1496   CFileItem item(*pItem);
1497   if (pItem->IsVideoDb())
1498   {
1499     item.SetPath(pItem->GetVideoInfoTag()->m_strFileNameAndPath);
1500     item.SetProperty("original_listitem_url", pItem->GetPath());
1501   }
1502   CLog::Log(LOGDEBUG, "%s %s", __FUNCTION__, item.GetPath().c_str());
1503
1504   if (item.GetPath().Left(17) == "pvr://recordings/")
1505   {
1506     if (!g_PVRManager.IsStarted())
1507       return false;
1508
1509     /* For recordings we check here for a available stream URL */
1510     CFileItemPtr tag = g_PVRRecordings->GetByPath(item.GetPath());
1511     if (tag && tag->HasPVRRecordingInfoTag() && !tag->GetPVRRecordingInfoTag()->m_strStreamURL.IsEmpty())
1512     {
1513       CStdString stream = tag->GetPVRRecordingInfoTag()->m_strStreamURL;
1514
1515       /* Isolate the folder from the filename */
1516       size_t found = stream.find_last_of("/");
1517       if (found == CStdString::npos)
1518         found = stream.find_last_of("\\");
1519
1520       if (found != CStdString::npos)
1521       {
1522         /* Check here for asterix at the begin of the filename */
1523         if (stream[found+1] == '*')
1524         {
1525           /* Create a "stack://" url with all files matching the extension */
1526           CStdString ext = URIUtils::GetExtension(stream);
1527           CStdString dir = stream.substr(0, found).c_str();
1528
1529           CFileItemList items;
1530           CDirectory::GetDirectory(dir, items);
1531           items.Sort(SORT_METHOD_FILE, SortOrderAscending);
1532
1533           vector<int> stack;
1534           for (int i = 0; i < items.Size(); ++i)
1535           {
1536             if (URIUtils::GetExtension(items[i]->GetPath()) == ext)
1537               stack.push_back(i);
1538           }
1539
1540           if (stack.size() > 0)
1541           {
1542             /* If we have a stack change the path of the item to it */
1543             CStackDirectory dir;
1544             CStdString stackPath = dir.ConstructStackPath(items, stack);
1545             item.SetPath(stackPath);
1546           }
1547         }
1548         else
1549         {
1550           /* If no asterix is present play only the given stream URL */
1551           item.SetPath(stream);
1552         }
1553       }
1554       else
1555       {
1556         CLog::Log(LOGERROR, "CGUIWindowTV: Can't open recording, no valid filename!");
1557         CGUIDialogOK::ShowAndGetInput(19033,0,19036,0);
1558         return false;
1559       }
1560     }
1561   }
1562
1563   PlayMovie(&item);
1564
1565   return true;
1566 }
1567
1568 bool CGUIWindowVideoBase::OnPlayAndQueueMedia(const CFileItemPtr &item)
1569 {
1570   // Get the current playlist and make sure it is not shuffled
1571   int iPlaylist = m_guiState->GetPlaylist();
1572   if (iPlaylist != PLAYLIST_NONE && g_playlistPlayer.IsShuffled(iPlaylist))
1573      g_playlistPlayer.SetShuffle(iPlaylist, false);
1574
1575   // Call the base method to actually queue the items
1576   // and start playing the given item
1577   return CGUIMediaWindow::OnPlayAndQueueMedia(item);
1578 }
1579
1580 void CGUIWindowVideoBase::PlayMovie(const CFileItem *item)
1581 {
1582   CFileItemPtr movieItem(new CFileItem(*item));
1583
1584   if(!ShowPlaySelection(movieItem))
1585     return;
1586
1587   g_playlistPlayer.Reset();
1588   g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_VIDEO);
1589   CPlayList& playlist = g_playlistPlayer.GetPlaylist(PLAYLIST_VIDEO);
1590   playlist.Clear();
1591   playlist.Add(movieItem);
1592
1593   if(m_thumbLoader.IsLoading())
1594     m_thumbLoader.StopAsync();
1595
1596   // play movie...
1597   g_playlistPlayer.Play(0);
1598
1599   if(!g_application.IsPlayingVideo())
1600     m_thumbLoader.Load(*m_vecItems);
1601 }
1602
1603 void CGUIWindowVideoBase::OnDeleteItem(int iItem)
1604 {
1605   if ( iItem < 0 || iItem >= m_vecItems->Size())
1606     return;
1607
1608   OnDeleteItem(m_vecItems->Get(iItem));
1609
1610   Refresh(true);
1611   m_viewControl.SetSelectedItem(iItem);
1612 }
1613
1614 void CGUIWindowVideoBase::OnDeleteItem(CFileItemPtr item)
1615 {
1616   // HACK: stacked files need to be treated as folders in order to be deleted
1617   if (item->IsStack())
1618     item->m_bIsFolder = true;
1619   if (g_settings.GetCurrentProfile().getLockMode() != LOCK_MODE_EVERYONE &&
1620       g_settings.GetCurrentProfile().filesLocked())
1621   {
1622     if (!g_passwordManager.IsMasterLockUnlocked(true))
1623       return;
1624   }
1625
1626   if ((g_guiSettings.GetBool("filelists.allowfiledeletion") ||
1627        m_vecItems->GetPath().Equals("special://videoplaylists/")) &&
1628       CUtil::SupportsWriteFileOperations(item->GetPath()))
1629     CFileUtils::DeleteItem(item);
1630 }
1631
1632 void CGUIWindowVideoBase::MarkWatched(const CFileItemPtr &item, bool bMark)
1633 {
1634   if (!g_settings.GetCurrentProfile().canWriteDatabases())
1635     return;
1636   // dont allow update while scanning
1637   if (g_application.IsVideoScanning())
1638   {
1639     CGUIDialogOK::ShowAndGetInput(257, 0, 14057, 0);
1640     return;
1641   }
1642
1643   CVideoDatabase database;
1644   if (database.Open())
1645   {
1646     CFileItemList items;
1647     if (item->m_bIsFolder)
1648     {
1649       CStdString strPath = item->GetPath();
1650       CDirectory::GetDirectory(strPath, items);
1651     }
1652     else
1653       items.Add(item);
1654
1655     for (int i=0;i<items.Size();++i)
1656     {
1657       CFileItemPtr pItem=items[i];
1658       if (pItem->m_bIsFolder)
1659       {
1660         MarkWatched(pItem, bMark);
1661         continue;
1662       }
1663
1664       if (pItem->HasVideoInfoTag() &&
1665           (( bMark && pItem->GetVideoInfoTag()->m_playCount) ||
1666            (!bMark && !(pItem->GetVideoInfoTag()->m_playCount))))
1667         continue;
1668
1669       // Clear resume bookmark
1670       if (bMark)
1671         database.ClearBookMarksOfFile(pItem->GetPath(), CBookmark::RESUME);
1672
1673       database.SetPlayCount(*pItem, bMark ? 1 : 0);
1674     }
1675     
1676     database.Close(); 
1677   }
1678 }
1679
1680 //Add change a title's name
1681 void CGUIWindowVideoBase::UpdateVideoTitle(const CFileItem* pItem)
1682 {
1683   // dont allow update while scanning
1684   if (g_application.IsVideoScanning())
1685   {
1686     CGUIDialogOK::ShowAndGetInput(257, 0, 14057, 0);
1687     return;
1688   }
1689
1690   CVideoInfoTag detail;
1691   CVideoDatabase database;
1692   database.Open();
1693   CVideoDatabaseDirectory dir;
1694   CQueryParams params;
1695   dir.GetQueryParams(pItem->GetPath(),params);
1696   int iDbId = pItem->GetVideoInfoTag()->m_iDbId;
1697
1698   VIDEODB_CONTENT_TYPE iType=VIDEODB_CONTENT_MOVIES;
1699   if (pItem->HasVideoInfoTag() && (!pItem->GetVideoInfoTag()->m_strShowTitle.IsEmpty() ||
1700       pItem->GetVideoInfoTag()->m_iEpisode > 0))
1701   {
1702     iType = VIDEODB_CONTENT_TVSHOWS;
1703   }
1704   if (pItem->HasVideoInfoTag() && pItem->GetVideoInfoTag()->m_iSeason > -1 && !pItem->m_bIsFolder)
1705     iType = VIDEODB_CONTENT_EPISODES;
1706   if (pItem->HasVideoInfoTag() && !pItem->GetVideoInfoTag()->m_artist.empty())
1707     iType = VIDEODB_CONTENT_MUSICVIDEOS;
1708   if (params.GetSetId() != -1 && params.GetMovieId() == -1)
1709     iType = VIDEODB_CONTENT_MOVIE_SETS;
1710   if (iType == VIDEODB_CONTENT_MOVIES)
1711     database.GetMovieInfo("", detail, pItem->GetVideoInfoTag()->m_iDbId);
1712   if (iType == VIDEODB_CONTENT_MOVIE_SETS)
1713     database.GetSetInfo(params.GetSetId(), detail);
1714   if (iType == VIDEODB_CONTENT_EPISODES)
1715     database.GetEpisodeInfo(pItem->GetPath(),detail,pItem->GetVideoInfoTag()->m_iDbId);
1716   if (iType == VIDEODB_CONTENT_TVSHOWS)
1717     database.GetTvShowInfo(pItem->GetVideoInfoTag()->m_strFileNameAndPath,detail,pItem->GetVideoInfoTag()->m_iDbId);
1718   if (iType == VIDEODB_CONTENT_MUSICVIDEOS)
1719     database.GetMusicVideoInfo(pItem->GetVideoInfoTag()->m_strFileNameAndPath,detail,pItem->GetVideoInfoTag()->m_iDbId);
1720
1721   CStdString strInput;
1722   strInput = detail.m_strTitle;
1723
1724   //Get the new title
1725   if (!CGUIKeyboardFactory::ShowAndGetInput(strInput, g_localizeStrings.Get(16105), false))
1726     return;
1727
1728   database.UpdateMovieTitle(iDbId, strInput, iType);
1729 }
1730
1731 void CGUIWindowVideoBase::LoadPlayList(const CStdString& strPlayList, int iPlayList /* = PLAYLIST_VIDEO */)
1732 {
1733   // if partymode is active, we disable it
1734   if (g_partyModeManager.IsEnabled())
1735     g_partyModeManager.Disable();
1736
1737   // load a playlist like .m3u, .pls
1738   // first get correct factory to load playlist
1739   auto_ptr<CPlayList> pPlayList (CPlayListFactory::Create(strPlayList));
1740   if (pPlayList.get())
1741   {
1742     // load it
1743     if (!pPlayList->Load(strPlayList))
1744     {
1745       CGUIDialogOK::ShowAndGetInput(6, 0, 477, 0);
1746       return; //hmmm unable to load playlist?
1747     }
1748   }
1749
1750   if (g_application.ProcessAndStartPlaylist(strPlayList, *pPlayList, iPlayList))
1751   {
1752     if (m_guiState.get())
1753       m_guiState->SetPlaylistDirectory("playlistvideo://");
1754   }
1755 }
1756
1757 void CGUIWindowVideoBase::PlayItem(int iItem)
1758 {
1759   // restrictions should be placed in the appropiate window code
1760   // only call the base code if the item passes since this clears
1761   // the currently playing temp playlist
1762
1763   const CFileItemPtr pItem = m_vecItems->Get(iItem);
1764   // if its a folder, build a temp playlist
1765   if (pItem->m_bIsFolder && !pItem->IsPlugin())
1766   {
1767     // take a copy so we can alter the queue state
1768     CFileItemPtr item(new CFileItem(*m_vecItems->Get(iItem)));
1769
1770     //  Allow queuing of unqueueable items
1771     //  when we try to queue them directly
1772     if (!item->CanQueue())
1773       item->SetCanQueue(true);
1774
1775     // skip ".."
1776     if (item->IsParentFolder())
1777       return;
1778
1779     // recursively add items to list
1780     CFileItemList queuedItems;
1781     AddItemToPlayList(item, queuedItems);
1782
1783     g_playlistPlayer.ClearPlaylist(PLAYLIST_VIDEO);
1784     g_playlistPlayer.Reset();
1785     g_playlistPlayer.Add(PLAYLIST_VIDEO, queuedItems);
1786     g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_VIDEO);
1787     g_playlistPlayer.Play();
1788   }
1789   else if (pItem->IsPlayList())
1790   {
1791     // load the playlist the old way
1792     LoadPlayList(pItem->GetPath(), PLAYLIST_VIDEO);
1793   }
1794   else
1795   {
1796     // single item, play it
1797     OnClick(iItem);
1798   }
1799 }
1800
1801 bool CGUIWindowVideoBase::Update(const CStdString &strDirectory, bool updateFilterPath /* = true */)
1802 {
1803   if (m_thumbLoader.IsLoading())
1804     m_thumbLoader.StopThread();
1805
1806   if (!CGUIMediaWindow::Update(strDirectory, updateFilterPath))
1807     return false;
1808
1809   // might already be running from GetGroupedItems
1810   if (!m_thumbLoader.IsLoading())
1811     m_thumbLoader.Load(*m_vecItems);
1812
1813   return true;
1814 }
1815
1816 bool CGUIWindowVideoBase::GetDirectory(const CStdString &strDirectory, CFileItemList &items)
1817 {
1818   bool bResult = CGUIMediaWindow::GetDirectory(strDirectory, items);
1819
1820   // add in the "New Playlist" item if we're in the playlists folder
1821   if ((items.GetPath() == "special://videoplaylists/") && !items.Contains("newplaylist://"))
1822   {
1823     CFileItemPtr newPlaylist(new CFileItem(g_settings.GetUserDataItem("PartyMode-Video.xsp"),false));
1824     newPlaylist->SetLabel(g_localizeStrings.Get(16035));
1825     newPlaylist->SetLabelPreformated(true);
1826     newPlaylist->m_bIsFolder = true;
1827     items.Add(newPlaylist);
1828
1829 /*    newPlaylist.reset(new CFileItem("newplaylist://", false));
1830     newPlaylist->SetLabel(g_localizeStrings.Get(525));
1831     newPlaylist->SetLabelPreformated(true);
1832     items.Add(newPlaylist);
1833 */
1834     newPlaylist.reset(new CFileItem("newsmartplaylist://video", false));
1835     newPlaylist->SetLabel(g_localizeStrings.Get(21437));  // "new smart playlist..."
1836     newPlaylist->SetLabelPreformated(true);
1837     items.Add(newPlaylist);
1838   }
1839
1840   m_stackingAvailable = StackingAvailable(items);
1841   // we may also be in a tvshow files listing
1842   // (ideally this should be removed, and our stack regexps tidied up if necessary
1843   // No "normal" episodes should stack, and multi-parts should be supported)
1844   ADDON::ScraperPtr info = m_database.GetScraperForPath(strDirectory);
1845   if (info && info->Content() == CONTENT_TVSHOWS)
1846     m_stackingAvailable = false;
1847
1848   if (m_stackingAvailable && !items.IsStack() && g_settings.m_videoStacking)
1849     items.Stack();
1850
1851   return bResult;
1852 }
1853
1854 bool CGUIWindowVideoBase::StackingAvailable(const CFileItemList &items) const
1855 {
1856   CURL url(items.GetPath());
1857   return !(items.IsTuxBox()         || items.IsPlugin()  ||
1858            items.IsAddonsPath()     || items.IsRSS()     ||
1859            items.IsInternetStream() || items.IsVideoDb() ||
1860            url.GetProtocol() == "playlistvideo");
1861 }
1862
1863 void CGUIWindowVideoBase::GetGroupedItems(CFileItemList &items)
1864 {
1865   CGUIMediaWindow::GetGroupedItems(items);
1866
1867   CQueryParams params;
1868   CVideoDatabaseDirectory dir;
1869   dir.GetQueryParams(items.GetPath(), params);
1870   VIDEODATABASEDIRECTORY::NODE_TYPE nodeType = CVideoDatabaseDirectory::GetDirectoryChildType(m_strFilterPath);
1871   if (items.GetContent().Equals("movies") && params.GetSetId() <= 0 &&
1872       nodeType == NODE_TYPE_TITLE_MOVIES &&
1873       g_guiSettings.GetBool("videolibrary.groupmoviesets"))
1874   {
1875     CFileItemList groupedItems;
1876     if (GroupUtils::Group(GroupBySet, items, groupedItems, GroupAttributeIgnoreSingleItems))
1877     {
1878       items.ClearItems();
1879       items.Append(groupedItems);
1880     }
1881   }
1882
1883   // reload thumbs after filtering and grouping
1884   if (m_thumbLoader.IsLoading())
1885     m_thumbLoader.StopThread();
1886
1887   m_thumbLoader.Load(items);
1888 }
1889
1890 bool CGUIWindowVideoBase::CheckFilterAdvanced(CFileItemList &items) const
1891 {
1892   CStdString content = items.GetContent();
1893   if ((items.IsVideoDb() || CanContainFilter(m_strFilterPath)) &&
1894       (content.Equals("movies") || content.Equals("tvshows") || content.Equals("episodes") || content.Equals("musicvideos")))
1895     return true;
1896
1897   return false;
1898 }
1899
1900 bool CGUIWindowVideoBase::CanContainFilter(const CStdString &strDirectory) const
1901 {
1902   return StringUtils::StartsWith(strDirectory, "videodb://");
1903 }
1904
1905 void CGUIWindowVideoBase::AddToDatabase(int iItem)
1906 {
1907   if (iItem < 0 || iItem >= m_vecItems->Size())
1908     return;
1909
1910   CFileItemPtr pItem = m_vecItems->Get(iItem);
1911   if (pItem->IsParentFolder() || pItem->m_bIsFolder)
1912     return;
1913
1914   CVideoInfoTag movie;
1915   movie.Reset();
1916
1917   // prompt for data
1918   // enter a new title
1919   CStdString strTitle = pItem->GetLabel();
1920   if (!CGUIKeyboardFactory::ShowAndGetInput(strTitle, g_localizeStrings.Get(528), false)) // Enter Title
1921     return;
1922
1923   // pick genre
1924   CGUIDialogSelect* pSelect = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
1925   if (!pSelect)
1926     return;
1927
1928   pSelect->SetHeading(530); // Select Genre
1929   pSelect->Reset();
1930   CFileItemList items;
1931   if (!CDirectory::GetDirectory("videodb://1/1/", items))
1932     return;
1933   pSelect->SetItems(&items);
1934   pSelect->EnableButton(true, 531); // New Genre
1935   pSelect->DoModal();
1936   CStdString strGenre;
1937   int iSelected = pSelect->GetSelectedLabel();
1938   if (iSelected >= 0)
1939     strGenre = items[iSelected]->GetLabel();
1940   else if (!pSelect->IsButtonPressed())
1941     return;
1942
1943   // enter new genre string
1944   if (strGenre.IsEmpty())
1945   {
1946     strGenre = g_localizeStrings.Get(532); // Manual Addition
1947     if (!CGUIKeyboardFactory::ShowAndGetInput(strGenre, g_localizeStrings.Get(533), false)) // Enter Genre
1948       return; // user backed out
1949     if (strGenre.IsEmpty())
1950       return; // no genre string
1951   }
1952
1953   // set movie info
1954   movie.m_strTitle = strTitle;
1955   movie.m_genre = StringUtils::Split(strGenre, g_advancedSettings.m_videoItemSeparator);
1956
1957   // everything is ok, so add to database
1958   m_database.Open();
1959   int idMovie = m_database.AddMovie(pItem->GetPath());
1960   movie.m_strIMDBNumber.Format("xx%08i", idMovie);
1961   m_database.SetDetailsForMovie(pItem->GetPath(), movie, pItem->GetArt());
1962   m_database.Close();
1963
1964   // done...
1965   CGUIDialogOK::ShowAndGetInput(20177, movie.m_strTitle, StringUtils::Join(movie.m_genre, g_advancedSettings.m_videoItemSeparator), movie.m_strIMDBNumber);
1966
1967   // library view cache needs to be cleared
1968   CUtil::DeleteVideoDatabaseDirectoryCache();
1969 }
1970
1971 /// \brief Search the current directory for a string got from the virtual keyboard
1972 void CGUIWindowVideoBase::OnSearch()
1973 {
1974   CStdString strSearch;
1975   if (!CGUIKeyboardFactory::ShowAndGetInput(strSearch, g_localizeStrings.Get(16017), false))
1976     return ;
1977
1978   strSearch.ToLower();
1979   if (m_dlgProgress)
1980   {
1981     m_dlgProgress->SetHeading(194);
1982     m_dlgProgress->SetLine(0, strSearch);
1983     m_dlgProgress->SetLine(1, "");
1984     m_dlgProgress->SetLine(2, "");
1985     m_dlgProgress->StartModal();
1986     m_dlgProgress->Progress();
1987   }
1988   CFileItemList items;
1989   DoSearch(strSearch, items);
1990
1991   if (m_dlgProgress)
1992     m_dlgProgress->Close();
1993
1994   if (items.Size())
1995   {
1996     CGUIDialogSelect* pDlgSelect = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
1997     pDlgSelect->Reset();
1998     pDlgSelect->SetHeading(283);
1999
2000     for (int i = 0; i < (int)items.Size(); i++)
2001     {
2002       CFileItemPtr pItem = items[i];
2003       pDlgSelect->Add(pItem->GetLabel());
2004     }
2005
2006     pDlgSelect->DoModal();
2007
2008     int iItem = pDlgSelect->GetSelectedLabel();
2009     if (iItem < 0)
2010       return;
2011
2012     CFileItemPtr pSelItem = items[iItem];
2013
2014     OnSearchItemFound(pSelItem.get());
2015   }
2016   else
2017   {
2018     CGUIDialogOK::ShowAndGetInput(194, 284, 0, 0);
2019   }
2020 }
2021
2022 /// \brief React on the selected search item
2023 /// \param pItem Search result item
2024 void CGUIWindowVideoBase::OnSearchItemFound(const CFileItem* pSelItem)
2025 {
2026   if (pSelItem->m_bIsFolder)
2027   {
2028     CStdString strPath = pSelItem->GetPath();
2029     CStdString strParentPath;
2030     URIUtils::GetParentPath(strPath, strParentPath);
2031
2032     Update(strParentPath);
2033
2034     if (pSelItem->IsVideoDb() && g_settings.m_bMyVideoNavFlatten)
2035       SetHistoryForPath("");
2036     else
2037       SetHistoryForPath(strParentPath);
2038
2039     strPath = pSelItem->GetPath();
2040     CURL url(strPath);
2041     if (pSelItem->IsSmb() && !URIUtils::HasSlashAtEnd(strPath))
2042       strPath += "/";
2043
2044     for (int i = 0; i < m_vecItems->Size(); i++)
2045     {
2046       CFileItemPtr pItem = m_vecItems->Get(i);
2047       if (pItem->GetPath() == strPath)
2048       {
2049         m_viewControl.SetSelectedItem(i);
2050         break;
2051       }
2052     }
2053   }
2054   else
2055   {
2056     CStdString strPath;
2057     URIUtils::GetDirectory(pSelItem->GetPath(), strPath);
2058
2059     Update(strPath);
2060
2061     if (pSelItem->IsVideoDb() && g_settings.m_bMyVideoNavFlatten)
2062       SetHistoryForPath("");
2063     else
2064       SetHistoryForPath(strPath);
2065
2066     for (int i = 0; i < (int)m_vecItems->Size(); i++)
2067     {
2068       CFileItemPtr pItem = m_vecItems->Get(i);
2069       if (pItem->GetPath() == pSelItem->GetPath())
2070       {
2071         m_viewControl.SetSelectedItem(i);
2072         break;
2073       }
2074     }
2075   }
2076   m_viewControl.SetFocused();
2077 }
2078
2079 int CGUIWindowVideoBase::GetScraperForItem(CFileItem *item, ADDON::ScraperPtr &info, SScanSettings& settings)
2080 {
2081   if (!item)
2082     return 0;
2083
2084   if (m_vecItems->IsPlugin() || m_vecItems->IsRSS())
2085   {
2086     info.reset();
2087     return 0;
2088   }
2089   else if(m_vecItems->IsLiveTV())
2090   {
2091     info.reset();
2092     return 0;
2093   }
2094
2095   bool foundDirectly = false;
2096   info = m_database.GetScraperForPath(item->HasVideoInfoTag() && !item->GetVideoInfoTag()->m_strPath.IsEmpty() ? item->GetVideoInfoTag()->m_strPath : item->GetPath(), settings, foundDirectly);
2097   return foundDirectly ? 1 : 0;
2098 }
2099
2100 void CGUIWindowVideoBase::OnScan(const CStdString& strPath, bool scanAll)
2101 {
2102     g_application.StartVideoScan(strPath, scanAll);
2103 }
2104
2105 CStdString CGUIWindowVideoBase::GetStartFolder(const CStdString &dir)
2106 {
2107   if (dir.Equals("$PLAYLISTS") || dir.Equals("Playlists"))
2108     return "special://videoplaylists/";
2109   else if (dir.Equals("Plugins") || dir.Equals("Addons"))
2110     return "addons://sources/video/";
2111   return CGUIMediaWindow::GetStartFolder(dir);
2112 }
2113
2114 void CGUIWindowVideoBase::AppendAndClearSearchItems(CFileItemList &searchItems, const CStdString &prependLabel, CFileItemList &results)
2115 {
2116   if (!searchItems.Size())
2117     return;
2118
2119   searchItems.Sort(g_guiSettings.GetBool("filelists.ignorethewhensorting") ? SORT_METHOD_LABEL_IGNORE_THE : SORT_METHOD_LABEL, SortOrderAscending);
2120   for (int i = 0; i < searchItems.Size(); i++)
2121     searchItems[i]->SetLabel(prependLabel + searchItems[i]->GetLabel());
2122   results.Append(searchItems);
2123
2124   searchItems.Clear();
2125 }
2126
2127 bool CGUIWindowVideoBase::OnUnAssignContent(const CStdString &path, int label1, int label2, int label3)
2128 {
2129   bool bCanceled;
2130   CVideoDatabase db;
2131   db.Open();
2132   if (CGUIDialogYesNo::ShowAndGetInput(label1,label2,label3,20022,bCanceled))
2133   {
2134     CGUIDialogProgress *progress = (CGUIDialogProgress *)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
2135     db.RemoveContentForPath(path, progress);
2136     db.Close();
2137     CUtil::DeleteVideoDatabaseDirectoryCache();
2138     return true;
2139   }
2140   else
2141   {
2142     if (!bCanceled)
2143     {
2144       ADDON::ScraperPtr info;
2145       SScanSettings settings;
2146       settings.exclude = true;
2147       db.SetScraperForPath(path,info,settings);
2148     }
2149   }
2150   db.Close();
2151   
2152   return false;
2153 }
2154
2155 void CGUIWindowVideoBase::OnAssignContent(const CStdString &path)
2156 {
2157   bool bScan=false;
2158   CVideoDatabase db;
2159   db.Open();
2160
2161   SScanSettings settings;
2162   ADDON::ScraperPtr info = db.GetScraperForPath(path, settings);
2163
2164   ADDON::ScraperPtr info2(info);
2165   
2166   if (CGUIDialogContentSettings::Show(info, settings))
2167   {
2168     if(settings.exclude || (!info && info2))
2169     {
2170       OnUnAssignContent(path,20375,20340,20341);
2171     }
2172     else if (info != info2)
2173     {
2174       if (OnUnAssignContent(path,20442,20443,20444))
2175         bScan = true;
2176     }
2177   }
2178
2179   db.SetScraperForPath(path,info,settings);
2180
2181   if (bScan)
2182   {
2183     g_application.StartVideoScan(path, true);
2184   }
2185 }
2186
2187 void CGUIWindowVideoBase::OnInitWindow()
2188 {
2189   CGUIMediaWindow::OnInitWindow();
2190   if (g_settings.m_videoNeedsUpdate == 63 && !g_application.IsVideoScanning() &&
2191       g_infoManager.GetLibraryBool(LIBRARY_HAS_VIDEO))
2192   {
2193     // rescan of video library required
2194     if (CGUIDialogYesNo::ShowAndGetInput(799, 12351, 12352, 12354))
2195     {
2196       CEdenVideoArtUpdater::Start();
2197       g_settings.m_videoNeedsUpdate = 0; // once is enough
2198       g_settings.Save();
2199     }
2200   }
2201 }