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