added: more polish to the content stuff.
[xbmc:xbmc-antiquated.git] / xbmc / GUIWindowVideoBase.cpp
1 //
2
3 #include "stdafx.h"
4 #include "GUIWindowVideoBase.h"
5 #include "Util.h"
6 #include "Utils/IMDB.h"
7 #include "Utils/HTTP.h"
8 #include "GUIWindowVideoInfo.h"
9 #include "PlayListFactory.h"
10 #include "Application.h"
11 #include "NFOFile.h"
12 #include "utils/fstrcmp.h"
13 #include "PlayListPlayer.h"
14 #include "GUIThumbnailPanel.h"
15 #ifdef PRE_SKIN_VERSION_2_1_COMPATIBILITY
16 #include "GUIFontManager.h"
17 #endif
18 #include "GUIPassword.h"
19 #include "FileSystem/ZipManager.h"
20 #include "FileSystem/StackDirectory.h"
21 #include "GUIDialogContextMenu.h"
22 #include "GUIDialogFileStacking.h"
23 #include "GUIDialogMediaSource.h"
24 #include "GUIWindowFileManager.h"
25 #include "FileSystem/VideoDatabaseDirectory.h"
26
27 #include "SkinInfo.h"
28
29 #define CONTROL_BTNVIEWASICONS     2 
30 #define CONTROL_BTNSORTBY          3
31 #define CONTROL_BTNSORTASC         4
32 #define CONTROL_BTNTYPE            5
33 #define CONTROL_LIST              50
34 #define CONTROL_THUMBS            51
35 #define CONTROL_BIGLIST           52
36 #define CONTROL_LABELFILES        12
37 #define CONTROL_LABELEMPTY        13
38
39 #define CONTROL_PLAY_DVD          6
40 #define CONTROL_STACK             7
41 #define CONTROL_BTNSCAN           8
42 #define CONTROL_IMDB              9
43 #define CONTROL_BTNSHOWMODE       10
44
45 using namespace VIDEODATABASEDIRECTORY;
46
47 CGUIWindowVideoBase::CGUIWindowVideoBase(DWORD dwID, const CStdString &xmlFile)
48     : CGUIMediaWindow(dwID, xmlFile)
49 {
50   m_bDisplayEmptyDatabaseMessage = false;
51   m_thumbLoader.SetObserver(this);
52 }
53
54 CGUIWindowVideoBase::~CGUIWindowVideoBase()
55 {
56 }
57
58 bool CGUIWindowVideoBase::OnMessage(CGUIMessage& message)
59 {
60   switch ( message.GetMessage() )
61   {
62   case GUI_MSG_WINDOW_DEINIT:
63     if (m_thumbLoader.IsLoading())
64       m_thumbLoader.StopThread();
65     m_database.Close();
66     break;
67
68   case GUI_MSG_WINDOW_INIT:
69     {
70       m_database.Open();
71
72       m_dlgProgress = (CGUIDialogProgress*)m_gWindowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
73
74       // save current window, unless the current window is the video playlist window
75       if (GetID() != WINDOW_VIDEO_PLAYLIST)
76         g_stSettings.m_iVideoStartWindow = GetID();
77       
78       
79       return CGUIMediaWindow::OnMessage(message);
80     }
81     break;
82
83   case GUI_MSG_CLICKED:
84     {
85       int iControl = message.GetSenderId();
86       if (iControl == CONTROL_PLAY_DVD)
87       {
88         // play movie...
89         CUtil::PlayDVD();
90       }
91       else if (iControl == CONTROL_BTNTYPE)
92       {
93         CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_BTNTYPE);
94         m_gWindowManager.SendMessage(msg);
95
96         int nSelected = msg.GetParam1();
97         int nNewWindow = WINDOW_VIDEO_FILES;
98         switch (nSelected)
99         {
100         case 0:  // Movies
101           nNewWindow = WINDOW_VIDEO_FILES;
102           break;
103         case 1:  // Library
104           nNewWindow = WINDOW_VIDEO_NAV;
105           break;
106         }
107
108         if (nNewWindow != GetID())
109         {
110           g_stSettings.m_iVideoStartWindow = nNewWindow;
111           g_settings.Save();
112           m_gWindowManager.ChangeActiveWindow(nNewWindow);
113           CGUIMessage msg2(GUI_MSG_SETFOCUS, nNewWindow, CONTROL_BTNTYPE);
114           g_graphicsContext.SendMessage(msg2);
115         }
116
117         return true;
118       }
119       else if (iControl == CONTROL_BTNSHOWMODE)
120             {
121         g_stSettings.m_iMyVideoWatchMode++;
122                     if (g_stSettings.m_iMyVideoWatchMode > VIDEO_SHOW_WATCHED)
123           g_stSettings.m_iMyVideoWatchMode = VIDEO_SHOW_ALL;
124         g_settings.Save();
125                     Update(m_vecItems.m_strPath);
126         return true;
127       }
128       else if (m_viewControl.HasControl(iControl))  // list/thumb control
129       {
130         // get selected item
131         int iItem = m_viewControl.GetSelectedItem();
132         int iAction = message.GetParam1();
133
134         // iItem is checked for validity inside these routines
135         if (iAction == ACTION_QUEUE_ITEM || iAction == ACTION_MOUSE_MIDDLE_CLICK)
136         {
137           OnQueueItem(iItem);
138           return true;
139         }
140         else if (iAction == ACTION_SHOW_INFO)
141         {
142           SScraperInfo info;
143           CStdString strDir;
144           CUtil::GetDirectory(m_vecItems[iItem]->m_strPath,strDir);
145           m_database.GetScraperForPath(strDir,info.strPath,info.strContent);
146           OnInfo(iItem,info);
147           return true;
148         }
149         else if (iAction == ACTION_CONTEXT_MENU || iAction == ACTION_MOUSE_RIGHT_CLICK)
150         {
151           OnPopupMenu(iItem);
152           return true;
153         }
154         else if (iAction == ACTION_PLAYER_PLAY && !g_application.IsPlayingVideo())
155         {
156           OnResumeItem(iItem);
157           return true;
158         }
159         else if (iAction == ACTION_DELETE_ITEM)
160         {
161           // is delete allowed?
162           // must be at the title window
163           if (GetID() == WINDOW_VIDEO_NAV)
164             OnDeleteItem(iItem);
165
166           // or be at the files window and have file deletion enabled
167           else if (GetID() == WINDOW_VIDEO_FILES && g_guiSettings.GetBool("filelists.allowfiledeletion"))
168             OnDeleteItem(iItem);
169
170           // or be at the video playlists location
171           else if (m_vecItems.m_strPath.Equals("special://videoplaylists/"))
172             OnDeleteItem(iItem);
173           else
174             return false;
175           return true;
176         }
177       }
178       else if (iControl == CONTROL_IMDB)
179       {
180         OnManualIMDB();
181       }
182     }
183     break;
184   }
185   return CGUIMediaWindow::OnMessage(message);
186 }
187
188 void CGUIWindowVideoBase::UpdateButtons()
189 {
190   // Remove labels from the window selection
191   CGUIMessage msg(GUI_MSG_LABEL_RESET, GetID(), CONTROL_BTNTYPE);
192   g_graphicsContext.SendMessage(msg);
193
194   // Add labels to the window selection
195   CStdString strItem = g_localizeStrings.Get(744); // Files
196   CGUIMessage msg2(GUI_MSG_LABEL_ADD, GetID(), CONTROL_BTNTYPE);
197   msg2.SetLabel(strItem);
198   g_graphicsContext.SendMessage(msg2);
199
200   strItem = g_localizeStrings.Get(14022); // Library
201   msg2.SetLabel(strItem);
202   g_graphicsContext.SendMessage(msg2);
203
204   // Select the current window as default item
205   int nWindow = g_stSettings.m_iVideoStartWindow-WINDOW_VIDEO_FILES;
206   CONTROL_SELECT_ITEM(CONTROL_BTNTYPE, nWindow);
207
208   // disable scan and manual imdb controls if internet lookups are disabled
209   if (g_guiSettings.GetBool("network.enableinternet"))
210   {
211     CONTROL_ENABLE(CONTROL_BTNSCAN);
212     CONTROL_ENABLE(CONTROL_IMDB);
213   }
214   else
215   {
216     CONTROL_DISABLE(CONTROL_BTNSCAN);
217     CONTROL_DISABLE(CONTROL_IMDB);
218   }
219
220   SET_CONTROL_LABEL(CONTROL_BTNSHOWMODE, g_localizeStrings.Get(16100 + g_stSettings.m_iMyVideoWatchMode));
221   CGUIMediaWindow::UpdateButtons();
222 }
223
224 void CGUIWindowVideoBase::OnInfo(int iItem, const SScraperInfo& info)
225 {
226   if ( iItem < 0 || iItem >= m_vecItems.Size() ) return ;
227   CFileItem* pItem = m_vecItems[iItem];
228   CStdString strFile = CUtil::GetFileName(pItem->m_strPath);
229   // ShowIMDB can kill the item as this window can be closed while we do it,
230   // so take a copy of the item now
231   CFileItem item(*pItem);
232   ShowIMDB(&item, info);
233   Update(m_vecItems.m_strPath);
234 }
235
236 // ShowIMDB is called as follows:
237 // 1.  To lookup info on a file.
238 // 2.  To lookup info on a folder (which may or may not contain a file)
239 // 3.  To lookup info just for fun (no file or folder related)
240
241 // We just need the item object for this.
242 // A "blank" item object is sent for 3.
243 // If a folder is sent, currently it sets strFolder and bFolder
244 // this is only used for setting the folder thumb, however.
245
246 // Steps should be:
247
248 // 1.  Check database to see if we have this information already
249 // 2.  Else, check for a nfoFile to get the URL
250 // 3.  Run a loop to check for refresh
251 // 4.  If no URL is present do a search to get the URL
252 // 4.  Once we have the URL, download the details
253 // 5.  Once we have the details, add to the database if necessary (case 1,2)
254 //     and show the information.
255 // 6.  Check for a refresh, and if so, go to 3.
256
257 void CGUIWindowVideoBase::ShowIMDB(CFileItem *item, const SScraperInfo& info)
258 {
259   /*
260   CLog::Log(LOGDEBUG,"CGUIWindowVideoBase::ShowIMDB");
261   CLog::Log(LOGDEBUG,"  strMovie  = [%s]", strMovie.c_str());
262   CLog::Log(LOGDEBUG,"  strFile   = [%s]", strFile.c_str());
263   CLog::Log(LOGDEBUG,"  strFolder = [%s]", strFolder.c_str());
264   CLog::Log(LOGDEBUG,"  bFolder   = [%s]", ((int)bFolder ? "true" : "false"));
265   */
266
267   CGUIDialogProgress* pDlgProgress = (CGUIDialogProgress*)m_gWindowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
268   CGUIDialogSelect* pDlgSelect = (CGUIDialogSelect*)m_gWindowManager.GetWindow(WINDOW_DIALOG_SELECT);
269   CGUIWindowVideoInfo* pDlgInfo = (CGUIWindowVideoInfo*)m_gWindowManager.GetWindow(WINDOW_VIDEO_INFO);
270
271   CIMDB IMDB;
272   bool bUpdate = false;
273   bool bFound = false;
274
275   if (!pDlgProgress) return ;
276   if (!pDlgSelect) return ;
277   if (!pDlgInfo) return ;
278   CUtil::ClearCache();
279
280   // 1.  Check for already downloaded information, and if we have it, display our dialog
281   //     Return if no Refresh is needed.
282   if (m_database.HasMovieInfo(item->m_strPath))
283   {
284     CIMDBMovie movieDetails;
285     m_database.GetMovieInfo(item->m_strPath, movieDetails);
286     pDlgInfo->SetMovie(movieDetails, item);
287     pDlgInfo->DoModal();
288     item->SetThumbnailImage(pDlgInfo->GetThumbnail());
289     if ( !pDlgInfo->NeedRefresh() ) return ;
290   }
291
292   // quietly return if Internet lookups are disabled
293   if (!g_guiSettings.GetBool("network.enableinternet")) return ;
294   if (!g_settings.m_vecProfiles[g_settings.m_iLastLoadedProfileIndex].canWriteDatabases() && !g_passwordManager.bMasterUser)
295     return;
296
297   CIMDBUrl url;
298   CIMDBMovie movieDetails;
299
300   // 2. Look for a nfo File to get the search URL
301   CStdString nfoFile = GetnfoFile(item);
302   if ( !nfoFile.IsEmpty() )
303   {
304     CLog::Log(LOGDEBUG,"Found matching nfo file: %s", nfoFile.c_str());
305     if ( CFile::Cache(nfoFile, "Z:\\movie.nfo", NULL, NULL))
306     {
307       CNfoFile nfoReader;
308       if ( nfoReader.Create("Z:\\movie.nfo") == S_OK)
309       {
310                 url.m_strURL.push_back(nfoReader.m_strImDbUrl);
311         CLog::Log(LOGDEBUG,"-- imdb url: %s", url.m_strURL[0].c_str());
312       }
313       else
314         CLog::Log(LOGERROR,"Unable to find an imdb url in nfo file: %s", nfoFile.c_str());
315     }
316     else
317       CLog::Log(LOGERROR,"Unable to cache nfo file: %s", nfoFile.c_str());
318   }
319
320   CStdString movieName = item->GetLabel();
321   // 3. Run a loop so that if we Refresh we re-run this block
322   bool needsRefresh(false);
323   do
324   {
325     // 4. if we don't have a url, or need to refresh the search
326     //    then do the web search
327     if (url.m_strURL.size() == 0 || needsRefresh)
328     {
329       // 4a. show dialog that we're busy querying www.imdb.com
330       pDlgProgress->SetHeading(197);
331       pDlgProgress->SetLine(0, movieName);
332       pDlgProgress->SetLine(1, "");
333       pDlgProgress->SetLine(2, "");
334       pDlgProgress->StartModal();
335       pDlgProgress->Progress();
336
337       // 4b. do the websearch
338       IMDB.SetScraperInfo(info);
339       IMDB_MOVIELIST movielist;
340       if (IMDB.FindMovie(movieName, movielist, pDlgProgress))
341       {
342         pDlgProgress->Close();
343         if (movielist.size() > 0)
344         {
345           // 4c. found movies - allow selection of the movie we found
346           pDlgSelect->SetHeading(196);
347           pDlgSelect->Reset();
348           for (unsigned int i = 0; i < movielist.size(); ++i)
349             pDlgSelect->Add(movielist[i].m_strTitle);
350           pDlgSelect->EnableButton(true);
351           pDlgSelect->SetButtonLabel(413); // manual
352           pDlgSelect->DoModal();
353
354           // and wait till user selects one
355           int iSelectedMovie = pDlgSelect->GetSelectedLabel();
356           if (iSelectedMovie >= 0)
357             url = movielist[iSelectedMovie];
358           else if (!pDlgSelect->IsButtonPressed())
359           {
360             return; // user backed out
361           }
362         }
363       }
364     }
365     // 4c. Check if url is still empty - occurs if user has selected to do a manual
366     //     lookup, or if the IMDb lookup failed or was cancelled.
367     if (url.m_strURL.size() == 0)
368     {
369       // Check for cancel of the progress dialog
370       pDlgProgress->Close();
371       if (pDlgProgress->IsCanceled())
372       {
373         return;
374       }
375
376       // Prompt the user to input the movieName
377       if (!CGUIDialogKeyboard::ShowAndGetInput(movieName, g_localizeStrings.Get(16009), false))
378       {
379         return; // user backed out
380       }
381
382       needsRefresh = true;
383     }
384     else
385     {
386       // 5. Download the movie information
387       // show dialog that we're downloading the movie info
388       pDlgProgress->SetHeading(198);
389       pDlgProgress->SetLine(0, movieName);
390       pDlgProgress->SetLine(1, url.m_strTitle);
391       pDlgProgress->SetLine(2, "");
392       pDlgProgress->StartModal();
393       pDlgProgress->Progress();
394
395       // get the movie info
396       if (IMDB.GetDetails(url, movieDetails, pDlgProgress))
397       {
398         // got all movie details :-)
399         OutputDebugString("got details\n");
400         pDlgProgress->Close();
401
402         // now show the imdb info
403         OutputDebugString("show info\n");
404
405         // Add to the database if applicable
406         if (item->m_strPath && (g_settings.m_vecProfiles[g_settings.m_iLastLoadedProfileIndex].canWriteDatabases() || g_passwordManager.bMasterUser))
407         {
408           m_database.SetMovieInfo(item->m_strPath, movieDetails);
409           // remove directory caches
410           CFileItemList items;
411           CDirectory::GetDirectory("z:\\",items,".fi",false);
412           for (int i=0;i<items.Size();++i)
413           {
414             if (!items[i]->m_bIsFolder)
415             {
416               CFile::Delete(items[i]->m_strPath);
417             }
418           }
419         }
420
421         pDlgInfo->SetMovie(movieDetails, item);
422         pDlgInfo->DoModal();
423         item->SetThumbnailImage(pDlgInfo->GetThumbnail());
424         needsRefresh = pDlgInfo->NeedRefresh();
425       }
426       else
427       {
428         pDlgProgress->Close();
429         if (pDlgProgress->IsCanceled())
430         {
431           return; // user cancelled
432         }
433         OutputDebugString("failed to get details\n");
434         // show dialog...
435         CGUIDialogOK *pDlgOK = (CGUIDialogOK*)m_gWindowManager.GetWindow(WINDOW_DIALOG_OK);
436         if (pDlgOK)
437         {
438           pDlgOK->SetHeading(195);
439           pDlgOK->SetLine(0, movieName);
440           pDlgOK->SetLine(1, "");
441           pDlgOK->SetLine(2, "");
442           pDlgOK->SetLine(3, "");
443           pDlgOK->DoModal();
444         }
445         return;
446       }
447     }
448     // 6. Check for a refresh
449   } while (needsRefresh);
450 }
451
452 void CGUIWindowVideoBase::Render()
453 {
454   if (m_bDisplayEmptyDatabaseMessage)
455   {
456     SET_CONTROL_LABEL(CONTROL_LABELEMPTY,g_localizeStrings.Get(745)+'\n'+g_localizeStrings.Get(746))
457   }
458   else
459   {
460     SET_CONTROL_LABEL(CONTROL_LABELEMPTY,"")
461   }
462   
463   CGUIMediaWindow::Render();
464 }
465
466 void CGUIWindowVideoBase::OnManualIMDB()
467 {
468   CStdString strInput;
469   if (!CGUIDialogKeyboard::ShowAndGetInput(strInput, g_localizeStrings.Get(16009), false)) return ;
470
471   CFileItem item(strInput);
472   item.m_strPath = "Z:\\";
473   ::DeleteFile(item.GetCachedVideoThumb().c_str());
474
475   SScraperInfo info;
476   info.strContent = "movies";
477   info.strPath = "imdb.xml";
478   ShowIMDB(&item,info);
479   
480   return ;
481 }
482
483 bool CGUIWindowVideoBase::IsCorrectDiskInDrive(const CStdString& strFileName, const CStdString& strDVDLabel)
484 {
485   CDetectDVDMedia::WaitMediaReady();
486   CCdInfo* pCdInfo = CDetectDVDMedia::GetCdInfo();
487   if (pCdInfo == NULL) return false;
488   if (!CFile::Exists(strFileName)) return false;
489   CStdString label = pCdInfo->GetDiscLabel().TrimRight(" ");
490   int iLabelCD = label.GetLength();
491   int iLabelDB = strDVDLabel.GetLength();
492   if (iLabelDB < iLabelCD) return false;
493   CStdString dbLabel = strDVDLabel.Left(iLabelCD);
494   return (dbLabel == label);
495 }
496
497 bool CGUIWindowVideoBase::CheckMovie(const CStdString& strFileName)
498 {
499   if (!m_database.HasMovieInfo(strFileName) ) return true;
500
501   CIMDBMovie movieDetails;
502   m_database.GetMovieInfo(strFileName, movieDetails);
503   CFileItem movieFile(movieDetails.m_strFileNameAndPath, false);
504   if ( !movieFile.IsOnDVD()) return true;
505   CGUIDialogOK *pDlgOK = (CGUIDialogOK*)m_gWindowManager.GetWindow(WINDOW_DIALOG_OK);
506   if (!pDlgOK) return true;
507   while (1)
508   {
509 //    if (IsCorrectDiskInDrive(strFileName, movieDetails.m_strDVDLabel))
510  //   {
511       return true;
512  //   }
513     pDlgOK->SetHeading( 428);
514     pDlgOK->SetLine( 0, 429 );
515 //    pDlgOK->SetLine( 1, movieDetails.m_strDVDLabel );
516     pDlgOK->SetLine( 2, "" );
517     pDlgOK->DoModal();
518     if (!pDlgOK->IsConfirmed())
519     {
520       break;
521     }
522   }
523   return false;
524 }
525
526 void CGUIWindowVideoBase::OnQueueItem(int iItem)
527 {
528   if ( iItem < 0 || iItem >= m_vecItems.Size() ) return ;
529   // add item 2 playlist
530   CFileItem movieItem(*m_vecItems[iItem]);
531   if (movieItem.IsRAR() || movieItem.IsZIP())
532     return;
533   if (movieItem.IsStack())
534   {
535     // TODO: Remove this once the main player code is capable of handling the stack:// protocol
536     vector<CStdString> movies;
537     GetStackedFiles(movieItem.m_strPath, movies);
538     if (movies.size() <= 0) return;
539     for (int i = 0; i < (int)movies.size(); ++i)
540     {
541       CFileItem movieFile(movies[i], false);
542       CStdString strFileNum;
543       strFileNum.Format("(%2.2i)",i+1);
544       movieFile.SetLabel(movieItem.GetLabel() + " " + strFileNum);
545       AddItemToPlayList(&movieFile);
546     }
547   }
548   else
549     AddItemToPlayList(&movieItem);
550   //move to next item
551   m_viewControl.SetSelectedItem(iItem + 1);
552 }
553
554 void CGUIWindowVideoBase::AddItemToPlayList(const CFileItem* pItem, int iPlaylist /* = PLAYLIST_VIDEO */)
555 {
556   if (pItem->m_bIsFolder)
557   {
558     // Check if we add a locked share
559     if ( pItem->m_bIsShareOrDrive )
560     {
561       CFileItem item = *pItem;
562       if ( !g_passwordManager.IsItemUnlocked( &item, "video" ) )
563         return ;
564     }
565
566     // recursive
567     if (pItem->IsParentFolder()) return ;
568     CStdString strDirectory = m_vecItems.m_strPath;
569     m_vecItems.m_strPath = pItem->m_strPath;
570     CFileItemList items;
571     GetDirectory(m_vecItems.m_strPath, items);
572
573     SortItems(items);
574
575     for (int i = 0; i < items.Size(); ++i)
576     {
577       if (items[i]->m_bIsFolder)
578       {
579         CStdString strPath = items[i]->m_strPath;
580         if (CUtil::HasSlashAtEnd(strPath))
581           strPath.erase(strPath.size()-1);
582         strPath.ToLower();
583         if (strPath.size() > 6)
584         {
585           CStdString strSub = strPath.substr(strPath.size()-6);
586           if (strPath.substr(strPath.size()-6) == "sample") // skip sample folders
587             continue;
588         }
589       }
590       AddItemToPlayList(items[i], iPlaylist);
591     }
592     m_vecItems.m_strPath = strDirectory;
593   }
594   else
595   {
596     if (!pItem->IsNFO() && pItem->IsVideo() && !pItem->IsPlayList())
597     {
598       CPlayList::CPlayListItem playlistItem ;
599       playlistItem.SetFileName(pItem->m_strPath);
600       playlistItem.SetDescription(pItem->GetLabel());
601       playlistItem.SetDuration(pItem->m_musicInfoTag.GetDuration());
602       g_playlistPlayer.GetPlaylist(iPlaylist).Add(playlistItem);
603     }
604   }
605 }
606
607 void CGUIWindowVideoBase::DisplayEmptyDatabaseMessage(bool bDisplay)
608 {
609   m_bDisplayEmptyDatabaseMessage = bDisplay;
610 }
611
612 int  CGUIWindowVideoBase::GetResumeItemOffset(const CFileItem *item)
613 {
614   m_database.Open();
615   long startoffset = 0;
616
617   if (item->IsStack() && !g_guiSettings.GetBool("myvideos.treatstackasfile") )
618   {
619
620     CStdStringArray movies;
621     GetStackedFiles(item->m_strPath, movies);
622
623     /* check if any of the stacked files have a resume bookmark */
624     for(unsigned i = 0; i<movies.size();i++)
625     {
626       CBookmark bookmark;
627       if(m_database.GetResumeBookMark(movies[i], bookmark))
628       {
629         startoffset = (long)(bookmark.timeInSeconds*75);
630         startoffset += 0x10000000 * (i+1); /* store file number in here */
631         break;
632       }
633     }
634   }
635   else if (!item->IsNFO() && !item->IsPlayList())
636   {
637     CBookmark bookmark;
638     if(m_database.GetResumeBookMark(item->m_strPath, bookmark))
639       startoffset = (long)(bookmark.timeInSeconds*75);
640   }
641   m_database.Close();
642   return startoffset;
643 }
644
645 bool CGUIWindowVideoBase::OnClick(int iItem)
646 {
647   if (g_guiSettings.GetBool("myvideos.autoresume"))
648     OnResumeItem(iItem);
649   else
650     return CGUIMediaWindow::OnClick(iItem);
651   
652   return true;
653 }
654
655 void CGUIWindowVideoBase::OnRestartItem(int iItem)
656 {
657   CGUIMediaWindow::OnClick(iItem);
658 }
659
660 void CGUIWindowVideoBase::OnResumeItem(int iItem)
661 {
662   m_vecItems[iItem]->m_lStartOffset = STARTOFFSET_RESUME;
663   CGUIMediaWindow::OnClick(iItem);
664 }
665
666 void CGUIWindowVideoBase::OnPopupMenu(int iItem, bool bContextDriven /* = true */)
667 {
668         // empty list in files view?
669         if (GetID() == WINDOW_VIDEO_FILES && m_vecItems.Size() == 0)
670                 bContextDriven = false;
671         if (bContextDriven && (iItem < 0 || iItem >= m_vecItems.Size())) return;
672   
673   // calculate our position
674   float posX = 200, posY = 100;
675   const CGUIControl *pList = GetControl(CONTROL_LIST);
676   if (pList)
677   {
678     posX = pList->GetXPosition() + pList->GetWidth() / 2;
679     posY = pList->GetYPosition() + pList->GetHeight() / 2;
680   }
681
682   // popup the context menu
683   CGUIDialogContextMenu *pMenu = (CGUIDialogContextMenu *)m_gWindowManager.GetWindow(WINDOW_DIALOG_CONTEXT_MENU);
684   if (!pMenu) return ;
685
686   // load our menu
687   pMenu->Initialize();
688
689         // contextual buttons
690   int btn_Queue = 0;                                    // Add to Playlist
691   int btn_PlayWith = 0;                         // Play
692   int btn_Restart = 0;                          // Restart Video from Beginning
693   int btn_Resume = 0;                                   // Resume Video
694   int btn_Show_Info = 0;                        // Show Video Information
695   int btn_Assign = 0;         // Assign content to directory
696   int btn_Update = 0;         // Update content information
697   int btn_Mark_UnWatched = 0;   // Clear Watched Status (DB)
698   int btn_Mark_Watched = 0;             // Set Watched Status (DB)
699   int btn_Update_Title = 0;             // Change Title (DB)
700         int btn_Delete = 0;                                     // Delete
701         int btn_Rename = 0;                                     // Rename
702
703         bool bSelected = false; 
704         VECPLAYERCORES vecCores;
705   int iFound = 0;
706   SScraperInfo info;
707
708         // contextual items only appear when the list is not empty
709         if (bContextDriven)
710         {
711                 // mark the item
712                 bSelected = m_vecItems[iItem]->IsSelected(); // item may already be selected (playlistitem)
713                 m_vecItems[iItem]->Select(true);
714
715                 // get players
716                 CPlayerCoreFactory::GetPlayers(*m_vecItems[iItem], vecCores);
717
718                 bool bIsGotoParent = m_vecItems[iItem]->IsParentFolder();
719                 if (!bIsGotoParent)
720                 {
721                         // don't show the add to playlist button in playlist window
722       if (GetID() != WINDOW_VIDEO_PLAYLIST)
723       {
724         if (GetID() == WINDOW_VIDEO_NAV)
725         {
726           if (!m_vecItems.m_strPath.IsEmpty())
727             btn_Queue = pMenu->AddButton(13347);      // Add to Playlist
728         }
729         else
730           btn_Queue = pMenu->AddButton(13347);      // Add to Playlist
731
732         if (vecCores.size() >= 1)
733           btn_PlayWith = pMenu->AddButton(15213);
734         // allow a folder to be ad-hoc queued and played by the default player
735         else if (GetID() == WINDOW_VIDEO_FILES && (m_vecItems[iItem]->m_bIsFolder || m_vecItems[iItem]->IsPlayList()))
736           btn_PlayWith = pMenu->AddButton(208);
737
738         // if autoresume is enabled then add restart video button
739         // check to see if the Resume Video button is applicable
740         if (GetResumeItemOffset(m_vecItems[iItem]) > 0)               
741                                 if (g_guiSettings.GetBool("myvideos.autoresume"))
742                                         btn_Restart = pMenu->AddButton(20132);    // Restart Video
743                                 else
744                                         btn_Resume = pMenu->AddButton(13381);     // Resume Video
745       }
746
747       if (GetID() == WINDOW_VIDEO_FILES && (g_settings.m_vecProfiles[g_settings.m_iLastLoadedProfileIndex].canWriteDatabases() || g_passwordManager.bMasterUser))
748       {
749         CStdString strPath = m_vecItems[iItem]->m_strPath;
750         CUtil::RemoveSlashAtEnd(strPath);
751         if (m_vecItems[iItem]->m_bIsFolder && m_database.GetScraperForPath(strPath, info.strPath, info.strContent))
752           iFound = 1;
753         else
754         {
755           CStdString strParent;
756           while (CUtil::GetParentPath(strPath, strParent))
757           {
758             CUtil::RemoveSlashAtEnd(strParent);
759             if (m_database.GetScraperForPath(strParent, info.strPath, info.strContent))
760             {
761               iFound = 2;
762               break;
763             }
764             strPath = strParent;
765           }
766         }
767         if (m_vecItems[iItem]->m_bIsFolder)
768         {
769           if (iFound==0)
770           {
771               btn_Assign = pMenu->AddButton(20333);
772           }
773           else
774           {
775             btn_Show_Info = pMenu->AddButton(13346);
776             btn_Update = pMenu->AddButton(13349);
777             btn_Assign = pMenu->AddButton(20333);
778           }
779         }
780         else
781         {
782           btn_Show_Info = pMenu->AddButton(13346);
783           if(!iFound)
784             pMenu->EnableButton(btn_Show_Info, false);
785         }
786       }
787     }
788     if (GetID() == WINDOW_VIDEO_NAV && !m_vecItems[iItem]->m_bIsFolder)
789       btn_Show_Info = pMenu->AddButton(13346);
790
791                 // is the item a database movie?
792                 if (GetID() == WINDOW_VIDEO_NAV && !m_vecItems[iItem]->m_musicInfoTag.GetURL().IsEmpty() && (g_settings.m_vecProfiles[g_settings.m_iLastLoadedProfileIndex].canWriteDatabases() || g_passwordManager.bMasterUser))
793                 {
794                         // uses Loaded to hold Watched/UnWatched status
795                         if (m_vecItems[iItem]->m_musicInfoTag.Loaded())
796                                 btn_Mark_UnWatched = pMenu->AddButton(16104); //Mark as UnWatched
797                         else
798                                 btn_Mark_Watched = pMenu->AddButton(16103);   //Mark as Watched
799
800                         if (g_settings.m_vecProfiles[g_settings.m_iLastLoadedProfileIndex].canWriteDatabases() || g_passwordManager.bMasterUser)
801                                 btn_Update_Title = pMenu->AddButton(16105); //Edit Title
802                 }
803
804           // hide delete button unless enabled, or in title window
805                 if (!bIsGotoParent)
806                 {
807                         // video playlists or file operations are allowed
808                         if ((m_vecItems.m_strPath.Equals("special://videoplaylists/")) || (GetID() == WINDOW_VIDEO_FILES && g_guiSettings.GetBool("filelists.allowfiledeletion")))
809                         {
810                                 if (!m_vecItems[iItem]->IsReadOnly())
811                                 { // enable only if writeable
812                                         btn_Delete = pMenu->AddButton(117);
813                                         btn_Rename = pMenu->AddButton(118);
814                                 }
815                         }
816                         // delete titles from database
817                         if (GetID() == WINDOW_VIDEO_NAV && (g_settings.m_vecProfiles[g_settings.m_iLastLoadedProfileIndex].canWriteDatabases() || g_passwordManager.bMasterUser))
818                         {
819         CVideoDatabaseDirectory dir;
820         NODE_TYPE node = dir.GetDirectoryChildType(m_vecItems.m_strPath);
821         if (node == NODE_TYPE_TITLE)
822           btn_Delete = pMenu->AddButton(646);
823                         }
824                 }
825         } // if (bContextDriven)
826
827         // non-contextual buttons
828   int btn_Settings = pMenu->AddButton(5);                       // Settings
829   int btn_GoToRoot = 0;
830   if (!m_vecItems.m_strPath.IsEmpty())
831     btn_GoToRoot = pMenu->AddButton(20128);
832
833         int btn_Switch = 0;                                                                                                     // Switch Media
834   int btn_NowPlaying = 0;                                                                                       // Now Playing
835
836         // Switch Media is only visible in files window
837         if (GetID() == WINDOW_VIDEO_FILES)
838         {
839                 btn_Switch = pMenu->AddButton(523); // switch media
840         }
841
842         // Now Playing... at the very bottom of the list for easy access
843         if (g_playlistPlayer.GetPlaylist(PLAYLIST_VIDEO).size() > 0)
844                         btn_NowPlaying = pMenu->AddButton(13350);
845
846   // position it correctly
847   pMenu->SetPosition(posX - pMenu->GetWidth() / 2, posY - pMenu->GetHeight() / 2);
848   pMenu->DoModal();
849   
850   int btnid = pMenu->GetButton();
851   if (btnid>0)
852   {
853                 // queue
854     if (btnid == btn_Queue)
855     {
856       OnQueueItem(iItem);
857     }
858                 // play
859     else if (btnid == btn_PlayWith)
860     {
861       // if folder, play with default player
862       if (m_vecItems[iItem]->m_bIsFolder)
863       {
864         PlayItem(iItem);
865       }
866       else
867       {
868         g_application.m_eForcedNextPlayer = CPlayerCoreFactory::SelectPlayerDialog(vecCores, posX, posY);
869         if( g_application.m_eForcedNextPlayer != EPC_NONE )
870           OnClick(iItem);
871       }
872     }
873                 // restart
874                 else if (btnid == btn_Restart)
875     {
876       OnRestartItem(iItem);
877     }
878                 // resume
879     else if (btnid == btn_Resume)
880     {
881       OnResumeItem(iItem);
882     }
883     else if (btnid == btn_Assign)
884     {
885       OnAssignContent(iItem,iFound,info);
886     }
887     else if (btnid  == btn_Update) // update content 
888     {
889       OnScan(m_vecItems[iItem]->m_strPath,info,-1,-1);
890     }
891                 // video info
892                 else if (btnid == btn_Show_Info)
893     {
894       OnInfo(iItem,info);
895                 }
896                 // unwatched
897     else if (btnid == btn_Mark_UnWatched)
898           {
899                   MarkUnWatched(iItem);
900           }
901                 // watched
902           else if (btnid == btn_Mark_Watched)
903           {
904                   MarkWatched(iItem);
905           }
906                 // update title
907           else if (btnid == btn_Update_Title)
908           {
909                   UpdateVideoTitle(iItem);
910           }
911                 // delete
912     else if (btnid == btn_Delete)
913     {
914       OnDeleteItem(iItem);
915     }
916                 // rename
917     else if (btnid == btn_Rename)
918     {
919       OnRenameItem(iItem);
920     }
921                 // settings
922                 else if (btnid == btn_Settings)
923     { 
924       m_gWindowManager.ActivateWindow(WINDOW_SETTINGS_MYVIDEOS);
925                         return;
926     }
927                 // go to root
928     else if (btnid == btn_GoToRoot)
929     {
930       Update("");
931       return;
932     }
933                 // switch media
934                 else if (btnid == btn_Switch)
935                 {
936                         CGUIDialogContextMenu::SwitchMedia("video", m_vecItems.m_strPath, posX, posY);
937                         return;
938                 }
939                 // now playing
940                 else if (btnid ==  btn_NowPlaying)
941     {
942       m_gWindowManager.ActivateWindow(WINDOW_VIDEO_PLAYLIST);
943       return;
944     }
945   }
946   if (iItem < m_vecItems.Size())
947     m_vecItems[iItem]->Select(bSelected);
948 }
949
950 void CGUIWindowVideoBase::GetStackedFiles(const CStdString &strFilePath1, vector<CStdString> &movies)
951 {
952   CStdString strFilePath = strFilePath1;  // we're gonna be altering it
953
954   movies.clear();
955
956   CURL url(strFilePath);
957   if (url.GetProtocol() == "stack")
958   {
959     CStackDirectory dir;
960     CFileItemList items;
961     dir.GetDirectory(strFilePath, items);
962     for (int i = 0; i < items.Size(); ++i)
963       movies.push_back(items[i]->m_strPath);
964   }
965   if (movies.empty())
966     movies.push_back(strFilePath);
967 }
968
969 bool CGUIWindowVideoBase::OnPlayMedia(int iItem)
970 {
971   // Reset Playlistplayer, playback started now does
972   // not use the playlistplayer.
973   g_playlistPlayer.Reset();
974   g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_NONE);
975
976   if ( iItem < 0 || iItem >= (int)m_vecItems.Size() ) return false;
977   CFileItem* pItem = m_vecItems[iItem];
978   
979   if (pItem->m_strPath == "add" && pItem->GetLabel() == g_localizeStrings.Get(1026)) // 'add source button' in empty root
980   {
981     if (CGUIDialogMediaSource::ShowAndAddMediaSource("video"))
982     {
983       Update("");
984       return true;
985     }
986     return false;
987   }
988
989   PlayMovie(pItem);
990
991   return true;
992 }
993
994 void CGUIWindowVideoBase::PlayMovie(const CFileItem *item)
995 {
996   CFileItemList movieList;
997   int selectedFile = 1;  
998   long startoffset = item->m_lStartOffset;
999
1000   if (item->IsStack() && !g_guiSettings.GetBool("myvideos.treatstackasfile"))
1001   {
1002     CStdStringArray movies;
1003     GetStackedFiles(item->m_strPath, movies);
1004
1005     if( item->m_lStartOffset == STARTOFFSET_RESUME )
1006     {
1007       startoffset = GetResumeItemOffset(item);
1008
1009       if( startoffset & 0xF0000000 ) /* file is specified as a flag */
1010       {
1011         selectedFile = (startoffset>>28);
1012         startoffset = startoffset & ~0xF0000000;
1013       }
1014       else
1015       {
1016         /* attempt to start on a specific time in a stack */
1017         /* if we are lucky, we might have stored timings for */
1018         /* this stack at some point */
1019
1020         m_database.Open();
1021
1022         /* figure out what file this time offset is */
1023         vector<long> times;
1024         m_database.GetStackTimes(item->m_strPath, times);
1025         long totaltime = 0;
1026         for(unsigned i = 0; i < times.size(); i++)
1027         {
1028           totaltime += times[i]*75;
1029           if( startoffset < totaltime )
1030           {
1031             selectedFile = i+1;
1032             startoffset -= totaltime - times[i]*75; /* rebase agains selected file */
1033             break;
1034           }
1035         }
1036         m_database.Close();
1037       }
1038     }
1039     else
1040     { // show file stacking dialog
1041       CGUIDialogFileStacking* dlg = (CGUIDialogFileStacking*)m_gWindowManager.GetWindow(WINDOW_DIALOG_FILESTACKING);
1042       if (dlg)
1043       {
1044         dlg->SetNumberOfFiles(movies.size());
1045         dlg->DoModal();
1046         selectedFile = dlg->GetSelectedFile();
1047         if (selectedFile < 1) return ;
1048       }
1049     }
1050     // add to our movie list
1051     for (unsigned int i = 0; i < movies.size(); i++)
1052     {
1053       movieList.Add(new CFileItem(movies[i], false));
1054     }
1055   }
1056   else
1057   {
1058     movieList.Add(new CFileItem(*item));
1059   }
1060
1061   g_playlistPlayer.Reset();
1062   g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_VIDEO_TEMP);
1063   CPlayList& playlist = g_playlistPlayer.GetPlaylist(PLAYLIST_VIDEO_TEMP);
1064   playlist.Clear();
1065   for (int i = selectedFile - 1; i < (int)movieList.Size(); ++i)
1066   {
1067     CPlayList::CPlayListItem playlistItem;
1068     CUtil::ConvertFileItemToPlayListItem(movieList[i], playlistItem);
1069     if (i == selectedFile - 1)
1070       playlistItem.m_lStartOffset = startoffset;
1071     playlist.Add(playlistItem);
1072   }
1073
1074   // play movie...
1075   g_playlistPlayer.PlayNext();
1076 }
1077
1078 void CGUIWindowVideoBase::OnDeleteItem(int iItem)
1079 {
1080   if ( iItem < 0 || iItem >= m_vecItems.Size()) return;
1081   // HACK: stacked files need to be treated as folders in order to be deleted
1082   if (m_vecItems[iItem]->IsStack())
1083     m_vecItems[iItem]->m_bIsFolder = true;
1084   if (g_settings.m_vecProfiles[g_settings.m_iLastLoadedProfileIndex].getLockMode() != LOCK_MODE_EVERYONE && g_settings.m_vecProfiles[g_settings.m_iLastLoadedProfileIndex].filesLocked())
1085     if (!g_passwordManager.IsMasterLockUnlocked(true))
1086       return;
1087
1088   if (!CGUIWindowFileManager::DeleteItem(m_vecItems[iItem]))
1089     return;
1090   Update(m_vecItems.m_strPath);
1091   m_viewControl.SetSelectedItem(iItem);
1092 }
1093
1094 void CGUIWindowVideoBase::MarkUnWatched(int iItem)
1095 {
1096   if ( iItem < 0 || iItem >= m_vecItems.Size() ) return ;
1097   CFileItem* pItem = m_vecItems[iItem];
1098   m_database.MarkAsUnWatched(atol(pItem->m_musicInfoTag.GetURL()));
1099   CUtil::ClearFileItemCache();
1100   m_viewControl.SetSelectedItem(iItem);
1101   Update(m_vecItems.m_strPath);
1102 }
1103
1104 //Add Mark a Title as watched
1105 void CGUIWindowVideoBase::MarkWatched(int iItem)
1106 {
1107   if ( iItem < 0 || iItem >= m_vecItems.Size() ) return ;
1108   CFileItem* pItem = m_vecItems[iItem];
1109   m_database.MarkAsWatched(atol(pItem->m_musicInfoTag.GetURL()));
1110   CUtil::ClearFileItemCache();
1111   m_viewControl.SetSelectedItem(iItem);
1112   Update(m_vecItems.m_strPath);
1113 }
1114
1115 //Add change a title's name
1116 void CGUIWindowVideoBase::UpdateVideoTitle(int iItem)
1117 {
1118   if ( iItem < 0 || iItem >= m_vecItems.Size() ) return ;
1119   CFileItem* pItem = m_vecItems[iItem];
1120
1121   //Get Current Name
1122   CIMDBMovie detail;
1123   m_database.GetMovieInfo("", detail, atol(pItem->m_musicInfoTag.GetURL()));
1124   CStdString strInput;
1125   strInput = detail.m_strTitle;
1126
1127   //Get the new title
1128   if (!CGUIDialogKeyboard::ShowAndGetInput(strInput, g_localizeStrings.Get(16105), false)) return ;
1129   m_database.UpdateMovieTitle(atol(pItem->m_musicInfoTag.GetURL()), strInput);
1130   UpdateVideoTitleXML(detail.m_strIMDBNumber, strInput);
1131   m_viewControl.SetSelectedItem(iItem);
1132   Update(m_vecItems.m_strPath);
1133 }
1134
1135 bool CGUIWindowVideoBase::UpdateVideoTitleXML(const CStdString strIMDBNumber, CStdString& strTitle)
1136 {
1137   CStdString strXMLFile;
1138   CUtil::AddFileToFolder(g_settings.GetIMDbFolder(), strIMDBNumber + ".xml", strXMLFile);
1139   TiXmlBase::SetCondenseWhiteSpace(false);
1140   TiXmlDocument doc;
1141   if (!doc.LoadFile(strXMLFile))
1142     return false;
1143
1144   TiXmlNode *details = doc.FirstChild("details");
1145   if (!details)
1146   {
1147     CLog::Log(LOGERROR, "IMDB: Invalid xml file");
1148     return false;
1149   }
1150
1151   TiXmlNode* pNode = details->FirstChild("title");
1152   if (!pNode)
1153     return false;
1154   if (pNode->FirstChild())
1155       pNode->FirstChild()->SetValue(strTitle);
1156   else
1157     return false;
1158
1159   return doc.SaveFile();
1160 }
1161
1162 void CGUIWindowVideoBase::LoadPlayList(const CStdString& strPlayList, int iPlayList /* = PLAYLIST_VIDEO */)
1163 {
1164   // load a playlist like .m3u, .pls
1165   // first get correct factory to load playlist
1166   CPlayListFactory factory;
1167   auto_ptr<CPlayList> pPlayList (factory.Create(strPlayList));
1168   if ( NULL != pPlayList.get())
1169   {
1170     // load it
1171     if (!pPlayList->Load(strPlayList))
1172     {
1173       CGUIDialogOK::ShowAndGetInput(6, 0, 477, 0);
1174       return ; //hmmm unable to load playlist?
1175     }
1176   }
1177
1178   if (g_application.ProcessAndStartPlaylist(strPlayList, *pPlayList, iPlayList))
1179   {
1180     if (m_guiState.get())
1181       m_guiState->SetPlaylistDirectory("playlistvideo://");
1182   }
1183 }
1184
1185 void CGUIWindowVideoBase::PlayItem(int iItem)
1186 {
1187   // restrictions should be placed in the appropiate window code
1188   // only call the base code if the item passes since this clears
1189   // the currently playing temp playlist
1190
1191   const CFileItem* pItem = m_vecItems[iItem];
1192   // if its a folder, build a temp playlist
1193   if (pItem->m_bIsFolder)
1194   {
1195     CFileItem item(*m_vecItems[iItem]);
1196   
1197     //  Allow queuing of unqueueable items
1198     //  when we try to queue them directly
1199     if (!item.CanQueue())
1200       item.SetCanQueue(true);
1201
1202     // skip ".."
1203     if (item.IsParentFolder())
1204       return;
1205
1206     // clear current temp playlist
1207     g_playlistPlayer.ClearPlaylist(PLAYLIST_VIDEO_TEMP);
1208     g_playlistPlayer.Reset();
1209
1210     // recursively add items to temp playlist
1211     AddItemToPlayList(&item, PLAYLIST_VIDEO_TEMP);
1212
1213     // play!
1214     g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_VIDEO_TEMP);
1215     g_playlistPlayer.Play();
1216   }
1217   else if (!g_advancedSettings.m_playlistAsFolders && pItem->IsPlayList())
1218   {
1219     LoadPlayList(pItem->m_strPath, PLAYLIST_VIDEO_TEMP);
1220   }
1221   // otherwise just play the song
1222   else
1223     OnClick(iItem);
1224 }
1225
1226 CStdString CGUIWindowVideoBase::GetnfoFile(CFileItem *item)
1227 {
1228   CStdString nfoFile;
1229   // Find a matching .nfo file
1230   if (item->m_bIsFolder)
1231   {
1232     // see if there is a unique nfo file in this folder, and if so, use that
1233     CFileItemList items;
1234     CDirectory dir;
1235     if (dir.GetDirectory(item->m_strPath, items, ".nfo") && items.Size())
1236     {
1237       int numNFO = -1;
1238       for (int i = 0; i < items.Size(); i++)
1239       {
1240         if (items[i]->IsNFO())
1241         {
1242           if (numNFO == -1)
1243             numNFO = i;
1244           else
1245           {
1246             numNFO = -1;
1247             break;
1248           }
1249         }
1250       }
1251       if (numNFO > -1)
1252         return items[numNFO]->m_strPath;
1253     }
1254   }
1255
1256   // file
1257   CStdString strExtension;
1258   CUtil::GetExtension(item->m_strPath, strExtension);
1259
1260   if (CUtil::IsInRAR(item->m_strPath)) // we have a rarred item - we want to check outside the rars
1261   {
1262     CFileItem item2(*item);
1263     CURL url(item->m_strPath);
1264     CStdString strPath;
1265     CUtil::GetDirectory(url.GetHostName(),strPath);
1266     CUtil::AddFileToFolder(strPath,CUtil::GetFileName(item->m_strPath),item2.m_strPath);
1267     return GetnfoFile(&item2);
1268   }
1269
1270   // already an .nfo file?
1271   if ( strcmpi(strExtension.c_str(), ".nfo") == 0 )
1272     nfoFile = item->m_strPath;
1273   // no, create .nfo file
1274   else
1275     CUtil::ReplaceExtension(item->m_strPath, ".nfo", nfoFile);
1276
1277   // test file existance
1278   if (!nfoFile.IsEmpty() && !CFile::Exists(nfoFile))
1279       nfoFile.Empty();
1280
1281   // try looking for .nfo file for a stacked item
1282   if (item->IsStack())
1283   {
1284     // first try .nfo file matching first file in stack
1285     CStackDirectory dir;
1286     CStdString firstFile = dir.GetFirstStackedFile(item->m_strPath);
1287     CFileItem item2;
1288     item2.m_strPath = firstFile;
1289     nfoFile = GetnfoFile(&item2);
1290     // else try .nfo file matching stacked title
1291     if (nfoFile.IsEmpty())
1292     {
1293       CStdString stackedTitlePath = dir.GetStackedTitlePath(item->m_strPath);
1294       item2.m_strPath = stackedTitlePath;
1295       nfoFile = GetnfoFile(&item2);
1296     }
1297   }
1298
1299   if (nfoFile.IsEmpty()) // final attempt - strip off any cd1 folders
1300   {
1301     CStdString strPath;
1302     CUtil::GetDirectory(item->m_strPath,strPath);
1303     CFileItem item2;
1304     if (strPath.Mid(strPath.size()-3).Equals("cd1"))
1305     {
1306       strPath = strPath.Mid(0,strPath.size()-3);
1307       CUtil::AddFileToFolder(strPath,CUtil::GetFileName(item->m_strPath),item2.m_strPath);
1308       return GetnfoFile(&item2);
1309     }
1310   }
1311
1312   return nfoFile;
1313 }
1314
1315 void CGUIWindowVideoBase::SetDatabaseDirectory(const VECMOVIES &movies, CFileItemList &items)
1316 {
1317   DWORD time = timeGetTime();
1318   for (int i = 0; i < (int)movies.size(); ++i)
1319   {
1320     CIMDBMovie movie = movies[i];
1321     // add the appropiate movies to m_vecItems based on the showmode
1322 /*    if (
1323       (g_stSettings.m_iMyVideoWatchMode == VIDEO_SHOW_ALL) ||
1324       (g_stSettings.m_iMyVideoWatchMode == VIDEO_SHOW_WATCHED && movie.m_bWatched == true) ||
1325       (g_stSettings.m_iMyVideoWatchMode == VIDEO_SHOW_UNWATCHED && movie.m_bWatched == false)
1326       )*/
1327     {
1328       // mark watched movies when showing all
1329       CStdString strTitle = movie.m_strTitle;
1330       CFileItem *pItem = new CFileItem(strTitle);
1331       pItem->m_strTitle=strTitle;
1332       pItem->m_strPath = movie.m_strFileNameAndPath;
1333       pItem->m_bIsFolder = false;
1334       pItem->m_bIsShareOrDrive = false;
1335
1336       pItem->m_fRating = movie.m_fRating;
1337       SYSTEMTIME time;
1338       time.wYear = (WORD)movie.m_iYear;
1339       pItem->m_musicInfoTag.SetReleaseDate(time);
1340 //      pItem->m_strDVDLabel = movie.m_strDVDLabel;
1341       pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED,movie.m_bWatched);
1342
1343       // Hack for extra info
1344       pItem->m_musicInfoTag.SetTitle(movie.m_strTitle);
1345       pItem->m_musicInfoTag.SetArtist(movie.m_strDirector);
1346       pItem->m_musicInfoTag.SetGenre(movie.m_strGenre);
1347       pItem->m_musicInfoTag.SetURL(movie.m_strSearchString);
1348       pItem->m_musicInfoTag.SetLoaded(movie.m_bWatched);
1349       // End hack for extra info
1350
1351       items.Add(pItem);
1352     }
1353   }
1354   CLog::Log(LOGDEBUG, "Time taken for SetDatabaseDirectory(): %i", timeGetTime() - time);
1355 }
1356
1357 void CGUIWindowVideoBase::ApplyIMDBThumbToFolder(const CStdString &folder, const CStdString &imdbThumb)
1358 {
1359   // copy icon to folder also;
1360   if (CFile::Exists(imdbThumb))
1361   {
1362     CFileItem folderItem(folder, true);
1363     CStdString strThumb(folderItem.GetCachedVideoThumb());
1364     CFile::Cache(imdbThumb.c_str(), strThumb.c_str(), NULL, NULL);
1365   }
1366 }
1367
1368 bool CGUIWindowVideoBase::Update(const CStdString &strDirectory)
1369 {
1370   if (m_thumbLoader.IsLoading())
1371     m_thumbLoader.StopThread();
1372
1373   if (!CGUIMediaWindow::Update(strDirectory))
1374     return false;
1375
1376   m_thumbLoader.Load(m_vecItems);
1377   return true;
1378 }
1379
1380 void CGUIWindowVideoBase::OnPrepareFileItems(CFileItemList &items)
1381 {
1382   items.SetCachedVideoThumbs();
1383 }
1384