fixed: markaswatched(cfileitem) wouldn't work. (unused function)
[xbmc:xbmc-antiquated.git] / xbmc / VideoDatabase.cpp
1 /*
2  *      Copyright (C) 2005-2007 Team XboxMediaCenter
3  *      http://www.xboxmediacenter.com
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 GNU Make; see the file COPYING.  If not, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 #include "stdafx.h"
23 #include "videodatabase.h"
24 #include "GUIWindowVideoBase.h"
25 #include "utils/fstrcmp.h"
26 #include "utils/RegExp.h"
27 #include "util.h"
28 #include "GUIPassword.h"
29 #include "filesystem/VirtualPathDirectory.h"
30 #include "filesystem/StackDirectory.h"
31
32 using namespace XFILE;
33 using namespace DIRECTORY;
34
35 #define VIDEO_DATABASE_VERSION 3
36 #define VIDEO_DATABASE_OLD_VERSION 3.f
37 #define VIDEO_DATABASE_NAME "MyVideos34.db"
38
39 CBookmark::CBookmark()
40 {
41   timeInSeconds = 0.0f;
42   type = STANDARD;
43 }
44
45 //********************************************************************************************************************************
46 CVideoDatabase::CVideoDatabase(void)
47 {
48   m_preV2version=VIDEO_DATABASE_OLD_VERSION;
49   m_version = VIDEO_DATABASE_VERSION;
50   m_strDatabaseFile=VIDEO_DATABASE_NAME;
51 }
52
53 //********************************************************************************************************************************
54 CVideoDatabase::~CVideoDatabase(void)
55 {}
56
57 //********************************************************************************************************************************
58 bool CVideoDatabase::CreateTables()
59 {
60   /* indexes should be added on any columns that are used in in  */ 
61   /* a where or a join. primary key on a column is the same as a */ 
62   /* unique index on that column, so there is no need to add any */
63   /* index if no other columns are refered                       */
64
65   /* order of indexes are important, for an index to be considered all  */
66   /* columns up to the column in question have to have been specified   */
67   /* select * from actorlinkmovie where idMovie = 1, can not take       */
68   /* advantage of a index that has been created on ( idGenre, idMovie ) */
69   /*, hower on on ( idMovie, idGenre ) will be considered for use       */
70
71   try
72   {
73     CDatabase::CreateTables();
74
75     CLog::Log(LOGINFO, "create bookmark table");
76     m_pDS->exec("CREATE TABLE bookmark ( idBookmark integer primary key, idFile integer, timeInSeconds double, thumbNailImage text, player text, playerState text, type integer)\n");
77
78     CLog::Log(LOGINFO, "create settings table");
79     m_pDS->exec("CREATE TABLE settings ( idFile integer, Interleaved bool, NoCache bool, Deinterlace bool, FilmGrain integer,"
80                 "ViewMode integer,ZoomAmount float, PixelRatio float, AudioStream integer, SubtitleStream integer,"
81                 "SubtitleDelay float, SubtitlesOn bool, Brightness integer, Contrast integer, Gamma integer,"
82                 "VolumeAmplification float, AudioDelay float, OutputToAllSpeakers bool, ResumeTime integer, Crop bool, CropLeft integer,"
83                 "CropRight integer, CropTop integer, CropBottom integer)\n");
84     m_pDS->exec("CREATE UNIQUE INDEX ix_settings ON settings ( idFile )\n");
85
86     CLog::Log(LOGINFO, "create stacktimes table");
87     m_pDS->exec("CREATE TABLE stacktimes (idFile integer, times text)\n");
88     m_pDS->exec("CREATE UNIQUE INDEX ix_stacktimes ON stacktimes ( idFile )\n");
89
90     CLog::Log(LOGINFO, "create genre table");
91     m_pDS->exec("CREATE TABLE genre ( idGenre integer primary key, strGenre text)\n");
92
93     CLog::Log(LOGINFO, "create genrelinkmovie table");
94     m_pDS->exec("CREATE TABLE genrelinkmovie ( idGenre integer, idMovie integer)\n");
95     m_pDS->exec("CREATE UNIQUE INDEX ix_genrelinkmovie_1 ON genrelinkmovie ( idGenre, idMovie)\n");
96     m_pDS->exec("CREATE UNIQUE INDEX ix_genrelinkmovie_2 ON genrelinkmovie ( idMovie, idGenre)\n");
97
98     CLog::Log(LOGINFO, "create movie table");
99     CStdString columns = "CREATE TABLE movie ( idMovie integer";
100     for (int i = 0; i < VIDEODB_MAX_COLUMNS; i++)
101     {
102       CStdString column;
103       column.Format(",c%02d text", i);
104       columns += column;
105     }
106     columns += ")";
107     m_pDS->exec(columns.c_str());
108     m_pDS->exec("CREATE UNIQUE INDEX ix_movie ON movie ( idMovie )\n");
109
110     CLog::Log(LOGINFO, "create actorlinkmovie table");
111     m_pDS->exec("CREATE TABLE actorlinkmovie ( idActor integer, idMovie integer, strRole text)\n");
112     m_pDS->exec("CREATE UNIQUE INDEX ix_actorlinkmovie_1 ON actorlinkmovie ( idActor, idMovie )\n");
113     m_pDS->exec("CREATE UNIQUE INDEX ix_actorlinkmovie_2 ON actorlinkmovie ( idMovie, idActor )\n");
114
115     CLog::Log(LOGINFO, "create directorlinkmovie table");
116     m_pDS->exec("CREATE TABLE directorlinkmovie ( idDirector integer, idMovie integer)\n");
117     m_pDS->exec("CREATE UNIQUE INDEX ix_directorlinkmovie_1 ON directorlinkmovie ( idDirector, idMovie )\n");
118     m_pDS->exec("CREATE UNIQUE INDEX ix_directorlinkmovie_2 ON directorlinkmovie ( idMovie, idDirector )\n");
119
120     CLog::Log(LOGINFO, "create actors table");
121     m_pDS->exec("CREATE TABLE actors ( idActor integer primary key, strActor text )\n");
122
123     CLog::Log(LOGINFO, "create movielinkfile table");
124     m_pDS->exec("CREATE TABLE movielinkfile (idMovie integer, idFile integer)\n");
125     m_pDS->exec("CREATE UNIQUE INDEX ix_movielinkfile_1 ON movielinkfile ( idMovie, idFile )\n");
126     m_pDS->exec("CREATE UNIQUE INDEX ix_movielinkfile_2 ON movielinkfile ( idFile, idMovie )\n");
127
128     CLog::Log(LOGINFO, "create path table");
129     m_pDS->exec("CREATE TABLE path ( idPath integer primary key, strPath text, strContent text, strScraper text)\n");
130     m_pDS->exec("CREATE UNIQUE INDEX ix_path ON path ( strPath )\n");
131
132     CLog::Log(LOGINFO, "create files table");
133     m_pDS->exec("CREATE TABLE files ( idFile integer primary key, idPath integer, strFilename text, idMovie integer, idEpisode integer)\n");
134     m_pDS->exec("CREATE UNIQUE INDEX ix_files ON files ( idPath, strFilename )\n");
135
136     CLog::Log(LOGINFO, "create tvshow table");
137     columns = "CREATE TABLE tvshow ( idShow integer";
138     for (int i = 0; i < VIDEODB_MAX_COLUMNS; i++)
139     {
140       CStdString column;
141       column.Format(",c%02d text", i);
142       columns += column;
143     }
144     columns += ")";
145     m_pDS->exec(columns.c_str());
146
147     CLog::Log(LOGINFO, "create directorlinktvshow table");
148     m_pDS->exec("CREATE TABLE directorlinktvshow ( idDirector integer, idShow integer)\n");
149     m_pDS->exec("CREATE UNIQUE INDEX ix_directorlinktvshow_1 ON directorlinktvshow ( idDirector, idShow )\n");
150     m_pDS->exec("CREATE UNIQUE INDEX ix_directorlinktvshow_2 ON directorlinktvshow ( idShow, idDirector )\n");
151
152     CLog::Log(LOGINFO, "create actorlinktvshow table");
153     m_pDS->exec("CREATE TABLE actorlinktvshow ( idActor integer, idShow integer, strRole text)\n");
154     m_pDS->exec("CREATE UNIQUE INDEX ix_actorlinktvshow_1 ON actorlinktvshow ( idActor, idShow )\n");
155     m_pDS->exec("CREATE UNIQUE INDEX ix_actorlinktvshow_2 ON actorlinktvshow ( idShow, idActor )\n");
156   
157     CLog::Log(LOGINFO, "create episode table");
158     columns = "CREATE TABLE episode ( idEpisode integer";
159     for (int i = 0; i < VIDEODB_MAX_COLUMNS; i++)
160     {
161       CStdString column;
162       column.Format(",c%02d text", i);
163       columns += column;
164     }
165     columns += ")";
166     m_pDS->exec(columns.c_str());
167
168     CLog::Log(LOGINFO, "create tvshowlinkepisode table");
169     m_pDS->exec("CREATE TABLE tvshowlinkepisode ( idShow integer, idEpisode integer)\n");
170
171     CLog::Log(LOGINFO, "create tvshowlinkpath table");
172     m_pDS->exec("CREATE TABLE tvshowlinkpath (idShow integer, idPath integer)\n");
173     m_pDS->exec("CREATE UNIQUE INDEX ix_tvshowlinkpath_1 ON tvshowlinkpath ( idShow, idPath )\n");
174     m_pDS->exec("CREATE UNIQUE INDEX ix_tvshowlinkpath_2 ON tvshowlinkpath ( idPath, idShow )\n");
175
176     CLog::Log(LOGINFO, "create actorlinkepisode table");
177     m_pDS->exec("CREATE TABLE actorlinkepisode ( idActor integer, idEpisode integer, strRole text)\n");
178     m_pDS->exec("CREATE UNIQUE INDEX ix_actorlinkepisode_1 ON actorlinkepisode ( idActor, idEpisode )\n");
179     m_pDS->exec("CREATE UNIQUE INDEX ix_actorlinkepisode_2 ON actorlinkepisode ( idEpisode, idActor )\n");
180
181     CLog::Log(LOGINFO, "create directorlinkepisode table");
182     m_pDS->exec("CREATE TABLE directorlinkepisode ( idDirector integer, idEpisode integer, strRole text)\n");
183     m_pDS->exec("CREATE UNIQUE INDEX ix_directorlinkepisode_1 ON directorlinkepisode ( idDirector, idEpisode )\n");
184     m_pDS->exec("CREATE UNIQUE INDEX ix_directorlinkepisode_2 ON directorlinkepisode ( idEpisode, idDirector )\n");
185
186     CLog::Log(LOGINFO, "create genrelinktvshow table");
187     m_pDS->exec("CREATE TABLE genrelinktvshow ( idGenre integer, idShow integer)\n");
188     m_pDS->exec("CREATE UNIQUE INDEX ix_genrelinktvshow_1 ON genrelinktvshow ( idGenre, idShow)\n");
189     m_pDS->exec("CREATE UNIQUE INDEX ix_genrelinktvshow_2 ON genrelinktvshow ( idShow, idGenre)\n");
190
191     CLog::Log(LOGINFO, "create genrelinkepisode table");
192     m_pDS->exec("CREATE TABLE genrelinkepisode ( idGenre integer, idEpisode integer)\n");
193     m_pDS->exec("CREATE UNIQUE INDEX ix_genrelinkepisode_1 ON genrelinkepisode ( idGenre, idEpisode)\n");
194     m_pDS->exec("CREATE UNIQUE INDEX ix_genrelinkepisode_2 ON genrelinkepisode ( idEpisode, idGenre)\n");
195   }
196   catch (...)
197   {
198     CLog::Log(LOGERROR, "videodatabase::unable to create tables:%i", GetLastError());
199     return false;
200   }
201
202   return true;
203 }
204
205 //********************************************************************************************************************************
206 long CVideoDatabase::GetPath(const CStdString& strPath)
207 {
208   CStdString strSQL;
209   try
210   {
211     long lPathId=-1;
212     if (NULL == m_pDB.get()) return -1;
213     if (NULL == m_pDS.get()) return -1;
214     
215     CStdString strPath1(strPath);
216     CUtil::RemoveSlashAtEnd(strPath1);
217
218     strSQL=FormatSQL("select idPath from path where strPath like '%s'",strPath1.c_str());
219     m_pDS->query(strSQL.c_str());
220     if (!m_pDS->eof())
221       lPathId = m_pDS->fv("path.idPath").get_asLong();
222
223     return lPathId;
224   }
225   catch (...)
226   {
227     CLog::Log(LOGERROR, "videodatabase:unable to addpath (%s)", strSQL.c_str());
228   }
229   return -1;
230 }
231
232 long CVideoDatabase::AddPath(const CStdString& strPath)
233 {
234   CStdString strSQL;
235   try
236   {
237     long lPathId;
238     if (NULL == m_pDB.get()) return -1;
239     if (NULL == m_pDS.get()) return -1;
240
241     CStdString strPath1(strPath);
242     CUtil::RemoveSlashAtEnd(strPath1);
243
244     strSQL=FormatSQL("insert into path (idPath, strPath, strContent, strScraper) values (NULL,'%s','','')", strPath1.c_str());
245     m_pDS->exec(strSQL.c_str());
246     lPathId = (long)sqlite3_last_insert_rowid( m_pDB->getHandle() );
247     return lPathId;
248   }
249   catch (...)
250   {
251     CLog::Log(LOGERROR, "videodatabase:unable to addpath (%s)", strSQL.c_str());
252   }
253   return -1;
254 }
255
256
257 //********************************************************************************************************************************
258 long CVideoDatabase::AddFile(const CStdString& strFileNameAndPath)
259 {
260   CStdString strSQL = "";
261   try
262   {
263     long lFileId;
264     if (NULL == m_pDB.get()) return -1;
265     if (NULL == m_pDS.get()) return -1;
266
267     CStdString strFileName, strPath;
268     CUtil::Split(strFileNameAndPath,strPath, strFileName);
269     long lPathId=GetPath(strPath);
270     if (lPathId < 0)
271       lPathId = AddPath(strPath);
272
273     if (lPathId < 0)
274       return -1;
275
276     CStdString strSQL=FormatSQL("select idFile from files where strFileName like '%s' and idPath=%u", strFileName.c_str(),lPathId);
277
278     m_pDS->query(strSQL.c_str());
279     if (m_pDS->num_rows() > 0)
280     {
281       lFileId = m_pDS->fv("idFile").get_asLong() ;
282       m_pDS->close();
283       return lFileId;
284     }
285     m_pDS->close();
286     strSQL=FormatSQL("insert into files (idFile,idPath,strFileName,idMovie,idEpisode) values(NULL, %u, '%s',-1,-1)", lPathId,strFileName.c_str());
287     m_pDS->exec(strSQL.c_str());
288     lFileId = (long)sqlite3_last_insert_rowid( m_pDB->getHandle() );
289     return lFileId;
290   }
291   catch (...)
292   {
293     CLog::Log(LOGERROR, "videodatabase:unable to addfile (%s)", strSQL.c_str());
294   }
295   return -1;
296 }
297
298
299 //********************************************************************************************************************************
300 long CVideoDatabase::GetFile(const CStdString& strFilenameAndPath, long& lMovieId, long& lEpisodeId, bool bExact)
301 {
302   try
303   {
304     if (NULL == m_pDB.get()) return -1;
305     if (NULL == m_pDS.get()) return -1;
306     CStdString strPath, strFileName ;
307     CUtil::Split(strFilenameAndPath, strPath, strFileName);
308     long lPathId = GetPath(strPath);
309     if (lPathId < 0)
310       return -1;
311
312     CStdString strSQL;
313     strSQL=FormatSQL("select idFile,idMovie,idEpisode from files where strFileName like '%s' and idPath=%u", strFileName.c_str(),lPathId);
314     m_pDS->query(strSQL.c_str());
315     if (m_pDS->num_rows() > 0)
316     {
317       long lFileId = m_pDS->fv("files.idFile").get_asLong();
318       lMovieId = m_pDS->fv("files.idMovie").get_asLong();
319       lEpisodeId = m_pDS->fv("files.idEpisode").get_asLong();
320       m_pDS->close();
321       return lFileId;
322     }
323   }
324   catch (...)
325   {
326     CLog::Log(LOGERROR, "CVideoDatabase::GetFile(%s) failed", strFilenameAndPath.c_str());
327   }
328   return -1;
329 }
330
331 //********************************************************************************************************************************
332
333 long CVideoDatabase::GetMovie(const CStdString& strFilenameAndPath)
334 {
335   long lMovieId, lEpisodeId;
336   if (GetFile(strFilenameAndPath, lMovieId, lEpisodeId) < 0)
337   {
338     return -1;
339   }
340   return lMovieId;
341 }
342
343 long CVideoDatabase::GetTvShow(const CStdString& strFilenameAndPath)
344 {
345   return GetTvShowInfo(strFilenameAndPath);
346 }
347
348 long CVideoDatabase::GetEpisode(const CStdString& strFilenameAndPath)
349 {
350   long lMovieId, lEpisodeId;
351   if (GetFile(strFilenameAndPath, lMovieId, lEpisodeId) < 0)
352   {
353     return -1;
354   }
355   return lEpisodeId;
356 }
357
358 long CVideoDatabase::GetMovieInfo(const CStdString& strFilenameAndPath)
359 {
360   try
361   {
362     if (NULL == m_pDB.get()) return -1;
363     if (NULL == m_pDS.get()) return -1;
364     long lMovieId = -1;
365
366     // needed for query parameters
367     CStdString strPath, strFile;
368     CUtil::Split(strFilenameAndPath, strPath, strFile);
369
370     // have to join movieinfo table for correct results
371     long lPathId = GetPath(strPath);
372     if (lPathId < 0 && strPath != strFilenameAndPath)
373       return -1;
374
375     CStdString strSQL;
376     if (strPath == strFilenameAndPath) // i.e. we where handed a path, we may have rarred items in it
377     {
378       if (lPathId == -1)
379       {
380         strSQL=FormatSQL("select files.idMovie from files, path where files.idpath = path.idpath and path.strPath like '%%%s%%'",strPath.c_str());
381         m_pDS->query(strSQL.c_str());
382         if (m_pDS->eof())
383         {
384           CUtil::URLEncode(strPath);
385           strSQL=FormatSQL("select files.idMovie from files, path where files.idpath = path.idpath and path.strPath like '%%%s%%'",strPath.c_str());
386         }
387       }
388       else
389       {
390         strSQL=FormatSQL("select idMovie from files where files.idpath = %u",lPathId);
391         m_pDS->query(strSQL.c_str());
392         if (m_pDS->num_rows() > 0)
393           lMovieId = m_pDS->fv("files.idMovie").get_asLong();  
394         if (m_pDS->eof() || lMovieId == -1)
395         {
396           strSQL=FormatSQL("select files.idMovie from files, path where files.idpath = path.idpath and path.strPath like '%%%s%%'",strPath.c_str());
397           m_pDS->query(strSQL.c_str());
398           if (m_pDS->eof())
399           {
400             CUtil::URLEncode(strPath);
401             strSQL=FormatSQL("select files.idMovie from files, path where files.idpath = path.idpath and path.strPath like '%%%s%%'",strPath.c_str());
402           }
403         }
404       }
405     }
406     else
407       strSQL=FormatSQL("select idMovie from files where strFileName like '%s' and idPath=%i", strFile.c_str(),lPathId);
408     
409     CLog::Log(LOGDEBUG,"CVideoDatabase::GetMovieInfo(%s), query = %s", strFilenameAndPath.c_str(), strSQL.c_str());
410     m_pDS->query(strSQL.c_str());
411     if (m_pDS->num_rows() > 0)
412       lMovieId = m_pDS->fv("files.idMovie").get_asLong();  
413     m_pDS->close();
414
415     return lMovieId;
416   }
417   catch (...)
418   {
419     CLog::Log(LOGERROR, "CVideoDatabase::GetMovieInfo(%s) failed", strFilenameAndPath.c_str());
420   }
421   return -1;
422 }
423
424 long CVideoDatabase::GetTvShowInfo(const CStdString& strFilenameAndPath)
425 {
426   try
427   {
428     if (NULL == m_pDB.get()) return -1;
429     if (NULL == m_pDS.get()) return -1;
430     long lTvShowId = -1;
431
432     // needed for query parameters
433     CStdString strPath, strFile;
434     CUtil::Split(strFilenameAndPath, strPath, strFile);
435
436     // have to join movieinfo table for correct results
437     long lPathId = GetPath(strPath);
438     if (lPathId < 0 && strPath != strFilenameAndPath)
439       return -1;
440
441     CStdString strSQL;
442     if (strPath == strFilenameAndPath) // i.e. we where handed a path, we may have rarred items in it
443     {
444       CStdString strPath1=strPath;
445       CStdString strParent;
446       int iFound=0;
447
448       if (lPathId != -1)
449       {
450         strSQL=FormatSQL("select tvshow.idshow from tvshow,tvshowlinkpath where tvshowlinkpath.idPath=%u and tvshow.idshow=tvshowlinkpath.idshow",lPathId);
451         m_pDS->query(strSQL);
452         if (!m_pDS->eof())
453           iFound = 2;
454       }
455       while (iFound == 0 && CUtil::GetParentPath(strPath1, strParent))
456       {
457         CUtil::RemoveSlashAtEnd(strParent);
458         strSQL=FormatSQL("select tvshowlinkpath.idShow from path,tvshowlinkpath where tvshowlinkpath.idpath = path.idpath and strPath like '%s'",strParent.c_str());
459         m_pDS->query(strSQL.c_str());
460         if (!m_pDS->eof())
461         {
462           long idShow = m_pDS->fv("tvshowlinkpath.idshow").get_asLong();
463           if (idShow != -1)
464           {
465             strSQL=FormatSQL("select tvshow.idshow from tvshow where idShow=%i",idShow);
466             iFound = 2;
467           }
468         }
469         strPath1 = strParent;
470       }
471     }
472     else
473       strSQL=FormatSQL("select tvshow.idshow from files,tvshow,tvshowlinkepisode where files.idepisode = tvshowlinkepisode.idepisode and tvshowlinkepisode.idshow = tvshow.idshow and files.strFileName like '%s' and files.idPath=%i", strFile.c_str(),lPathId);
474     
475     CLog::Log(LOGDEBUG,"CVideoDatabase::GetTvShowInfo(%s), query = %s", strFilenameAndPath.c_str(), strSQL.c_str());
476     m_pDS->query(strSQL.c_str());
477     if (m_pDS->num_rows() > 0)
478       lTvShowId = m_pDS->fv("tvshow.idShow").get_asLong();  
479     m_pDS->close();
480
481     return lTvShowId;
482   }
483   catch (...)
484   {
485     CLog::Log(LOGERROR, "CVideoDatabase::GetTvShowInfo(%s) failed", strFilenameAndPath.c_str());
486   }
487   return -1;
488 }
489
490 long CVideoDatabase::GetEpisodeInfo(const CStdString& strFilenameAndPath)
491 {
492   try
493   {
494     if (NULL == m_pDB.get()) return -1;
495     if (NULL == m_pDS.get()) return -1;
496     long lEpisodeId = -1;
497
498     // needed for query parameters
499     CStdString strPath, strFile;
500     CUtil::Split(strFilenameAndPath, strPath, strFile);
501
502     // have to join movieinfo table for correct results
503     long lPathId = GetPath(strPath);
504     if (lPathId < 0 && strPath != strFilenameAndPath)
505       return -1;
506
507     CStdString strSQL;
508     if (strPath == strFilenameAndPath) // i.e. we where handed a path, we may have rarred items in it
509     {
510       if (lPathId == -1)
511       {
512         strSQL=FormatSQL("select files.idEpisode from files, path where files.idpath = path.idpath and path.strPath like '%%%s%%'",strPath.c_str());
513         m_pDS->query(strSQL.c_str());
514         if (m_pDS->eof())
515         {
516           CUtil::URLEncode(strPath);
517           strSQL=FormatSQL("select files.idEpisode from files, path where files.idpath = path.idpath and path.strPath like '%%%s%%'",strPath.c_str());
518         }
519       }
520       else
521       {
522         strSQL=FormatSQL("select idEpisode from files where files.idpath = %u",lPathId);
523         m_pDS->query(strSQL.c_str());
524         if (m_pDS->num_rows() > 0)
525           lEpisodeId = m_pDS->fv("files.idEpisode").get_asLong();  
526         if (m_pDS->eof() || lEpisodeId == -1)
527         {
528           strSQL=FormatSQL("select files.idEpisode from files, path where files.idpath = path.idpath and path.strPath like '%%%s%%'",strPath.c_str());
529           m_pDS->query(strSQL.c_str());
530           if (m_pDS->eof())
531           {
532             CUtil::URLEncode(strPath);
533             strSQL=FormatSQL("select files.idEpisode from files, path where files.idpath = path.idpath and path.strPath like '%%%s%%'",strPath.c_str());
534           }
535         }
536       }
537     }
538     else
539       strSQL=FormatSQL("select idEpisode from files where strFileName like '%s' and idPath=%i", strFile.c_str(),lPathId);
540     
541     CLog::Log(LOGDEBUG,"CVideoDatabase::GetEpisodeInfo(%s), query = %s", strFilenameAndPath.c_str(), strSQL.c_str());
542     m_pDS->query(strSQL.c_str());
543     if (m_pDS->num_rows() > 0)
544       lEpisodeId = m_pDS->fv("files.idEpisode").get_asLong();  
545     m_pDS->close();
546
547     return lEpisodeId;
548   }
549   catch (...)
550   {
551     CLog::Log(LOGERROR, "CVideoDatabase::GetEpisodeInfo(%s) failed", strFilenameAndPath.c_str());
552   }
553   return -1;
554 }
555
556 int CVideoDatabase::GetRecentMovies(long* pMovieIdArray, int nSize)
557 {
558   int count = 0;
559
560   try
561   {
562     if (NULL == m_pDB.get())
563       return -1;
564
565     if (NULL == m_pDS.get())
566       return -1;
567
568     CStdString strSQL=FormatSQL("select idMovie from movie order by idMovie desc limit %d", nSize);
569     if (m_pDS->query(strSQL.c_str()))
570     {
571       while ((!m_pDS->eof()) && (count < nSize))
572       {
573         pMovieIdArray[count++] = m_pDS->fv("idMovie").get_asLong() ;
574         m_pDS->next();
575       }
576       m_pDS->close();
577     }
578   }
579   catch (...)
580   {
581     CLog::Log(LOGERROR, "CVideoDatabase::GetRecentMovies failed.");
582   }
583
584   return count;
585 }
586
587 //********************************************************************************************************************************
588 long CVideoDatabase::AddMovie(const CStdString& strFilenameAndPath)
589 {
590   try
591   {
592     if (NULL == m_pDB.get()) return -1;
593     if (NULL == m_pDS.get()) return -1;
594     
595     long lFileId, lMovieId=-1,lEpisodeId=-1;
596     lFileId = GetFile(strFilenameAndPath,lMovieId,lEpisodeId);
597     if (lFileId < 0)
598       lFileId = AddFile(strFilenameAndPath);
599     if (lMovieId < 0)
600     {
601       CStdString strSQL=FormatSQL("insert into movie (idMovie) values (0)");
602       m_pDS->exec(strSQL.c_str());
603       lMovieId = (long)sqlite3_last_insert_rowid(m_pDB->getHandle());
604       strSQL=FormatSQL("update movie set idMovie=%i where idMovie=0",lMovieId);
605       m_pDS->exec(strSQL.c_str());
606       
607       // update file info to reflect it points to this movie
608       CStdString strPath, strFileName;
609       CUtil::Split(strFilenameAndPath,strPath,strFileName);
610       long lPathId = GetPath(strPath);
611       if (lPathId < 0)
612         lPathId = AddPath(strPath);
613       strSQL=FormatSQL("update files set idMovie=%i,idEpisode=-1 where strFilename like '%s' and idPath=%u",lMovieId,strFileName.c_str(),lPathId);
614       m_pDS->exec(strSQL.c_str());
615       CommitTransaction();
616     }
617     
618     return lMovieId;
619   }
620   catch (...)
621   {
622     CLog::Log(LOGERROR, "CVideoDatabase::AddMovie(%s) failed", strFilenameAndPath.c_str());
623   }
624   return -1;
625 }
626
627 long CVideoDatabase::AddTvShow(const CStdString& strPath)
628 {
629   try
630   {
631     if (NULL == m_pDB.get()) return -1;
632     if (NULL == m_pDS.get()) return -1;
633     
634     CStdString strSQL=FormatSQL("select tvshowlinkpath.idShow from path,tvshowlinkpath where path.strPath like '%s' and path.idPath = tvshowlinkpath.idPath",strPath.c_str());
635     m_pDS->query(strSQL.c_str());
636     if (m_pDS->num_rows() != 0)
637       return m_pDS->fv("tvshowlinkpath.idShow").get_asLong();
638
639     strSQL=FormatSQL("insert into tvshow (idShow) values (0)");
640     m_pDS->exec(strSQL.c_str());
641     long lTvShow = (long)sqlite3_last_insert_rowid(m_pDB->getHandle());
642     strSQL=FormatSQL("update tvshow set idShow=%i where idShow=0",lTvShow);
643     m_pDS->exec(strSQL.c_str());
644     
645     long lPathId = GetPath(strPath);
646     if (lPathId < 0)
647       lPathId = AddPath(strPath);
648     strSQL=FormatSQL("insert into tvshowlinkpath values (%i,%i)",lTvShow,lPathId);
649     m_pDS->exec(strSQL.c_str());
650
651     CommitTransaction();
652     
653     return lTvShow;
654   }
655   catch (...)
656   {
657     CLog::Log(LOGERROR, "CVideoDatabase::AddTvShow(%s) failed", strPath.c_str());
658   }
659   return -1;
660 }
661
662 //********************************************************************************************************************************
663 long CVideoDatabase::AddEpisode(long idShow, const CStdString& strFilenameAndPath)
664 {
665   try
666   {
667     if (NULL == m_pDB.get()) return -1;
668     if (NULL == m_pDS.get()) return -1;
669     
670     long lFileId, lMovieId=-1,lEpisodeId=-1;
671     lFileId = GetFile(strFilenameAndPath,lMovieId,lEpisodeId);
672     if (lFileId < 0)
673       lFileId = AddFile(strFilenameAndPath);
674     if (lEpisodeId < 0)
675     {
676       CStdString strSQL=FormatSQL("insert into episode (idEpisode) values (0)");
677       m_pDS->exec(strSQL.c_str());
678       lEpisodeId = (long)sqlite3_last_insert_rowid(m_pDB->getHandle());
679       strSQL=FormatSQL("update episode set idEpisode=%i where idEpisode=0",lEpisodeId);
680       m_pDS->exec(strSQL.c_str());
681       
682       // update file info to reflect it points to this episode
683       CStdString strPath, strFileName;
684       CUtil::Split(strFilenameAndPath,strPath,strFileName);
685       long lPathId = GetPath(strPath);
686       if (lPathId < 0)
687         lPathId = AddPath(strPath);
688       strSQL=FormatSQL("update files set idMovie=-1,idEpisode=%i where strFilename like '%s' and idPath=%u",lEpisodeId,strFileName.c_str(),lPathId);
689       m_pDS->exec(strSQL.c_str());
690       strSQL=FormatSQL("insert into tvshowlinkepisode (idShow,idEpisode) values (%i,%i)",idShow,lEpisodeId);
691       m_pDS->exec(strSQL.c_str());
692       // and update the show
693       strSQL=FormatSQL("update tvshow set c%02d=c%02d+1 where idshow=%u",VIDEODB_ID_TV_EPISODES,VIDEODB_ID_TV_EPISODES,idShow);
694       m_pDS->exec(strSQL.c_str());
695       CommitTransaction();
696     }
697     
698     return lEpisodeId;
699   }
700   catch (...)
701   {
702     CLog::Log(LOGERROR, "CVideoDatabase::AddEpisode(%s) failed", strFilenameAndPath.c_str());
703   }
704   return -1;
705 }
706
707 //********************************************************************************************************************************
708 long CVideoDatabase::AddGenre(const CStdString& strGenre)
709 {
710   try
711   {
712     if (NULL == m_pDB.get()) return -1;
713     if (NULL == m_pDS.get()) return -1;
714
715     CStdString strSQL=FormatSQL("select idGenre from genre where strGenre like '%s'", strGenre.c_str());
716     m_pDS->query(strSQL.c_str());
717     if (m_pDS->num_rows() == 0)
718     {
719       m_pDS->close();
720       // doesnt exists, add it
721       strSQL=FormatSQL("insert into genre (idGenre, strGenre) values( NULL, '%s')", strGenre.c_str());
722       m_pDS->exec(strSQL.c_str());
723       long lGenreId = (long)sqlite3_last_insert_rowid(m_pDB->getHandle());
724       return lGenreId;
725     }
726     else
727     {
728       const field_value value = m_pDS->fv("idGenre");
729       long lGenreId = value.get_asLong() ;
730       m_pDS->close();
731       return lGenreId;
732     }
733   }
734   catch (...)
735   {
736     CLog::Log(LOGERROR, "CVideoDatabase::AddGenre(%s) failed", strGenre.c_str() );
737   }
738
739   return -1;
740 }
741
742
743 //********************************************************************************************************************************
744 long CVideoDatabase::AddActor(const CStdString& strActor)
745 {
746   try
747   {
748     if (NULL == m_pDB.get()) return -1;
749     if (NULL == m_pDS.get()) return -1;
750     CStdString strSQL=FormatSQL("select idActor from Actors where strActor like '%s'", strActor.c_str());
751     m_pDS->query(strSQL.c_str());
752     if (m_pDS->num_rows() == 0)
753     {
754       m_pDS->close();
755       // doesnt exists, add it
756       strSQL=FormatSQL("insert into Actors (idActor, strActor) values( NULL, '%s')", strActor.c_str());
757       m_pDS->exec(strSQL.c_str());
758       long lActorId = (long)sqlite3_last_insert_rowid(m_pDB->getHandle());
759       return lActorId;
760     }
761     else
762     {
763       const field_value value = m_pDS->fv("idActor");
764       long lActorId = value.get_asLong() ;
765       m_pDS->close();
766       return lActorId;
767     }
768
769   }
770   catch (...)
771   {
772     CLog::Log(LOGERROR, "CVideoDatabase::AddActor(%s) failed", strActor.c_str() );
773   }
774   return -1;
775 }
776 //********************************************************************************************************************************
777 void CVideoDatabase::AddGenreToMovie(long lMovieId, long lGenreId)
778 {
779   try
780   {
781     if (NULL == m_pDB.get()) return ;
782     if (NULL == m_pDS.get()) return ;
783
784     CStdString strSQL=FormatSQL("select * from genrelinkmovie where idGenre=%i and idMovie=%i", lGenreId, lMovieId);
785     m_pDS->query(strSQL.c_str());
786     if (m_pDS->num_rows() == 0)
787     {
788       // doesnt exists, add it
789       strSQL=FormatSQL("insert into genrelinkmovie (idGenre, idMovie) values( %i,%i)", lGenreId, lMovieId);
790       m_pDS->exec(strSQL.c_str());
791     }
792     m_pDS->close();
793   }
794   catch (...)
795   {
796     CLog::Log(LOGERROR, "CVideoDatabase::AddGenreToMovie() failed");
797   }
798 }
799
800 void CVideoDatabase::AddGenreToTvShow(long lTvShowId, long lGenreId)
801 {
802   try
803   {
804     if (NULL == m_pDB.get()) return ;
805     if (NULL == m_pDS.get()) return ;
806
807     CStdString strSQL=FormatSQL("select * from genrelinktvshow where idGenre=%i and idShow=%i", lGenreId, lTvShowId);
808     m_pDS->query(strSQL.c_str());
809     if (m_pDS->num_rows() == 0)
810     {
811       // doesnt exists, add it
812       strSQL=FormatSQL("insert into genrelinktvshow (idGenre, idShow) values( %i,%i)", lGenreId, lTvShowId);
813       m_pDS->exec(strSQL.c_str());
814     }
815     m_pDS->close();
816   }
817   catch (...)
818   {
819     CLog::Log(LOGERROR, "CVideoDatabase::AddGenreToTvShow() failed");
820   }
821 }
822
823 void CVideoDatabase::AddGenreToEpisode(long lEpisodeId, long lGenreId)
824 {
825   try
826   {
827     if (NULL == m_pDB.get()) return ;
828     if (NULL == m_pDS.get()) return ;
829
830     CStdString strSQL=FormatSQL("select * from genrelinkepisode where idGenre=%i and idEpisode=%i", lGenreId, lEpisodeId);
831     m_pDS->query(strSQL.c_str());
832     if (m_pDS->num_rows() == 0)
833     {
834       // doesnt exists, add it
835       strSQL=FormatSQL("insert into genrelinkepisode (idGenre, idEpisode) values( %i,%i)", lGenreId, lEpisodeId);
836       m_pDS->exec(strSQL.c_str());
837     }
838     m_pDS->close();
839   }
840   catch (...)
841   {
842     CLog::Log(LOGERROR, "CVideoDatabase::AddGenreToEpisode() failed");
843   }
844 }
845
846 //********************************************************************************************************************************
847 void CVideoDatabase::AddActorToMovie(long lMovieId, long lActorId, const CStdString& strRole)
848 {
849   try
850   {
851     if (NULL == m_pDB.get()) return ;
852     if (NULL == m_pDS.get()) return ;
853
854     CStdString strSQL=FormatSQL("select * from actorlinkmovie where idActor=%u and idMovie=%u", lActorId, lMovieId);
855     m_pDS->query(strSQL.c_str());
856     if (m_pDS->num_rows() == 0)
857     {
858       // doesnt exists, add it
859       strSQL=FormatSQL("insert into actorlinkmovie (idActor, idMovie, strRole) values( %i,%i,'%s')", lActorId, lMovieId, strRole.c_str());
860       m_pDS->exec(strSQL.c_str());
861     }
862     m_pDS->close();
863   }
864   catch (...)
865   {
866     CLog::Log(LOGERROR, "CVideoDatabase::AddActorToMovie() failed");
867   }
868 }
869
870 void CVideoDatabase::AddActorToTvShow(long lTvShowId, long lActorId, const CStdString& strRole)
871 {
872   try
873   {
874     if (NULL == m_pDB.get()) return ;
875     if (NULL == m_pDS.get()) return ;
876
877     CStdString strSQL=FormatSQL("select * from actorlinktvshow where idActor=%u and idShow=%u", lActorId, lTvShowId);
878     m_pDS->query(strSQL.c_str());
879     if (m_pDS->num_rows() == 0)
880     {
881       // doesnt exists, add it
882       strSQL=FormatSQL("insert into actorlinktvshow (idActor, idShow, strRole) values( %i,%i,'%s')", lActorId, lTvShowId, strRole.c_str());
883       m_pDS->exec(strSQL.c_str());
884     }
885     m_pDS->close();
886   }
887   catch (...)
888   {
889     CLog::Log(LOGERROR, "CVideoDatabase::AddActorToTvShow() failed");
890   }
891 }
892
893 void CVideoDatabase::AddActorToEpisode(long lEpisodeId, long lActorId, const CStdString& strRole)
894 {
895   try
896   {
897     if (NULL == m_pDB.get()) return ;
898     if (NULL == m_pDS.get()) return ;
899
900     CStdString strSQL=FormatSQL("select * from actorlinkepisode where idActor=%u and idEpisode=%u", lActorId, lEpisodeId);
901     m_pDS->query(strSQL.c_str());
902     if (m_pDS->num_rows() == 0)
903     {
904       // doesnt exists, add it
905       strSQL=FormatSQL("insert into actorlinkepisode (idActor, idEpisode, strRole) values( %i,%i,'%s')", lActorId, lEpisodeId, strRole.c_str());
906       m_pDS->exec(strSQL.c_str());
907     }
908     m_pDS->close();
909   }
910   catch (...)
911   {
912     CLog::Log(LOGERROR, "CVideoDatabase::AddActorToEpisode() failed");
913   }
914 }
915
916 //********************************************************************************************************************************
917 void CVideoDatabase::AddDirectorToMovie(long lMovieId, long lDirectorId)
918 {
919   try
920   {
921     if (NULL == m_pDB.get()) return ;
922     if (NULL == m_pDS.get()) return ;
923
924     CStdString strSQL=FormatSQL("select * from directorlinkmovie where idDirector=%u and idMovie=%u", lDirectorId, lMovieId);
925     m_pDS->query(strSQL.c_str());
926     if (m_pDS->num_rows() == 0)
927     {
928       // doesnt exists, add it
929       strSQL=FormatSQL("insert into directorlinkmovie (idDirector, idMovie) values( %i,%i)", lDirectorId, lMovieId);
930       m_pDS->exec(strSQL.c_str());
931     }
932     m_pDS->close();
933   }
934   catch (...)
935   {
936     CLog::Log(LOGERROR, "CVideoDatabase::AddDirectorToMovie() failed");
937   }
938 }
939
940 void CVideoDatabase::AddDirectorToTvShow(long lTvShowId, long lDirectorId)
941 {
942   try
943   {
944     if (NULL == m_pDB.get()) return ;
945     if (NULL == m_pDS.get()) return ;
946
947     CStdString strSQL=FormatSQL("select * from directorlinktvshow where idDirector=%u and idShow=%u", lDirectorId, lTvShowId);
948     m_pDS->query(strSQL.c_str());
949     if (m_pDS->num_rows() == 0)
950     {
951       // doesnt exists, add it
952       strSQL=FormatSQL("insert into directorlinktvshow (idDirector, idShow) values( %i,%i)", lDirectorId, lTvShowId);
953       m_pDS->exec(strSQL.c_str());
954     }
955     m_pDS->close();
956   }
957   catch (...)
958   {
959     CLog::Log(LOGERROR, "CVideoDatabase::AddDirectorToTvShow() failed");
960   }
961 }
962
963 void CVideoDatabase::AddDirectorToEpisode(long lEpisodeId, long lDirectorId)
964 {
965   try
966   {
967     if (NULL == m_pDB.get()) return ;
968     if (NULL == m_pDS.get()) return ;
969
970     CStdString strSQL=FormatSQL("select * from directorlinkepisode where idDirector=%u and idEpisode=%u", lDirectorId, lEpisodeId);
971     m_pDS->query(strSQL.c_str());
972     if (m_pDS->num_rows() == 0)
973     {
974       // doesnt exists, add it
975       strSQL=FormatSQL("insert into directorlinkepisode (idDirector, idEpisode) values( %i,%i)", lDirectorId, lEpisodeId);
976       m_pDS->exec(strSQL.c_str());
977     }
978     m_pDS->close();
979   }
980   catch (...)
981   {
982     CLog::Log(LOGERROR, "CVideoDatabase::AddDirectorToEpisode() failed");
983   }
984 }
985
986 //********************************************************************************************************************************
987 bool CVideoDatabase::HasMovieInfo(const CStdString& strFilenameAndPath)
988 {
989   try
990   {
991     if (NULL == m_pDB.get()) return false;
992     if (NULL == m_pDS.get()) return false;
993     long lMovieId = GetMovieInfo(strFilenameAndPath);
994     if ( lMovieId < 0) return false;
995
996     CStdString strSQL=FormatSQL("select idMovie from movie where movie.idmovie=%i", lMovieId);
997     m_pDS->query(strSQL.c_str());
998     if (m_pDS->num_rows() == 0)
999     {
1000       m_pDS->close();
1001       return false;
1002     }
1003     m_pDS->close();
1004     return true;
1005   }
1006   catch (...)
1007   {
1008     CLog::Log(LOGERROR, "CVideoDatabase::HasMovieInfo(%s) failed", strFilenameAndPath.c_str());
1009   }
1010
1011   return false;
1012 }
1013
1014 bool CVideoDatabase::HasTvShowInfo(const CStdString& strFilenameAndPath)
1015 {
1016   try
1017   {
1018     if (NULL == m_pDB.get()) return false;
1019     if (NULL == m_pDS.get()) return false;
1020     long lTvShowId = GetTvShowInfo(strFilenameAndPath);
1021     if ( lTvShowId < 0) return false;
1022     return true;
1023   }
1024   catch (...)
1025   {
1026     CLog::Log(LOGERROR, "CVideoDatabase::HasTvShowInfo(%s) failed", strFilenameAndPath.c_str());
1027   }
1028
1029   return false;
1030 }
1031
1032 bool CVideoDatabase::HasEpisodeInfo(const CStdString& strFilenameAndPath)
1033 {
1034   try
1035   {
1036     if (NULL == m_pDB.get()) return false;
1037     if (NULL == m_pDS.get()) return false;
1038     long lEpisodeId = GetEpisode(strFilenameAndPath);
1039     if ( lEpisodeId < 0) return false;
1040     return true;
1041   }
1042   catch (...)
1043   {
1044     CLog::Log(LOGERROR, "CVideoDatabase::HasEpisodeInfo(%s) failed", strFilenameAndPath.c_str());
1045   }
1046
1047   return false;
1048 }
1049
1050 //********************************************************************************************************************************
1051 void CVideoDatabase::DeleteDetailsForMovie(const CStdString& strFileNameAndPath)
1052 {
1053   try
1054   {
1055     if (NULL == m_pDB.get()) return ;
1056     if (NULL == m_pDS.get()) return ;
1057
1058     long lMovieId = GetMovie(strFileNameAndPath);
1059     if ( lMovieId < 0) return ;
1060
1061     CStdString strSQL;
1062     strSQL=FormatSQL("delete from genrelinkmovie where idmovie=%i", lMovieId);
1063     m_pDS->exec(strSQL.c_str());
1064
1065     strSQL=FormatSQL("delete from actorlinkmovie where idmovie=%i", lMovieId);
1066     m_pDS->exec(strSQL.c_str());
1067
1068     strSQL=FormatSQL("delete from directorlinkmovie where idmovie=%i", lMovieId);
1069     m_pDS->exec(strSQL.c_str());
1070
1071     // remove all info other than the id
1072     // we do this due to the way we have the link between the file + movie tables.
1073
1074     // IMO it may be better to link from the movie->file table instead of vice-versa
1075     // (ie have movie.idFile and movie.idPath instead of file.idMovie)
1076     // then when we remove from the movie table, we don't care if it's still in the file table
1077     // Alternatively, we could remove from the file table as well (I don't see any point in keeping it there, unless
1078     // we're planning on having stuff linked to the file table for settings or whatever).  In fact,
1079     // the file table is pretty useless as is, except for the link to the path table.  Shouldn't the movie
1080     // table be the base, as movie->file is a 1:1 mapping?  In this case, there's no reason why the filename can be
1081     // directly in the movie table, and idPath in the movie table as well.
1082     strSQL = "update movie set ";
1083     for (int iType = VIDEODB_ID_MIN + 1; iType < VIDEODB_ID_MAX; iType++)
1084     {
1085       CStdString column;
1086       column.Format("c%02d=NULL,", iType);
1087       strSQL += column;
1088     }
1089     strSQL = strSQL.Mid(0, strSQL.size() - 1) + FormatSQL(" where idMovie=%i", lMovieId);
1090     m_pDS->exec(strSQL.c_str());
1091   }
1092   catch (...)
1093   {
1094     CLog::Log(LOGERROR, "CVideoDatabase::DeleteDetailsForMovie(%s) failed", strFileNameAndPath.c_str());
1095   }
1096 }
1097
1098 void CVideoDatabase::DeleteDetailsForTvShow(const CStdString& strPath)
1099 {
1100   try
1101   {
1102     if (NULL == m_pDB.get()) return ;
1103     if (NULL == m_pDS.get()) return ;
1104
1105     long lTvShowId = GetTvShowInfo(strPath);
1106     if ( lTvShowId < 0) return ;
1107
1108     CStdString strSQL;
1109     strSQL=FormatSQL("delete from genrelinktvshow where idshow=%i", lTvShowId);
1110     m_pDS->exec(strSQL.c_str());
1111
1112     strSQL=FormatSQL("delete from actorlinktvshow where idshow=%i", lTvShowId);
1113     m_pDS->exec(strSQL.c_str());
1114
1115     strSQL=FormatSQL("delete from directorlinktvshow where idshow=%i", lTvShowId);
1116     m_pDS->exec(strSQL.c_str());
1117
1118     // remove all info other than the id
1119     // we do this due to the way we have the link between the file + movie tables.
1120
1121     strSQL = "update tvshow set ";
1122     for (int iType = VIDEODB_ID_TV_MIN + 1; iType < VIDEODB_ID_TV_MAX; iType++)
1123     {
1124       CStdString column;
1125       column.Format("c%02d=NULL,", iType);
1126       strSQL += column;
1127     }
1128     strSQL = strSQL.Mid(0, strSQL.size() - 1) + FormatSQL(" where idShow=%i", lTvShowId);
1129     m_pDS->exec(strSQL.c_str());
1130   }
1131   catch (...)
1132   {
1133     CLog::Log(LOGERROR, "CVideoDatabase::DeleteDetailsForTvShow(%s) failed", strPath.c_str());
1134   }
1135 }
1136
1137 void CVideoDatabase::DeleteDetailsForEpisode(const CStdString& strFilenameAndPath)
1138 {
1139   try
1140   {
1141     if (NULL == m_pDB.get()) return ;
1142     if (NULL == m_pDS.get()) return ;
1143
1144     long lEpisodeId = GetEpisode(strFilenameAndPath);
1145     if ( lEpisodeId < 0) return ;
1146
1147     CStdString strSQL;
1148     strSQL=FormatSQL("delete from genrelinkepisode where idepisode=%i", lEpisodeId);
1149     m_pDS->exec(strSQL.c_str());
1150
1151     strSQL=FormatSQL("delete from actorlinkepisode where idepisode=%i", lEpisodeId);
1152     m_pDS->exec(strSQL.c_str());
1153
1154     strSQL=FormatSQL("delete from directorlinkepisode where idepisode=%i", lEpisodeId);
1155     m_pDS->exec(strSQL.c_str());
1156
1157     // remove all info other than the id
1158     // we do this due to the way we have the link between the file + movie tables.
1159
1160     strSQL = "update episode set ";
1161     for (int iType = VIDEODB_ID_EPISODE_MIN + 1; iType < VIDEODB_ID_EPISODE_MAX; iType++)
1162     {
1163       CStdString column;
1164       column.Format("c%02d=NULL,", iType);
1165       strSQL += column;
1166     }
1167     strSQL = strSQL.Mid(0, strSQL.size() - 1) + FormatSQL(" where idEpisode=%i", lEpisodeId);
1168     m_pDS->exec(strSQL.c_str());
1169   }
1170   catch (...)
1171   {
1172     CLog::Log(LOGERROR, "CVideoDatabase::DeleteDetailsForEpisode(%s) failed", strFilenameAndPath.c_str());
1173   }
1174 }
1175
1176 //********************************************************************************************************************************
1177 void CVideoDatabase::GetMoviesByActor(const CStdString& strActor, VECMOVIES& movies)
1178 {
1179   try
1180   {
1181     movies.erase(movies.begin(), movies.end());
1182     if (NULL == m_pDB.get()) return ;
1183     if (NULL == m_pDS.get()) return ;
1184
1185     CStdString strSQL=FormatSQL("select movie.*,files.strFileName,path.strPath from movie join files on files.idMovie=movie.idMovie join path on files.idPath=path.idPath join actorlinkmovie on actorlinkmovie.idmovie=movie.idmovie join actors on actors.idActor=actorlinkmovie.idActor where actors.stractor='%s'", strActor.c_str());
1186     m_pDS->query( strSQL.c_str() );
1187
1188     long lLastPathId = -1;
1189     while (!m_pDS->eof())
1190     {
1191       movies.push_back(GetDetailsForMovie(m_pDS));
1192       m_pDS->next();
1193     }
1194     m_pDS->close();
1195   }
1196   catch (...)
1197   {
1198     CLog::Log(LOGERROR, "CVideoDatabase::GetMoviesByActor(%s) failed", strActor.c_str());
1199   }
1200 }
1201
1202 void CVideoDatabase::GetTvShowsByActor(const CStdString& strActor, VECMOVIES& movies)
1203 {
1204   try
1205   {
1206     movies.erase(movies.begin(), movies.end());
1207     if (NULL == m_pDB.get()) return ;
1208     if (NULL == m_pDS.get()) return ;
1209
1210     CStdString strSQL=FormatSQL("select tvshow.*,path.strPath,path.strPath from tvshow join path on tvshowlinkpath.idpath = path.idpath join tvshowlinkpath on tvshowlinkpath.idshow=tvshow.idshow join actorlinktvshow on actorlinktvshow.idshow=tvshow.idshow join actors on actors.idActor=actorlinktvshow.idActor where actors.stractor='%s'", strActor.c_str());
1211     m_pDS->query( strSQL.c_str() );
1212
1213     long lLastPathId = -1;
1214     while (!m_pDS->eof())
1215     {
1216       movies.push_back(GetDetailsForTvShow(m_pDS));
1217       m_pDS->next();
1218     }
1219     m_pDS->close();
1220   }
1221   catch (...)
1222   {
1223     CLog::Log(LOGERROR, "CVideoDatabase::GetTvShowsByActor(%s) failed", strActor.c_str());
1224   }
1225 }
1226
1227 void CVideoDatabase::GetEpisodesByActor(const CStdString& strActor, VECMOVIES& movies)
1228 {
1229   try
1230   {
1231     movies.erase(movies.begin(), movies.end());
1232     if (NULL == m_pDB.get()) return ;
1233     if (NULL == m_pDS.get()) return ;
1234
1235     CStdString strSQL=FormatSQL("select episode.*,files.strFileName,path.strPath from episode join files on files.idEpisode=episode.idEpisode join path on files.idPath=path.idPath join actorlinkepisode on actorlinkepisode.idepisode=episode.idepisode join actors on actors.idActor=actorlinkepisode.idActor where actors.stractor='%s'", strActor.c_str());
1236     m_pDS->query( strSQL.c_str() );
1237
1238     long lLastPathId = -1;
1239     while (!m_pDS->eof())
1240     {
1241       movies.push_back(GetDetailsForEpisode(m_pDS));
1242       m_pDS->next();
1243     }
1244     m_pDS->close();
1245   }
1246   catch (...)
1247   {
1248     CLog::Log(LOGERROR, "CVideoDatabase::GetEpisodesByActor(%s) failed", strActor.c_str());
1249   }
1250 }
1251
1252 //********************************************************************************************************************************
1253 void CVideoDatabase::GetMovieInfo(const CStdString& strFilenameAndPath, CIMDBMovie& details, long lMovieId /* = -1 */)
1254 {
1255   try
1256   {
1257     // TODO: Optimize this - no need for all the queries!
1258     if (lMovieId < 0)
1259       lMovieId = GetMovieInfo(strFilenameAndPath);
1260     if (lMovieId < 0) return ;
1261
1262     CStdString sql = FormatSQL("select movie.*,files.strFileName,path.strPath from movie join files on files.idMovie=movie.idMovie join path on files.idPath=path.idPath where movie.idMovie=%i", lMovieId);
1263     if (!m_pDS->query(sql.c_str()))
1264       return;
1265     details = GetDetailsForMovie(m_pDS, true);
1266   }
1267   catch (...)
1268   {
1269     CLog::Log(LOGERROR, "CVideoDatabase::GetMovieInfo(%s) failed", strFilenameAndPath.c_str());
1270   }
1271 }
1272
1273 //********************************************************************************************************************************
1274 void CVideoDatabase::GetTvShowInfo(const CStdString& strFilenameAndPath, CIMDBMovie& details, long lTvShowId /* = -1 */)
1275 {
1276   try
1277   {
1278     // TODO: Optimize this - no need for all the queries!
1279     if (lTvShowId < 0)
1280       lTvShowId = GetTvShowInfo(strFilenameAndPath);
1281     if (lTvShowId < 0) return ;
1282
1283 //    CStdString sql = FormatSQL("select tvshow.*,files.strFileName,path.strPath from tvshow join files on files.idEpisode=tvshowlinkepisode.idEpisode join path on files.idPath=path.idPath where tvshow.idshow=%i", lTvShowId);
1284     CStdString sql = FormatSQL("select tvshow.*,tvshowlinkpath.idpath,tvshowlinkpath.idpath from tvshow,tvshowlinkpath where tvshow.idshow=%i and tvshowlinkpath.idshow=tvshow.idshow", lTvShowId);
1285     if (!m_pDS->query(sql.c_str()))
1286       return;
1287     details = GetDetailsForTvShow(m_pDS, true);
1288   }
1289   catch (...)
1290   {
1291     CLog::Log(LOGERROR, "CVideoDatabase::GetTvShowInfo(%s) failed", strFilenameAndPath.c_str());
1292   }
1293 }
1294
1295 bool CVideoDatabase::GetEpisodeInfo(const CStdString& strFilenameAndPath, CIMDBMovie& details, long lEpisodeId /* = -1 */)
1296 {
1297   try
1298   {
1299     // TODO: Optimize this - no need for all the queries!
1300     if (lEpisodeId < 0)
1301       lEpisodeId = GetEpisodeInfo(strFilenameAndPath);
1302     if (lEpisodeId < 0) return false;
1303
1304     CStdString sql = FormatSQL("select episode.*,files.strFileName,path.strPath from episode join files on files.idEpisode=episode.idEpisode join path on files.idPath=path.idPath where episode.idEpisode=%i", lEpisodeId);
1305     if (!m_pDS->query(sql.c_str()))
1306       return false;
1307     details = GetDetailsForEpisode(m_pDS, true);
1308     return true;
1309   }
1310   catch (...)
1311   {
1312     CLog::Log(LOGERROR, "CVideoDatabase::GetEpisodeInfo(%s) failed", strFilenameAndPath.c_str());
1313   }
1314   return false;
1315 }
1316
1317 void CVideoDatabase::AddGenreAndDirectors(const CIMDBMovie& details, vector<long>& vecDirectors, vector<long>& vecGenres)
1318 {
1319   // add all directors
1320   char szDirector[1024];
1321   strcpy(szDirector, details.m_strDirector.c_str());
1322   if (strstr(szDirector, "/"))
1323   {
1324     char *pToken = strtok(szDirector, "/");
1325     while ( pToken != NULL )
1326     {
1327       CStdString strDirector = pToken;
1328       strDirector.Trim();
1329       long lDirectorId = AddActor(strDirector);
1330       vecDirectors.push_back(lDirectorId);
1331       pToken = strtok( NULL, "/" );
1332     }
1333   }
1334   else if (!details.m_strDirector.IsEmpty())
1335   {
1336     CStdString strDirector = details.m_strDirector;
1337     strDirector.Trim();
1338     long lDirectorId = AddActor(strDirector);
1339     vecDirectors.push_back(lDirectorId);
1340   }
1341
1342   // add all genres
1343   char szGenres[1024];
1344   strcpy(szGenres, details.m_strGenre.c_str());
1345   if (strstr(szGenres, "/"))
1346   {
1347     char *pToken = strtok(szGenres, "/");
1348     while ( pToken != NULL )
1349     {
1350       CStdString strGenre = pToken;
1351       strGenre.Trim();
1352       long lGenreId = AddGenre(strGenre);
1353       vecGenres.push_back(lGenreId);
1354       pToken = strtok( NULL, "/" );
1355     }
1356   }
1357   else if (!details.m_strGenre.IsEmpty())
1358   {
1359     CStdString strGenre = details.m_strGenre;
1360     strGenre.Trim();
1361     long lGenreId = AddGenre(strGenre);
1362     vecGenres.push_back(lGenreId);
1363   }
1364 }
1365
1366 //********************************************************************************************************************************
1367 void CVideoDatabase::SetDetailsForMovie(const CStdString& strFilenameAndPath, CIMDBMovie& details)
1368 {
1369   try
1370   {
1371     long lMovieId = GetMovie(strFilenameAndPath);
1372     if (lMovieId < 0)
1373       lMovieId = AddMovie(strFilenameAndPath);
1374
1375     BeginTransaction();
1376
1377     vector<long> vecDirectors;
1378     vector<long> vecGenres;
1379     AddGenreAndDirectors(details,vecDirectors,vecGenres);
1380     
1381     // add cast...
1382     for (CIMDBMovie::iCast it = details.m_cast.begin(); it != details.m_cast.end(); ++it)
1383     {
1384       long lActor = AddActor(it->first);
1385       AddActorToMovie(lMovieId, lActor, it->second);
1386     }
1387     
1388     for (int i = 0; i < (int)vecGenres.size(); ++i)
1389     {
1390       AddGenreToMovie(lMovieId, vecGenres[i]);
1391     }
1392
1393     for (i = 0; i < (int)vecDirectors.size(); ++i)
1394     {
1395       AddDirectorToMovie(lMovieId, vecDirectors[i]);
1396     }
1397
1398     // delete the current row for this movie
1399     CStdString sql = FormatSQL("delete from movie where movie.idMovie=%i", lMovieId);
1400     m_pDS->exec(sql.c_str());
1401
1402     // and insert the new row
1403     CStdString sqlColumns = "insert into movie (idMovie";
1404     CStdString strValues = FormatSQL(") values (%i", lMovieId);
1405     for (int iType=VIDEODB_ID_MIN+1;iType<VIDEODB_ID_MAX;++iType)
1406     {
1407       CStdString strValue;
1408       switch (DbMovieOffsets[iType].type)
1409       {
1410       case VIDEODB_TYPE_STRING:
1411         strValue = *(CStdString*)(((char*)&details)+DbMovieOffsets[iType].offset);
1412         break;
1413       case VIDEODB_TYPE_INT:
1414         strValue.Format("%i",*(int*)(((char*)&details)+DbMovieOffsets[iType].offset));
1415         break;
1416       case VIDEODB_TYPE_BOOL:
1417         strValue = *(bool*)(((char*)&details)+DbMovieOffsets[iType].offset)?"true":"false";
1418         break;
1419       case VIDEODB_TYPE_FLOAT:
1420         strValue.Format("%f",*(float*)(((char*)&details)+DbMovieOffsets[iType].offset));
1421         break;
1422       }
1423       sqlColumns += FormatSQL(",c%02d", iType);
1424       strValues += FormatSQL(",'%s'", strValue.c_str());
1425     }
1426     CStdString strSQL = sqlColumns + strValues + ")";
1427     m_pDS->exec(strSQL.c_str());
1428     CommitTransaction();
1429   }
1430   catch (...)
1431   {
1432     CLog::Log(LOGERROR, "CVideoDatabase::SetDetailsForMovie(%s) failed", strFilenameAndPath.c_str());
1433   }
1434 }
1435
1436 long CVideoDatabase::SetDetailsForTvShow(const CStdString& strPath, CIMDBMovie& details)
1437 {
1438   try
1439   {
1440     long lTvShowId = GetTvShow(strPath);
1441     if (lTvShowId < 0)
1442       lTvShowId = AddTvShow(strPath);
1443
1444     BeginTransaction();
1445
1446     vector<long> vecDirectors;
1447     vector<long> vecGenres;
1448     AddGenreAndDirectors(details,vecDirectors,vecGenres);
1449   
1450     // add cast...
1451     for (CIMDBMovie::iCast it = details.m_cast.begin(); it != details.m_cast.end(); ++it)
1452     {
1453       long lActor = AddActor(it->first);
1454       AddActorToTvShow(lTvShowId, lActor, it->second);
1455     }
1456     
1457     for (int i = 0; i < (int)vecGenres.size(); ++i)
1458     {
1459       AddGenreToTvShow(lTvShowId, vecGenres[i]);
1460     }
1461
1462     for (i = 0; i < (int)vecDirectors.size(); ++i)
1463     {
1464       AddDirectorToTvShow(lTvShowId, vecDirectors[i]);
1465     }
1466
1467     // delete the current row for this movie
1468     CStdString sql = FormatSQL("delete from tvshow where tvshow.idShow=%i", lTvShowId);
1469     m_pDS->exec(sql.c_str());
1470
1471     // and insert the new row
1472     CStdString sqlColumns = "insert into tvshow (idShow";
1473     CStdString strValues = FormatSQL(") values (%i", lTvShowId);
1474     for (int iType=VIDEODB_ID_MIN+1;iType<VIDEODB_ID_MAX;++iType)
1475     {
1476       CStdString strValue;
1477       switch (DbTvShowOffsets[iType].type)
1478       {
1479       case VIDEODB_TYPE_STRING:
1480         strValue = *(CStdString*)(((char*)&details)+DbTvShowOffsets[iType].offset);
1481         break;
1482       case VIDEODB_TYPE_INT:
1483         strValue.Format("%i",*(int*)(((char*)&details)+DbTvShowOffsets[iType].offset));
1484         break;
1485       case VIDEODB_TYPE_BOOL:
1486         strValue = *(bool*)(((char*)&details)+DbTvShowOffsets[iType].offset)?"true":"false";
1487         break;
1488       case VIDEODB_TYPE_FLOAT:
1489         strValue.Format("%f",*(float*)(((char*)&details)+DbTvShowOffsets[iType].offset));
1490         break;
1491       }
1492       sqlColumns += FormatSQL(",c%02d", iType);
1493       strValues += FormatSQL(",'%s'", strValue.c_str());
1494     }
1495     CStdString strSQL = sqlColumns + strValues + ")";
1496     m_pDS->exec(strSQL.c_str());
1497     // update tvshowlinkpath info to reflect it points to this tvshow
1498     long lPathId = GetPath(strPath);
1499     if (lPathId < 0)
1500       lPathId = AddPath(strPath);
1501     CommitTransaction();
1502     return lTvShowId;
1503   }
1504   catch (...)
1505   {
1506     CLog::Log(LOGERROR, "CVideoDatabase::SetDetailsForTvShow(%s) failed", strPath.c_str());
1507   }
1508
1509   return -1;
1510 }
1511
1512 void CVideoDatabase::SetDetailsForEpisode(const CStdString& strFilenameAndPath, CIMDBMovie& details, long idShow)
1513 {
1514   try
1515   {
1516     long lEpisodeId = GetEpisode(strFilenameAndPath);
1517     if (lEpisodeId < 0)
1518       lEpisodeId = AddEpisode(idShow,strFilenameAndPath);
1519     if (lEpisodeId < 0)
1520       return;
1521
1522     BeginTransaction();
1523
1524     vector<long> vecDirectors;
1525     vector<long> vecGenres;
1526     AddGenreAndDirectors(details,vecDirectors,vecGenres);
1527     
1528     // add cast...
1529     for (CIMDBMovie::iCast it = details.m_cast.begin(); it != details.m_cast.end(); ++it)
1530     {
1531       long lActor = AddActor(it->first);
1532       AddActorToEpisode(lEpisodeId, lActor, it->second);
1533     }
1534     
1535     for (int i = 0; i < (int)vecGenres.size(); ++i)
1536     {
1537       AddGenreToEpisode(lEpisodeId, vecGenres[i]);
1538     }
1539
1540     for (i = 0; i < (int)vecDirectors.size(); ++i)
1541     {
1542       AddDirectorToEpisode(lEpisodeId, vecDirectors[i]);
1543     }
1544
1545     // delete the current row for this movie
1546     CStdString sql = FormatSQL("delete from episode where episode.idEpisode=%i", lEpisodeId);
1547     m_pDS->exec(sql.c_str());
1548
1549     // and insert the new row
1550     CStdString sqlColumns = "insert into episode (idEpisode";
1551     CStdString strValues = FormatSQL(") values (%i", lEpisodeId);
1552     for (int iType=VIDEODB_ID_EPISODE_MIN+1;iType<VIDEODB_ID_EPISODE_MAX;++iType)
1553     {
1554       CStdString strValue;
1555       switch (DbEpisodeOffsets[iType].type)
1556       {
1557       case VIDEODB_TYPE_STRING:
1558         strValue = *(CStdString*)(((char*)&details)+DbEpisodeOffsets[iType].offset);
1559         break;
1560       case VIDEODB_TYPE_INT:
1561         strValue.Format("%i",*(int*)(((char*)&details)+DbEpisodeOffsets[iType].offset));
1562         break;
1563       case VIDEODB_TYPE_BOOL:
1564         strValue = *(bool*)(((char*)&details)+DbEpisodeOffsets[iType].offset)?"true":"false";
1565         break;
1566       case VIDEODB_TYPE_FLOAT:
1567         strValue.Format("%f",*(float*)(((char*)&details)+DbEpisodeOffsets[iType].offset));
1568         break;
1569       }
1570       sqlColumns += FormatSQL(",c%02d", iType);
1571       strValues += FormatSQL(",'%s'", strValue.c_str());
1572     }
1573     CStdString strSQL = sqlColumns + strValues + ")";
1574     m_pDS->exec(strSQL.c_str());
1575     CommitTransaction();
1576   }
1577   catch (...)
1578   {
1579     CLog::Log(LOGERROR, "CVideoDatabase::SetDetailsForEpisode(%s) failed", strFilenameAndPath.c_str());
1580   }
1581 }
1582
1583 //********************************************************************************************************************************
1584 void CVideoDatabase::GetMoviesByPath(const CStdString& strPath1, VECMOVIES& movies)
1585 {
1586   try
1587   {
1588     if (strPath1.size() == 0) return;
1589     movies.erase(movies.begin(), movies.end());
1590
1591     vector<CStdString> vecPaths;
1592     CStdString strPath = strPath1;
1593     if (strPath.Left(14).Equals("virtualpath://"))
1594     {
1595       CVirtualPathDirectory vpath;
1596       if (!vpath.GetPathes(strPath, vecPaths))
1597         return;
1598     }
1599     else
1600       vecPaths.push_back(strPath);
1601
1602     // query for each patg in the vector!
1603     for (int i = 0; i < (int)vecPaths.size(); ++i)
1604     {
1605       strPath = vecPaths[i];
1606       if (CUtil::HasSlashAtEnd(strPath)) strPath = strPath.Left(strPath.size() - 1);
1607       CStdString strStackPath = "stack://" + strPath;
1608
1609       if (NULL == m_pDB.get()) return ;
1610       if (NULL == m_pDS.get()) return ;
1611       CStdString strSQL=FormatSQL("select * from path join files on path.idPath = files.idPath join movieinfo on files.idMovie = movieinfo.idMovie where path.strPath like '%%%s' or path.strPath like '%%%s'", strPath.c_str(), strStackPath.c_str());
1612       CLog::Log(LOGDEBUG,"CVideoDatabase::GetMoviesByPath query = %s", strSQL.c_str());
1613
1614       m_pDS->query( strSQL.c_str() );
1615       while (!m_pDS->eof())
1616       {
1617         CIMDBMovie details;
1618         long lMovieId = m_pDS->fv("files.idMovie").get_asLong();
1619         details.m_strSearchString.Format("%i", lMovieId);
1620         details.m_strIMDBNumber = m_pDS->fv("movieinfo.IMDBID").get_asString();
1621         details.m_strFile = m_pDS->fv("files.strFilename").get_asString();
1622         details.m_strPath = m_pDS->fv("path.strPath").get_asString();
1623         //CLog::Log(LOGDEBUG,"  movie [%s%s]", details.m_strPath.c_str(), details.m_strFile.c_str());
1624         movies.push_back(details);
1625         m_pDS->next();
1626       }
1627       m_pDS->close();
1628     }
1629   }
1630   catch (...)
1631   {
1632     CLog::Log(LOGERROR, "CVideoDatabase::GetMoviesByPath(%s) failed", strPath1.c_str());
1633   }
1634 }
1635
1636 //********************************************************************************************************************************
1637 void CVideoDatabase::GetFilePath(long lMovieId, CStdString &filePath, int iType)
1638 {
1639   try
1640   {
1641     if (NULL == m_pDB.get()) return ;
1642     if (NULL == m_pDS.get()) return ;
1643
1644     if (lMovieId < 0) return ;
1645     
1646     CStdString strSQL;
1647     if (iType == 0)
1648       strSQL=FormatSQL("select path.strPath,files.strFileName from path, files where path.idPath=files.idPath and files.idmovie=%i order by strFilename", lMovieId );
1649     if (iType == 1)
1650       strSQL=FormatSQL("select path.strPath,files.strFileName from path, files where path.idPath=files.idPath and files.idepisode=%i order by strFilename", lMovieId );
1651     if (iType == 2)
1652       strSQL=FormatSQL("select path.strPath from path,tvshowlinkpath where path.idpath=tvshowlinkpath.idpath and tvshowlinkpath.idshow=%i", lMovieId );
1653
1654     m_pDS->query( strSQL.c_str() );
1655     if (!m_pDS->eof())
1656     {
1657       if (iType != 2)
1658         CUtil::AddFileToFolder(m_pDS->fv("path.strPath").get_asString(),m_pDS->fv("files.strFilename").get_asString(),filePath);
1659       else
1660         filePath = m_pDS->fv("path.strPath").get_asString();
1661     }
1662     m_pDS->close();
1663   }
1664   catch (...)
1665   {
1666     CLog::Log(LOGERROR, "CVideoDatabase::GetFilePath() failed");
1667   }
1668 }
1669
1670 //********************************************************************************************************************************
1671 void CVideoDatabase::GetBookMarksForFile(const CStdString& strFilenameAndPath, VECBOOKMARKS& bookmarks, CBookmark::EType type /*= CBookmark::STANDARD*/)
1672 {
1673   try
1674   {
1675     long lMovieId, lEpisodeId;
1676     long lFileId = GetFile(strFilenameAndPath, lMovieId, lEpisodeId, true);
1677     if (lFileId < 0) return ;
1678     bookmarks.erase(bookmarks.begin(), bookmarks.end());
1679     if (NULL == m_pDB.get()) return ;
1680     if (NULL == m_pDS.get()) return ;
1681
1682     CStdString strSQL=FormatSQL("select * from bookmark where idFile=%i and type=%i order by timeInSeconds", lFileId, (int)type);
1683     m_pDS->query( strSQL.c_str() );
1684     while (!m_pDS->eof())
1685     {
1686       CBookmark bookmark;
1687       bookmark.timeInSeconds = m_pDS->fv("timeInSeconds").get_asDouble();
1688       bookmark.thumbNailImage = m_pDS->fv("thumbNailImage").get_asString();
1689       bookmark.playerState = m_pDS->fv("playerState").get_asString();
1690       bookmark.player = m_pDS->fv("player").get_asString();
1691       bookmark.type = type;
1692       bookmarks.push_back(bookmark);
1693       m_pDS->next();
1694     }
1695     //sort(bookmarks.begin(), bookmarks.end(), SortBookmarks);
1696     m_pDS->close();
1697   }
1698   catch (...)
1699   {
1700     CLog::Log(LOGERROR, "CVideoDatabase::GetBookMarksForMovie(%s) failed", strFilenameAndPath.c_str());
1701   }
1702 }
1703
1704 bool CVideoDatabase::GetResumeBookMark(const CStdString& strFilenameAndPath, CBookmark &bookmark)
1705 {
1706   VECBOOKMARKS bookmarks;
1707   GetBookMarksForFile(strFilenameAndPath, bookmarks, CBookmark::RESUME);
1708   if(bookmarks.size()>0)
1709   {
1710     bookmark = bookmarks[0];
1711     return true;
1712   }
1713   return false;
1714 }
1715
1716 //********************************************************************************************************************************
1717 void CVideoDatabase::AddBookMarkToFile(const CStdString& strFilenameAndPath, const CBookmark &bookmark, CBookmark::EType type /*= CBookmark::STANDARD*/)
1718 {
1719   try
1720   {
1721     long lMovieId, lEpisodeId;
1722     long lFileId = GetFile(strFilenameAndPath, lMovieId, lEpisodeId, true);
1723     if (lFileId < 0)
1724     {
1725       // Doesn't exist in the database yet - add it.
1726       // TODO: It doesn't appear to me that the CDLabel parameter or the subtitles
1727       // parameter is anywhere in use in XBMC.
1728       lFileId = AddFile(strFilenameAndPath);
1729       if (lFileId < 0)
1730         return ;
1731     }
1732     if (NULL == m_pDB.get()) return ;
1733     if (NULL == m_pDS.get()) return ;
1734
1735     CStdString strSQL;
1736     int idBookmark=-1;
1737     if( type == CBookmark::RESUME ) // get the same resume mark bookmark each time type
1738     {
1739       strSQL=FormatSQL("select idBookmark from bookmark where idFile=%i and type=1", lFileId);   
1740     }
1741     else // get the same bookmark again, and update. not sure here as a dvd can have same time in multiple places, state will differ thou
1742     {
1743       /* get a bookmark within the same time as previous */
1744       double mintime = bookmark.timeInSeconds - 0.5f;
1745       double maxtime = bookmark.timeInSeconds + 0.5f;
1746       strSQL=FormatSQL("select idBookmark from bookmark where idFile=%i and type=%i and (timeInSeconds between %f and %f) and playerState='%s'", lFileId, (int)type, mintime, maxtime, bookmark.playerState.c_str());
1747     }
1748
1749     // get current id
1750     m_pDS->query( strSQL.c_str() );
1751     if (m_pDS->num_rows() != 0)
1752       idBookmark = m_pDS->get_field_value("idBookmark").get_asInteger();            
1753     m_pDS->close();
1754
1755     // update or insert depending if it existed before
1756     if( idBookmark >= 0 )
1757       strSQL=FormatSQL("update bookmark set timeInSeconds = %f, thumbNailImage = '%s', player = '%s', playerState = '%s' where idBookmark = %i", bookmark.timeInSeconds, bookmark.thumbNailImage.c_str(), bookmark.player.c_str(), bookmark.playerState.c_str(), idBookmark);
1758     else
1759       strSQL=FormatSQL("insert into bookmark (idBookmark, idFile, timeInSeconds, thumbNailImage, player, playerState, type) values(NULL,%i,%f,'%s','%s','%s', %i)", lFileId, bookmark.timeInSeconds, bookmark.thumbNailImage.c_str(), bookmark.player.c_str(), bookmark.playerState.c_str(), (int)type);
1760
1761     m_pDS->exec(strSQL.c_str());
1762   }
1763   catch (...)
1764   {
1765     CLog::Log(LOGERROR, "CVideoDatabase::AddBookMarkToMovie(%s) failed", strFilenameAndPath.c_str());
1766   }
1767 }
1768
1769 void CVideoDatabase::ClearBookMarkOfFile(const CStdString& strFilenameAndPath, CBookmark& bookmark, CBookmark::EType type /*= CBookmark::STANDARD*/)
1770 {
1771   try
1772   {
1773     long lMovieId, lEpisodeId;
1774     long lFileId = GetFile(strFilenameAndPath, lMovieId, lEpisodeId, true);
1775     if (lFileId < 0) return ;
1776     if (NULL == m_pDB.get()) return ;
1777     if (NULL == m_pDS.get()) return ;
1778
1779     /* a litle bit uggly, we clear first bookmark that is within one second of given */
1780     /* should be no problem since we never add bookmarks that are closer than that   */
1781     double mintime = bookmark.timeInSeconds - 0.5f;
1782     double maxtime = bookmark.timeInSeconds + 0.5f;
1783     CStdString strSQL=FormatSQL("select idBookmark from bookmark where idFile=%i and type=%i and (timeInSeconds between %f and %f)", lFileId, type, mintime, maxtime);
1784     m_pDS->query( strSQL.c_str() );
1785     if (m_pDS->num_rows() != 0)
1786     {
1787       int idBookmark = m_pDS->get_field_value("idBookmark").get_asInteger();
1788       strSQL=FormatSQL("delete from bookmark where idBookmark=%i",idBookmark);
1789       m_pDS->exec(strSQL.c_str());
1790     }
1791
1792     m_pDS->close();
1793   }
1794   catch (...)
1795   {
1796     CLog::Log(LOGERROR, "CVideoDatabase::ClearBookMarkOfFile(%s) failed", strFilenameAndPath.c_str());
1797   }
1798 }
1799
1800 //********************************************************************************************************************************
1801 void CVideoDatabase::ClearBookMarksOfFile(const CStdString& strFilenameAndPath, CBookmark::EType type /*= CBookmark::STANDARD*/)
1802 {
1803   try
1804   {
1805     long lMovieId, lEpisodeId;
1806     long lFileId = GetFile(strFilenameAndPath, lMovieId, lEpisodeId, true);
1807     if (lFileId < 0) return ;
1808     if (NULL == m_pDB.get()) return ;
1809     if (NULL == m_pDS.get()) return ;
1810
1811     CStdString strSQL=FormatSQL("delete from bookmark where idFile=%i and type=%i", lFileId, (int)type);
1812     m_pDS->exec(strSQL.c_str());
1813   }
1814   catch (...)
1815   {
1816     CLog::Log(LOGERROR, "CVideoDatabase::ClearBookMarksOfMovie(%s) failed", strFilenameAndPath.c_str());
1817   }
1818 }
1819
1820 //********************************************************************************************************************************
1821 void CVideoDatabase::DeleteMovie(const CStdString& strFilenameAndPath)
1822 {
1823   try
1824   {
1825     long lMovieId, lEpisodeId;
1826     if (NULL == m_pDB.get()) return ;
1827     if (NULL == m_pDS.get()) return ;
1828     if (GetFile(strFilenameAndPath, lMovieId, lEpisodeId) < 0)
1829     {
1830       return ;
1831     }
1832
1833     ClearBookMarksOfFile(strFilenameAndPath);
1834
1835     CStdString strSQL;
1836     strSQL=FormatSQL("update files set idMovie=-1 where idmovie=%i",lMovieId);
1837     m_pDS->exec(strSQL.c_str());
1838
1839     strSQL=FormatSQL("delete from genrelinkmovie where idmovie=%i", lMovieId);
1840     m_pDS->exec(strSQL.c_str());
1841
1842     strSQL=FormatSQL("delete from actorlinkmovie where idmovie=%i", lMovieId);
1843     m_pDS->exec(strSQL.c_str());
1844
1845     strSQL=FormatSQL("delete from directorlinkmovie where idmovie=%i", lMovieId);
1846     m_pDS->exec(strSQL.c_str());
1847
1848     strSQL=FormatSQL("delete from movie where idmovie=%i", lMovieId);
1849     m_pDS->exec(strSQL.c_str());
1850   }
1851   catch (...)
1852   {
1853     CLog::Log(LOGERROR, "CVideoDatabase::DeleteMovie() failed");
1854   }
1855 }
1856
1857 void CVideoDatabase::DeleteTvShow(const CStdString& strPath)
1858 {
1859   try
1860   {
1861     long lTvShowId=-1;
1862     if (NULL == m_pDB.get()) return ;
1863     if (NULL == m_pDS.get()) return ;
1864     lTvShowId = GetTvShowInfo(strPath);
1865     if (lTvShowId < 0)
1866     {
1867       return ;
1868     }
1869
1870     BeginTransaction();
1871     CStdString strSQL=FormatSQL("select idepisode from tvshowlinkepisode where tvshowlinkepisode.idshow=%u",lTvShowId);
1872     m_pDS2->query(strSQL.c_str());
1873     while (!m_pDS2->eof())
1874     {
1875       DeleteEpisode("",m_pDS2->fv(0).get_asLong());
1876       m_pDS2->next();
1877     }
1878
1879     strSQL=FormatSQL("delete from genrelinktvshow where idshow=%i", lTvShowId);
1880     m_pDS->exec(strSQL.c_str());
1881
1882     strSQL=FormatSQL("delete from actorlinktvshow where idshow=%i", lTvShowId);
1883     m_pDS->exec(strSQL.c_str());
1884
1885     strSQL=FormatSQL("delete from directorlinktvshow where idshow=%i", lTvShowId);
1886     m_pDS->exec(strSQL.c_str());
1887
1888     strSQL=FormatSQL("delete from tvshow where idshow=%i", lTvShowId);
1889     m_pDS->exec(strSQL.c_str());
1890
1891     CommitTransaction();
1892   }
1893   catch (...)
1894   {
1895     CLog::Log(LOGERROR, "CVideoDatabase::DeleteTvShow() failed");
1896   }
1897 }
1898
1899 void CVideoDatabase::DeleteEpisode(const CStdString& strFilenameAndPath, long lEpisodeId)
1900 {
1901   try
1902   {
1903     long lMovieId;
1904     if (NULL == m_pDB.get()) return ;
1905     if (NULL == m_pDS.get()) return ;
1906     if (lEpisodeId < 0)
1907     {
1908       if (GetFile(strFilenameAndPath, lMovieId, lEpisodeId) < 0)
1909       {
1910         return ;
1911       }
1912     }
1913
1914     ClearBookMarksOfFile(strFilenameAndPath);
1915
1916     CStdString strSQL;
1917     strSQL=FormatSQL("update files set idEpisode=-1 where idepisode=%i",lEpisodeId);
1918     m_pDS->exec(strSQL.c_str());
1919
1920     strSQL=FormatSQL("delete from genrelinkepisode where idepisode=%i", lEpisodeId);
1921     m_pDS->exec(strSQL.c_str());
1922
1923     strSQL=FormatSQL("delete from actorlinkepisode where idepisode=%i", lEpisodeId);
1924     m_pDS->exec(strSQL.c_str());
1925
1926     strSQL=FormatSQL("delete from directorlinkepisode where idepisode=%i", lEpisodeId);
1927     m_pDS->exec(strSQL.c_str());
1928
1929     strSQL=FormatSQL("select tvshowlinkepisode.idshow from tvshowlinkepisode where idepisode=%u",lEpisodeId);
1930     m_pDS->query(strSQL.c_str());
1931
1932     strSQL=FormatSQL("update tvshow set c%02d=c%02d-1 where idshow=%u",VIDEODB_ID_TV_EPISODES,VIDEODB_ID_TV_EPISODES,m_pDS->fv(0).get_asString());
1933     m_pDS->exec(strSQL);
1934
1935     strSQL=FormatSQL("delete from tvshowlinkepisode where idepisode=%i", lEpisodeId);
1936     m_pDS->exec(strSQL.c_str());
1937
1938     strSQL=FormatSQL("delete from episode where idepisode=%i", lEpisodeId);
1939     m_pDS->exec(strSQL.c_str());
1940   }
1941   catch (...)
1942   {
1943     CLog::Log(LOGERROR, "CVideoDatabase::DeleteEpisode() failed");
1944   }
1945 }
1946
1947 DWORD movieTime = 0;
1948 DWORD castTime = 0;
1949
1950 CIMDBMovie CVideoDatabase::GetDetailsForMovie(auto_ptr<Dataset> &pDS, bool needsCast /* = false */)
1951 {
1952   CIMDBMovie details;
1953   details.Reset();
1954
1955   DWORD time = timeGetTime();
1956   long lMovieId = pDS->fv(0).get_asLong();
1957
1958   for (int iType = VIDEODB_ID_MIN + 1; iType < VIDEODB_ID_MAX; iType++)
1959   {
1960     switch (DbMovieOffsets[iType].type)
1961     {
1962     case VIDEODB_TYPE_STRING:
1963       *(CStdString*)(((char*)&details)+DbMovieOffsets[iType].offset) = pDS->fv(iType+1).get_asString();
1964       break;
1965     case VIDEODB_TYPE_INT:
1966       *(int*)(((char*)&details)+DbMovieOffsets[iType].offset) = pDS->fv(iType+1).get_asInteger();
1967       break;
1968     case VIDEODB_TYPE_BOOL:
1969       *(bool*)(((char*)&details)+DbMovieOffsets[iType].offset) = pDS->fv(iType+1).get_asBool();
1970       break;
1971     case VIDEODB_TYPE_FLOAT:
1972       *(float*)(((char*)&details)+DbMovieOffsets[iType].offset) = pDS->fv(iType+1).get_asFloat();
1973       break;
1974     }
1975   }
1976   details.m_strSearchString.Format("%i", lMovieId);
1977
1978   details.m_strPath = m_pDS->fv(VIDEODB_DETAILS_PATH).get_asString();
1979   CUtil::AddFileToFolder(details.m_strPath, m_pDS->fv(VIDEODB_DETAILS_FILE).get_asString(),details.m_strFileNameAndPath);
1980   movieTime += timeGetTime() - time; time = timeGetTime();
1981
1982   if (needsCast)
1983   {
1984     // create cast string
1985     CStdString strSQL = FormatSQL("select actors.strActor,actorlinkmovie.strRole from actorlinkmovie,actors where actorlinkmovie.idMovie=%u and actorlinkmovie.idActor = actors.idActor",lMovieId);
1986     m_pDS2->query(strSQL.c_str());
1987     while (!m_pDS2->eof())
1988     {
1989       details.m_cast.push_back(make_pair(m_pDS2->fv("actors.strActor").get_asString(), m_pDS2->fv("actorlinkmovie.strRole").get_asString()));
1990       m_pDS2->next();
1991     }
1992     castTime += timeGetTime() - time; time = timeGetTime();
1993   }
1994   return details;
1995 }
1996
1997 CIMDBMovie CVideoDatabase::GetDetailsForTvShow(auto_ptr<Dataset> &pDS, bool needsCast /* = false */, const CStdString &baseDir)
1998 {
1999   CIMDBMovie details;
2000   details.Reset();
2001
2002   DWORD time = timeGetTime();
2003   long lTvShowId = pDS->fv(0).get_asLong();
2004
2005   for (int iType = VIDEODB_ID_TV_MIN + 1; iType < VIDEODB_ID_TV_MAX; iType++)
2006   {
2007     switch (DbTvShowOffsets[iType].type)
2008     {
2009     case VIDEODB_TYPE_STRING:
2010       *(CStdString*)(((char*)&details)+DbTvShowOffsets[iType].offset) = pDS->fv(iType+1).get_asString();
2011       break;
2012     case VIDEODB_TYPE_INT:
2013       *(int*)(((char*)&details)+DbTvShowOffsets[iType].offset) = pDS->fv(iType+1).get_asInteger();
2014       break;
2015     case VIDEODB_TYPE_BOOL:
2016       *(bool*)(((char*)&details)+DbTvShowOffsets[iType].offset) = pDS->fv(iType+1).get_asBool();
2017       break;
2018     case VIDEODB_TYPE_FLOAT:
2019       *(float*)(((char*)&details)+DbTvShowOffsets[iType].offset) = pDS->fv(iType+1).get_asFloat();
2020       break;
2021     }
2022   }
2023   details.m_strSearchString.Format("%i", lTvShowId);
2024   details.m_strPath = m_pDS->fv(VIDEODB_DETAILS_PATH).get_asString();
2025   if (baseDir.IsEmpty())
2026     details.m_strFileNameAndPath = details.m_strPath;
2027   else
2028     details.m_strFileNameAndPath.Format("%s%i/", baseDir.c_str(), lTvShowId);
2029
2030   movieTime += timeGetTime() - time; time = timeGetTime();
2031
2032   if (needsCast)
2033   {
2034     // create cast string
2035     CStdString strSQL = FormatSQL("select actors.strActor,actorlinktvshow.strRole from actorlinktvshow,actors where actorlinktvshow.idShow=%u and actorlinktvshow.idActor = actors.idActor",lTvShowId);
2036     m_pDS2->query(strSQL.c_str());
2037     while (!m_pDS2->eof())
2038     {
2039       details.m_cast.push_back(make_pair(m_pDS2->fv("actors.strActor").get_asString(), m_pDS2->fv("actorlinktvshow.strRole").get_asString()));
2040       m_pDS2->next();
2041     }
2042     castTime += timeGetTime() - time; time = timeGetTime();
2043   }
2044   return details;
2045 }
2046
2047 CIMDBMovie CVideoDatabase::GetDetailsForEpisode(auto_ptr<Dataset> &pDS, bool needsCast /* = false */)
2048 {
2049   CIMDBMovie details;
2050   details.Reset();
2051
2052   DWORD time = timeGetTime();
2053   long lEpisodeId = pDS->fv(0).get_asLong();
2054
2055   for (int iType = VIDEODB_ID_EPISODE_MIN + 1; iType < VIDEODB_ID_EPISODE_MAX; iType++)
2056   {
2057     switch (DbEpisodeOffsets[iType].type)
2058     {
2059     case VIDEODB_TYPE_STRING:
2060       *(CStdString*)(((char*)&details)+DbEpisodeOffsets[iType].offset) = pDS->fv(iType+1).get_asString();
2061       break;
2062     case VIDEODB_TYPE_INT:
2063       *(int*)(((char*)&details)+DbEpisodeOffsets[iType].offset) = pDS->fv(iType+1).get_asInteger();
2064       break;
2065     case VIDEODB_TYPE_BOOL:
2066       *(bool*)(((char*)&details)+DbEpisodeOffsets[iType].offset) = pDS->fv(iType+1).get_asBool();
2067       break;
2068     case VIDEODB_TYPE_FLOAT:
2069       *(float*)(((char*)&details)+DbEpisodeOffsets[iType].offset) = pDS->fv(iType+1).get_asFloat();
2070       break;
2071     }
2072   }
2073   details.m_strSearchString.Format("%i", lEpisodeId);
2074
2075   details.m_strPath = m_pDS->fv(VIDEODB_DETAILS_PATH).get_asString();
2076   CUtil::AddFileToFolder(details.m_strPath, m_pDS->fv(VIDEODB_DETAILS_FILE).get_asString(),details.m_strFileNameAndPath);
2077   movieTime += timeGetTime() - time; time = timeGetTime();
2078
2079   if (needsCast)
2080   {
2081     // create cast string
2082     CStdString strSQL = FormatSQL("select actors.strActor,actorlinkepisode.strRole from actorlinkepisode,actors where actorlinkepisode.idEpisode=%u and actorlinkepisode.idActor = actors.idActor",lEpisodeId);
2083     m_pDS2->query(strSQL.c_str());
2084     while (!m_pDS2->eof())
2085     {
2086       details.m_cast.push_back(make_pair(m_pDS2->fv("actors.strActor").get_asString(), m_pDS2->fv("actorlinkepisode.strRole").get_asString()));
2087       m_pDS2->next();
2088     }
2089     castTime += timeGetTime() - time; time = timeGetTime();
2090   }
2091   return details;
2092 }
2093
2094 /// \brief GetVideoSettings() obtains any saved video settings for the current file.
2095 /// \retval Returns true if the settings exist, false otherwise.
2096 bool CVideoDatabase::GetVideoSettings(const CStdString &strFilenameAndPath, CVideoSettings &settings)
2097 {
2098   try
2099   {
2100     // obtain the FileID (if it exists)
2101 #ifdef NEW_VIDEODB_METHODS
2102     if (NULL == m_pDB.get()) return false;
2103     if (NULL == m_pDS.get()) return false;
2104     CStdString strPath, strFileName;
2105     CUtil::Split(strFilenameAndPath, strPath, strFileName);
2106     CStdString strSQL=FormatSQL("select * from settings, files, path where settings.idfile=files.idfile and path.idpath=files.idpath and path.strPath like '%s' and files.strFileName like '%s'", strPath.c_str() , strFileName.c_str());
2107 #else
2108     long lPathId, lMovieId;
2109     long lFileId = GetFile(strFilenameAndPath, lPathId, lMovieId, true);
2110     if (lFileId < 0) return false;
2111     if (NULL == m_pDB.get()) return false;
2112     if (NULL == m_pDS.get()) return false;
2113     // ok, now obtain the settings for this file
2114     CStdString strSQL=FormatSQL("select * from settings where settings.idFile = '%i'", lFileId);
2115 #endif
2116     m_pDS->query( strSQL.c_str() );
2117     if (m_pDS->num_rows() > 0)
2118     { // get the video settings info
2119       settings.m_AudioDelay = m_pDS->fv("AudioDelay").get_asFloat();
2120       settings.m_AudioStream = m_pDS->fv("AudioStream").get_asInteger();
2121       settings.m_Brightness = m_pDS->fv("Brightness").get_asInteger();
2122       settings.m_Contrast = m_pDS->fv("Contrast").get_asInteger();
2123       settings.m_CustomPixelRatio = m_pDS->fv("PixelRatio").get_asFloat();
2124       settings.m_CustomZoomAmount = m_pDS->fv("ZoomAmount").get_asFloat();
2125       settings.m_Gamma = m_pDS->fv("Gamma").get_asInteger();
2126       settings.m_NonInterleaved = m_pDS->fv("Interleaved").get_asBool();
2127       settings.m_NoCache = m_pDS->fv("NoCache").get_asBool();
2128       settings.m_SubtitleDelay = m_pDS->fv("SubtitleDelay").get_asFloat();
2129       settings.m_SubtitleOn = m_pDS->fv("SubtitlesOn").get_asBool();
2130       settings.m_SubtitleStream = m_pDS->fv("SubtitleStream").get_asInteger();
2131       settings.m_ViewMode = m_pDS->fv("ViewMode").get_asInteger();
2132       settings.m_ResumeTime = m_pDS->fv("ResumeTime").get_asInteger();
2133       settings.m_Crop = m_pDS->fv("Crop").get_asBool();
2134       settings.m_CropLeft = m_pDS->fv("CropLeft").get_asInteger();
2135       settings.m_CropRight = m_pDS->fv("CropRight").get_asInteger();
2136       settings.m_CropTop = m_pDS->fv("CropTop").get_asInteger();
2137       settings.m_CropBottom = m_pDS->fv("CropBottom").get_asInteger();
2138       settings.m_InterlaceMethod = (EINTERLACEMETHOD)m_pDS->fv("Deinterlace").get_asInteger();
2139       settings.m_VolumeAmplification = m_pDS->fv("VolumeAmplification").get_asFloat();
2140       settings.m_OutputToAllSpeakers = m_pDS->fv("OutputToAllSpeakers").get_asBool();
2141       settings.m_SubtitleCached = false;
2142       m_pDS->close();
2143       return true;
2144     }
2145     m_pDS->close();
2146   }
2147   catch (...)
2148   {
2149     CLog::Log(LOGERROR, "CVideoDatabase::GetVideoSettings() failed");
2150   }
2151   return false;
2152 }
2153
2154 /// \brief Sets the settings for a particular video file
2155 void CVideoDatabase::SetVideoSettings(const CStdString& strFilenameAndPath, const CVideoSettings &setting)
2156 {
2157   try
2158   {
2159     long lMovieId, lEpisodeId;
2160     if (NULL == m_pDB.get()) return ;
2161     if (NULL == m_pDS.get()) return ;
2162     long lFileId = GetFile(strFilenameAndPath, lMovieId, lEpisodeId, true);
2163     if (lFileId < 0)
2164     { // no files found - we have to add one
2165       lFileId = AddFile(strFilenameAndPath);
2166       if (lFileId < 0) return ;
2167     }
2168     CStdString strSQL;
2169     strSQL.Format("select * from settings where idFile=%i", lFileId);
2170     m_pDS->query( strSQL.c_str() );
2171     if (m_pDS->num_rows() > 0)
2172     {
2173       m_pDS->close();
2174       // update the item
2175       strSQL=FormatSQL("update settings set Interleaved=%i,NoCache=%i,Deinterlace=%i,FilmGrain=%i,ViewMode=%i,ZoomAmount=%f,PixelRatio=%f,"
2176                        "AudioStream=%i,SubtitleStream=%i,SubtitleDelay=%f,SubtitlesOn=%i,Brightness=%i,Contrast=%i,Gamma=%i,"
2177                        "VolumeAmplification=%f,AudioDelay=%f,OutputToAllSpeakers=%i,",
2178                        setting.m_NonInterleaved, setting.m_NoCache, setting.m_InterlaceMethod, setting.m_FilmGrain, setting.m_ViewMode, setting.m_CustomZoomAmount, setting.m_CustomPixelRatio,
2179                        setting.m_AudioStream, setting.m_SubtitleStream, setting.m_SubtitleDelay, setting.m_SubtitleOn,
2180                        setting.m_Brightness, setting.m_Contrast, setting.m_Gamma, setting.m_VolumeAmplification, setting.m_AudioDelay,
2181                        setting.m_OutputToAllSpeakers);
2182       CStdString strSQL2;
2183       strSQL2=FormatSQL("ResumeTime=%i,Crop=%i,CropLeft=%i,CropRight=%i,CropTop=%i,CropBottom=%i where idFile=%i\n", setting.m_ResumeTime, setting.m_Crop, setting.m_CropLeft, setting.m_CropRight, setting.m_CropTop, setting.m_CropBottom, lFileId);
2184       strSQL += strSQL2;
2185       m_pDS->exec(strSQL.c_str());
2186       return ;
2187     }
2188     else
2189     { // add the items
2190       m_pDS->close();
2191       strSQL=FormatSQL("insert into settings ( idFile,Interleaved,NoCache,Deinterlace,FilmGrain,ViewMode,ZoomAmount,PixelRatio,"
2192                        "AudioStream,SubtitleStream,SubtitleDelay,SubtitlesOn,Brightness,Contrast,Gamma,"
2193                        "VolumeAmplification,AudioDelay,OutputToAllSpeakers,ResumeTime,Crop,CropLeft,CropRight,CropTop,CropBottom)"
2194                        " values (%i,%i,%i,%i,%i,%i,%f,%f,%i,%i,%f,%i,%i,%i,%i,%f,%f,",
2195                        lFileId, setting.m_NonInterleaved, setting.m_NoCache, setting.m_InterlaceMethod, setting.m_FilmGrain, setting.m_ViewMode, setting.m_CustomZoomAmount, setting.m_CustomPixelRatio,
2196                        setting.m_AudioStream, setting.m_SubtitleStream, setting.m_SubtitleDelay, setting.m_SubtitleOn,
2197                        setting.m_Brightness, setting.m_Contrast, setting.m_Gamma, setting.m_VolumeAmplification, setting.m_AudioDelay);
2198       CStdString strSQL2;
2199       strSQL2=FormatSQL("%i,%i,%i,%i,%i,%i,%i)\n", setting.m_OutputToAllSpeakers, setting.m_ResumeTime, setting.m_Crop, setting.m_CropLeft, setting.m_CropRight,
2200                     setting.m_CropTop, setting.m_CropBottom);
2201       strSQL += strSQL2;
2202       m_pDS->exec(strSQL.c_str());
2203     }
2204   }
2205   catch (...)
2206   {
2207     CLog::Log(LOGERROR, "CVideoDatabase::SetVideoSettings(%s) failed", strFilenameAndPath.c_str());
2208   }
2209 }
2210
2211 /// \brief GetStackTimes() obtains any saved video times for the stacked file
2212 /// \retval Returns true if the stack times exist, false otherwise.
2213 bool CVideoDatabase::GetStackTimes(const CStdString &filePath, vector<long> &times)
2214 {
2215   try
2216   {
2217     // obtain the FileID (if it exists)
2218     long lMovieId, lEpisodeId;
2219     long lFileId = GetFile(filePath, lMovieId, lEpisodeId, true);
2220     if (lFileId < 0) return false;
2221     if (NULL == m_pDB.get()) return false;
2222     if (NULL == m_pDS.get()) return false;
2223     // ok, now obtain the settings for this file
2224     CStdString strSQL=FormatSQL("select times from stacktimes where idFile=%i\n", lFileId);
2225     m_pDS->query( strSQL.c_str() );
2226     if (m_pDS->num_rows() > 0)
2227     { // get the video settings info
2228       CStdStringArray timeString;
2229       long timeTotal = 0;
2230       StringUtils::SplitString(m_pDS->fv("times").get_asString(), ",", timeString);
2231       times.clear();
2232       for (unsigned int i = 0; i < timeString.size(); i++)
2233       {
2234         times.push_back(atoi(timeString[i].c_str()));
2235         timeTotal += atoi(timeString[i].c_str());
2236       }
2237       m_pDS->close();
2238       return (timeTotal > 0);
2239     }
2240     m_pDS->close();
2241   }
2242   catch (...)
2243   {
2244     CLog::Log(LOGERROR, "CVideoDatabase::GetStackTimes() failed");
2245   }
2246   return false;
2247 }
2248
2249 /// \brief Sets the stack times for a particular video file
2250 void CVideoDatabase::SetStackTimes(const CStdString& filePath, vector<long> &times)
2251 {
2252   try
2253   {
2254     long lMovieId, lEpisodeId;
2255     if (NULL == m_pDB.get()) return ;
2256     if (NULL == m_pDS.get()) return ;
2257     long lFileId = GetFile(filePath, lMovieId, lEpisodeId, true);
2258     if (lFileId < 0)
2259     { // no files found - we have to add one
2260       lMovieId = AddMovie(filePath);
2261       lFileId = GetFile(filePath, lMovieId, lEpisodeId, true);
2262       if (lFileId < 0) return ;
2263     }
2264
2265     // delete any existing items
2266     m_pDS->exec( FormatSQL("delete from stacktimes where idFile=%i", lFileId) );
2267
2268     // add the items
2269     CStdString timeString;
2270     timeString.Format("%i", times[0]);
2271     for (unsigned int i = 1; i < times.size(); i++)
2272     {
2273       CStdString time;
2274       time.Format(",%i", times[i]);
2275       timeString += time;
2276     }
2277     m_pDS->exec( FormatSQL("insert into stacktimes (idFile,times) values (%i,'%s')\n", lFileId, timeString.c_str()) );
2278   }
2279   catch (...)
2280   {
2281     CLog::Log(LOGERROR, "CVideoDatabase::SetStackTimes(%s) failed", filePath.c_str());
2282   }
2283 }
2284
2285 void CVideoDatabase::RemoveContentForPath(const CStdString& strPath)
2286 {
2287   try
2288   {
2289     if (NULL == m_pDB.get()) return ;
2290     if (NULL == m_pDS.get()) return ;
2291
2292     std::auto_ptr<Dataset> pDS(m_pDB->CreateDataset());
2293     CStdString strPath1(strPath);
2294     CUtil::RemoveSlashAtEnd(strPath1);
2295
2296     
2297     CStdString strSQL = FormatSQL("select idPath,strContent,strPath from path where strPath like '%%%s%%'",strPath1.c_str());
2298     pDS->query(strSQL.c_str());
2299     bool bEncodedChecked=false;
2300     while (!pDS->eof())
2301     {
2302       long lPathId = pDS->fv("path.idPath").get_asLong();
2303       CStdString strCurrPath = pDS->fv("path.strPath").get_asString();
2304 //      if (pDS->fv("path.strContent").get_asString() == "movies")
2305       {
2306         strSQL=FormatSQL("select strFilename from files where files.idPath=%u and NOT (files.idMovie=-1)",lPathId);
2307         m_pDS2->query(strSQL.c_str());
2308         while (!m_pDS2->eof())
2309         {
2310           CStdString strMoviePath;
2311           CUtil::AddFileToFolder(strCurrPath,m_pDS2->fv("files.strFilename").get_asString(),strMoviePath);
2312           DeleteMovie(strMoviePath);
2313           m_pDS2->next();
2314         }
2315       }
2316       pDS->next();
2317       if (pDS->eof() && !bEncodedChecked) // rarred titles needs this
2318       {
2319         CStdString strEncoded(strPath);
2320         CUtil::URLEncode(strEncoded);
2321         CStdString strSQL = FormatSQL("select idPath,strContent,strPath from path where strPath like '%%%s%%'",strEncoded.c_str());
2322         pDS->query(strSQL.c_str());
2323         bEncodedChecked = true;
2324       }
2325     }
2326     strSQL = FormatSQL("update path set strContent = '', strScraper='' where strPath like '%%%s%%'",strPath1.c_str());
2327     pDS->exec(strSQL);
2328
2329     CStdString strEncoded(strPath);
2330     CUtil::URLEncode(strEncoded);
2331     strSQL = FormatSQL("update path set strContent = '', strScraper='' where strPath like '%%%s%%'",strEncoded.c_str());
2332     pDS->exec(strSQL);
2333   }
2334   catch (...)
2335   {
2336     CLog::Log(LOGERROR, "CVideoDatabase::RemoveContentFromPath(%s) failed", strPath.c_str());
2337   }
2338 }
2339
2340 void CVideoDatabase::SetScraperForPath(const CStdString& filePath, const CStdString& strScraper, const CStdString& strContent)
2341 {
2342   try
2343   {
2344     if (NULL == m_pDB.get()) return ;
2345     if (NULL == m_pDS.get()) return ;
2346     long lPathId = GetPath(filePath);
2347     if (lPathId < 0)
2348     { // no path found - we have to add one
2349       lPathId = AddPath(filePath);
2350       if (lPathId < 0) return ;
2351     }
2352
2353     // Update
2354     CStdString strSQL =FormatSQL("update path set strContent='%s',strScraper='%s' where idPath=%u", strContent.c_str(), strScraper.c_str(), lPathId);
2355     m_pDS->exec(strSQL.c_str());
2356   }
2357   catch (...)
2358   {
2359     CLog::Log(LOGERROR, "CVideoDatabase::SetScraperForPath(%s) failed", filePath.c_str());
2360   }
2361 }
2362
2363 bool CVideoDatabase::UpdateOldVersion(int iVersion)
2364 {
2365   return true;
2366 }
2367
2368 void CVideoDatabase::MarkAsWatched(const CFileItem &item)
2369 {
2370   // find the movie in the db
2371   long movieID = -1;
2372   if (item.m_musicInfoTag.GetURL().IsEmpty())
2373     movieID = GetMovieInfo(item.m_strPath);
2374   else
2375     movieID = atol(item.m_musicInfoTag.GetURL().c_str());
2376   bool bEpisode=false;
2377   if (movieID < 0)
2378   {
2379     bEpisode = true;
2380     movieID = GetEpisodeInfo(item.m_strPath);
2381     if (movieID < 0)
2382       return;    
2383   }
2384   // and mark as watched
2385   MarkAsWatched(movieID,bEpisode);
2386 }
2387
2388 void CVideoDatabase::MarkAsWatched(long lMovieId, bool bEpisode /* = false */)
2389 {
2390   try
2391   {
2392     if (NULL == m_pDB.get()) return ;
2393     if (NULL == m_pDS.get()) return ;
2394     CStdString strSQL;
2395     if (bEpisode)
2396     {
2397       CLog::Log(LOGINFO, "Updating Episode:%i as Watched", lMovieId);
2398       strSQL.Format("UPDATE episode set c%02d='true' WHERE idEpisode=%u", VIDEODB_ID_EPISODE_WATCHED, lMovieId);
2399     }
2400     else
2401     {
2402       CLog::Log(LOGINFO, "Updating Movie:%i as Watched", lMovieId);
2403       strSQL.Format("UPDATE movie set c%02d='true' WHERE idMovie=%u", VIDEODB_ID_WATCHED, lMovieId);
2404     }
2405
2406     m_pDS->exec(strSQL.c_str());
2407   }
2408   catch (...)
2409   {
2410           CLog::Log(LOGERROR, "CVideoDatabase::MarkAsWatched(long lMovieId) failed on MovieID:%i", lMovieId);
2411   }
2412 }
2413
2414 void CVideoDatabase::MarkAsUnWatched(long lMovieId, bool bEpisode /* = false */)
2415 {
2416   try
2417   {
2418     if (NULL == m_pDB.get()) return ;
2419     if (NULL == m_pDS.get()) return ;
2420     CStdString strSQL;
2421     if (bEpisode)
2422     {
2423       CLog::Log(LOGINFO, "Updating Episode:%i as UnWatched", lMovieId);
2424       strSQL.Format("UPDATE episode set c%02d='false' WHERE idEpisode=%u", VIDEODB_ID_EPISODE_WATCHED, lMovieId);
2425     }
2426     else
2427     {
2428       CLog::Log(LOGINFO, "Updating Movie:%i as UnWatched", lMovieId);
2429       strSQL.Format("UPDATE movie set c%02d='false' WHERE idMovie=%u", VIDEODB_ID_WATCHED, lMovieId);
2430     }
2431     m_pDS->exec(strSQL.c_str());
2432   }
2433   catch (...)
2434   {
2435     CLog::Log(LOGERROR, "CVideoDatabase::MarkAsUnWatched(long lMovieId) failed on MovieID:%i", lMovieId);
2436   }
2437 }
2438
2439 void CVideoDatabase::UpdateMovieTitle(long lMovieId, const CStdString& strNewMovieTitle, int iType)
2440 {
2441   try
2442   {
2443     if (NULL == m_pDB.get()) return ;
2444     if (NULL == m_pDS.get()) return ;
2445     CStdString strSQL;
2446     if (iType == 2)
2447     {
2448       CLog::Log(LOGINFO, "Changing TvShow:id:%i New Title:%s", lMovieId, strNewMovieTitle.c_str());
2449       strSQL.Format("UPDATE tvshow SET c%02d='%s' WHERE idShow=%i", VIDEODB_ID_TV_TITLE, strNewMovieTitle.c_str(), lMovieId );
2450     }
2451     else if (iType == 1)
2452     {
2453       CLog::Log(LOGINFO, "Changing Episode:id:%i New Title:%s", lMovieId, strNewMovieTitle.c_str());
2454       strSQL.Format("UPDATE episode SET c%02d='%s' WHERE idEpisode=%i", VIDEODB_ID_EPISODE_TITLE, strNewMovieTitle.c_str(), lMovieId );
2455     }
2456     else
2457     {
2458       CLog::Log(LOGINFO, "Changing Movie:id:%i New Title:%s", lMovieId, strNewMovieTitle.c_str());
2459       strSQL.Format("UPDATE movie SET c%02d='%s' WHERE idMovie=%i", VIDEODB_ID_TITLE, strNewMovieTitle.c_str(), lMovieId );
2460     }
2461     m_pDS->exec(strSQL.c_str());
2462   }
2463   catch (...)
2464   {
2465           CLog::Log(LOGERROR, "CVideoDatabase::UpdateMovieTitle(long lMovieId, const CStdString& strNewMovieTitle) failed on MovieID:%i and Title:%s", lMovieId, strNewMovieTitle);
2466   }
2467 }
2468
2469 /// \brief EraseVideoSettings() Erases the videoSettings table and reconstructs it
2470 void CVideoDatabase::EraseVideoSettings()
2471 {
2472   try
2473   {
2474     CLog::Log(LOGINFO, "Deleting settings information for all movies");
2475     m_pDS->exec("delete from settings");
2476   }
2477   catch (...)
2478   {
2479     CLog::Log(LOGERROR, "CVideoDatabase::EraseVideoSettings() failed");
2480   }
2481 }
2482
2483 bool CVideoDatabase::GetGenresNav(const CStdString& strBaseDir, CFileItemList& items, long idContent)
2484 {
2485   try
2486   {
2487     if (NULL == m_pDB.get()) return false;
2488     if (NULL == m_pDS.get()) return false;
2489
2490 //    DWORD time = timeGetTime();
2491     // get primary genres for movies
2492     CStdString strSQL;
2493     if (g_settings.m_vecProfiles[0].getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
2494     {
2495       if (idContent == VIDEODB_CONTENT_MOVIES)
2496       {
2497         strSQL=FormatSQL("select genre.idgenre,genre.strgenre,path.strPath from genre,genrelinkmovie,movie,path,files where genre.idGenre=genrelinkMovie.idGenre and genrelinkMovie.idMovie = movie.idMovie and files.idMovie=movie.idMovie and path.idPath = files.idPath");
2498         if (g_stSettings.m_iMyVideoWatchMode == 1)
2499           strSQL += FormatSQL(" and movie.c%02d='false'", VIDEODB_ID_WATCHED);
2500
2501         if (g_stSettings.m_iMyVideoWatchMode == 2)
2502           strSQL += FormatSQL(" and movie.c%02d='true'", VIDEODB_ID_WATCHED);
2503       }
2504       else if (idContent == VIDEODB_CONTENT_TVSHOWS)
2505       {
2506         strSQL=FormatSQL("select genre.idgenre,genre.strgenre,path.strPath from genre,genrelinktvshow,tvshow,tvshowlinkpath,files,path where genre.idGenre=genrelinkTvShow.idGenre and genrelinkTvShow.idShow = tvshow.idshow and files.idPath=tvshowlinkpath.idPath and tvshowlinkpath.idShow=tvshow.idShow and path.idPath = files.idPath");
2507       }
2508     }
2509     else
2510     {
2511       if (idContent == VIDEODB_CONTENT_MOVIES)
2512       {
2513         strSQL=FormatSQL("select distinct genre.idgenre,genre.strgenre from genre,genrelinkmovie,movie where genre.idGenre=genrelinkMovie.idGenre and genrelinkMovie.idMovie = movie.idMovie");
2514         if (g_stSettings.m_iMyVideoWatchMode == 1)
2515           strSQL += FormatSQL(" and movie.c%02d='false'", VIDEODB_ID_WATCHED);
2516
2517         if (g_stSettings.m_iMyVideoWatchMode == 2)
2518           strSQL += FormatSQL(" and movie.c%02d='true'", VIDEODB_ID_WATCHED);
2519       }
2520       else if (idContent == VIDEODB_CONTENT_TVSHOWS)
2521       {
2522         strSQL=FormatSQL("select distinct genre.idgenre,genre.strgenre from genre,genrelinktvshow,tvshow where genre.idGenre=genrelinkTvShow.idGenre and genrelinkTvShow.idShow = tvshow.idshow");
2523       }
2524     }
2525
2526     // run query
2527     CLog::Log(LOGDEBUG, "CVideoDatabase::GetGenresNav() query: %s", strSQL.c_str());
2528     if (!m_pDS->query(strSQL.c_str())) return false;
2529     int iRowsFound = m_pDS->num_rows();
2530     if (iRowsFound == 0)
2531     {
2532       m_pDS->close();
2533       return true;
2534     }
2535
2536     if (g_settings.m_vecProfiles[0].getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
2537     {
2538       map<long, CStdString> mapGenres;
2539       map<long, CStdString>::iterator it;
2540       while (!m_pDS->eof())
2541       {
2542         long lGenreId = m_pDS->fv("genre.idgenre").get_asLong();
2543         CStdString strGenre = m_pDS->fv("genre.strgenre").get_asString();
2544         it = mapGenres.find(lGenreId);
2545         // was this genre already found?
2546         if (it == mapGenres.end())
2547         {
2548           // check path
2549           CStdString strPath;
2550           if (g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_vecMyVideoShares))
2551             mapGenres.insert(pair<long, CStdString>(lGenreId, strGenre));
2552         }
2553         m_pDS->next();
2554       }
2555       m_pDS->close();
2556
2557       for (it=mapGenres.begin();it != mapGenres.end();++it)
2558       {
2559         CFileItem* pItem=new CFileItem(it->second);
2560         CStdString strDir;
2561         strDir.Format("%ld/", it->first);
2562         pItem->m_strPath=strBaseDir + strDir;
2563         pItem->m_bIsFolder=true;
2564         pItem->SetLabelPreformated(true);
2565         items.Add(pItem);
2566       }
2567     }
2568     else
2569     {
2570       while (!m_pDS->eof())
2571       {
2572         CFileItem* pItem=new CFileItem(m_pDS->fv("genre.strgenre").get_asString());
2573         CStdString strDir;
2574         strDir.Format("%ld/", m_pDS->fv("genre.idgenre").get_asLong());
2575         pItem->m_strPath=strBaseDir + strDir;
2576         pItem->m_bIsFolder=true;
2577         pItem->SetLabelPreformated(true);
2578         items.Add(pItem);
2579         m_pDS->next();
2580       }
2581       m_pDS->close();
2582     }
2583
2584 //    CLog::Log(LOGDEBUG, __FUNCTION__" Time: %d ms", timeGetTime() - time);
2585     return true;
2586   }
2587   catch (...)
2588   {
2589     CLog::Log(LOGERROR, "CVideoDatabase:GetGenresNav() failed");
2590   }
2591   return false;
2592 }
2593
2594 bool CVideoDatabase::GetDirectorsNav(const CStdString& strBaseDir, CFileItemList& items, long idContent)
2595 {
2596   try
2597   {
2598     if (NULL == m_pDB.get()) return false;
2599     if (NULL == m_pDS.get()) return false;
2600
2601     // get primary genres for movies
2602     CStdString strSQL;
2603     if (g_settings.m_vecProfiles[0].getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
2604     {
2605       if (idContent == VIDEODB_CONTENT_MOVIES)
2606       {
2607         strSQL=FormatSQL("select actors.idActor,actors.strActor,path.strPath from actors,directorlinkmovie,movie,path,files where actor.idActor=directorlinkMovie.idDirector and directorlinkMovie.idMovie = movie.idMovie and files.idMovie=movie.idMovie and path.idPath = files.idPath");
2608         if (g_stSettings.m_iMyVideoWatchMode == 1)
2609           strSQL += FormatSQL(" and movie.c%02d='true')", VIDEODB_ID_WATCHED);
2610         if (g_stSettings.m_iMyVideoWatchMode == 2)
2611           strSQL += FormatSQL(" and movie.c%02d='true'", VIDEODB_ID_WATCHED);
2612       }
2613       else if (idContent == VIDEODB_CONTENT_TVSHOWS)
2614       {
2615         strSQL=FormatSQL("select actors.idActor,actors.strActor,path.strPath from actors,directorlinktvshow,tvshow,path,files,tvshowlinkepisode where actor.idActor=directorlinktvshow.idDirector and directorlinktvshow.idShow = tvshow.idShow and files.idEpisode=episode.idEpisode and tvshowlinkepisode.idShow=tvshow.idShow and episode.idEpisode=tvshowlinkepisode.idEpisode and path.idPath = files.idPath");
2616       }
2617       else
2618       { // TODO: JOINED QUERY IN LOCKED STATE
2619       }
2620     }
2621     else
2622     {
2623       if (idContent == VIDEODB_CONTENT_MOVIES)
2624       {
2625         strSQL=FormatSQL("select distinct actors.idActor,actors.strActor from actors,directorlinkmovie,movie where actors.idActor=directorlinkMovie.idDirector and directorlinkMovie.idMovie = movie.idMovie");
2626         if (g_stSettings.m_iMyVideoWatchMode == 1)
2627           strSQL += FormatSQL(" and movie.c%02d='true')", VIDEODB_ID_WATCHED);
2628
2629         if (g_stSettings.m_iMyVideoWatchMode == 2)
2630           strSQL += FormatSQL(" and movie.c%02d='true'", VIDEODB_ID_WATCHED);
2631       }
2632       else if (idContent == VIDEODB_CONTENT_TVSHOWS)
2633       {
2634         strSQL=FormatSQL("select distinct actors.idActor,actors.strActor from actors,directorlinktvshow,tvshow where actors.idActor=directorlinktvshow.idDirector and directorlinktvshow.idShow = tvshow.idShow");
2635       }
2636       else
2637       {
2638         if (g_stSettings.m_iMyVideoWatchMode == 1)
2639           strSQL=FormatSQL("select distinct actors.idActor,actors.strActor from actors,directorlinkmovie,movie where actors.idActor=directorlinkMovie.idDirector and directorlinkMovie.idMovie = movie.idMovie and movie.c%02d='false' union select distinct actors.idActor,actors.strActor from actors,directorlinktvshow,tvshow where actors.idActor=directorlinktvshow.idDirector and directorlinktvshow.idShow = tvshow.idShow",VIDEODB_ID_WATCHED); 
2640         else if (g_stSettings.m_iMyVideoWatchMode == 2)
2641           strSQL=FormatSQL("select distinct actors.idActor,actors.strActor from actors,directorlinkmovie,movie where actors.idActor=directorlinkMovie.idDirector and directorlinkMovie.idMovie = movie.idMovie and movie.c%02d='true' union select distinct actors.idActor,actors.strActor from actors,directorlinktvshow,tvshow where actors.idActor=directorlinktvshow.idDirector and directorlinktvshow.idShow = tvshow.idShow",VIDEODB_ID_WATCHED); 
2642         else
2643           strSQL=FormatSQL("select distinct actors.idActor,actors.strActor from actors,directorlinkmovie,movie where actors.idActor=directorlinkMovie.idDirector and directorlinkMovie.idMovie = movie.idMovie union select distinct actors.idActor,actors.strActor from actors,directorlinktvshow,tvshow where actors.idActor=directorlinktvshow.idDirector and directorlinktvshow.idShow = tvshow.idShow"); 
2644       }
2645     }
2646
2647     // run query
2648     CLog::Log(LOGDEBUG, "CVideoDatabase::GetDirectorsNav() query: %s", strSQL.c_str());
2649     if (!m_pDS->query(strSQL.c_str())) return false;
2650     int iRowsFound = m_pDS->num_rows();
2651     if (iRowsFound == 0)
2652     {
2653       m_pDS->close();
2654       return true;
2655     }
2656
2657     if (g_settings.m_vecProfiles[0].getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
2658     {
2659       map<long, CStdString> mapDirector;
2660       map<long, CStdString>::iterator it;
2661       while (!m_pDS->eof())
2662       {
2663         long lDirectorId = m_pDS->fv("actors.idactor").get_asLong();
2664         CStdString strDirector = m_pDS->fv("actors.strActor").get_asString();
2665         it = mapDirector.find(lDirectorId);
2666         // was this genre already found?
2667         if (it == mapDirector.end())
2668         {
2669           // check path
2670           CStdString strPath;
2671           if (g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_vecMyVideoShares))
2672             mapDirector.insert(pair<long, CStdString>(lDirectorId, strDirector));
2673         }
2674         m_pDS->next();
2675       }
2676       m_pDS->close();
2677
2678       for (it=mapDirector.begin();it != mapDirector.end();++it)
2679       {
2680         CFileItem* pItem=new CFileItem(it->second);
2681         CStdString strDir;
2682         strDir.Format("%ld/", it->first);
2683         pItem->m_strPath=strBaseDir + strDir;
2684         pItem->m_bIsFolder=true;
2685         pItem->SetLabelPreformated(true);
2686         items.Add(pItem);
2687       }
2688     }
2689     else
2690     {
2691       while (!m_pDS->eof())
2692       {
2693         CFileItem* pItem=new CFileItem(m_pDS->fv("actors.strActor").get_asString());
2694         CStdString strDir;
2695         strDir.Format("%ld/", m_pDS->fv("actors.idactor").get_asLong());
2696         pItem->m_strPath=strBaseDir + strDir;
2697         pItem->m_bIsFolder=true;
2698         pItem->SetLabelPreformated(true);
2699         items.Add(pItem);
2700         m_pDS->next();
2701       }
2702       m_pDS->close();
2703     }
2704       
2705     return true;
2706   }
2707   catch (...)
2708   {
2709     CLog::Log(LOGERROR, "CVideoDatabase:GetDirectorsNav() failed");
2710   }
2711   return false;
2712 }
2713
2714 bool CVideoDatabase::GetActorsNav(const CStdString& strBaseDir, CFileItemList& items, long idContent)
2715 {
2716   try
2717   {
2718     if (NULL == m_pDB.get()) return false;
2719     if (NULL == m_pDS.get()) return false;
2720
2721 //    DWORD time = timeGetTime();
2722     CStdString strSQL;
2723     
2724     if (g_settings.m_vecProfiles[0].getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
2725     {
2726       if (idContent == VIDEODB_CONTENT_MOVIES)
2727       {
2728         strSQL=FormatSQL("select actors.idactor,actors.strActor,path.strPath from actorlinkmovie,actors,movie,files,path where actors.idActor=actorlinkmovie.idActor and actorlinkmovie.idmovie=movie.idmovie and files.idMovie = movie.idMovie and files.idPath = path.idPath");
2729         if (g_stSettings.m_iMyVideoWatchMode == 1)
2730           strSQL += FormatSQL(" and movie.c%02d='false'", VIDEODB_ID_WATCHED);
2731         if (g_stSettings.m_iMyVideoWatchMode == 2)
2732           strSQL += FormatSQL(" and movie.c%02d='true'", VIDEODB_ID_WATCHED);
2733       }
2734       if (idContent == VIDEODB_CONTENT_TVSHOWS)
2735       {
2736         strSQL=FormatSQL("select actors.idactor,actors.strActor,path.strPath from actorlinkepisode,actors,episode,files,path where actors.idActor=actorlinkepisode.idActor and actorlinkepisode.idepisode=episode.idepisode and files.idEpisode = episode.idEpisode and files.idPath = path.idPath");
2737         if (g_stSettings.m_iMyVideoWatchMode == 1)
2738           strSQL += FormatSQL(" and episode.c%02d='false'", VIDEODB_ID_WATCHED);
2739         if (g_stSettings.m_iMyVideoWatchMode == 2)
2740           strSQL += FormatSQL(" and episode.c%02d='true'", VIDEODB_ID_WATCHED);
2741       }
2742     }
2743     else
2744     {
2745       if (idContent == VIDEODB_CONTENT_MOVIES)
2746       {
2747         strSQL=FormatSQL("select distinct actors.idactor,actors.strActor from actorlinkmovie,actors,movie where actors.idActor=actorlinkmovie.idActor and actorlinkmovie.idmovie=movie.idmovie");
2748         if (g_stSettings.m_iMyVideoWatchMode == 1)
2749           strSQL += FormatSQL(" and movie.c%02d='false'", VIDEODB_ID_WATCHED);
2750         if (g_stSettings.m_iMyVideoWatchMode == 2)
2751           strSQL += FormatSQL(" and movie.c%02d='true'", VIDEODB_ID_WATCHED);
2752       }
2753       else if (idContent == VIDEODB_CONTENT_TVSHOWS)
2754       {
2755         strSQL=FormatSQL("select distinct actors.idactor,actors.strActor from actorlinktvshow,actors,tvshow where actors.idActor=actorlinktvshow.idActor and actorlinktvshow.idshow=tvshow.idshow");
2756       }
2757     }
2758
2759     if (!m_pDS->query(strSQL.c_str())) return false;
2760     int iRowsFound = m_pDS->num_rows();
2761     if (iRowsFound == 0)
2762     {
2763       m_pDS->close();
2764       return true;
2765     }
2766
2767     if (g_settings.m_vecProfiles[0].getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
2768     {
2769       map<long, CStdString> mapActors;
2770       map<long, CStdString>::iterator it;
2771       long lLastPathId = -1;
2772
2773       while (!m_pDS->eof())
2774       {
2775         long lActorId = m_pDS->fv("actors.idactor").get_asLong();
2776         CStdString strActor = m_pDS->fv("actors.strActor").get_asString();
2777         it = mapActors.find(lActorId);
2778         // is this actor already known?
2779         if (it == mapActors.end())
2780         {
2781           // check path
2782           if (g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_vecMyVideoShares))
2783             mapActors.insert(pair<long, CStdString>(lActorId, strActor));
2784         }
2785         m_pDS->next();
2786       }
2787       m_pDS->close();
2788
2789       for (it=mapActors.begin();it != mapActors.end();++it)
2790       {
2791         CFileItem* pItem=new CFileItem(it->second);
2792         CStdString strDir;
2793         strDir.Format("%ld/", it->first);
2794         pItem->m_strPath=strBaseDir + strDir;
2795         pItem->m_bIsFolder=true;
2796         items.Add(pItem);
2797       }
2798     }
2799     else
2800     {
2801       while (!m_pDS->eof())
2802       {
2803         CFileItem* pItem=new CFileItem(m_pDS->fv("actors.strActor").get_asString());
2804         CStdString strDir;
2805         strDir.Format("%ld/", m_pDS->fv("actors.idactor").get_asLong());
2806         pItem->m_strPath=strBaseDir + strDir;
2807         pItem->m_bIsFolder=true;
2808         items.Add(pItem);
2809         m_pDS->next();
2810       }
2811       m_pDS->close();
2812     }
2813
2814 //    CLog::Log(LOGDEBUG, __FUNCTION__" Time: %d ms", timeGetTime() - time);
2815     return true;
2816   }
2817   catch (...)
2818   {
2819     CLog::Log(LOGERROR, "CVideoDatabase:GetActorsNav() failed");
2820   }
2821   return false;
2822 }
2823
2824 bool CVideoDatabase::GetYearsNav(const CStdString& strBaseDir, CFileItemList& items, long idContent)
2825 {
2826   try
2827   {
2828     if (NULL == m_pDB.get()) return false;
2829     if (NULL == m_pDS.get()) return false;
2830
2831     CStdString strSQL;
2832     CStdString addParam;
2833     if (idContent == VIDEODB_CONTENT_MOVIES)
2834     {
2835       if (g_stSettings.m_iMyVideoWatchMode == 1)
2836         addParam = FormatSQL("movie.c%02d='false'", VIDEODB_ID_WATCHED);
2837
2838       if (g_stSettings.m_iMyVideoWatchMode == 2)
2839         addParam = FormatSQL("movie.c%02d='true'", VIDEODB_ID_WATCHED);
2840
2841       if (g_settings.m_vecProfiles[0].getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
2842       {
2843         if (!addParam.IsEmpty())
2844           addParam = " and "+addParam;
2845         strSQL = FormatSQL("select movie.c%02d,path.strPath from movie,files,path where movie.idMovie = files.idMovie and files.idPath = path.idPath", VIDEODB_ID_YEAR);
2846       }
2847       else
2848       {
2849         if (!addParam.IsEmpty())
2850           addParam = " where "+addParam;
2851         strSQL = FormatSQL("select distinct movie.c%02d from movie", VIDEODB_ID_YEAR);
2852       }
2853     }
2854     else if (idContent == VIDEODB_CONTENT_TVSHOWS)
2855     {
2856       if (g_settings.m_vecProfiles[0].getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
2857         strSQL = FormatSQL("select tvshow.c%02d,path.strPath from tvshow,files,path,tvshowlinkepisode where tvshow.idShow = tvshowlinkepisode.idShow and files.idEpisode = tvshowlinkepisode.idEpisode and files.idPath = path.idPath", VIDEODB_ID_YEAR);
2858       else
2859         strSQL = FormatSQL("select distinct tvshow.c%02d from tvshow", VIDEODB_ID_YEAR);
2860     }     
2861
2862     strSQL += addParam;
2863
2864     // run query
2865     CLog::Log(LOGDEBUG, "CVideoDatabase::GetYearsNav() query: %s", strSQL.c_str());
2866     if (!m_pDS->query(strSQL.c_str())) return false;
2867     int iRowsFound = m_pDS->num_rows();
2868     if (iRowsFound == 0)
2869     {
2870       m_pDS->close();
2871       return true;
2872     }
2873
2874     if (g_settings.m_vecProfiles[0].getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
2875     {
2876       map<long, CStdString> mapYears;
2877       map<long, CStdString>::iterator it;
2878       long lLastPathId = -1;
2879       while (!m_pDS->eof())
2880       {
2881         long lYear = m_pDS->fv(0).get_asLong();
2882         it = mapYears.find(lYear);
2883         if (it == mapYears.end())
2884         {
2885           // check path
2886           if (g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_vecMyVideoShares))
2887           {
2888             CStdString year;
2889             year.Format("%d", lYear);
2890             mapYears.insert(pair<long, CStdString>(lYear, year));
2891           }
2892         }
2893         m_pDS->next();
2894       }
2895       m_pDS->close();
2896