2 * Copyright (C) 2005-2008 Team XBMC
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)
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.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; 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
22 #include "VideoDatabase.h"
23 #include "video/windows/GUIWindowVideoBase.h"
24 #include "utils/RegExp.h"
25 #include "addons/AddonManager.h"
26 #include "GUIInfoManager.h"
28 #include "utils/URIUtils.h"
29 #include "utils/XMLUtils.h"
30 #include "GUIPassword.h"
31 #include "filesystem/StackDirectory.h"
32 #include "filesystem/MultiPathDirectory.h"
33 #include "VideoInfoScanner.h"
34 #include "guilib/GUIWindowManager.h"
35 #include "filesystem/Directory.h"
36 #include "filesystem/File.h"
37 #include "filesystem/SpecialProtocol.h"
38 #include "dialogs/GUIDialogProgress.h"
39 #include "dialogs/GUIDialogYesNo.h"
41 #include "settings/AdvancedSettings.h"
42 #include "settings/GUISettings.h"
43 #include "settings/Settings.h"
44 #include "utils/StringUtils.h"
45 #include "guilib/LocalizeStrings.h"
46 #include "utils/TimeUtils.h"
47 #include "utils/log.h"
48 #include "TextureCache.h"
49 #include "addons/AddonInstaller.h"
50 #include "interfaces/AnnouncementManager.h"
53 using namespace dbiplus;
54 using namespace XFILE;
55 using namespace VIDEO;
56 using namespace ADDON;
58 //********************************************************************************************************************************
59 CVideoDatabase::CVideoDatabase(void)
63 //********************************************************************************************************************************
64 CVideoDatabase::~CVideoDatabase(void)
67 //********************************************************************************************************************************
68 bool CVideoDatabase::Open()
70 return CDatabase::Open(g_advancedSettings.m_databaseVideo);
73 bool CVideoDatabase::CreateTables()
75 /* indexes should be added on any columns that are used in in */
76 /* a where or a join. primary key on a column is the same as a */
77 /* unique index on that column, so there is no need to add any */
78 /* index if no other columns are refered */
80 /* order of indexes are important, for an index to be considered all */
81 /* columns up to the column in question have to have been specified */
82 /* select * from actorlinkmovie where idMovie = 1, can not take */
83 /* advantage of a index that has been created on ( idGenre, idMovie ) */
84 /*, hower on on ( idMovie, idGenre ) will be considered for use */
89 CDatabase::CreateTables();
91 CLog::Log(LOGINFO, "create bookmark table");
92 m_pDS->exec("CREATE TABLE bookmark ( idBookmark integer primary key, idFile integer, timeInSeconds double, totalTimeInSeconds double, thumbNailImage text, player text, playerState text, type integer)\n");
93 m_pDS->exec("CREATE INDEX ix_bookmark ON bookmark (idFile)");
95 CLog::Log(LOGINFO, "create settings table");
96 m_pDS->exec("CREATE TABLE settings ( idFile integer, Deinterlace bool,"
97 "ViewMode integer,ZoomAmount float, PixelRatio float, VerticalShift float, AudioStream integer, SubtitleStream integer,"
98 "SubtitleDelay float, SubtitlesOn bool, Brightness float, Contrast float, Gamma float,"
99 "VolumeAmplification float, AudioDelay float, OutputToAllSpeakers bool, ResumeTime integer, Crop bool, CropLeft integer,"
100 "CropRight integer, CropTop integer, CropBottom integer, Sharpness float, NoiseReduction float, NonLinStretch bool, PostProcess bool)\n");
101 m_pDS->exec("CREATE UNIQUE INDEX ix_settings ON settings ( idFile )\n");
103 CLog::Log(LOGINFO, "create stacktimes table");
104 m_pDS->exec("CREATE TABLE stacktimes (idFile integer, times text)\n");
105 m_pDS->exec("CREATE UNIQUE INDEX ix_stacktimes ON stacktimes ( idFile )\n");
107 CLog::Log(LOGINFO, "create genre table");
108 m_pDS->exec("CREATE TABLE genre ( idGenre integer primary key, strGenre text)\n");
110 CLog::Log(LOGINFO, "create genrelinkmovie table");
111 m_pDS->exec("CREATE TABLE genrelinkmovie ( idGenre integer, idMovie integer)\n");
112 m_pDS->exec("CREATE UNIQUE INDEX ix_genrelinkmovie_1 ON genrelinkmovie ( idGenre, idMovie)\n");
113 m_pDS->exec("CREATE UNIQUE INDEX ix_genrelinkmovie_2 ON genrelinkmovie ( idMovie, idGenre)\n");
115 CLog::Log(LOGINFO, "create country table");
116 m_pDS->exec("CREATE TABLE country ( idCountry integer primary key, strCountry text)\n");
118 CLog::Log(LOGINFO, "create countrylinkmovie table");
119 m_pDS->exec("CREATE TABLE countrylinkmovie ( idCountry integer, idMovie integer)\n");
120 m_pDS->exec("CREATE UNIQUE INDEX ix_countrylinkmovie_1 ON countrylinkmovie ( idCountry, idMovie)\n");
121 m_pDS->exec("CREATE UNIQUE INDEX ix_countrylinkmovie_2 ON countrylinkmovie ( idMovie, idCountry)\n");
123 CLog::Log(LOGINFO, "create movie table");
124 CStdString columns = "CREATE TABLE movie ( idMovie integer primary key, idFile integer";
125 for (int i = 0; i < VIDEODB_MAX_COLUMNS; i++)
128 column.Format(",c%02d text", i);
132 m_pDS->exec(columns.c_str());
133 m_pDS->exec("CREATE UNIQUE INDEX ix_movie_file_1 ON movie (idFile, idMovie)");
134 m_pDS->exec("CREATE UNIQUE INDEX ix_movie_file_2 ON movie (idMovie, idFile)");
136 CLog::Log(LOGINFO, "create actorlinkmovie table");
137 m_pDS->exec("CREATE TABLE actorlinkmovie ( idActor integer, idMovie integer, strRole text)\n");
138 m_pDS->exec("CREATE UNIQUE INDEX ix_actorlinkmovie_1 ON actorlinkmovie ( idActor, idMovie )\n");
139 m_pDS->exec("CREATE UNIQUE INDEX ix_actorlinkmovie_2 ON actorlinkmovie ( idMovie, idActor )\n");
141 CLog::Log(LOGINFO, "create directorlinkmovie table");
142 m_pDS->exec("CREATE TABLE directorlinkmovie ( idDirector integer, idMovie integer)\n");
143 m_pDS->exec("CREATE UNIQUE INDEX ix_directorlinkmovie_1 ON directorlinkmovie ( idDirector, idMovie )\n");
144 m_pDS->exec("CREATE UNIQUE INDEX ix_directorlinkmovie_2 ON directorlinkmovie ( idMovie, idDirector )\n");
146 CLog::Log(LOGINFO, "create writerlinkmovie table");
147 m_pDS->exec("CREATE TABLE writerlinkmovie ( idWriter integer, idMovie integer)\n");
148 m_pDS->exec("CREATE UNIQUE INDEX ix_writerlinkmovie_1 ON writerlinkmovie ( idWriter, idMovie )\n");
149 m_pDS->exec("CREATE UNIQUE INDEX ix_writerlinkmovie_2 ON writerlinkmovie ( idMovie, idWriter )\n");
151 CLog::Log(LOGINFO, "create actors table");
152 m_pDS->exec("CREATE TABLE actors ( idActor integer primary key, strActor text, strThumb text )\n");
154 CLog::Log(LOGINFO, "create path table");
155 m_pDS->exec("CREATE TABLE path ( idPath integer primary key, strPath text, strContent text, strScraper text, strHash text, scanRecursive integer, useFolderNames bool, strSettings text, noUpdate bool, exclude bool)");
156 m_pDS->exec("CREATE UNIQUE INDEX ix_path ON path ( strPath(255) )");
158 CLog::Log(LOGINFO, "create files table");
159 m_pDS->exec("CREATE TABLE files ( idFile integer primary key, idPath integer, strFilename text, playCount integer, lastPlayed text)");
160 m_pDS->exec("CREATE UNIQUE INDEX ix_files ON files ( idPath, strFilename(255) )");
162 CLog::Log(LOGINFO, "create tvshow table");
163 columns = "CREATE TABLE tvshow ( idShow integer primary key";
164 for (int i = 0; i < VIDEODB_MAX_COLUMNS; i++)
167 column.Format(",c%02d text", i);
171 m_pDS->exec(columns.c_str());
173 CLog::Log(LOGINFO, "create directorlinktvshow table");
174 m_pDS->exec("CREATE TABLE directorlinktvshow ( idDirector integer, idShow integer)\n");
175 m_pDS->exec("CREATE UNIQUE INDEX ix_directorlinktvshow_1 ON directorlinktvshow ( idDirector, idShow )\n");
176 m_pDS->exec("CREATE UNIQUE INDEX ix_directorlinktvshow_2 ON directorlinktvshow ( idShow, idDirector )\n");
178 CLog::Log(LOGINFO, "create actorlinktvshow table");
179 m_pDS->exec("CREATE TABLE actorlinktvshow ( idActor integer, idShow integer, strRole text)\n");
180 m_pDS->exec("CREATE UNIQUE INDEX ix_actorlinktvshow_1 ON actorlinktvshow ( idActor, idShow )\n");
181 m_pDS->exec("CREATE UNIQUE INDEX ix_actorlinktvshow_2 ON actorlinktvshow ( idShow, idActor )\n");
183 CLog::Log(LOGINFO, "create studiolinktvshow table");
184 m_pDS->exec("CREATE TABLE studiolinktvshow ( idStudio integer, idShow integer)\n");
185 m_pDS->exec("CREATE UNIQUE INDEX ix_studiolinktvshow_1 ON studiolinktvshow ( idStudio, idShow)\n");
186 m_pDS->exec("CREATE UNIQUE INDEX ix_studiolinktvshow_2 ON studiolinktvshow ( idShow, idStudio)\n");
188 CLog::Log(LOGINFO, "create episode table");
189 columns = "CREATE TABLE episode ( idEpisode integer primary key, idFile integer";
190 for (int i = 0; i < VIDEODB_MAX_COLUMNS; i++)
193 if ( i == VIDEODB_ID_EPISODE_SEASON || i == VIDEODB_ID_EPISODE_EPISODE || i == VIDEODB_ID_EPISODE_BOOKMARK)
194 column.Format(",c%02d varchar(24)", i);
196 column.Format(",c%02d text", i);
201 m_pDS->exec(columns.c_str());
202 m_pDS->exec("CREATE UNIQUE INDEX ix_episode_file_1 on episode (idEpisode, idFile)");
203 m_pDS->exec("CREATE UNIQUE INDEX id_episode_file_2 on episode (idFile, idEpisode)");
204 CStdString createColIndex;
205 createColIndex.Format("CREATE INDEX ix_episode_season_episode on episode (c%02d, c%02d)", VIDEODB_ID_EPISODE_SEASON, VIDEODB_ID_EPISODE_EPISODE);
206 m_pDS->exec(createColIndex.c_str());
207 createColIndex.Format("CREATE INDEX ix_episode_bookmark on episode (c%02d)", VIDEODB_ID_EPISODE_BOOKMARK);
208 m_pDS->exec(createColIndex.c_str());
210 CLog::Log(LOGINFO, "create tvshowlinkepisode table");
211 m_pDS->exec("CREATE TABLE tvshowlinkepisode ( idShow integer, idEpisode integer)\n");
212 m_pDS->exec("CREATE UNIQUE INDEX ix_tvshowlinkepisode_1 ON tvshowlinkepisode ( idShow, idEpisode )\n");
213 m_pDS->exec("CREATE UNIQUE INDEX ix_tvshowlinkepisode_2 ON tvshowlinkepisode ( idEpisode, idShow )\n");
215 CLog::Log(LOGINFO, "create tvshowlinkpath table");
216 m_pDS->exec("CREATE TABLE tvshowlinkpath (idShow integer, idPath integer)\n");
217 m_pDS->exec("CREATE UNIQUE INDEX ix_tvshowlinkpath_1 ON tvshowlinkpath ( idShow, idPath )\n");
218 m_pDS->exec("CREATE UNIQUE INDEX ix_tvshowlinkpath_2 ON tvshowlinkpath ( idPath, idShow )\n");
220 CLog::Log(LOGINFO, "create actorlinkepisode table");
221 m_pDS->exec("CREATE TABLE actorlinkepisode ( idActor integer, idEpisode integer, strRole text)\n");
222 m_pDS->exec("CREATE UNIQUE INDEX ix_actorlinkepisode_1 ON actorlinkepisode ( idActor, idEpisode )\n");
223 m_pDS->exec("CREATE UNIQUE INDEX ix_actorlinkepisode_2 ON actorlinkepisode ( idEpisode, idActor )\n");
225 CLog::Log(LOGINFO, "create directorlinkepisode table");
226 m_pDS->exec("CREATE TABLE directorlinkepisode ( idDirector integer, idEpisode integer)\n");
227 m_pDS->exec("CREATE UNIQUE INDEX ix_directorlinkepisode_1 ON directorlinkepisode ( idDirector, idEpisode )\n");
228 m_pDS->exec("CREATE UNIQUE INDEX ix_directorlinkepisode_2 ON directorlinkepisode ( idEpisode, idDirector )\n");
230 CLog::Log(LOGINFO, "create writerlinkepisode table");
231 m_pDS->exec("CREATE TABLE writerlinkepisode ( idWriter integer, idEpisode integer)\n");
232 m_pDS->exec("CREATE UNIQUE INDEX ix_writerlinkepisode_1 ON writerlinkepisode ( idWriter, idEpisode )\n");
233 m_pDS->exec("CREATE UNIQUE INDEX ix_writerlinkepisode_2 ON writerlinkepisode ( idEpisode, idWriter )\n");
235 CLog::Log(LOGINFO, "create genrelinktvshow table");
236 m_pDS->exec("CREATE TABLE genrelinktvshow ( idGenre integer, idShow integer)\n");
237 m_pDS->exec("CREATE UNIQUE INDEX ix_genrelinktvshow_1 ON genrelinktvshow ( idGenre, idShow)\n");
238 m_pDS->exec("CREATE UNIQUE INDEX ix_genrelinktvshow_2 ON genrelinktvshow ( idShow, idGenre)\n");
240 CLog::Log(LOGINFO, "create movielinktvshow table");
241 m_pDS->exec("CREATE TABLE movielinktvshow ( idMovie integer, IdShow integer)\n");
242 m_pDS->exec("CREATE UNIQUE INDEX ix_movielinktvshow_1 ON movielinktvshow ( idShow, idMovie)\n");
243 m_pDS->exec("CREATE UNIQUE INDEX ix_movielinktvshow_2 ON movielinktvshow ( idMovie, idShow)\n");
245 CLog::Log(LOGINFO, "create studio table");
246 m_pDS->exec("CREATE TABLE studio ( idStudio integer primary key, strStudio text)\n");
248 CLog::Log(LOGINFO, "create studiolinkmovie table");
249 m_pDS->exec("CREATE TABLE studiolinkmovie ( idStudio integer, idMovie integer)\n");
250 m_pDS->exec("CREATE UNIQUE INDEX ix_studiolinkmovie_1 ON studiolinkmovie ( idStudio, idMovie)\n");
251 m_pDS->exec("CREATE UNIQUE INDEX ix_studiolinkmovie_2 ON studiolinkmovie ( idMovie, idStudio)\n");
253 CLog::Log(LOGINFO, "create musicvideo table");
254 columns = "CREATE TABLE musicvideo ( idMVideo integer primary key, idFile integer";
255 for (int i = 0; i < VIDEODB_MAX_COLUMNS; i++)
258 column.Format(",c%02d text", i);
262 m_pDS->exec(columns.c_str());
263 m_pDS->exec("CREATE UNIQUE INDEX ix_musicvideo_file_1 on musicvideo (idMVideo, idFile)");
264 m_pDS->exec("CREATE UNIQUE INDEX ix_musicvideo_file_2 on musicvideo (idFile, idMVideo)");
266 CLog::Log(LOGINFO, "create artistlinkmusicvideo table");
267 m_pDS->exec("CREATE TABLE artistlinkmusicvideo ( idArtist integer, idMVideo integer)\n");
268 m_pDS->exec("CREATE UNIQUE INDEX ix_artistlinkmusicvideo_1 ON artistlinkmusicvideo ( idArtist, idMVideo)\n");
269 m_pDS->exec("CREATE UNIQUE INDEX ix_artistlinkmusicvideo_2 ON artistlinkmusicvideo ( idMVideo, idArtist)\n");
271 CLog::Log(LOGINFO, "create genrelinkmusicvideo table");
272 m_pDS->exec("CREATE TABLE genrelinkmusicvideo ( idGenre integer, idMVideo integer)\n");
273 m_pDS->exec("CREATE UNIQUE INDEX ix_genrelinkmusicvideo_1 ON genrelinkmusicvideo ( idGenre, idMVideo)\n");
274 m_pDS->exec("CREATE UNIQUE INDEX ix_genrelinkmusicvideo_2 ON genrelinkmusicvideo ( idMVideo, idGenre)\n");
276 CLog::Log(LOGINFO, "create studiolinkmusicvideo table");
277 m_pDS->exec("CREATE TABLE studiolinkmusicvideo ( idStudio integer, idMVideo integer)\n");
278 m_pDS->exec("CREATE UNIQUE INDEX ix_studiolinkmusicvideo_1 ON studiolinkmusicvideo ( idStudio, idMVideo)\n");
279 m_pDS->exec("CREATE UNIQUE INDEX ix_studiolinkmusicvideo_2 ON studiolinkmusicvideo ( idMVideo, idStudio)\n");
281 CLog::Log(LOGINFO, "create directorlinkmusicvideo table");
282 m_pDS->exec("CREATE TABLE directorlinkmusicvideo ( idDirector integer, idMVideo integer)\n");
283 m_pDS->exec("CREATE UNIQUE INDEX ix_directorlinkmusicvideo_1 ON directorlinkmusicvideo ( idDirector, idMVideo )\n");
284 m_pDS->exec("CREATE UNIQUE INDEX ix_directorlinkmusicvideo_2 ON directorlinkmusicvideo ( idMVideo, idDirector )\n");
286 CLog::Log(LOGINFO, "create streaminfo table");
287 m_pDS->exec("CREATE TABLE streamdetails (idFile integer, iStreamType integer, "
288 "strVideoCodec text, fVideoAspect float, iVideoWidth integer, iVideoHeight integer, "
289 "strAudioCodec text, iAudioChannels integer, strAudioLanguage text, strSubtitleLanguage text, iVideoDuration integer)");
290 m_pDS->exec("CREATE INDEX ix_streamdetails ON streamdetails (idFile)");
292 CLog::Log(LOGINFO, "create episodeview");
293 CStdString episodeview = PrepareSQL("create view episodeview as select episode.*,files.strFileName as strFileName,"
294 "path.strPath as strPath,files.playCount as playCount,files.lastPlayed as lastPlayed,tvshow.c%02d as strTitle,tvshow.c%02d as strStudio,tvshow.idShow as idShow,"
295 "tvshow.c%02d as premiered, tvshow.c%02d as mpaa from episode "
296 "join files on files.idFile=episode.idFile "
297 "join tvshowlinkepisode on episode.idepisode=tvshowlinkepisode.idEpisode "
298 "join tvshow on tvshow.idShow=tvshowlinkepisode.idShow "
299 "join path on files.idPath=path.idPath",VIDEODB_ID_TV_TITLE, VIDEODB_ID_TV_STUDIOS, VIDEODB_ID_TV_PREMIERED, VIDEODB_ID_TV_MPAA);
300 m_pDS->exec(episodeview.c_str());
302 CLog::Log(LOGINFO, "create tvshowview");
303 CStdString tvshowview = PrepareSQL("CREATE VIEW tvshowview AS SELECT "
305 "path.strPath AS strPath,"
306 " NULLIF(COUNT(episode.c12), 0) AS totalCount,"
307 " SUM(files.playCount) AS watchedcount,"
308 " NULLIF(COUNT(DISTINCT(episode.c12)), 0) AS totalSeasons "
310 " LEFT JOIN tvshowlinkpath ON"
311 " tvshowlinkpath.idShow=tvshow.idShow"
313 " path.idPath=tvshowlinkpath.idPath"
314 " LEFT JOIN tvshowlinkepisode ON"
315 " tvshowlinkepisode.idShow=tvshow.idShow"
316 " LEFT JOIN episode ON"
317 " episode.idEpisode=tvshowlinkepisode.idEpisode"
318 " LEFT JOIN files ON"
319 " files.idFile=episode.idFile "
320 "GROUP BY tvshow.idShow;");
321 m_pDS->exec(tvshowview.c_str());
323 CLog::Log(LOGINFO, "create musicvideoview");
324 m_pDS->exec("create view musicvideoview as select musicvideo.*,files.strFileName as strFileName,path.strPath as strPath,files.playCount as playCount,files.lastPlayed as lastPlayed "
325 "from musicvideo join files on files.idFile=musicvideo.idFile join path on path.idPath=files.idPath");
327 CLog::Log(LOGINFO, "create movieview");
328 m_pDS->exec("create view movieview as select movie.*,files.strFileName as strFileName,path.strPath as strPath,files.playCount as playCount,files.lastPlayed as lastPlayed "
329 "from movie join files on files.idFile=movie.idFile join path on path.idPath=files.idPath");
331 CLog::Log(LOGINFO, "create sets table");
332 m_pDS->exec("CREATE TABLE sets ( idSet integer primary key, strSet text)\n");
334 CLog::Log(LOGINFO, "create setlinkmovie table");
335 m_pDS->exec("CREATE TABLE setlinkmovie ( idSet integer, idMovie integer)\n");
336 m_pDS->exec("CREATE UNIQUE INDEX ix_setlinkmovie_1 ON setlinkmovie ( idSet, idMovie)\n");
337 m_pDS->exec("CREATE UNIQUE INDEX ix_setlinkmovie_2 ON setlinkmovie ( idMovie, idSet)\n");
339 // create basepath indices
340 m_pDS->exec("CREATE INDEX ixMovieBasePath ON movie ( c22(255) )");
341 m_pDS->exec("CREATE INDEX ixMusicVideoBasePath ON musicvideo ( c13(255) )");
342 m_pDS->exec("CREATE INDEX ixEpisodeBasePath ON episode ( c18(255) )");
343 m_pDS->exec("CREATE INDEX ixTVShowBasePath on tvshow ( c16(255) )");
347 CLog::Log(LOGERROR, "%s unable to create tables:%i", __FUNCTION__, (int)GetLastError());
348 RollbackTransaction();
355 //********************************************************************************************************************************
356 int CVideoDatabase::GetPathId(const CStdString& strPath)
362 if (NULL == m_pDB.get()) return -1;
363 if (NULL == m_pDS.get()) return -1;
365 CStdString strPath1(strPath);
366 if (URIUtils::IsStack(strPath) || strPath.Mid(0,6).Equals("rar://") || strPath.Mid(0,6).Equals("zip://"))
367 URIUtils::GetParentPath(strPath,strPath1);
369 URIUtils::AddSlashAtEnd(strPath1);
371 strSQL=PrepareSQL("select idPath from path where strPath like '%s'",strPath1.c_str());
372 m_pDS->query(strSQL.c_str());
374 idPath = m_pDS->fv("path.idPath").get_asInt();
381 CLog::Log(LOGERROR, "%s unable to getpath (%s)", __FUNCTION__, strSQL.c_str());
386 bool CVideoDatabase::GetPaths(set<CStdString> &paths)
390 if (NULL == m_pDB.get()) return false;
391 if (NULL == m_pDS.get()) return false;
395 // grab all paths with movie content set
396 if (!m_pDS->query("select strPath,noUpdate from path"
397 " where (strContent = 'movies' or strContent = 'musicvideos')"
398 " and strPath NOT like 'multipath://%%'"
399 " order by strPath"))
402 while (!m_pDS->eof())
404 if (!m_pDS->fv("noUpdate").get_asBool())
405 paths.insert(m_pDS->fv("strPath").get_asString());
410 // then grab all tvshow paths
411 if (!m_pDS->query("select strPath,noUpdate from path"
412 " where ( strContent = 'tvshows'"
413 " or idPath in (select idPath from tvshowlinkpath))"
414 " and strPath NOT like 'multipath://%%'"
415 " order by strPath"))
418 while (!m_pDS->eof())
420 if (!m_pDS->fv("noUpdate").get_asBool())
421 paths.insert(m_pDS->fv("strPath").get_asString());
426 // finally grab all other paths holding a movie which is not a stack or a rar archive
427 // - this isnt perfect but it should do fine in most situations.
428 // reason we need it to hold a movie is stacks from different directories (cdx folders for instance)
429 // not making mistakes must take priority
430 if (!m_pDS->query("select strPath,noUpdate from path"
431 " where idPath in (select idPath from files join movie on movie.idFile=files.idFile)"
432 " and idPath NOT in (select idPath from tvshowlinkpath)"
433 " and idPath NOT in (select idPath from files where strFileName like 'video_ts.ifo')" // dvd folders get stacked to a single item in parent folder
434 " and idPath NOT in (select idPath from files where strFileName like 'index.bdmv')" // bluray folders get stacked to a single item in parent folder
435 " and strPath NOT like 'multipath://%%'"
436 " and strContent NOT in ('movies', 'tvshows', 'None')" // these have been added above
437 " order by strPath"))
440 while (!m_pDS->eof())
442 if (!m_pDS->fv("noUpdate").get_asBool())
443 paths.insert(m_pDS->fv("strPath").get_asString());
451 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
456 bool CVideoDatabase::GetPathsForTvShow(int idShow, vector<int>& paths)
461 if (NULL == m_pDB.get()) return false;
462 if (NULL == m_pDS.get()) return false;
463 strSQL = PrepareSQL("SELECT DISTINCT idPath FROM files JOIN episode ON episode.idFile=files.idFile JOIN tvshowlinkepisode ON tvshowlinkepisode.idEpisode=episode.idEpisode WHERE tvshowlinkepisode.idShow=%i",idShow);
464 m_pDS->query(strSQL.c_str());
465 while (!m_pDS->eof())
467 paths.push_back(m_pDS->fv(0).get_asInt());
475 CLog::Log(LOGERROR, "%s error during query: %s",__FUNCTION__, strSQL.c_str());
480 int CVideoDatabase::RunQuery(const CStdString &sql)
482 unsigned int time = CTimeUtils::GetTimeMS();
484 if (m_pDS->query(sql.c_str()))
486 rows = m_pDS->num_rows();
490 CLog::Log(LOGDEBUG, "%s took %d ms for %d items query: %s", __FUNCTION__, CTimeUtils::GetTimeMS() - time, rows, sql.c_str());
494 bool CVideoDatabase::GetSubPaths(const CStdString &basepath, vector<int>& subpaths)
499 if (!m_pDB.get() || !m_pDS.get())
502 sql = PrepareSQL("SELECT idPath FROM path WHERE strPath LIKE '%s%%'", basepath.c_str());
503 m_pDS->query(sql.c_str());
504 while (!m_pDS->eof())
506 subpaths.push_back(m_pDS->fv(0).get_asInt());
514 CLog::Log(LOGERROR, "%s error during query: %s",__FUNCTION__, sql.c_str());
519 int CVideoDatabase::AddPath(const CStdString& strPath)
525 if (NULL == m_pDB.get()) return -1;
526 if (NULL == m_pDS.get()) return -1;
528 CStdString strPath1(strPath);
529 if (URIUtils::IsStack(strPath) || strPath.Mid(0,6).Equals("rar://") || strPath.Mid(0,6).Equals("zip://"))
530 URIUtils::GetParentPath(strPath,strPath1);
532 URIUtils::AddSlashAtEnd(strPath1);
534 strSQL=PrepareSQL("insert into path (idPath, strPath, strContent, strScraper) values (NULL,'%s','','')", strPath1.c_str());
535 m_pDS->exec(strSQL.c_str());
536 idPath = (int)m_pDS->lastinsertid();
541 CLog::Log(LOGERROR, "%s unable to addpath (%s)", __FUNCTION__, strSQL.c_str());
546 bool CVideoDatabase::GetPathHash(const CStdString &path, CStdString &hash)
550 if (NULL == m_pDB.get()) return false;
551 if (NULL == m_pDS.get()) return false;
553 CStdString strSQL=PrepareSQL("select strHash from path where strPath like '%s'", path.c_str());
554 m_pDS->query(strSQL.c_str());
555 if (m_pDS->num_rows() == 0)
557 hash = m_pDS->fv("strHash").get_asString();
562 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, path.c_str());
568 //********************************************************************************************************************************
569 int CVideoDatabase::AddFile(const CStdString& strFileNameAndPath)
571 CStdString strSQL = "";
575 if (NULL == m_pDB.get()) return -1;
576 if (NULL == m_pDS.get()) return -1;
578 CStdString strFileName, strPath;
579 SplitPath(strFileNameAndPath,strPath,strFileName);
581 int idPath=GetPathId(strPath);
583 idPath = AddPath(strPath);
588 CStdString strSQL=PrepareSQL("select idFile from files where strFileName like '%s' and idPath=%i", strFileName.c_str(),idPath);
590 m_pDS->query(strSQL.c_str());
591 if (m_pDS->num_rows() > 0)
593 idFile = m_pDS->fv("idFile").get_asInt() ;
598 strSQL=PrepareSQL("insert into files (idFile,idPath,strFileName) values(NULL, %i, '%s')", idPath,strFileName.c_str());
599 m_pDS->exec(strSQL.c_str());
600 idFile = (int)m_pDS->lastinsertid();
605 CLog::Log(LOGERROR, "%s unable to addfile (%s)", __FUNCTION__, strSQL.c_str());
610 int CVideoDatabase::AddFile(const CFileItem& item)
612 if (item.IsVideoDb() && item.HasVideoInfoTag())
613 return AddFile(item.GetVideoInfoTag()->m_strFileNameAndPath);
614 return AddFile(item.m_strPath);
617 bool CVideoDatabase::SetPathHash(const CStdString &path, const CStdString &hash)
621 if (NULL == m_pDB.get()) return false;
622 if (NULL == m_pDS.get()) return false;
625 { // this is an empty folder - we need only add it to the path table
626 // if the path actually exists
627 if (!CDirectory::Exists(path))
630 int idPath = GetPathId(path);
632 idPath = AddPath(path);
633 if (idPath < 0) return false;
635 CStdString strSQL=PrepareSQL("update path set strHash='%s' where idPath=%ld", hash.c_str(), idPath);
636 m_pDS->exec(strSQL.c_str());
642 CLog::Log(LOGERROR, "%s (%s, %s) failed", __FUNCTION__, path.c_str(), hash.c_str());
648 bool CVideoDatabase::LinkMovieToTvshow(int idMovie, int idShow, bool bRemove)
652 if (NULL == m_pDB.get()) return false;
653 if (NULL == m_pDS.get()) return false;
655 if (bRemove) // delete link
657 CStdString strSQL=PrepareSQL("delete from movielinktvshow where idMovie=%i and idShow=%i", idMovie, idShow);
658 m_pDS->exec(strSQL.c_str());
662 CStdString strSQL=PrepareSQL("insert into movielinktvshow (idShow,idMovie) values (%i,%i)", idShow,idMovie);
663 m_pDS->exec(strSQL.c_str());
669 CLog::Log(LOGERROR, "%s (%i, %i) failed", __FUNCTION__, idMovie, idShow);
675 bool CVideoDatabase::IsLinkedToTvshow(int idMovie)
679 if (NULL == m_pDB.get()) return false;
680 if (NULL == m_pDS.get()) return false;
682 CStdString strSQL=PrepareSQL("select * from movielinktvshow where idMovie=%i", idMovie);
683 m_pDS->query(strSQL.c_str());
695 CLog::Log(LOGERROR, "%s (%i) failed", __FUNCTION__, idMovie);
701 bool CVideoDatabase::GetLinksToTvShow(int idMovie, vector<int>& ids)
705 if (NULL == m_pDB.get()) return false;
706 if (NULL == m_pDS.get()) return false;
708 CStdString strSQL=PrepareSQL("select * from movielinktvshow where idMovie=%i", idMovie);
709 m_pDS2->query(strSQL.c_str());
710 while (!m_pDS2->eof())
712 ids.push_back(m_pDS2->fv(1).get_asInt());
721 CLog::Log(LOGERROR, "%s (%i) failed", __FUNCTION__, idMovie);
728 //********************************************************************************************************************************
729 int CVideoDatabase::GetFileId(const CStdString& strFilenameAndPath)
733 if (NULL == m_pDB.get()) return -1;
734 if (NULL == m_pDS.get()) return -1;
735 CStdString strPath, strFileName;
736 SplitPath(strFilenameAndPath,strPath,strFileName);
738 int idPath = GetPathId(strPath);
742 strSQL=PrepareSQL("select idFile from files where strFileName like '%s' and idPath=%i", strFileName.c_str(),idPath);
743 m_pDS->query(strSQL.c_str());
744 if (m_pDS->num_rows() > 0)
746 int idFile = m_pDS->fv("files.idFile").get_asInt();
754 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
759 int CVideoDatabase::GetFileId(const CFileItem &item)
761 if (item.IsVideoDb() && item.HasVideoInfoTag())
762 return GetFileId(item.GetVideoInfoTag()->m_strFileNameAndPath);
763 return GetFileId(item.m_strPath);
766 //********************************************************************************************************************************
767 int CVideoDatabase::GetMovieId(const CStdString& strFilenameAndPath)
771 if (NULL == m_pDB.get()) return -1;
772 if (NULL == m_pDS.get()) return -1;
775 // needed for query parameters
776 int idFile = GetFileId(strFilenameAndPath);
782 SplitPath(strFilenameAndPath,strPath,strFile);
784 // have to join movieinfo table for correct results
785 idPath = GetPathId(strPath);
786 if (idPath < 0 && strPath != strFilenameAndPath)
790 if (idFile == -1 && strPath != strFilenameAndPath)
795 strSQL=PrepareSQL("select idMovie from movie join files on files.idFile=movie.idFile where files.idPath=%i",idPath);
797 strSQL=PrepareSQL("select idMovie from movie where idFile=%i", idFile);
799 CLog::Log(LOGDEBUG, "%s (%s), query = %s", __FUNCTION__, strFilenameAndPath.c_str(), strSQL.c_str());
800 m_pDS->query(strSQL.c_str());
801 if (m_pDS->num_rows() > 0)
802 idMovie = m_pDS->fv("idMovie").get_asInt();
809 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
814 int CVideoDatabase::GetTvShowId(const CStdString& strPath)
818 if (NULL == m_pDB.get()) return -1;
819 if (NULL == m_pDS.get()) return -1;
822 // have to join movieinfo table for correct results
823 int idPath = GetPathId(strPath);
828 CStdString strPath1=strPath;
829 CStdString strParent;
832 strSQL=PrepareSQL("select idShow from tvshowlinkpath where tvshowlinkpath.idPath=%i",idPath);
833 m_pDS->query(strSQL);
837 while (iFound == 0 && URIUtils::GetParentPath(strPath1, strParent))
839 strSQL=PrepareSQL("select idShow from path,tvshowlinkpath where tvshowlinkpath.idPath=path.idPath and strPath like '%s'",strParent.c_str());
840 m_pDS->query(strSQL.c_str());
843 int idShow = m_pDS->fv("idShow").get_asInt();
847 strPath1 = strParent;
850 if (m_pDS->num_rows() > 0)
851 idTvShow = m_pDS->fv("idShow").get_asInt();
858 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strPath.c_str());
863 int CVideoDatabase::GetEpisodeId(const CStdString& strFilenameAndPath, int idEpisode, int idSeason) // input value is episode/season number hint - for multiparters
867 if (NULL == m_pDB.get()) return -1;
868 if (NULL == m_pDS.get()) return -1;
870 // need this due to the nested GetEpisodeInfo query
871 auto_ptr<Dataset> pDS;
872 pDS.reset(m_pDB->CreateDataset());
873 if (NULL == pDS.get()) return -1;
875 int idFile = GetFileId(strFilenameAndPath);
879 CStdString strSQL=PrepareSQL("select idEpisode from episode where idFile=%i", idFile);
881 CLog::Log(LOGDEBUG, "%s (%s), query = %s", __FUNCTION__, strFilenameAndPath.c_str(), strSQL.c_str());
882 pDS->query(strSQL.c_str());
883 if (pDS->num_rows() > 0)
886 idEpisode = pDS->fv("episode.idEpisode").get_asInt();
887 else // use the hint!
892 int idTmpEpisode = pDS->fv("episode.idEpisode").get_asInt();
893 GetEpisodeInfo(strFilenameAndPath,tag,idTmpEpisode);
894 if (tag.m_iEpisode == idEpisode && (idSeason == -1 || tag.m_iSeason == idSeason)) {
895 // match on the episode hint, and there's no season hint or a season hint match
896 idEpisode = idTmpEpisode;
914 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
919 int CVideoDatabase::GetMusicVideoId(const CStdString& strFilenameAndPath)
923 if (NULL == m_pDB.get()) return -1;
924 if (NULL == m_pDS.get()) return -1;
926 int idFile = GetFileId(strFilenameAndPath);
930 CStdString strSQL=PrepareSQL("select idMVideo from musicvideo where idFile=%i", idFile);
932 CLog::Log(LOGDEBUG, "%s (%s), query = %s", __FUNCTION__, strFilenameAndPath.c_str(), strSQL.c_str());
933 m_pDS->query(strSQL.c_str());
935 if (m_pDS->num_rows() > 0)
936 idMVideo = m_pDS->fv("idMVideo").get_asInt();
943 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
948 //********************************************************************************************************************************
949 int CVideoDatabase::AddMovie(const CStdString& strFilenameAndPath)
953 if (NULL == m_pDB.get()) return -1;
954 if (NULL == m_pDS.get()) return -1;
956 int idMovie = GetMovieId(strFilenameAndPath);
959 int idFile = AddFile(strFilenameAndPath);
962 CStdString strSQL=PrepareSQL("insert into movie (idMovie, idFile) values (NULL, %i)", idFile);
963 m_pDS->exec(strSQL.c_str());
964 idMovie = (int)m_pDS->lastinsertid();
965 // CommitTransaction();
972 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
977 int CVideoDatabase::AddTvShow(const CStdString& strPath)
981 if (NULL == m_pDB.get()) return -1;
982 if (NULL == m_pDS.get()) return -1;
984 CStdString strSQL=PrepareSQL("select tvshowlinkpath.idShow from path,tvshowlinkpath where path.strPath like '%s' and path.idPath=tvshowlinkpath.idPath",strPath.c_str());
985 m_pDS->query(strSQL.c_str());
986 if (m_pDS->num_rows() != 0)
987 return m_pDS->fv("tvshowlinkpath.idShow").get_asInt();
989 strSQL=PrepareSQL("insert into tvshow (idShow) values (NULL)");
990 m_pDS->exec(strSQL.c_str());
991 int idTvShow = (int)m_pDS->lastinsertid();
993 int idPath = GetPathId(strPath);
995 idPath = AddPath(strPath);
996 strSQL=PrepareSQL("insert into tvshowlinkpath values (%i,%i)",idTvShow,idPath);
997 m_pDS->exec(strSQL.c_str());
999 // CommitTransaction();
1005 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strPath.c_str());
1010 //********************************************************************************************************************************
1011 int CVideoDatabase::AddEpisode(int idShow, const CStdString& strFilenameAndPath)
1015 if (NULL == m_pDB.get()) return -1;
1016 if (NULL == m_pDS.get()) return -1;
1018 int idFile = AddFile(strFilenameAndPath);
1022 CStdString strSQL=PrepareSQL("insert into episode (idEpisode, idFile) values (NULL, %i)", idFile);
1023 m_pDS->exec(strSQL.c_str());
1024 int idEpisode = (int)m_pDS->lastinsertid();
1026 strSQL=PrepareSQL("insert into tvshowlinkepisode (idShow,idEpisode) values (%i,%i)",idShow,idEpisode);
1027 m_pDS->exec(strSQL.c_str());
1029 // CommitTransaction();
1035 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
1040 int CVideoDatabase::AddMusicVideo(const CStdString& strFilenameAndPath)
1044 if (NULL == m_pDB.get()) return -1;
1045 if (NULL == m_pDS.get()) return -1;
1047 int idMVideo = GetMusicVideoId(strFilenameAndPath);
1050 int idFile = AddFile(strFilenameAndPath);
1053 CStdString strSQL=PrepareSQL("insert into musicvideo (idMVideo, idFile) values (NULL, %i)", idFile);
1054 m_pDS->exec(strSQL.c_str());
1055 idMVideo = (int)m_pDS->lastinsertid();
1062 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
1067 //********************************************************************************************************************************
1068 int CVideoDatabase::AddToTable(const CStdString& table, const CStdString& firstField, const CStdString& secondField, const CStdString& value)
1072 if (NULL == m_pDB.get()) return -1;
1073 if (NULL == m_pDS.get()) return -1;
1075 CStdString strSQL = PrepareSQL("select %s from %s where %s like '%s'", firstField.c_str(), table.c_str(), secondField.c_str(), value.c_str());
1076 m_pDS->query(strSQL.c_str());
1077 if (m_pDS->num_rows() == 0)
1080 // doesnt exists, add it
1081 strSQL = PrepareSQL("insert into %s (%s, %s) values( NULL, '%s')", table.c_str(), firstField.c_str(), secondField.c_str(), value.c_str());
1082 m_pDS->exec(strSQL.c_str());
1083 int id = (int)m_pDS->lastinsertid();
1088 int id = m_pDS->fv(firstField).get_asInt();
1095 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, value.c_str() );
1101 int CVideoDatabase::AddSet(const CStdString& strSet)
1103 return AddToTable("sets", "idSet", "strSet", strSet);
1106 int CVideoDatabase::AddGenre(const CStdString& strGenre)
1108 return AddToTable("genre", "idGenre", "strGenre", strGenre);
1111 int CVideoDatabase::AddStudio(const CStdString& strStudio)
1113 return AddToTable("studio", "idStudio", "strStudio", strStudio);
1116 //********************************************************************************************************************************
1117 int CVideoDatabase::AddCountry(const CStdString& strCountry)
1119 return AddToTable("country", "idCountry", "strCountry", strCountry);
1122 int CVideoDatabase::AddActor(const CStdString& strActor, const CStdString& strThumb)
1126 if (NULL == m_pDB.get()) return -1;
1127 if (NULL == m_pDS.get()) return -1;
1128 CStdString strSQL=PrepareSQL("select idActor from actors where strActor like '%s'", strActor.c_str());
1129 m_pDS->query(strSQL.c_str());
1130 if (m_pDS->num_rows() == 0)
1133 // doesnt exists, add it
1134 strSQL=PrepareSQL("insert into actors (idActor, strActor, strThumb) values( NULL, '%s','%s')", strActor.c_str(),strThumb.c_str());
1135 m_pDS->exec(strSQL.c_str());
1136 int idActor = (int)m_pDS->lastinsertid();
1141 const field_value value = m_pDS->fv("idActor");
1142 int idActor = value.get_asInt() ;
1143 // update the thumb url's
1144 if (!strThumb.IsEmpty())
1145 strSQL=PrepareSQL("update actors set strThumb='%s' where idActor=%i",strThumb.c_str(),idActor);
1153 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strActor.c_str() );
1160 void CVideoDatabase::AddLinkToActor(const char *table, int actorID, const char *secondField, int secondID, const CStdString &role)
1164 if (NULL == m_pDB.get()) return ;
1165 if (NULL == m_pDS.get()) return ;
1167 CStdString strSQL=PrepareSQL("select * from %s where idActor=%i and %s=%i", table, actorID, secondField, secondID);
1168 m_pDS->query(strSQL.c_str());
1169 if (m_pDS->num_rows() == 0)
1171 // doesnt exists, add it
1172 strSQL=PrepareSQL("insert into %s (idActor, %s, strRole) values(%i,%i,'%s')", table, secondField, actorID, secondID, role.c_str());
1173 m_pDS->exec(strSQL.c_str());
1179 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
1183 void CVideoDatabase::AddToLinkTable(const char *table, const char *firstField, int firstID, const char *secondField, int secondID)
1187 if (NULL == m_pDB.get()) return ;
1188 if (NULL == m_pDS.get()) return ;
1190 CStdString strSQL=PrepareSQL("select * from %s where %s=%i and %s=%i", table, firstField, firstID, secondField, secondID);
1191 m_pDS->query(strSQL.c_str());
1192 if (m_pDS->num_rows() == 0)
1194 // doesnt exists, add it
1195 strSQL=PrepareSQL("insert into %s (%s,%s) values(%i,%i)", table, firstField, secondField, firstID, secondID);
1196 m_pDS->exec(strSQL.c_str());
1202 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
1207 void CVideoDatabase::AddSetToMovie(int idMovie, int idSet)
1209 AddToLinkTable("setlinkmovie", "idSet", idSet, "idMovie", idMovie);
1213 void CVideoDatabase::AddActorToMovie(int idMovie, int idActor, const CStdString& strRole)
1215 AddLinkToActor("actorlinkmovie", idActor, "idMovie", idMovie, strRole);
1218 void CVideoDatabase::AddActorToTvShow(int idTvShow, int idActor, const CStdString& strRole)
1220 AddLinkToActor("actorlinktvshow", idActor, "idShow", idTvShow, strRole);
1223 void CVideoDatabase::AddActorToEpisode(int idEpisode, int idActor, const CStdString& strRole)
1225 AddLinkToActor("actorlinkepisode", idActor, "idEpisode", idEpisode, strRole);
1228 void CVideoDatabase::AddArtistToMusicVideo(int idMVideo, int idArtist)
1230 AddToLinkTable("artistlinkmusicvideo", "idArtist", idArtist, "idMVideo", idMVideo);
1233 //****Directors + Writers****
1234 void CVideoDatabase::AddDirectorToMovie(int idMovie, int idDirector)
1236 AddToLinkTable("directorlinkmovie", "idDirector", idDirector, "idMovie", idMovie);
1239 void CVideoDatabase::AddDirectorToTvShow(int idTvShow, int idDirector)
1241 AddToLinkTable("directorlinktvshow", "idDirector", idDirector, "idShow", idTvShow);
1244 void CVideoDatabase::AddWriterToEpisode(int idEpisode, int idWriter)
1246 AddToLinkTable("writerlinkepisode", "idWriter", idWriter, "idEpisode", idEpisode);
1249 void CVideoDatabase::AddWriterToMovie(int idMovie, int idWriter)
1251 AddToLinkTable("writerlinkmovie", "idWriter", idWriter, "idMovie", idMovie);
1254 void CVideoDatabase::AddDirectorToEpisode(int idEpisode, int idDirector)
1256 AddToLinkTable("directorlinkepisode", "idDirector", idDirector, "idEpisode", idEpisode);
1259 void CVideoDatabase::AddDirectorToMusicVideo(int idMVideo, int idDirector)
1261 AddToLinkTable("directorlinkmusicvideo", "idDirector", idDirector, "idMVideo", idMVideo);
1265 void CVideoDatabase::AddStudioToMovie(int idMovie, int idStudio)
1267 AddToLinkTable("studiolinkmovie", "idStudio", idStudio, "idMovie", idMovie);
1270 void CVideoDatabase::AddStudioToTvShow(int idTvShow, int idStudio)
1272 AddToLinkTable("studiolinktvshow", "idStudio", idStudio, "idShow", idTvShow);
1275 void CVideoDatabase::AddStudioToMusicVideo(int idMVideo, int idStudio)
1277 AddToLinkTable("studiolinkmusicvideo", "idStudio", idStudio, "idMVideo", idMVideo);
1281 void CVideoDatabase::AddGenreToMovie(int idMovie, int idGenre)
1283 AddToLinkTable("genrelinkmovie", "idGenre", idGenre, "idMovie", idMovie);
1286 void CVideoDatabase::AddGenreToTvShow(int idTvShow, int idGenre)
1288 AddToLinkTable("genrelinktvshow", "idGenre", idGenre, "idShow", idTvShow);
1291 void CVideoDatabase::AddGenreToMusicVideo(int idMVideo, int idGenre)
1293 AddToLinkTable("genrelinkmusicvideo", "idGenre", idGenre, "idMVideo", idMVideo);
1297 void CVideoDatabase::AddCountryToMovie(int idMovie, int idCountry)
1299 AddToLinkTable("countrylinkmovie", "idCountry", idCountry, "idMovie", idMovie);
1302 //********************************************************************************************************************************
1303 bool CVideoDatabase::HasMovieInfo(const CStdString& strFilenameAndPath)
1307 if (NULL == m_pDB.get()) return false;
1308 if (NULL == m_pDS.get()) return false;
1309 int idMovie = GetMovieId(strFilenameAndPath);
1310 return (idMovie > 0); // index of zero is also invalid
1315 // get title. if no title, the id was "deleted" for in-place update
1316 CVideoInfoTag details;
1317 GetMovieInfo(strFilenameAndPath, details, idMovie);
1318 if (!details.m_strTitle.IsEmpty()) return true;
1324 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
1329 bool CVideoDatabase::HasTvShowInfo(const CStdString& strPath)
1333 if (NULL == m_pDB.get()) return false;
1334 if (NULL == m_pDS.get()) return false;
1335 int idTvShow = GetTvShowId(strPath);
1336 return (idTvShow > 0); // index of zero is also invalid
1341 // get title. if no title, the id was "deleted" for in-place update
1342 CVideoInfoTag details;
1343 GetTvShowInfo(strPath, details, idTvShow);
1344 if (!details.m_strTitle.IsEmpty()) return true;
1350 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strPath.c_str());
1355 bool CVideoDatabase::HasEpisodeInfo(const CStdString& strFilenameAndPath)
1359 if (NULL == m_pDB.get()) return false;
1360 if (NULL == m_pDS.get()) return false;
1361 int idEpisode = GetEpisodeId(strFilenameAndPath);
1362 return (idEpisode > 0); // index of zero is also invalid
1367 // get title. if no title, the id was "deleted" for in-place update
1368 CVideoInfoTag details;
1369 GetEpisodeInfo(strFilenameAndPath, details, idEpisode);
1370 if (!details.m_strTitle.IsEmpty()) return true;
1376 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
1381 bool CVideoDatabase::HasMusicVideoInfo(const CStdString& strFilenameAndPath)
1385 if (NULL == m_pDB.get()) return false;
1386 if (NULL == m_pDS.get()) return false;
1387 int idMVideo = GetMusicVideoId(strFilenameAndPath);
1388 return (idMVideo > 0); // index of zero is also invalid
1393 // get title. if no title, the id was "deleted" for in-place update
1394 CVideoInfoTag details;
1395 GetMusicVideoInfo(strFilenameAndPath, details, idMVideo);
1396 if (!details.m_strTitle.IsEmpty()) return true;
1402 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
1407 void CVideoDatabase::DeleteDetailsForTvShow(const CStdString& strPath)
1408 {// TODO: merge into DeleteTvShow
1411 if (NULL == m_pDB.get()) return ;
1412 if (NULL == m_pDS.get()) return ;
1414 int idTvShow = GetTvShowId(strPath);
1415 if ( idTvShow < 0) return ;
1417 CFileItemList items;
1418 CStdString strPath2;
1419 strPath2.Format("videodb://2/2/%i/",idTvShow);
1420 GetSeasonsNav(strPath2,items,-1,-1,-1,-1,idTvShow);
1421 for( int i=0;i<items.Size();++i )
1422 CTextureCache::Get().ClearCachedImage(items[i]->GetCachedSeasonThumb(), true);
1423 DeleteThumbForItem(strPath,true);
1426 strSQL=PrepareSQL("delete from genrelinktvshow where idShow=%i", idTvShow);
1427 m_pDS->exec(strSQL.c_str());
1429 strSQL=PrepareSQL("delete from actorlinktvshow where idShow=%i", idTvShow);
1430 m_pDS->exec(strSQL.c_str());
1432 strSQL=PrepareSQL("delete from directorlinktvshow where idShow=%i", idTvShow);
1433 m_pDS->exec(strSQL.c_str());
1435 strSQL=PrepareSQL("delete from studiolinktvshow where idShow=%i", idTvShow);
1436 m_pDS->exec(strSQL.c_str());
1438 // remove all info other than the id
1439 // we do this due to the way we have the link between the file + movie tables.
1441 strSQL = "update tvshow set ";
1442 for (int iType = VIDEODB_ID_TV_MIN + 1; iType < VIDEODB_ID_TV_MAX; iType++)
1445 column.Format("c%02d=NULL,", iType);
1448 strSQL = strSQL.Mid(0, strSQL.size() - 1) + PrepareSQL(" where idShow=%i", idTvShow);
1449 m_pDS->exec(strSQL.c_str());
1453 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strPath.c_str());
1457 //********************************************************************************************************************************
1458 void CVideoDatabase::GetMoviesByActor(const CStdString& strActor, CFileItemList& items)
1460 CStdString where = PrepareSQL("join actorlinkmovie on actorlinkmovie.idMovie=movieview.idMovie "
1461 "join actors on actors.idActor=actorlinkmovie.idActor "
1462 "where actors.strActor='%s'", strActor.c_str());
1463 GetMoviesByWhere("videodb://1/2/", where, "", items);
1466 void CVideoDatabase::GetTvShowsByActor(const CStdString& strActor, CFileItemList& items)
1468 CStdString where = PrepareSQL("join actorlinktvshow on actorlinktvshow.idShow=tvshow.idShow "
1469 "join actors on actors.idActor=actorlinktvshow.idActor "
1470 "where actors.strActor='%s'", strActor.c_str());
1471 GetTvShowsByWhere("videodb://2/2/", where, items);
1474 void CVideoDatabase::GetEpisodesByActor(const CStdString& strActor, CFileItemList& items)
1476 CStdString where = PrepareSQL("join actorlinkepisode on actorlinkepisode.idEpisode=episodeview.idEpisode "
1477 "join actors on actors.idActor=actorlinkepisode.idActor "
1478 "where actors.strActor='%s'", strActor.c_str());
1479 GetEpisodesByWhere("videodb://2/2/", where, items);
1482 void CVideoDatabase::GetMusicVideosByArtist(const CStdString& strArtist, CFileItemList& items)
1487 if (NULL == m_pDB.get()) return ;
1488 if (NULL == m_pDS.get()) return ;
1491 if (strArtist.IsEmpty()) // TODO: SMARTPLAYLISTS what is this here for???
1492 strSQL=PrepareSQL("select distinct * from musicvideoview join artistlinkmusicvideo on artistlinkmusicvideo.idMVideo=musicvideoview.idMVideo join actors on actors.idActor=artistlinkmusicvideo.idArtist");
1494 strSQL=PrepareSQL("select * from musicvideoview join artistlinkmusicvideo on artistlinkmusicvideo.idMVideo=musicvideoview.idMVideo join actors on actors.idActor=artistlinkmusicvideo.idArtist where actors.strActor='%s'", strArtist.c_str());
1495 m_pDS->query( strSQL.c_str() );
1497 while (!m_pDS->eof())
1499 CVideoInfoTag tag = GetDetailsForMusicVideo(m_pDS);
1500 CFileItemPtr pItem(new CFileItem(tag));
1501 pItem->SetLabel(tag.m_strArtist);
1509 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strArtist.c_str());
1513 //********************************************************************************************************************************
1514 void CVideoDatabase::GetMovieInfo(const CStdString& strFilenameAndPath, CVideoInfoTag& details, int idMovie /* = -1 */)
1518 // TODO: Optimize this - no need for all the queries!
1520 idMovie = GetMovieId(strFilenameAndPath);
1521 if (idMovie < 0) return ;
1523 CStdString sql = PrepareSQL("select * from movieview where idMovie=%i", idMovie);
1524 if (!m_pDS->query(sql.c_str()))
1526 details = GetDetailsForMovie(m_pDS, true);
1530 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
1534 //********************************************************************************************************************************
1535 void CVideoDatabase::GetTvShowInfo(const CStdString& strPath, CVideoInfoTag& details, int idTvShow /* = -1 */)
1540 idTvShow = GetTvShowId(strPath);
1541 if (idTvShow < 0) return ;
1543 CStdString sql = PrepareSQL("SELECT * FROM tvshowview WHERE idShow=%i", idTvShow);
1544 if (!m_pDS->query(sql.c_str()))
1546 details = GetDetailsForTvShow(m_pDS, true);
1550 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strPath.c_str());
1554 bool CVideoDatabase::GetEpisodeInfo(const CStdString& strFilenameAndPath, CVideoInfoTag& details, int idEpisode /* = -1 */)
1558 // TODO: Optimize this - no need for all the queries!
1560 idEpisode = GetEpisodeId(strFilenameAndPath);
1561 if (idEpisode < 0) return false;
1563 CStdString sql = PrepareSQL("select * from episodeview where idEpisode=%i",idEpisode);
1564 if (!m_pDS->query(sql.c_str()))
1566 details = GetDetailsForEpisode(m_pDS, true);
1571 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
1576 void CVideoDatabase::GetMusicVideoInfo(const CStdString& strFilenameAndPath, CVideoInfoTag& details, int idMVideo /* = -1 */)
1580 // TODO: Optimize this - no need for all the queries!
1582 idMVideo = GetMusicVideoId(strFilenameAndPath);
1583 if (idMVideo < 0) return ;
1585 CStdString sql = PrepareSQL("select * from musicvideoview where idMVideo=%i", idMVideo);
1586 if (!m_pDS->query(sql.c_str()))
1588 details = GetDetailsForMusicVideo(m_pDS);
1592 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
1596 void CVideoDatabase::AddGenreAndDirectorsAndStudios(const CVideoInfoTag& details, vector<int>& vecDirectors, vector<int>& vecGenres, vector<int>& vecStudios)
1598 // add all directors
1599 if (!details.m_strDirector.IsEmpty())
1601 CStdStringArray directors;
1602 StringUtils::SplitString(details.m_strDirector, g_advancedSettings.m_videoItemSeparator, directors);
1603 for (unsigned int i = 0; i < directors.size(); i++)
1605 CStdString strDirector(directors[i]);
1607 int idDirector = AddActor(strDirector,"");
1608 vecDirectors.push_back(idDirector);
1613 if (!details.m_strGenre.IsEmpty())
1615 CStdStringArray genres;
1616 StringUtils::SplitString(details.m_strGenre, g_advancedSettings.m_videoItemSeparator, genres);
1617 for (unsigned int i = 0; i < genres.size(); i++)
1619 CStdString strGenre(genres[i]);
1621 int idGenre = AddGenre(strGenre);
1622 vecGenres.push_back(idGenre);
1626 if (!details.m_strStudio.IsEmpty())
1628 CStdStringArray studios;
1629 StringUtils::SplitString(details.m_strStudio, g_advancedSettings.m_videoItemSeparator, studios);
1630 for (unsigned int i = 0; i < studios.size(); i++)
1632 CStdString strStudio(studios[i]);
1634 int idStudio = AddStudio(strStudio);
1635 vecStudios.push_back(idStudio);
1640 CStdString CVideoDatabase::GetValueString(const CVideoInfoTag &details, int min, int max, const SDbTableOffsets *offsets) const
1643 for (int i = min + 1; i < max; ++i)
1645 switch (offsets[i].type)
1647 case VIDEODB_TYPE_STRING:
1648 sql += PrepareSQL("c%02d='%s',", i, ((CStdString*)(((char*)&details)+offsets[i].offset))->c_str());
1650 case VIDEODB_TYPE_INT:
1651 sql += PrepareSQL("c%02d='%i',", i, *(int*)(((char*)&details)+offsets[i].offset));
1653 case VIDEODB_TYPE_COUNT:
1655 int value = *(int*)(((char*)&details)+offsets[i].offset);
1657 sql += PrepareSQL("c%02d=%i,", i, value);
1659 sql += PrepareSQL("c%02d=NULL,", i);
1662 case VIDEODB_TYPE_BOOL:
1663 sql += PrepareSQL("c%02d='%s',", i, *(bool*)(((char*)&details)+offsets[i].offset)?"true":"false");
1665 case VIDEODB_TYPE_FLOAT:
1666 sql += PrepareSQL("c%02d='%f',", i, *(float*)(((char*)&details)+offsets[i].offset));
1674 //********************************************************************************************************************************
1675 int CVideoDatabase::SetDetailsForMovie(const CStdString& strFilenameAndPath, const CVideoInfoTag& details)
1679 CVideoInfoTag info = details;
1681 int idMovie = GetMovieId(strFilenameAndPath);
1683 DeleteMovie(strFilenameAndPath, true); // true to keep the table entry
1687 idMovie = AddMovie(strFilenameAndPath);
1690 CommitTransaction();
1694 vector<int> vecDirectors;
1695 vector<int> vecGenres;
1696 vector<int> vecStudios;
1697 AddGenreAndDirectorsAndStudios(info,vecDirectors,vecGenres,vecStudios);
1699 for (unsigned int i = 0; i < vecGenres.size(); ++i)
1700 AddGenreToMovie(idMovie, vecGenres[i]);
1702 for (unsigned int i = 0; i < vecDirectors.size(); ++i)
1703 AddDirectorToMovie(idMovie, vecDirectors[i]);
1705 for (unsigned int i = 0; i < vecStudios.size(); ++i)
1706 AddStudioToMovie(idMovie, vecStudios[i]);
1709 if (!info.m_strWritingCredits.IsEmpty())
1711 CStdStringArray writers;
1712 StringUtils::SplitString(info.m_strWritingCredits, g_advancedSettings.m_videoItemSeparator, writers);
1713 for (unsigned int i = 0; i < writers.size(); i++)
1715 CStdString writer(writers[i]);
1717 int idWriter = AddActor(writer,"");
1718 AddWriterToMovie(idMovie, idWriter );
1723 for (CVideoInfoTag::iCast it = info.m_cast.begin(); it != info.m_cast.end(); ++it)
1725 int idActor = AddActor(it->strName,it->thumbUrl.m_xml);
1726 AddActorToMovie(idMovie, idActor, it->strRole);
1730 if (!info.m_strSet.IsEmpty())
1732 CStdStringArray sets;
1733 StringUtils::SplitString(info.m_strSet, g_advancedSettings.m_videoItemSeparator, sets);
1734 for (unsigned int i = 0; i < sets.size(); i++)
1736 CStdString set(sets[i]);
1738 int idSet = AddSet(set);
1739 AddSetToMovie(idMovie, idSet);
1744 if (!info.m_strCountry.IsEmpty())
1746 CStdStringArray countries;
1747 StringUtils::SplitString(info.m_strCountry, g_advancedSettings.m_videoItemSeparator, countries);
1748 for (unsigned int i = 0; i < countries.size(); i++)
1750 CStdString country(countries[i]);
1752 int idCountry = AddCountry(country);
1753 AddCountryToMovie(idMovie, idCountry);
1757 if (details.HasStreamDetails())
1758 SetStreamDetailsForFileId(details.m_streamDetails, GetFileId(strFilenameAndPath));
1760 // update our movie table (we know it was added already above)
1761 // and insert the new row
1762 CStdString sql = "update movie set " + GetValueString(info, VIDEODB_ID_MIN, VIDEODB_ID_MAX, DbMovieOffsets);
1763 sql += PrepareSQL(" where idMovie=%i", idMovie);
1764 m_pDS->exec(sql.c_str());
1765 CommitTransaction();
1767 AnnounceUpdate("movie", idMovie);
1773 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
1778 int CVideoDatabase::SetDetailsForTvShow(const CStdString& strPath, const CVideoInfoTag& details)
1782 if (!m_pDB.get() || !m_pDS.get())
1784 CLog::Log(LOGERROR, "%s: called without database open", __FUNCTION__);
1790 int idTvShow = GetTvShowId(strPath);
1792 idTvShow = AddTvShow(strPath);
1794 vector<int> vecDirectors;
1795 vector<int> vecGenres;
1796 vector<int> vecStudios;
1797 AddGenreAndDirectorsAndStudios(details,vecDirectors,vecGenres,vecStudios);
1800 for (CVideoInfoTag::iCast it = details.m_cast.begin(); it != details.m_cast.end(); ++it)
1802 int idActor = AddActor(it->strName,it->thumbUrl.m_xml);
1803 AddActorToTvShow(idTvShow, idActor, it->strRole);
1807 for (i = 0; i < vecGenres.size(); ++i)
1809 AddGenreToTvShow(idTvShow, vecGenres[i]);
1812 for (i = 0; i < vecDirectors.size(); ++i)
1814 AddDirectorToTvShow(idTvShow, vecDirectors[i]);
1817 for (i = 0; i < vecStudios.size(); ++i)
1819 AddStudioToTvShow(idTvShow, vecStudios[i]);
1822 // and insert the new row
1823 CStdString sql = "update tvshow set " + GetValueString(details, VIDEODB_ID_TV_MIN, VIDEODB_ID_TV_MAX, DbTvShowOffsets);
1824 sql += PrepareSQL("where idShow=%i", idTvShow);
1825 m_pDS->exec(sql.c_str());
1826 CommitTransaction();
1828 AnnounceUpdate("tvshow", idTvShow);
1834 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strPath.c_str());
1840 int CVideoDatabase::SetDetailsForEpisode(const CStdString& strFilenameAndPath, const CVideoInfoTag& details, int idShow, int idEpisode)
1845 if (idEpisode == -1)
1847 idEpisode = GetEpisodeId(strFilenameAndPath);
1849 DeleteEpisode(strFilenameAndPath,idEpisode);
1851 idEpisode = AddEpisode(idShow,strFilenameAndPath);
1854 CommitTransaction();
1859 vector<int> vecDirectors;
1860 vector<int> vecGenres;
1861 vector<int> vecStudios;
1862 AddGenreAndDirectorsAndStudios(details,vecDirectors,vecGenres,vecStudios);
1865 for (CVideoInfoTag::iCast it = details.m_cast.begin(); it != details.m_cast.end(); ++it)
1867 int idActor = AddActor(it->strName,it->thumbUrl.m_xml);
1868 AddActorToEpisode(idEpisode, idActor, it->strRole);
1872 if (!details.m_strWritingCredits.IsEmpty())
1874 CStdStringArray writers;
1875 StringUtils::SplitString(details.m_strWritingCredits, g_advancedSettings.m_videoItemSeparator, writers);
1876 for (unsigned int i = 0; i < writers.size(); i++)
1878 CStdString writer(writers[i]);
1880 int idWriter = AddActor(writer,"");
1881 AddWriterToEpisode(idEpisode, idWriter );
1885 for (unsigned int i = 0; i < vecDirectors.size(); ++i)
1887 AddDirectorToEpisode(idEpisode, vecDirectors[i]);
1890 if (details.HasStreamDetails())
1892 if (details.m_iFileId != -1)
1893 SetStreamDetailsForFileId(details.m_streamDetails, details.m_iFileId);
1895 SetStreamDetailsForFile(details.m_streamDetails, strFilenameAndPath);
1898 // and insert the new row
1899 CStdString sql = "update episode set " + GetValueString(details, VIDEODB_ID_EPISODE_MIN, VIDEODB_ID_EPISODE_MAX, DbEpisodeOffsets);
1900 sql += PrepareSQL("where idEpisode=%i", idEpisode);
1901 m_pDS->exec(sql.c_str());
1902 CommitTransaction();
1904 AnnounceUpdate("episode", idEpisode);
1910 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
1915 int CVideoDatabase::SetDetailsForMusicVideo(const CStdString& strFilenameAndPath, const CVideoInfoTag& details)
1921 int idMVideo = GetMusicVideoId(strFilenameAndPath);
1924 DeleteMusicVideo(strFilenameAndPath);
1926 idMVideo = AddMusicVideo(strFilenameAndPath);
1929 CommitTransaction();
1933 vector<int> vecDirectors;
1934 vector<int> vecGenres;
1935 vector<int> vecStudios;
1936 AddGenreAndDirectorsAndStudios(details,vecDirectors,vecGenres,vecStudios);
1939 if (!details.m_strArtist.IsEmpty())
1941 CStdStringArray vecArtists;
1942 StringUtils::SplitString(details.m_strArtist, g_advancedSettings.m_videoItemSeparator, vecArtists);
1943 for (unsigned int i = 0; i < vecArtists.size(); i++)
1945 CStdString artist = vecArtists[i];
1947 int idArtist = AddActor(artist,"");
1948 AddArtistToMusicVideo(idMVideo, idArtist);
1953 for (i = 0; i < vecGenres.size(); ++i)
1955 AddGenreToMusicVideo(idMVideo, vecGenres[i]);
1958 for (i = 0; i < vecDirectors.size(); ++i)
1960 AddDirectorToMusicVideo(idMVideo, vecDirectors[i]);
1963 for (i = 0; i < vecStudios.size(); ++i)
1965 AddStudioToMusicVideo(idMVideo, vecStudios[i]);
1968 if (details.HasStreamDetails())
1969 SetStreamDetailsForFileId(details.m_streamDetails, GetFileId(strFilenameAndPath));
1971 // update our movie table (we know it was added already above)
1972 // and insert the new row
1973 CStdString sql = "update musicvideo set " + GetValueString(details, VIDEODB_ID_MUSICVIDEO_MIN, VIDEODB_ID_MUSICVIDEO_MAX, DbMusicVideoOffsets);
1974 sql += PrepareSQL(" where idMVideo=%i", idMVideo);
1975 m_pDS->exec(sql.c_str());
1976 CommitTransaction();
1978 AnnounceUpdate("musicvideo", idMVideo);
1984 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
1989 void CVideoDatabase::SetStreamDetailsForFile(const CStreamDetails& details, const CStdString &strFileNameAndPath)
1991 // AddFile checks to make sure the file isn't already in the DB first
1992 int idFile = AddFile(strFileNameAndPath);
1995 SetStreamDetailsForFileId(details, idFile);
1998 void CVideoDatabase::SetStreamDetailsForFileId(const CStreamDetails& details, int idFile)
2006 m_pDS->exec(PrepareSQL("DELETE FROM streamdetails WHERE idFile = %i", idFile));
2008 for (int i=1; i<=details.GetVideoStreamCount(); i++)
2010 m_pDS->exec(PrepareSQL("INSERT INTO streamdetails "
2011 "(idFile, iStreamType, strVideoCodec, fVideoAspect, iVideoWidth, iVideoHeight, iVideoDuration) "
2012 "VALUES (%i,%i,'%s',%f,%i,%i,%i)",
2013 idFile, (int)CStreamDetail::VIDEO,
2014 details.GetVideoCodec(i).c_str(), details.GetVideoAspect(i),
2015 details.GetVideoWidth(i), details.GetVideoHeight(i), details.GetVideoDuration(i)));
2017 for (int i=1; i<=details.GetAudioStreamCount(); i++)
2019 m_pDS->exec(PrepareSQL("INSERT INTO streamdetails "
2020 "(idFile, iStreamType, strAudioCodec, iAudioChannels, strAudioLanguage) "
2021 "VALUES (%i,%i,'%s',%i,'%s')",
2022 idFile, (int)CStreamDetail::AUDIO,
2023 details.GetAudioCodec(i).c_str(), details.GetAudioChannels(i),
2024 details.GetAudioLanguage(i).c_str()));
2026 for (int i=1; i<=details.GetSubtitleStreamCount(); i++)
2028 m_pDS->exec(PrepareSQL("INSERT INTO streamdetails "
2029 "(idFile, iStreamType, strSubtitleLanguage) "
2030 "VALUES (%i,%i,'%s')",
2031 idFile, (int)CStreamDetail::SUBTITLE,
2032 details.GetSubtitleLanguage(i).c_str()));
2035 CommitTransaction();
2039 RollbackTransaction();
2040 CLog::Log(LOGERROR, "%s (%i) failed", __FUNCTION__, idFile);
2044 //********************************************************************************************************************************
2045 void CVideoDatabase::GetFilePathById(int idMovie, CStdString &filePath, VIDEODB_CONTENT_TYPE iType)
2049 if (NULL == m_pDB.get()) return ;
2050 if (NULL == m_pDS.get()) return ;
2052 if (idMovie < 0) return ;
2055 if (iType == VIDEODB_CONTENT_MOVIES)
2056 strSQL=PrepareSQL("select path.strPath,files.strFileName from path, files, movie where path.idPath=files.idPath and files.idFile=movie.idFile and movie.idMovie=%i order by strFilename", idMovie );
2057 if (iType == VIDEODB_CONTENT_EPISODES)
2058 strSQL=PrepareSQL("select path.strPath,files.strFileName from path, files, episode where path.idPath=files.idPath and files.idFile=episode.idFile and episode.idEpisode=%i order by strFilename", idMovie );
2059 if (iType == VIDEODB_CONTENT_TVSHOWS)
2060 strSQL=PrepareSQL("select path.strPath from path,tvshowlinkpath where path.idPath=tvshowlinkpath.idPath and tvshowlinkpath.idShow=%i", idMovie );
2061 if (iType ==VIDEODB_CONTENT_MUSICVIDEOS)
2062 strSQL=PrepareSQL("select path.strPath,files.strFileName from path, files, musicvideo where path.idPath=files.idPath and files.idFile=musicvideo.idFile and musicvideo.idMVideo=%i order by strFilename", idMovie );
2064 m_pDS->query( strSQL.c_str() );
2067 if (iType != VIDEODB_CONTENT_TVSHOWS)
2069 CStdString fileName = m_pDS->fv("files.strFilename").get_asString();
2070 ConstructPath(filePath,m_pDS->fv("path.strPath").get_asString(),fileName);
2073 filePath = m_pDS->fv("path.strPath").get_asString();
2079 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
2083 //********************************************************************************************************************************
2084 void CVideoDatabase::GetBookMarksForFile(const CStdString& strFilenameAndPath, VECBOOKMARKS& bookmarks, CBookmark::EType type /*= CBookmark::STANDARD*/, bool bAppend)
2088 int idFile = GetFileId(strFilenameAndPath);
2089 if (idFile < 0) return ;
2091 bookmarks.erase(bookmarks.begin(), bookmarks.end());
2092 if (NULL == m_pDB.get()) return ;
2093 if (NULL == m_pDS.get()) return ;
2095 CStdString strSQL=PrepareSQL("select * from bookmark where idFile=%i and type=%i order by timeInSeconds", idFile, (int)type);
2096 m_pDS->query( strSQL.c_str() );
2097 while (!m_pDS->eof())
2100 bookmark.timeInSeconds = m_pDS->fv("timeInSeconds").get_asDouble();
2101 bookmark.totalTimeInSeconds = m_pDS->fv("totalTimeInSeconds").get_asDouble();
2102 bookmark.thumbNailImage = m_pDS->fv("thumbNailImage").get_asString();
2103 bookmark.playerState = m_pDS->fv("playerState").get_asString();
2104 bookmark.player = m_pDS->fv("player").get_asString();
2105 bookmark.type = type;
2106 if (type == CBookmark::EPISODE)
2108 CStdString strSQL2=PrepareSQL("select c%02d, c%02d from episode where c%02d=%i order by c%02d, c%02d", VIDEODB_ID_EPISODE_EPISODE, VIDEODB_ID_EPISODE_SEASON, VIDEODB_ID_EPISODE_BOOKMARK, m_pDS->fv("idBookmark").get_asInt(), VIDEODB_ID_EPISODE_SORTSEASON, VIDEODB_ID_EPISODE_SORTEPISODE);
2109 m_pDS2->query(strSQL2.c_str());
2110 bookmark.episodeNumber = m_pDS2->fv(0).get_asInt();
2111 bookmark.seasonNumber = m_pDS2->fv(1).get_asInt();
2114 bookmarks.push_back(bookmark);
2117 //sort(bookmarks.begin(), bookmarks.end(), SortBookmarks);
2122 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
2126 bool CVideoDatabase::GetResumeBookMark(const CStdString& strFilenameAndPath, CBookmark &bookmark)
2128 VECBOOKMARKS bookmarks;
2129 GetBookMarksForFile(strFilenameAndPath, bookmarks, CBookmark::RESUME);
2130 if (bookmarks.size() > 0)
2132 bookmark = bookmarks[0];
2138 void CVideoDatabase::DeleteResumeBookMark(const CStdString &strFilenameAndPath)
2140 if (!m_pDB.get() || !m_pDS.get())
2143 int fileID = GetFileId(strFilenameAndPath);
2149 CStdString sql = PrepareSQL("delete from bookmark where idFile=%i and type=%i", fileID, CBookmark::RESUME);
2150 m_pDS->exec(sql.c_str());
2154 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
2158 void CVideoDatabase::GetEpisodesByFile(const CStdString& strFilenameAndPath, vector<CVideoInfoTag>& episodes)
2162 CStdString strSQL = PrepareSQL("select * from episodeview where idFile=%i order by c%02d, c%02d asc", GetFileId(strFilenameAndPath), VIDEODB_ID_EPISODE_SORTSEASON, VIDEODB_ID_EPISODE_SORTEPISODE);
2163 m_pDS->query(strSQL.c_str());
2164 while (!m_pDS->eof())
2166 episodes.push_back(GetDetailsForEpisode(m_pDS));
2173 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
2177 //********************************************************************************************************************************
2178 void CVideoDatabase::AddBookMarkToFile(const CStdString& strFilenameAndPath, const CBookmark &bookmark, CBookmark::EType type /*= CBookmark::STANDARD*/)
2182 int idFile = AddFile(strFilenameAndPath);
2185 if (NULL == m_pDB.get()) return ;
2186 if (NULL == m_pDS.get()) return ;
2190 if (type == CBookmark::RESUME) // get the same resume mark bookmark each time type
2192 strSQL=PrepareSQL("select idBookmark from bookmark where idFile=%i and type=1", idFile);
2194 else if (type == CBookmark::STANDARD) // get the same bookmark again, and update. not sure here as a dvd can have same time in multiple places, state will differ thou
2196 /* get a bookmark within the same time as previous */
2197 double mintime = bookmark.timeInSeconds - 0.5f;
2198 double maxtime = bookmark.timeInSeconds + 0.5f;
2199 strSQL=PrepareSQL("select idBookmark from bookmark where idFile=%i and type=%i and (timeInSeconds between %f and %f) and playerState='%s'", idFile, (int)type, mintime, maxtime, bookmark.playerState.c_str());
2202 if (type != CBookmark::EPISODE)
2205 m_pDS->query( strSQL.c_str() );
2206 if (m_pDS->num_rows() != 0)
2207 idBookmark = m_pDS->get_field_value("idBookmark").get_asInt();
2210 // update or insert depending if it existed before
2211 if (idBookmark >= 0 )
2212 strSQL=PrepareSQL("update bookmark set timeInSeconds = %f, totalTimeInSeconds = %f, thumbNailImage = '%s', player = '%s', playerState = '%s' where idBookmark = %i", bookmark.timeInSeconds, bookmark.totalTimeInSeconds, bookmark.thumbNailImage.c_str(), bookmark.player.c_str(), bookmark.playerState.c_str(), idBookmark);
2214 strSQL=PrepareSQL("insert into bookmark (idBookmark, idFile, timeInSeconds, totalTimeInSeconds, thumbNailImage, player, playerState, type) values(NULL,%i,%f,%f,'%s','%s','%s', %i)", idFile, bookmark.timeInSeconds, bookmark.totalTimeInSeconds, bookmark.thumbNailImage.c_str(), bookmark.player.c_str(), bookmark.playerState.c_str(), (int)type);
2216 m_pDS->exec(strSQL.c_str());
2220 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
2224 void CVideoDatabase::ClearBookMarkOfFile(const CStdString& strFilenameAndPath, CBookmark& bookmark, CBookmark::EType type /*= CBookmark::STANDARD*/)
2228 int idFile = GetFileId(strFilenameAndPath);
2229 if (idFile < 0) return ;
2230 if (NULL == m_pDB.get()) return ;
2231 if (NULL == m_pDS.get()) return ;
2233 /* a litle bit uggly, we clear first bookmark that is within one second of given */
2234 /* should be no problem since we never add bookmarks that are closer than that */
2235 double mintime = bookmark.timeInSeconds - 0.5f;
2236 double maxtime = bookmark.timeInSeconds + 0.5f;
2237 CStdString strSQL = PrepareSQL("select idBookmark from bookmark where idFile=%i and type=%i and playerState like '%s' and player like '%s' and (timeInSeconds between %f and %f)", idFile, type, bookmark.playerState.c_str(), bookmark.player.c_str(), mintime, maxtime);
2239 m_pDS->query( strSQL.c_str() );
2240 if (m_pDS->num_rows() != 0)
2242 int idBookmark = m_pDS->get_field_value("idBookmark").get_asInt();
2243 strSQL=PrepareSQL("delete from bookmark where idBookmark=%i",idBookmark);
2244 m_pDS->exec(strSQL.c_str());
2245 if (type == CBookmark::EPISODE)
2247 strSQL=PrepareSQL("update episode set c%02d=-1 where idFile=%i and c%02d=%i", VIDEODB_ID_EPISODE_BOOKMARK, idFile, VIDEODB_ID_EPISODE_BOOKMARK, idBookmark);
2248 m_pDS->exec(strSQL.c_str());
2256 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
2260 //********************************************************************************************************************************
2261 void CVideoDatabase::ClearBookMarksOfFile(const CStdString& strFilenameAndPath, CBookmark::EType type /*= CBookmark::STANDARD*/)
2265 int idFile = GetFileId(strFilenameAndPath);
2266 if (idFile < 0) return ;
2267 if (NULL == m_pDB.get()) return ;
2268 if (NULL == m_pDS.get()) return ;
2270 CStdString strSQL=PrepareSQL("delete from bookmark where idFile=%i and type=%i", idFile, (int)type);
2271 m_pDS->exec(strSQL.c_str());
2272 if (type == CBookmark::EPISODE)
2274 strSQL=PrepareSQL("update episode set c%02d=-1 where idFile=%i", VIDEODB_ID_EPISODE_BOOKMARK, idFile);
2275 m_pDS->exec(strSQL.c_str());
2280 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
2285 bool CVideoDatabase::GetBookMarkForEpisode(const CVideoInfoTag& tag, CBookmark& bookmark)
2289 CStdString strSQL = PrepareSQL("select bookmark.* from bookmark join episode on episode.c%02d=bookmark.idBookmark where episode.idEpisode=%i", VIDEODB_ID_EPISODE_BOOKMARK, tag.m_iDbId);
2290 m_pDS->query( strSQL.c_str() );
2293 bookmark.timeInSeconds = m_pDS->fv("timeInSeconds").get_asDouble();
2294 bookmark.totalTimeInSeconds = m_pDS->fv("totalTimeInSeconds").get_asDouble();
2295 bookmark.thumbNailImage = m_pDS->fv("thumbNailImage").get_asString();
2296 bookmark.playerState = m_pDS->fv("playerState").get_asString();
2297 bookmark.player = m_pDS->fv("player").get_asString();
2298 bookmark.type = (CBookmark::EType)m_pDS->fv("type").get_asInt();
2309 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
2315 void CVideoDatabase::AddBookMarkForEpisode(const CVideoInfoTag& tag, const CBookmark& bookmark)
2319 int idFile = GetFileId(tag.m_strFileNameAndPath);
2320 // delete the current episode for the selected episode number
2321 CStdString strSQL = PrepareSQL("delete from bookmark where idBookmark in (select c%02d from episode where c%02d=%i and c%02d=%i and idFile=%i)", VIDEODB_ID_EPISODE_BOOKMARK, VIDEODB_ID_EPISODE_SEASON, tag.m_iSeason, VIDEODB_ID_EPISODE_EPISODE, tag.m_iEpisode, idFile);
2322 m_pDS->exec(strSQL.c_str());
2324 AddBookMarkToFile(tag.m_strFileNameAndPath, bookmark, CBookmark::EPISODE);
2325 int idBookmark = (int)m_pDS->lastinsertid();
2326 strSQL = PrepareSQL("update episode set c%02d=%i where c%02d=%i and c%02d=%i and idFile=%i", VIDEODB_ID_EPISODE_BOOKMARK, idBookmark, VIDEODB_ID_EPISODE_SEASON, tag.m_iSeason, VIDEODB_ID_EPISODE_EPISODE, tag.m_iEpisode, idFile);
2327 m_pDS->exec(strSQL.c_str());
2331 CLog::Log(LOGERROR, "%s (%i) failed", __FUNCTION__, tag.m_iDbId);
2335 void CVideoDatabase::DeleteBookMarkForEpisode(const CVideoInfoTag& tag)
2339 CStdString strSQL = PrepareSQL("delete from bookmark where idBookmark in (select c%02d from episode where idEpisode=%i)", VIDEODB_ID_EPISODE_BOOKMARK, tag.m_iDbId);
2340 m_pDS->exec(strSQL.c_str());
2341 strSQL = PrepareSQL("update episode set c%02d=-1 where idEpisode=%i", VIDEODB_ID_EPISODE_BOOKMARK, tag.m_iDbId);
2342 m_pDS->exec(strSQL.c_str());
2346 CLog::Log(LOGERROR, "%s (%i) failed", __FUNCTION__, tag.m_iDbId);
2350 //********************************************************************************************************************************
2351 void CVideoDatabase::DeleteMovie(const CStdString& strFilenameAndPath, bool bKeepId /* = false */, bool bKeepThumb /* = false */)
2355 if (NULL == m_pDB.get()) return ;
2356 if (NULL == m_pDS.get()) return ;
2357 int idMovie = GetMovieId(strFilenameAndPath);
2366 strSQL=PrepareSQL("delete from genrelinkmovie where idMovie=%i", idMovie);
2367 m_pDS->exec(strSQL.c_str());
2369 strSQL=PrepareSQL("delete from actorlinkmovie where idMovie=%i", idMovie);
2370 m_pDS->exec(strSQL.c_str());
2372 strSQL=PrepareSQL("delete from directorlinkmovie where idMovie=%i", idMovie);
2373 m_pDS->exec(strSQL.c_str());
2375 strSQL=PrepareSQL("delete from studiolinkmovie where idMovie=%i", idMovie);
2376 m_pDS->exec(strSQL.c_str());
2378 strSQL=PrepareSQL("delete from setlinkmovie where idMovie=%i", idMovie);
2379 m_pDS->exec(strSQL.c_str());
2381 strSQL=PrepareSQL("delete from countrylinkmovie where idMovie=%i", idMovie);
2382 m_pDS->exec(strSQL.c_str());
2385 DeleteThumbForItem(strFilenameAndPath,false);
2387 DeleteStreamDetails(GetFileId(strFilenameAndPath));
2389 // keep the movie table entry, linking to tv shows, and bookmarks
2390 // so we can update the data in place
2391 // the ancilliary tables are still purged
2394 ClearBookMarksOfFile(strFilenameAndPath);
2396 strSQL=PrepareSQL("delete from movie where idMovie=%i", idMovie);
2397 m_pDS->exec(strSQL.c_str());
2399 strSQL=PrepareSQL("delete from movielinktvshow where idMovie=%i", idMovie);
2400 m_pDS->exec(strSQL.c_str());
2407 strSQL=PrepareSQL("update movie set c%02d=NULL where idmovie=%i", VIDEODB_ID_TITLE, idMovie);
2408 m_pDS->exec(strSQL.c_str());
2412 CStdString strPath, strFileName;
2413 SplitPath(strFilenameAndPath,strPath,strFileName);
2414 InvalidatePathHash(strPath);
2415 CommitTransaction();
2418 AnnounceRemove("movie", idMovie);
2422 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
2426 void CVideoDatabase::DeleteTvShow(const CStdString& strPath, bool bKeepId /* = false */, bool bKeepThumb /* = false */)
2431 if (NULL == m_pDB.get()) return ;
2432 if (NULL == m_pDS.get()) return ;
2433 idTvShow = GetTvShowId(strPath);
2441 CStdString strSQL=PrepareSQL("select tvshowlinkepisode.idEpisode,path.strPath,files.strFileName from tvshowlinkepisode,path,files,episode where tvshowlinkepisode.idShow=%i and tvshowlinkepisode.idEpisode=episode.idEpisode and episode.idFile=files.idFile and files.idPath=path.idPath",idTvShow);
2442 m_pDS2->query(strSQL.c_str());
2443 while (!m_pDS2->eof())
2445 CStdString strFilenameAndPath;
2446 CStdString strPath = m_pDS2->fv("path.strPath").get_asString();
2447 CStdString strFileName = m_pDS2->fv("files.strFilename").get_asString();
2448 ConstructPath(strFilenameAndPath, strPath, strFileName);
2449 DeleteEpisode(strFilenameAndPath, m_pDS2->fv(0).get_asInt(), bKeepId);
2453 strSQL=PrepareSQL("delete from genrelinktvshow where idShow=%i", idTvShow);
2454 m_pDS->exec(strSQL.c_str());
2456 strSQL=PrepareSQL("delete from actorlinktvshow where idShow=%i", idTvShow);
2457 m_pDS->exec(strSQL.c_str());
2459 strSQL=PrepareSQL("delete from directorlinktvshow where idShow=%i", idTvShow);
2460 m_pDS->exec(strSQL.c_str());
2462 strSQL=PrepareSQL("delete from tvshowlinkpath where idShow=%i", idTvShow);
2463 m_pDS->exec(strSQL.c_str());
2465 strSQL=PrepareSQL("delete from studiolinktvshow where idShow=%i", idTvShow);
2466 m_pDS->exec(strSQL.c_str());
2469 DeleteThumbForItem(strPath,true);
2471 // keep tvshow table and movielink table so we can update data in place
2474 strSQL=PrepareSQL("delete from tvshow where idShow=%i", idTvShow);
2475 m_pDS->exec(strSQL.c_str());
2477 strSQL=PrepareSQL("delete from movielinktvshow where idShow=%i", idTvShow);
2478 m_pDS->exec(strSQL.c_str());
2481 InvalidatePathHash(strPath);
2483 CommitTransaction();
2486 AnnounceRemove("tvshow", idTvShow);
2490 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strPath.c_str());
2494 void CVideoDatabase::DeleteEpisode(const CStdString& strFilenameAndPath, int idEpisode, bool bKeepId /* = false */, bool bKeepThumb /* = false */)
2498 if (NULL == m_pDB.get()) return ;
2499 if (NULL == m_pDS.get()) return ;
2502 idEpisode = GetEpisodeId(strFilenameAndPath);
2510 strSQL=PrepareSQL("delete from actorlinkepisode where idEpisode=%i", idEpisode);
2511 m_pDS->exec(strSQL.c_str());
2513 strSQL=PrepareSQL("delete from directorlinkepisode where idEpisode=%i", idEpisode);
2514 m_pDS->exec(strSQL.c_str());
2516 strSQL=PrepareSQL("select tvshowlinkepisode.idshow from tvshowlinkepisode where idEpisode=%i",idEpisode);
2517 m_pDS->query(strSQL.c_str());
2519 strSQL=PrepareSQL("delete from tvshowlinkepisode where idEpisode=%i", idEpisode);
2520 m_pDS->exec(strSQL.c_str());
2523 DeleteThumbForItem(strFilenameAndPath, false, idEpisode);
2525 DeleteStreamDetails(GetFileId(strFilenameAndPath));
2527 // keep episode table entry and bookmarks so we can update the data in place
2528 // the ancilliary tables are still purged
2531 ClearBookMarksOfFile(strFilenameAndPath);
2533 strSQL=PrepareSQL("delete from episode where idEpisode=%i", idEpisode);
2534 m_pDS->exec(strSQL.c_str());
2538 AnnounceRemove("episode", idEpisode);
2542 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
2546 void CVideoDatabase::DeleteMusicVideo(const CStdString& strFilenameAndPath, bool bKeepId /* = false */, bool bKeepThumb /* = false */)
2550 if (NULL == m_pDB.get()) return ;
2551 if (NULL == m_pDS.get()) return ;
2552 int idMVideo = GetMusicVideoId(strFilenameAndPath);
2561 strSQL=PrepareSQL("delete from genrelinkmusicvideo where idMVideo=%i", idMVideo);
2562 m_pDS->exec(strSQL.c_str());
2564 strSQL=PrepareSQL("delete from artistlinkmusicvideo where idMVideo=%i", idMVideo);
2565 m_pDS->exec(strSQL.c_str());
2567 strSQL=PrepareSQL("delete from directorlinkmusicvideo where idMVideo=%i", idMVideo);
2568 m_pDS->exec(strSQL.c_str());
2570 strSQL=PrepareSQL("delete from studiolinkmusicvideo where idMVideo=%i", idMVideo);
2571 m_pDS->exec(strSQL.c_str());
2574 DeleteThumbForItem(strFilenameAndPath,false);
2576 DeleteStreamDetails(GetFileId(strFilenameAndPath));
2578 // keep the music video table entry and bookmarks so we can update data in place
2579 // the ancilliary tables are still purged
2582 ClearBookMarksOfFile(strFilenameAndPath);
2584 strSQL=PrepareSQL("delete from musicvideo where idMVideo=%i", idMVideo);
2585 m_pDS->exec(strSQL.c_str());
2592 strSQL=PrepareSQL("update musicvideo set c%02d=NULL where idmvideo=%i", VIDEODB_ID_MUSICVIDEO_TITLE, idMVideo);
2593 m_pDS->exec(strSQL.c_str());
2597 CStdString strPath, strFileName;
2598 SplitPath(strFilenameAndPath,strPath,strFileName);
2599 InvalidatePathHash(strPath);
2600 CommitTransaction();
2603 AnnounceRemove("musicvideo", idMVideo);
2607 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
2611 void CVideoDatabase::DeleteStreamDetails(int idFile)
2613 m_pDS->exec(PrepareSQL("delete from streamdetails where idFile=%i", idFile));
2616 void CVideoDatabase::DeleteSet(int idSet)
2620 if (NULL == m_pDB.get()) return ;
2621 if (NULL == m_pDS.get()) return ;
2624 strSQL=PrepareSQL("delete from sets where idSet=%i", idSet);
2625 m_pDS->exec(strSQL.c_str());
2626 strSQL=PrepareSQL("delete from setlinkmovie where idSet=%i", idSet);
2627 m_pDS->exec(strSQL.c_str());
2631 CLog::Log(LOGERROR, "%s (%i) failed", __FUNCTION__, idSet);
2635 void CVideoDatabase::GetDetailsFromDB(auto_ptr<Dataset> &pDS, int min, int max, const SDbTableOffsets *offsets, CVideoInfoTag &details, int idxOffset)
2637 for (int i = min + 1; i < max; i++)
2639 switch (offsets[i].type)
2641 case VIDEODB_TYPE_STRING:
2642 *(CStdString*)(((char*)&details)+offsets[i].offset) = pDS->fv(i+idxOffset).get_asString();
2644 case VIDEODB_TYPE_INT:
2645 case VIDEODB_TYPE_COUNT:
2646 *(int*)(((char*)&details)+offsets[i].offset) = pDS->fv(i+idxOffset).get_asInt();
2648 case VIDEODB_TYPE_BOOL:
2649 *(bool*)(((char*)&details)+offsets[i].offset) = pDS->fv(i+idxOffset).get_asBool();
2651 case VIDEODB_TYPE_FLOAT:
2652 *(float*)(((char*)&details)+offsets[i].offset) = pDS->fv(i+idxOffset).get_asFloat();
2658 DWORD movieTime = 0;
2661 CVideoInfoTag CVideoDatabase::GetDetailsByTypeAndId(VIDEODB_CONTENT_TYPE type, int id)
2663 CVideoInfoTag details;
2668 case VIDEODB_CONTENT_MOVIES:
2669 GetMovieInfo("", details, id);
2671 case VIDEODB_CONTENT_TVSHOWS:
2672 GetTvShowInfo("", details, id);
2674 case VIDEODB_CONTENT_EPISODES:
2675 GetEpisodeInfo("", details, id);
2677 case VIDEODB_CONTENT_MUSICVIDEOS:
2678 GetMusicVideoInfo("", details, id);
2686 bool CVideoDatabase::GetStreamDetailsForFileId(CStreamDetails& details, int idFile) const
2691 bool retVal = false;
2693 dbiplus::Dataset *pDS = m_pDB->CreateDataset();
2694 CStdString strSQL = PrepareSQL("SELECT * FROM streamdetails WHERE idFile = %i", idFile);
2700 CStreamDetail::StreamType e = (CStreamDetail::StreamType)pDS->fv(1).get_asInt();
2703 case CStreamDetail::VIDEO:
2705 CStreamDetailVideo *p = new CStreamDetailVideo();
2706 p->m_strCodec = pDS->fv(2).get_asString();
2707 p->m_fAspect = pDS->fv(3).get_asFloat();
2708 p->m_iWidth = pDS->fv(4).get_asInt();
2709 p->m_iHeight = pDS->fv(5).get_asInt();
2710 p->m_iDuration = pDS->fv(10).get_asInt();
2711 details.AddStream(p);
2715 case CStreamDetail::AUDIO:
2717 CStreamDetailAudio *p = new CStreamDetailAudio();
2718 p->m_strCodec = pDS->fv(6).get_asString();
2719 if (pDS->fv(7).get_isNull())
2720 p->m_iChannels = -1;
2722 p->m_iChannels = pDS->fv(7).get_asInt();
2723 p->m_strLanguage = pDS->fv(8).get_asString();
2724 details.AddStream(p);
2728 case CStreamDetail::SUBTITLE:
2730 CStreamDetailSubtitle *p = new CStreamDetailSubtitle();
2731 p->m_strLanguage = pDS->fv(9).get_asString();
2732 details.AddStream(p);
2742 details.DetermineBestStreams();
2747 CVideoInfoTag CVideoDatabase::GetDetailsForMovie(auto_ptr<Dataset> &pDS, bool needsCast /* = false */)
2749 CVideoInfoTag details;
2752 DWORD time = CTimeUtils::GetTimeMS();
2753 int idMovie = pDS->fv(0).get_asInt();
2755 GetDetailsFromDB(pDS, VIDEODB_ID_MIN, VIDEODB_ID_MAX, DbMovieOffsets, details);
2757 details.m_iDbId = idMovie;
2758 GetCommonDetails(pDS, details);
2759 movieTime += CTimeUtils::GetTimeMS() - time; time = CTimeUtils::GetTimeMS();
2761 GetStreamDetailsForFileId(details.m_streamDetails, details.m_iFileId);
2765 // create cast string
2766 CStdString strSQL = PrepareSQL("SELECT actors.strActor,actorlinkmovie.strRole,actors.strThumb FROM actorlinkmovie,actors WHERE actorlinkmovie.idMovie=%i AND actorlinkmovie.idActor=actors.idActor ORDER BY actors.idActor",idMovie);
2767 m_pDS2->query(strSQL.c_str());
2768 while (!m_pDS2->eof())
2771 info.strName = m_pDS2->fv("actors.strActor").get_asString();
2772 info.strRole = m_pDS2->fv("actorlinkmovie.strRole").get_asString();
2773 info.thumbUrl.ParseString(m_pDS2->fv("actors.strThumb").get_asString());
2774 details.m_cast.push_back(info);
2777 castTime += CTimeUtils::GetTimeMS() - time; time = CTimeUtils::GetTimeMS();
2778 details.m_strPictureURL.Parse();
2780 // create sets string
2781 strSQL = PrepareSQL("SELECT sets.strSet FROM sets,setlinkmovie WHERE setlinkmovie.idMovie=%i AND setlinkmovie.idSet=sets.idSet ORDER BY sets.idSet",idMovie);
2782 m_pDS2->query(strSQL.c_str());
2783 while (!m_pDS2->eof())
2785 CStdString setName = m_pDS2->fv("sets.strSet").get_asString();
2786 if (!details.m_strSet.IsEmpty())
2787 details.m_strSet += g_advancedSettings.m_videoItemSeparator;
2788 details.m_strSet += setName;
2792 // create tvshowlink string
2794 GetLinksToTvShow(idMovie,links);
2795 for (unsigned int i=0;i<links.size();++i)
2797 strSQL = PrepareSQL("select c%02d from tvshow where idShow=%i",
2798 VIDEODB_ID_TV_TITLE,links[i]);
2799 m_pDS2->query(strSQL.c_str());
2802 if (!details.m_strShowLink.IsEmpty())
2803 details.m_strShowLink += g_advancedSettings.m_videoItemSeparator;
2804 details.m_strShowLink += m_pDS2->fv(0).get_asString();
2812 CVideoInfoTag CVideoDatabase::GetDetailsForTvShow(auto_ptr<Dataset> &pDS, bool needsCast /* = false */)
2814 CVideoInfoTag details;
2817 DWORD time = CTimeUtils::GetTimeMS();
2818 int idTvShow = pDS->fv(0).get_asInt();
2820 GetDetailsFromDB(pDS, VIDEODB_ID_TV_MIN, VIDEODB_ID_TV_MAX, DbTvShowOffsets, details, 1);
2821 details.m_iDbId = idTvShow;
2822 details.m_strPath = pDS->fv(VIDEODB_DETAILS_TVSHOW_PATH).get_asString();
2823 details.m_iEpisode = m_pDS->fv(VIDEODB_DETAILS_TVSHOW_NUM_EPISODES).get_asInt();
2824 details.m_playCount = m_pDS->fv(VIDEODB_DETAILS_TVSHOW_NUM_WATCHED).get_asInt();
2825 details.m_strShowTitle = details.m_strTitle;
2827 movieTime += CTimeUtils::GetTimeMS() - time; time = CTimeUtils::GetTimeMS();
2831 // create cast string
2832 CStdString strSQL = PrepareSQL("select actors.strActor,actorlinktvshow.strRole,actors.strThumb from actorlinktvshow,actors where actorlinktvshow.idShow=%i and actorlinktvshow.idActor = actors.idActor",idTvShow);
2833 m_pDS2->query(strSQL.c_str());
2834 while (!m_pDS2->eof())
2837 info.strName = m_pDS2->fv("actors.strActor").get_asString();
2838 info.strRole = m_pDS2->fv("actorlinktvshow.strRole").get_asString();
2839 info.thumbUrl.ParseString(m_pDS2->fv("actors.strThumb").get_asString());
2840 details.m_cast.push_back(info);
2843 castTime += CTimeUtils::GetTimeMS() - time; time = CTimeUtils::GetTimeMS();
2844 details.m_strPictureURL.Parse();
2849 CVideoInfoTag CVideoDatabase::GetDetailsForEpisode(auto_ptr<Dataset> &pDS, bool needsCast /* = false */)
2851 CVideoInfoTag details;
2854 DWORD time = CTimeUtils::GetTimeMS();
2855 int idEpisode = pDS->fv(0).get_asInt();
2857 GetDetailsFromDB(pDS, VIDEODB_ID_EPISODE_MIN, VIDEODB_ID_EPISODE_MAX, DbEpisodeOffsets, details);
2858 details.m_iDbId = idEpisode;
2859 GetCommonDetails(pDS, details);
2860 movieTime += CTimeUtils::GetTimeMS() - time; time = CTimeUtils::GetTimeMS();
2862 details.m_strMPAARating = pDS->fv(VIDEODB_DETAILS_EPISODE_TVSHOW_MPAA).get_asString();
2863 details.m_strShowTitle = pDS->fv(VIDEODB_DETAILS_EPISODE_TVSHOW_NAME).get_asString();
2864 details.m_strStudio = pDS->fv(VIDEODB_DETAILS_EPISODE_TVSHOW_STUDIO).get_asString();
2865 details.m_strPremiered = pDS->fv(VIDEODB_DETAILS_EPISODE_TVSHOW_AIRED).get_asString();
2867 GetStreamDetailsForFileId(details.m_streamDetails, details.m_iFileId);
2872 set<int>::iterator it;
2874 // create cast string
2875 CStdString strSQL = PrepareSQL("select actors.idActor,actors.strActor,actorlinkepisode.strRole,actors.strThumb from actorlinkepisode,actors where actorlinkepisode.idEpisode=%i and actorlinkepisode.idActor = actors.idActor",idEpisode);
2876 m_pDS2->query(strSQL.c_str());
2877 bool showCast=false;
2878 while (!m_pDS2->eof() || !showCast)
2882 int idActor = m_pDS2->fv("actors.idActor").get_asInt();
2883 it = actors.find(idActor);
2885 if (it == actors.end())
2888 info.strName = m_pDS2->fv("actors.strActor").get_asString();
2889 info.strRole = m_pDS2->fv("actorlinkepisode.strRole").get_asString();
2890 info.thumbUrl.ParseString(m_pDS2->fv("actors.strThumb").get_asString());
2891 details.m_cast.push_back(info);
2892 actors.insert(idActor);
2896 if (m_pDS2->eof() && !showCast)
2899 int idShow = GetTvShowForEpisode(details.m_iDbId);
2902 strSQL = PrepareSQL("select actors.idActor,actors.strActor,actorlinktvshow.strRole,actors.strThumb from actorlinktvshow,actors where actorlinktvshow.idShow=%i and actorlinktvshow.idActor = actors.idActor",idShow);
2903 m_pDS2->query(strSQL.c_str());
2907 castTime += CTimeUtils::GetTimeMS() - time; time = CTimeUtils::GetTimeMS();
2908 details.m_strPictureURL.Parse();
2909 strSQL=PrepareSQL("select * from bookmark join episode on episode.c%02d=bookmark.idBookmark where episode.idEpisode=%i and bookmark.type=%i", VIDEODB_ID_EPISODE_BOOKMARK,details.m_iDbId,CBookmark::EPISODE);
2910 m_pDS2->query(strSQL.c_str());
2912 details.m_fEpBookmark = m_pDS2->fv("bookmark.timeInSeconds").get_asFloat();
2918 CVideoInfoTag CVideoDatabase::GetDetailsForMusicVideo(auto_ptr<Dataset> &pDS)
2920 CVideoInfoTag details;
2923 DWORD time = CTimeUtils::GetTimeMS();
2924 int idMovie = pDS->fv(0).get_asInt();
2926 GetDetailsFromDB(pDS, VIDEODB_ID_MUSICVIDEO_MIN, VIDEODB_ID_MUSICVIDEO_MAX, DbMusicVideoOffsets, details);
2927 details.m_iDbId = idMovie;
2928 GetCommonDetails(pDS, details);
2929 movieTime += CTimeUtils::GetTimeMS() - time; time = CTimeUtils::GetTimeMS();
2931 GetStreamDetailsForFileId(details.m_streamDetails, details.m_iFileId);
2933 details.m_strPictureURL.Parse();
2937 void CVideoDatabase::GetCommonDetails(auto_ptr<Dataset> &pDS, CVideoInfoTag &details)
2939 details.m_iFileId = pDS->fv(VIDEODB_DETAILS_FILEID).get_asInt();
2940 details.m_strPath = pDS->fv(VIDEODB_DETAILS_PATH).get_asString();
2941 CStdString strFileName = pDS->fv(VIDEODB_DETAILS_FILE).get_asString();
2942 ConstructPath(details.m_strFileNameAndPath,details.m_strPath,strFileName);
2943 details.m_playCount = pDS->fv(VIDEODB_DETAILS_PLAYCOUNT).get_asInt();
2944 details.m_lastPlayed = pDS->fv(VIDEODB_DETAILS_LASTPLAYED).get_asString();
2947 /// \brief GetVideoSettings() obtains any saved video settings for the current file.
2948 /// \retval Returns true if the settings exist, false otherwise.
2949 bool CVideoDatabase::GetVideoSettings(const CStdString &strFilenameAndPath, CVideoSettings &settings)
2953 // obtain the FileID (if it exists)
2954 #ifdef NEW_VIDEODB_METHODS
2955 if (NULL == m_pDB.get()) return false;
2956 if (NULL == m_pDS.get()) return false;
2957 CStdString strPath, strFileName;
2958 URIUtils::Split(strFilenameAndPath, strPath, strFileName);
2959 CStdString strSQL=PrepareSQL("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());
2961 int idFile = GetFileId(strFilenameAndPath);
2962 if (idFile < 0) return false;
2963 if (NULL == m_pDB.get()) return false;
2964 if (NULL == m_pDS.get()) return false;
2965 // ok, now obtain the settings for this file
2966 CStdString strSQL=PrepareSQL("select * from settings where settings.idFile = '%i'", idFile);
2968 m_pDS->query( strSQL.c_str() );
2969 if (m_pDS->num_rows() > 0)
2970 { // get the video settings info
2971 settings.m_AudioDelay = m_pDS->fv("AudioDelay").get_asFloat();
2972 settings.m_AudioStream = m_pDS->fv("AudioStream").get_asInt();
2973 settings.m_Brightness = m_pDS->fv("Brightness").get_asFloat();
2974 settings.m_Contrast = m_pDS->fv("Contrast").get_asFloat();
2975 settings.m_CustomPixelRatio = m_pDS->fv("PixelRatio").get_asFloat();
2976 settings.m_CustomNonLinStretch = m_pDS->fv("NonLinStretch").get_asBool();
2977 settings.m_NoiseReduction = m_pDS->fv("NoiseReduction").get_asFloat();
2978 settings.m_PostProcess = m_pDS->fv("PostProcess").get_asBool();
2979 settings.m_Sharpness = m_pDS->fv("Sharpness").get_asFloat();
2980 settings.m_CustomZoomAmount = m_pDS->fv("ZoomAmount").get_asFloat();
2981 settings.m_CustomVerticalShift = m_pDS->fv("VerticalShift").get_asFloat();
2982 settings.m_Gamma = m_pDS->fv("Gamma").get_asFloat();
2983 settings.m_SubtitleDelay = m_pDS->fv("SubtitleDelay").get_asFloat();
2984 settings.m_SubtitleOn = m_pDS->fv("SubtitlesOn").get_asBool();
2985 settings.m_SubtitleStream = m_pDS->fv("SubtitleStream").get_asInt();
2986 settings.m_ViewMode = m_pDS->fv("ViewMode").get_asInt();
2987 settings.m_ResumeTime = m_pDS->fv("ResumeTime").get_asInt();
2988 settings.m_Crop = m_pDS->fv("Crop").get_asBool();
2989 settings.m_CropLeft = m_pDS->fv("CropLeft").get_asInt();
2990 settings.m_CropRight = m_pDS->fv("CropRight").get_asInt();
2991 settings.m_CropTop = m_pDS->fv("CropTop").get_asInt();
2992 settings.m_CropBottom = m_pDS->fv("CropBottom").get_asInt();
2993 settings.m_InterlaceMethod = (EINTERLACEMETHOD)m_pDS->fv("Deinterlace").get_asInt();
2994 settings.m_VolumeAmplification = m_pDS->fv("VolumeAmplification").get_asFloat();
2995 settings.m_OutputToAllSpeakers = m_pDS->fv("OutputToAllSpeakers").get_asBool();
2996 settings.m_SubtitleCached = false;
3004 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
3009 /// \brief Sets the settings for a particular video file
3010 void CVideoDatabase::SetVideoSettings(const CStdString& strFilenameAndPath, const CVideoSettings &setting)
3014 if (NULL == m_pDB.get()) return ;
3015 if (NULL == m_pDS.get()) return ;
3016 int idFile = AddFile(strFilenameAndPath);
3020 strSQL.Format("select * from settings where idFile=%i", idFile);
3021 m_pDS->query( strSQL.c_str() );
3022 if (m_pDS->num_rows() > 0)
3026 strSQL=PrepareSQL("update settings set Deinterlace=%i,ViewMode=%i,ZoomAmount=%f,PixelRatio=%f,VerticalShift=%f,"
3027 "AudioStream=%i,SubtitleStream=%i,SubtitleDelay=%f,SubtitlesOn=%i,Brightness=%f,Contrast=%f,Gamma=%f,"
3028 "VolumeAmplification=%f,AudioDelay=%f,OutputToAllSpeakers=%i,Sharpness=%f,NoiseReduction=%f,NonLinStretch=%i,PostProcess=%i,",
3029 setting.m_InterlaceMethod, setting.m_ViewMode, setting.m_CustomZoomAmount, setting.m_CustomPixelRatio, setting.m_CustomVerticalShift,
3030 setting.m_AudioStream, setting.m_SubtitleStream, setting.m_SubtitleDelay, setting.m_SubtitleOn,
3031 setting.m_Brightness, setting.m_Contrast, setting.m_Gamma, setting.m_VolumeAmplification, setting.m_AudioDelay,
3032 setting.m_OutputToAllSpeakers,setting.m_Sharpness,setting.m_NoiseReduction,setting.m_CustomNonLinStretch,setting.m_PostProcess);
3034 strSQL2=PrepareSQL("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, idFile);
3036 m_pDS->exec(strSQL.c_str());
3042 strSQL= "INSERT INTO settings (idFile,Deinterlace,ViewMode,ZoomAmount,PixelRatio, VerticalShift, "
3043 "AudioStream,SubtitleStream,SubtitleDelay,SubtitlesOn,Brightness,"
3044 "Contrast,Gamma,VolumeAmplification,AudioDelay,OutputToAllSpeakers,"
3045 "ResumeTime,Crop,CropLeft,CropRight,CropTop,CropBottom,"
3046 "Sharpness,NoiseReduction,NonLinStretch,PostProcess) "
3048 strSQL += PrepareSQL("(%i,%i,%i,%f,%f,%f,%i,%i,%f,%i,%f,%f,%f,%f,%f,%i,%i,%i,%i,%i,%i,%i,%f,%f,%i,%i)",
3049 idFile, setting.m_InterlaceMethod, setting.m_ViewMode, setting.m_CustomZoomAmount, setting.m_CustomPixelRatio, setting.m_CustomVerticalShift,
3050 setting.m_AudioStream, setting.m_SubtitleStream, setting.m_SubtitleDelay, setting.m_SubtitleOn, setting.m_Brightness,
3051 setting.m_Contrast, setting.m_Gamma, setting.m_VolumeAmplification, setting.m_AudioDelay, setting.m_OutputToAllSpeakers,
3052 setting.m_ResumeTime, setting.m_Crop, setting.m_CropLeft, setting.m_CropRight, setting.m_CropTop, setting.m_CropBottom,
3053 setting.m_Sharpness, setting.m_NoiseReduction, setting.m_CustomNonLinStretch, setting.m_PostProcess);
3054 m_pDS->exec(strSQL.c_str());
3059 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
3063 /// \brief GetStackTimes() obtains any saved video times for the stacked file
3064 /// \retval Returns true if the stack times exist, false otherwise.
3065 bool CVideoDatabase::GetStackTimes(const CStdString &filePath, vector<int> ×)
3069 // obtain the FileID (if it exists)
3070 int idFile = GetFileId(filePath);
3071 if (idFile < 0) return false;
3072 if (NULL == m_pDB.get()) return false;
3073 if (NULL == m_pDS.get()) return false;
3074 // ok, now obtain the settings for this file
3075 CStdString strSQL=PrepareSQL("select times from stacktimes where idFile=%i\n", idFile);
3076 m_pDS->query( strSQL.c_str() );
3077 if (m_pDS->num_rows() > 0)
3078 { // get the video settings info
3079 CStdStringArray timeString;
3081 StringUtils::SplitString(m_pDS->fv("times").get_asString(), ",", timeString);
3083 for (unsigned int i = 0; i < timeString.size(); i++)
3085 times.push_back(atoi(timeString[i].c_str()));
3086 timeTotal += atoi(timeString[i].c_str());
3089 return (timeTotal > 0);
3095 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
3100 /// \brief Sets the stack times for a particular video file
3101 void CVideoDatabase::SetStackTimes(const CStdString& filePath, vector<int> ×)
3105 if (NULL == m_pDB.get()) return ;
3106 if (NULL == m_pDS.get()) return ;
3107 int idFile = AddFile(filePath);
3111 // delete any existing items
3112 m_pDS->exec( PrepareSQL("delete from stacktimes where idFile=%i", idFile) );
3115 CStdString timeString;
3116 timeString.Format("%i", times[0]);
3117 for (unsigned int i = 1; i < times.size(); i++)
3120 time.Format(",%i", times[i]);
3123 m_pDS->exec( PrepareSQL("insert into stacktimes (idFile,times) values (%i,'%s')\n", idFile, timeString.c_str()) );
3127 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, filePath.c_str());
3131 void CVideoDatabase::RemoveContentForPath(const CStdString& strPath, CGUIDialogProgress *progress /* = NULL */)
3133 if(URIUtils::IsMultiPath(strPath))
3135 vector<CStdString> paths;
3136 CMultiPathDirectory::GetPaths(strPath, paths);
3138 for(unsigned i=0;i<paths.size();i++)
3139 RemoveContentForPath(paths[i], progress);
3144 if (NULL == m_pDB.get()) return ;
3145 if (NULL == m_pDS.get()) return ;
3147 auto_ptr<Dataset> pDS(m_pDB->CreateDataset());
3148 CStdString strPath1(strPath);
3149 CStdString strSQL = PrepareSQL("select idPath,strContent,strPath from path where strPath like '%%%s%%'",strPath1.c_str());
3150 progress = (CGUIDialogProgress *)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
3151 pDS->query(strSQL.c_str());
3154 progress->SetHeading(700);
3155 progress->SetLine(0, "");
3156 progress->SetLine(1, 313);
3157 progress->SetLine(2, 330);
3158 progress->SetPercentage(0);
3159 progress->StartModal();
3160 progress->ShowProgressBar(true);
3163 int iMax = pDS->num_rows();
3166 bool bMvidsChecked=false;
3169 progress->SetPercentage((int)((float)(iCurr++)/iMax*100.f));
3170 progress->Progress();
3172 int idPath = pDS->fv("path.idPath").get_asInt();
3173 CStdString strCurrPath = pDS->fv("path.strPath").get_asString();
3174 if (HasTvShowInfo(strCurrPath))
3175 DeleteTvShow(strCurrPath);
3178 strSQL=PrepareSQL("select files.strFilename from files join movie on movie.idFile=files.idFile where files.idPath=%i",idPath);
3179 m_pDS2->query(strSQL.c_str());
3182 strSQL=PrepareSQL("select files.strFilename from files join musicvideo on musicvideo.idFile=files.idFile where files.idPath=%i",idPath);
3183 m_pDS2->query(strSQL.c_str());
3184 bMvidsChecked = true;
3186 while (!m_pDS2->eof())
3188 CStdString strMoviePath;
3189 CStdString strFileName = m_pDS2->fv("files.strFilename").get_asString();
3190 ConstructPath(strMoviePath, strCurrPath, strFileName);
3191 if (HasMovieInfo(strMoviePath))
3192 DeleteMovie(strMoviePath);
3193 if (HasMusicVideoInfo(strMoviePath))
3194 DeleteMusicVideo(strMoviePath);
3196 if (m_pDS2->eof() && !bMvidsChecked)
3198 strSQL=PrepareSQL("select files.strFilename from files join musicvideo on musicvideo.idFile=files.idFile where files.idPath=%i",idPath);
3199 m_pDS2->query(strSQL.c_str());
3200 bMvidsChecked = true;
3207 strSQL = PrepareSQL("update path set strContent = '', strScraper='', strHash='',strSettings='',useFolderNames=0,scanRecursive=0 where strPath like '%%%s%%'",strPath1.c_str());
3208 pDS->exec(strSQL.c_str());
3212 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strPath.c_str());
3218 void CVideoDatabase::SetScraperForPath(const CStdString& filePath, const ScraperPtr& scraper, const VIDEO::SScanSettings& settings)
3220 // if we have a multipath, set scraper for all contained paths too
3221 if(URIUtils::IsMultiPath(filePath))
3223 vector<CStdString> paths;
3224 CMultiPathDirectory::GetPaths(filePath, paths);
3226 for(unsigned i=0;i<paths.size();i++)
3227 SetScraperForPath(paths[i],scraper,settings);
3232 if (NULL == m_pDB.get()) return ;
3233 if (NULL == m_pDS.get()) return ;
3234 int idPath = GetPathId(filePath);
3236 { // no path found - we have to add one
3237 idPath = AddPath(filePath);
3238 if (idPath < 0) return ;
3243 if (settings.exclude)
3244 { //NB See note in ::GetScraperForPath about strContent=='none'
3245 strSQL=PrepareSQL("update path set strContent='', strScraper='', scanRecursive=0, useFolderNames=0, strSettings='', noUpdate=0 , exclude=1 where idPath=%i", idPath);
3248 { // catch clearing content, but not excluding
3249 strSQL=PrepareSQL("update path set strContent='', strScraper='', scanRecursive=0, useFolderNames=0, strSettings='', noUpdate=0, exclude=0 where idPath=%i", idPath);
3253 CStdString content = TranslateContent(scraper->Content());
3254 strSQL=PrepareSQL("update path set strContent='%s', strScraper='%s', scanRecursive=%i, useFolderNames=%i, strSettings='%s', noUpdate=%i, exclude=0 where idPath=%i", content.c_str(), scraper->ID().c_str(),settings.recurse,settings.parent_name,scraper->GetPathSettings().c_str(),settings.noupdate, idPath);
3256 m_pDS->exec(strSQL.c_str());
3260 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, filePath.c_str());
3264 bool CVideoDatabase::ScraperInUse(const CStdString &scraperID) const
3268 if (NULL == m_pDB.get()) return false;
3269 if (NULL == m_pDS.get()) return false;
3271 CStdString sql = PrepareSQL("select count(1) from path where strScraper='%s'", scraperID.c_str());
3272 if (!m_pDS->query(sql.c_str()) || m_pDS->num_rows() == 0)
3274 bool found = m_pDS->fv(0).get_asInt() > 0;
3280 CLog::Log(LOGERROR, "%s(%s) failed", __FUNCTION__, scraperID.c_str());
3285 bool CVideoDatabase::UpdateOldVersion(int iVersion)
3293 m_pDS->exec("alter table settings add NonLinStretch bool");
3297 m_pDS->exec("alter table path add exclude bool");
3302 CStdString columnsSelect, columns;
3303 for (int i = 0; i < 21; i++)
3306 column.Format(",c%02d", i);
3307 columnsSelect += column;
3308 columns += column + " text";
3312 m_pDS->exec(PrepareSQL("CREATE TABLE movienew ( idMovie integer primary key, idFile integer%s)", columns.c_str()));
3313 m_pDS->exec(PrepareSQL("INSERT INTO movienew select idMovie,idFile%s from movie", columnsSelect.c_str()));
3314 m_pDS->exec("DROP TABLE movie");
3315 m_pDS->exec("ALTER TABLE movienew RENAME TO movie");
3317 m_pDS->exec("CREATE UNIQUE INDEX ix_movie_file_1 ON movie (idFile, idMovie)");
3318 m_pDS->exec("CREATE UNIQUE INDEX ix_movie_file_2 ON movie (idMovie, idFile)");
3321 m_pDS->exec(PrepareSQL("CREATE TABLE episodenew ( idEpisode integer primary key, idFile integer%s)", columns.c_str()));
3322 m_pDS->exec(PrepareSQL("INSERT INTO episodenew select idEpisode,idFile%s from episode", columnsSelect.c_str()));
3323 m_pDS->exec("DROP TABLE episode");
3324 m_pDS->exec("ALTER TABLE episodenew RENAME TO episode");
3326 m_pDS->exec("CREATE UNIQUE INDEX ix_episode_file_1 on episode (idEpisode, idFile)");
3327 m_pDS->exec("CREATE UNIQUE INDEX id_episode_file_2 on episode (idFile, idEpisode)");
3328 m_pDS->exec(PrepareSQL("CREATE INDEX ix_episode_season_episode on episode (c%02d, c%02d)", VIDEODB_ID_EPISODE_SEASON, VIDEODB_ID_EPISODE_EPISODE));
3329 m_pDS->exec(PrepareSQL("CREATE INDEX ix_episode_bookmark on episode (c%02d)", VIDEODB_ID_EPISODE_BOOKMARK));
3332 m_pDS->exec(PrepareSQL("CREATE TABLE musicvideonew ( idMVideo integer primary key, idFile integer%s)", columns.c_str()));
3333 m_pDS->exec(PrepareSQL("INSERT INTO musicvideonew select idMVideo,idFile%s from musicvideo", columnsSelect.c_str()));
3334 m_pDS->exec("DROP TABLE musicvideo");
3335 m_pDS->exec("ALTER TABLE musicvideonew RENAME TO musicvideo");
3337 m_pDS->exec("CREATE UNIQUE INDEX ix_musicvideo_file_1 on musicvideo (idMVideo, idFile)");
3338 m_pDS->exec("CREATE UNIQUE INDEX ix_musicvideo_file_2 on musicvideo (idFile, idMVideo)");
3342 m_pDS->exec("ALTER table movie add c21 text");
3343 m_pDS->exec("ALTER table episode add c21 text");
3344 m_pDS->exec("ALTER table musicvideo add c21 text");
3345 m_pDS->exec("ALTER table tvshow add c21 text");
3347 CLog::Log(LOGINFO, "create country table");
3348 m_pDS->exec("CREATE TABLE country ( idCountry integer primary key, strCountry text)\n");
3350 CLog::Log(LOGINFO, "create countrylinkmovie table");
3351 m_pDS->exec("CREATE TABLE countrylinkmovie ( idCountry integer, idMovie integer)\n");
3352 m_pDS->exec("CREATE UNIQUE INDEX ix_countrylinkmovie_1 ON countrylinkmovie ( idCountry, idMovie)\n");
3353 m_pDS->exec("CREATE UNIQUE INDEX ix_countrylinkmovie_2 ON countrylinkmovie ( idMovie, idCountry)\n");
3356 { // update for old scrapers
3357 m_pDS->query("select idPath,strScraper from path");
3358 set<CStdString> scrapers;
3359 while (!m_pDS->eof())
3361 // translate the addon
3362 CStdString scraperID = ADDON::UpdateVideoScraper(m_pDS->fv(1).get_asString());
3363 if (!scraperID.IsEmpty())
3365 scrapers.insert(scraperID);
3366 CStdString update = PrepareSQL("update path set strScraper='%s' where idPath=%i", scraperID.c_str(), m_pDS->fv(0).get_asInt());
3367 m_pDS2->exec(update);
3372 // ensure these scrapers are installed
3373 CAddonInstaller::Get().InstallFromXBMCRepo(scrapers);
3377 m_pDS->exec("DELETE FROM streamdetails");
3378 m_pDS->exec("ALTER table streamdetails add iVideoDuration integer");
3382 m_pDS->exec("ALTER table settings add PostProcess bool");
3386 m_pDS->exec("DELETE FROM streamdetails"); //Roll the stream details as changed from minutes to seconds
3390 m_pDS->exec("ALTER table settings add VerticalShift float");
3394 // only if MySQL is used and default character set is not utf8
3395 // string data needs to be converted to proper utf8
3396 CStdString charset = m_pDS->getDatabase()->getDefaultCharset();
3397 if (!m_sqlite && !charset.empty() && charset != "utf8")
3399 map<CStdString, CStdStringArray> tables;
3400 map<CStdString, CStdStringArray>::iterator itt;
3401 CStdStringArray::iterator itc;
3403 // columns that need to be converted
3405 CStdStringArray c_columns;
3406 for (int i = 0; i < 22; i++)
3409 c.Format("c%02d", i);
3410 c_columns.push_back(c);
3413 tables.insert(pair<CStdString, CStdStringArray> ("episode", c_columns));
3414 tables.insert(pair<CStdString, CStdStringArray> ("movie", c_columns));
3415 tables.insert(pair<CStdString, CStdStringArray> ("musicvideo", c_columns));
3416 tables.insert(pair<CStdString, CStdStringArray> ("tvshow", c_columns));
3420 c1.push_back("strRole");
3421 tables.insert(pair<CStdString, CStdStringArray> ("actorlinkepisode", c1));
3422 tables.insert(pair<CStdString, CStdStringArray> ("actorlinkmovie", c1));
3423 tables.insert(pair<CStdString, CStdStringArray> ("actorlinktvshow", c1));
3427 c2.push_back("strActor");
3428 tables.insert(pair<CStdString, CStdStringArray> ("actors", c2));
3431 c3.push_back("strCountry");
3432 tables.insert(pair<CStdString, CStdStringArray> ("country", c3));
3435 c4.push_back("strFilename");
3436 tables.insert(pair<CStdString, CStdStringArray> ("files", c4));
3439 c5.push_back("strGenre");
3440 tables.insert(pair<CStdString, CStdStringArray> ("genre", c5));
3443 c6.push_back("strSet");
3444 tables.insert(pair<CStdString, CStdStringArray> ("sets", c6));
3447 c7.push_back("strStudio");
3448 tables.insert(pair<CStdString, CStdStringArray> ("studio", c7));
3450 for (itt = tables.begin(); itt != tables.end(); ++itt)
3453 q = PrepareSQL("UPDATE `%s` SET", itt->first.c_str());
3454 for (itc = itt->second.begin(); itc != itt->second.end(); ++itc)
3456 q += PrepareSQL(" `%s` = CONVERT(CAST(CONVERT(`%s` USING %s) AS BINARY) USING utf8)",
3457 itc->c_str(), itc->c_str(), charset.c_str());
3458 if (*itc != itt->second.back())
3469 m_pDS->exec("ALTER table movie add c22 text");
3470 m_pDS->exec("ALTER table episode add c22 text");
3471 m_pDS->exec("ALTER table musicvideo add c22 text");
3472 m_pDS->exec("ALTER table tvshow add c22 text");
3473 // Now update our tables
3474 UpdateBasePath("movie", "idMovie", VIDEODB_ID_BASEPATH);
3475 UpdateBasePath("musicvideo", "idMVideo", VIDEODB_ID_MUSICVIDEO_BASEPATH);
3476 UpdateBasePath("episode", "idEpisode", VIDEODB_ID_EPISODE_BASEPATH);
3477 UpdateBasePath("tvshow", "idShow", VIDEODB_ID_TV_BASEPATH, true);
3480 { // add indices for dir entry lookups
3481 m_pDS->exec("CREATE INDEX ixMovieBasePath ON movie ( c22(255) )");
3482 m_pDS->exec("CREATE INDEX ixMusicVideoBasePath ON musicvideo ( c13(255) )");
3483 m_pDS->exec("CREATE INDEX ixEpisodeBasePath ON episode ( c18(255) )");
3484 m_pDS->exec("CREATE INDEX ixTVShowBasePath ON tvshow ( c16(255) )");
3488 CLog::Log(LOGINFO, "create tvshowview");
3489 m_pDS->exec("DROP VIEW IF EXISTS tvshowview");
3490 CStdString tvshowview = PrepareSQL("CREATE VIEW tvshowview AS SELECT "
3492 "path.strPath AS strPath,"
3493 " NULLIF(COUNT(episode.c12), 0) AS totalCount,"
3494 " SUM(files.playCount) AS watchedcount,"
3495 " NULLIF(COUNT(DISTINCT(episode.c12)), 0) AS totalSeasons "
3497 " LEFT JOIN tvshowlinkpath ON"
3498 " tvshowlinkpath.idShow=tvshow.idShow"
3499 " LEFT JOIN path ON"
3500 " path.idPath=tvshowlinkpath.idPath"
3501 " LEFT JOIN tvshowlinkepisode ON"
3502 " tvshowlinkepisode.idShow=tvshow.idShow"
3503 " LEFT JOIN episode ON"
3504 " episode.idEpisode=tvshowlinkepisode.idEpisode"
3505 " LEFT JOIN files ON"
3506 " files.idFile=episode.idFile "
3507 "GROUP BY tvshow.idShow;");
3508 m_pDS->exec(tvshowview.c_str());
3512 CLog::Log(LOGINFO, "recreate episodeview");
3513 m_pDS->exec("DROP VIEW IF EXISTS episodeview");
3514 CStdString episodeview = PrepareSQL("CREATE VIEW episodeview AS SELECT "
3515 " episode.*,files.strFileName as strFileName,"
3516 " path.strPath as strPath,files.playCount as playCount,files.lastPlayed as lastPlayed,"
3517 " tvshow.c%02d as strTitle,tvshow.c%02d as strStudio,tvshow.idShow as idShow,"
3518 " tvshow.c%02d as premiered, tvshow.c%02d as mpaa "
3521 " files.idFile=episode.idFile "
3522 " JOIN tvshowlinkepisode ON "
3523 " episode.idepisode=tvshowlinkepisode.idEpisode "
3525 " tvshow.idShow=tvshowlinkepisode.idShow "
3527 " files.idPath=path.idPath", VIDEODB_ID_TV_TITLE, VIDEODB_ID_TV_STUDIOS, VIDEODB_ID_TV_PREMIERED, VIDEODB_ID_TV_MPAA);
3528 m_pDS->exec(episodeview.c_str());
3530 CLog::Log(LOGINFO, "recreate musicvideoview");
3531 m_pDS->exec("DROP VIEW IF EXISTS musicvideoview");
3532 m_pDS->exec("CREATE VIEW musicvideoview AS SELECT "
3533 " musicvideo.*,files.strFileName AS strFileName,path.strPath AS strPath,"
3534 " files.playCount AS playCount,files.lastPlayed as lastPlayed "
3537 " files.idFile=musicvideo.idFile"
3539 " path.idPath=files.idPath");
3541 CLog::Log(LOGINFO, "recreate movieview");
3542 m_pDS->exec("DROP VIEW IF EXISTS movieview");
3543 m_pDS->exec("CREATE VIEW movieview AS SELECT "
3544 " movie.*,files.strFileName as strFileName,path.strPath as strPath,"
3545 " files.playCount as playCount,files.lastPlayed as lastPlayed "
3548 " files.idFile=movie.idFile"
3550 " path.idPath=files.idPath");
3555 CLog::Log(LOGERROR, "Error attempting to update the database version!");
3556 RollbackTransaction();
3559 CommitTransaction();
3563 void CVideoDatabase::UpdateBasePath(const char *table, const char *id, int column, bool shows)
3567 query = PrepareSQL("SELECT idShow,path.strPath from tvshowlinkpath join path on tvshowlinkpath.idPath=path.idPath");
3569 query = PrepareSQL("SELECT %s.%s,path.strPath,files.strFileName from %s join files on %s.idFile=files.idFile join path on files.idPath=path.idPath", table, id, table, table);
3571 map<CStdString, bool> paths;
3572 m_pDS2->query(query.c_str());
3573 while (!m_pDS2->eof())
3575 CStdString path(m_pDS2->fv(1).get_asString());
3576 map<CStdString, bool>::iterator i = paths.find(path);
3577 if (i == paths.end())
3579 SScanSettings settings;
3580 bool foundDirectly = false;
3581 ScraperPtr scraper = GetScraperForPath(path, settings, foundDirectly);
3582 if (scraper && scraper->Content() == CONTENT_TVSHOWS && !shows)
3583 paths.insert(make_pair(path, false)); // episodes
3585 paths.insert(make_pair(path, settings.parent_name_root)); // shows, movies, musicvids
3586 i = paths.find(path);
3588 CStdString filename;
3590 ConstructPath(filename, path, m_pDS2->fv(2).get_asString());
3593 CFileItem item(filename, shows);
3594 path = item.GetBaseMoviePath(i->second);
3595 CStdString sql = PrepareSQL("UPDATE %s set c%02d='%s' where %s.%s=%i", table, column, path.c_str(), table, id, m_pDS2->fv(0).get_asInt());
3596 m_pDS->exec(sql.c_str());
3602 int CVideoDatabase::GetPlayCount(const CFileItem &item)
3604 int id = GetFileId(item);
3606 return 0; // not in db, so not watched
3611 if (NULL == m_pDB.get()) return -1;
3612 if (NULL == m_pDS.get()) return -1;
3614 CStdString strSQL = PrepareSQL("select playCount from files WHERE idFile=%i", id);
3616 if (m_pDS->query(strSQL.c_str()))
3618 // there should only ever be one row returned
3619 if (m_pDS->num_rows() == 1)
3620 count = m_pDS->fv(0).get_asInt();
3627 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
3632 void CVideoDatabase::UpdateFanart(const CFileItem &item, VIDEODB_CONTENT_TYPE type)
3634 if (NULL == m_pDB.get()) return;
3635 if (NULL == m_pDS.get()) return;
3636 if (!item.HasVideoInfoTag() || item.GetVideoInfoTag()->m_iDbId < 0) return;
3639 if (type == VIDEODB_CONTENT_TVSHOWS)
3640 exec = PrepareSQL("UPDATE tvshow set c%02d='%s' WHERE idShow=%i", VIDEODB_ID_TV_FANART, item.GetVideoInfoTag()->m_fanart.m_xml.c_str(), item.GetVideoInfoTag()->m_iDbId);
3641 else if (type == VIDEODB_CONTENT_MOVIES)
3642 exec = PrepareSQL("UPDATE movie set c%02d='%s' WHERE idMovie=%i", VIDEODB_ID_FANART, item.GetVideoInfoTag()->m_fanart.m_xml.c_str(), item.GetVideoInfoTag()->m_iDbId);
3646 m_pDS->exec(exec.c_str());
3648 if (type == VIDEODB_CONTENT_TVSHOWS)
3649 AnnounceUpdate("tvshow", item.GetVideoInfoTag()->m_iDbId);
3650 else if (type == VIDEODB_CONTENT_MOVIES)
3651 AnnounceUpdate("movie", item.GetVideoInfoTag()->m_iDbId);
3655 CLog::Log(LOGERROR, "%s - error updating fanart for %s", __FUNCTION__, item.m_strPath.c_str());
3659 void CVideoDatabase::SetPlayCount(const CFileItem &item, int count, const CStdString &date)
3661 int id = AddFile(item);
3665 // and mark as watched
3668 if (NULL == m_pDB.get()) return ;
3669 if (NULL == m_pDS.get()) return ;
3675 strSQL = PrepareSQL("update files set playCount=%i,lastPlayed='%s' where idFile=%i", count, CDateTime::GetCurrentDateTime().GetAsDBDateTime().c_str(), id);
3677 strSQL = PrepareSQL("update files set playCount=%i,lastPlayed='%s' where idFile=%i", count, date.c_str(), id);
3682 strSQL = PrepareSQL("update files set playCount=NULL,lastPlayed=NULL where idFile=%i", id);
3684 strSQL = PrepareSQL("update files set playCount=NULL,lastPlayed='%s' where idFile=%i", date.c_str(), id);
3687 m_pDS->exec(strSQL.c_str());
3690 data["playcount"] = count;
3691 ANNOUNCEMENT::CAnnouncementManager::Announce(ANNOUNCEMENT::Library, "xbmc", "NewPlayCount", CFileItemPtr(new CFileItem(item)), data);
3695 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
3699 void CVideoDatabase::IncrementPlayCount(const CFileItem &item)
3701 SetPlayCount(item, GetPlayCount(item) + 1);
3704 void CVideoDatabase::UpdateLastPlayed(const CFileItem &item)
3706 SetPlayCount(item, GetPlayCount(item), CDateTime::GetCurrentDateTime().GetAsDBDateTime());
3709 void CVideoDatabase::UpdateMovieTitle(int idMovie, const CStdString& strNewMovieTitle, VIDEODB_CONTENT_TYPE iType)
3713 if (NULL == m_pDB.get()) return ;
3714 if (NULL == m_pDS.get()) return ;
3717 if (iType == VIDEODB_CONTENT_MOVIES)
3719 CLog::Log(LOGINFO, "Changing Movie:id:%i New Title:%s", idMovie, strNewMovieTitle.c_str());
3720 strSQL = PrepareSQL("UPDATE movie SET c%02d='%s' WHERE idMovie=%i", VIDEODB_ID_TITLE, strNewMovieTitle.c_str(), idMovie );
3723 else if (iType == VIDEODB_CONTENT_EPISODES)
3725 CLog::Log(LOGINFO, "Changing Episode:id:%i New Title:%s", idMovie, strNewMovieTitle.c_str());
3726 strSQL = PrepareSQL("UPDATE episode SET c%02d='%s' WHERE idEpisode=%i", VIDEODB_ID_EPISODE_TITLE, strNewMovieTitle.c_str(), idMovie );
3727 content = "episode";
3729 else if (iType == VIDEODB_CONTENT_TVSHOWS)
3731 CLog::Log(LOGINFO, "Changing TvShow:id:%i New Title:%s", idMovie, strNewMovieTitle.c_str());
3732 strSQL = PrepareSQL("UPDATE tvshow SET c%02d='%s' WHERE idShow=%i", VIDEODB_ID_TV_TITLE, strNewMovieTitle.c_str(), idMovie );
3735 else if (iType == VIDEODB_CONTENT_MUSICVIDEOS)
3737 CLog::Log(LOGINFO, "Changing MusicVideo:id:%i New Title:%s", idMovie, strNewMovieTitle.c_str());
3738 strSQL = PrepareSQL("UPDATE musicvideo SET c%02d='%s' WHERE idMVideo=%i", VIDEODB_ID_MUSICVIDEO_TITLE, strNewMovieTitle.c_str(), idMovie );
3739 content = "musicvideo";
3741 else if (iType == VIDEODB_CONTENT_MOVIE_SETS)
3743 CLog::Log(LOGINFO, "Changing Movie set:id:%i New Title:%s", idMovie, strNewMovieTitle.c_str());
3744 strSQL = PrepareSQL("UPDATE sets SET strSet='%s' WHERE idSet=%i", strNewMovieTitle.c_str(), idMovie );
3746 m_pDS->exec(strSQL.c_str());
3748 if (content.size() > 0)
3749 AnnounceUpdate(content, idMovie);
3753 CLog::Log(LOGERROR, "%s (int idMovie, const CStdString& strNewMovieTitle) failed on MovieID:%i and Title:%s", __FUNCTION__, idMovie, strNewMovieTitle.c_str());
3757 /// \brief EraseVideoSettings() Erases the videoSettings table and reconstructs it
3758 void CVideoDatabase::EraseVideoSettings()
3762 CLog::Log(LOGINFO, "Deleting settings information for all movies");
3763 m_pDS->exec("delete from settings");
3767 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
3771 bool CVideoDatabase::GetGenresNav(const CStdString& strBaseDir, CFileItemList& items, int idContent)
3773 return GetNavCommon(strBaseDir, items, "genre", idContent);
3776 bool CVideoDatabase::GetCountriesNav(const CStdString& strBaseDir, CFileItemList& items, int idContent)
3778 return GetNavCommon(strBaseDir, items, "country", idContent);
3781 bool CVideoDatabase::GetStudiosNav(const CStdString& strBaseDir, CFileItemList& items, int idContent)
3783 return GetNavCommon(strBaseDir, items, "studio", idContent);
3786 bool CVideoDatabase::GetNavCommon(const CStdString& strBaseDir, CFileItemList& items, const CStdString &type, int idContent)
3790 if (NULL == m_pDB.get()) return false;
3791 if (NULL == m_pDS.get()) return false;
3794 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
3796 if (idContent == VIDEODB_CONTENT_MOVIES)
3797 strSQL = PrepareSQL("select %s.id%s,%s.str%s,path.strPath,files.playCount from %s join %slinkmovie on %s.id%s=%slinkmovie.id%s join movie on %slinkmovie.idMovie = movie.idMovie join files on files.idFile=movie.idFile join path on path.idPath=files.idPath",
3798 type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str());
3799 else if (idContent == VIDEODB_CONTENT_TVSHOWS) //this will not get tvshows with 0 episodes
3800 strSQL = PrepareSQL("select %s.id%s,%s.str%s,path.strPath from %s join %slinktvshow on %s.id%s=%slinktvshow.id%s join tvshow on %slinktvshow.idShow=tvshow.idShow join tvshowlinkepisode on tvshowlinkepisode.idShow=tvshow.idShow join episode on episode.idEpisode=tvshowlinkepisode.idEpisode join files on files.idFile=episode.idFile join path on path.idPath=files.idPath",
3801 type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str());
3802 else if (idContent == VIDEODB_CONTENT_MUSICVIDEOS)
3803 strSQL = PrepareSQL("select %s.id%s,%s.str%s,path.strPath,files.playCount from %s join %slinkmusicvideo on %s.id%s=%slinkmusicvideo.id%s join musicvideo on %slinkmusicvideo.idMVideo = musicvideo.idMVideo join files on files.idFile=musicvideo.idFile join path on path.idPath=files.idPath",
3804 type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str());
3808 if (idContent == VIDEODB_CONTENT_MOVIES)
3809 strSQL = PrepareSQL("select %s.id%s,%s.str%s,count(1),count(files.playCount) from %s join %slinkmovie on %s.id%s=%slinkmovie.id%s join movie on %slinkmovie.idMovie=movie.idMovie join files on files.idFile=movie.idFile group by %s.id%s",
3810 type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str());
3811 else if (idContent == VIDEODB_CONTENT_TVSHOWS)
3812 strSQL = PrepareSQL("select distinct %s.id%s,%s.str%s from %s join %slinktvshow on %s.id%s=%slinktvshow.id%s join tvshow on %slinktvshow.idShow=tvshow.idShow",
3813 type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str());
3814 else if (idContent == VIDEODB_CONTENT_MUSICVIDEOS)
3815 strSQL = PrepareSQL("select %s.id%s,%s.str%s,count(1),count(files.playCount) from %s join %slinkmusicvideo on %s.id%s=%slinkmusicvideo.id%s join musicvideo on %slinkmusicvideo.idMVideo=musicvideo.idMVideo join files on files.idFile=musicvideo.idFile group by %s.id%s",
3816 type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str());
3819 int iRowsFound = RunQuery(strSQL);
3820 if (iRowsFound <= 0)
3821 return iRowsFound == 0;
3823 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
3825 map<int, pair<CStdString,int> > mapItems;
3826 map<int, pair<CStdString,int> >::iterator it;
3827 while (!m_pDS->eof())
3829 int id = m_pDS->fv(0).get_asInt();
3830 CStdString str = m_pDS->fv(1).get_asString();
3832 // was this already found?
3833 it = mapItems.find(id);
3834 if (it == mapItems.end())
3837 if (g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv(2).get_asString()),g_settings.m_videoSources))
3839 if (idContent == VIDEODB_CONTENT_MOVIES || idContent == VIDEODB_CONTENT_MUSICVIDEOS)
3840 mapItems.insert(pair<int, pair<CStdString,int> >(id, pair<CStdString,int>(str,m_pDS->fv(3).get_asInt()))); //fv(3) is file.playCount
3841 else if (idContent == VIDEODB_CONTENT_TVSHOWS)
3842 mapItems.insert(pair<int, pair<CStdString,int> >(id, pair<CStdString,int>(str,0)));
3849 for (it = mapItems.begin(); it != mapItems.end(); ++it)
3851 CFileItemPtr pItem(new CFileItem(it->second.first));
3853 strDir.Format("%ld/", it->first);
3854 pItem->m_strPath = strBaseDir + strDir;
3855 pItem->m_bIsFolder = true;
3856 if (idContent == VIDEODB_CONTENT_MOVIES || idContent == VIDEODB_CONTENT_MUSICVIDEOS)
3857 pItem->GetVideoInfoTag()->m_playCount = it->second.second;
3858 if (!items.Contains(pItem->m_strPath))
3860 pItem->SetLabelPreformated(true);
3867 while (!m_pDS->eof())
3869 CFileItemPtr pItem(new CFileItem(m_pDS->fv(1).get_asString()));
3871 strDir.Format("%ld/", m_pDS->fv(0).get_asInt());
3872 pItem->m_strPath = strBaseDir + strDir;
3873 pItem->m_bIsFolder = true;
3874 pItem->SetLabelPreformated(true);
3875 if (idContent == VIDEODB_CONTENT_MOVIES || idContent == VIDEODB_CONTENT_MUSICVIDEOS)
3876 { // fv(3) is the number of videos watched, fv(2) is the total number. We set the playcount
3877 // only if the number of videos watched is equal to the total number (i.e. every video watched)
3878 pItem->GetVideoInfoTag()->m_playCount = (m_pDS->fv(3).get_asInt() == m_pDS->fv(2).get_asInt()) ? 1 : 0;
3889 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
3894 bool CVideoDatabase::GetSetsNav(const CStdString& strBaseDir, CFileItemList& items, int idContent, const CStdString &where)
3898 if (NULL == m_pDB.get()) return false;
3899 if (NULL == m_pDS.get()) return false;
3901 // get primary sets for movies
3903 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
3905 if (idContent == VIDEODB_CONTENT_MOVIES)
3906 strSQL=PrepareSQL("SELECT sets.idSet,sets.strSet,path.strPath,files.playCount FROM sets JOIN setlinkmovie ON sets.idSet=setlinkmovie.idSet JOIN (SELECT idSet, COUNT(1) AS c FROM setlinkmovie GROUP BY idSet HAVING c>1) s2 ON s2.idSet=sets.idSet JOIN movie ON setlinkmovie.idMovie=movie.idMovie JOIN files ON files.idFile=movie.idFile JOIN path ON path.idPath=files.idPath");
3912 if (idContent == VIDEODB_CONTENT_MOVIES)
3914 strSQL=PrepareSQL("SELECT sets.idSet,sets.strSet,COUNT(1) AS c,count(files.playCount) FROM sets JOIN setlinkmovie ON sets.idSet=setlinkmovie.idSet JOIN movie ON setlinkmovie.idMovie=movie.idMovie JOIN files ON files.idFile=movie.idFile ");
3915 group = " GROUP BY sets.idSet HAVING c>1";
3921 int iRowsFound = RunQuery(strSQL);
3922 if (iRowsFound <= 0)
3923 return iRowsFound == 0;
3925 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
3927 map<int, pair<CStdString,int> > mapSets;
3928 map<int, pair<CStdString,int> >::iterator it;
3929 while (!m_pDS->eof())
3931 int idSet = m_pDS->fv("sets.idSet").get_asInt();
3932 CStdString strSet = m_pDS->fv("sets.strSet").get_asString();
3933 it = mapSets.find(idSet);
3934 // was this set already found?
3935 if (it == mapSets.end())
3938 if (g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
3940 if (idContent == VIDEODB_CONTENT_MOVIES || idContent == VIDEODB_CONTENT_MUSICVIDEOS)
3941 mapSets.insert(pair<int, pair<CStdString,int> >(idSet, pair<CStdString,int>(strSet,m_pDS->fv(3).get_asInt())));
3943 mapSets.insert(pair<int, pair<CStdString,int> >(idSet, pair<CStdString,int>(strSet,0)));
3950 for (it=mapSets.begin();it != mapSets.end();++it)
3952 CFileItemPtr pItem(new CFileItem(it->second.first));
3954 strDir.Format("%ld/", it->first);
3955 pItem->m_strPath=strBaseDir + strDir;
3956 pItem->m_bIsFolder=true;
3957 if (idContent == VIDEODB_CONTENT_MOVIES || idContent == VIDEODB_CONTENT_MUSICVIDEOS)
3959 pItem->GetVideoInfoTag()->m_playCount = it->second.second;
3960 pItem->GetVideoInfoTag()->m_strTitle = pItem->GetLabel();
3962 if (!items.Contains(pItem->m_strPath))
3964 pItem->SetLabelPreformated(true);
3971 while (!m_pDS->eof())
3973 CFileItemPtr pItem(new CFileItem(m_pDS->fv("sets.strSet").get_asString()));
3975 strDir.Format("%ld/", m_pDS->fv("sets.idSet").get_asInt());
3976 pItem->m_strPath=strBaseDir + strDir;
3977 pItem->m_bIsFolder=true;
3978 pItem->SetLabelPreformated(true);
3979 if (idContent == VIDEODB_CONTENT_MOVIES || idContent==VIDEODB_CONTENT_MUSICVIDEOS)
3981 // fv(3) is the number of videos watched, fv(2) is the total number. We set the playcount
3982 // only if the number of videos watched is equal to the total number (i.e. every video watched)
3983 pItem->GetVideoInfoTag()->m_playCount = (m_pDS->fv(3).get_asInt() == m_pDS->fv(2).get_asInt()) ? 1 : 0;
3984 pItem->GetVideoInfoTag()->m_strTitle = pItem->GetLabel();
3986 bool thumb=false,fanart=false;
3987 if (CFile::Exists(pItem->GetCachedVideoThumb()))
3989 pItem->SetThumbnailImage(pItem->GetCachedVideoThumb());
3992 if (CFile::Exists(pItem->GetCachedFanart()))
3994 pItem->SetProperty("fanart_image",pItem->GetCachedFanart());
3997 if (!thumb || !fanart) // use the first item's thumb
3999 CStdString strSQL = PrepareSQL("select strPath, strFileName from movieview join setlinkmovie on setlinkmovie.idMovie=movieview.idMovie where setlinkmovie.idSet=%u", m_pDS->fv("sets.idSet").get_asInt());
4000 m_pDS2->query(strSQL.c_str());
4004 ConstructPath(path,m_pDS2->fv(0).get_asString(),m_pDS2->fv(1).get_asString());
4005 CFileItem item(path,false);
4006 if (!thumb && CFile::Exists(item.GetCachedVideoThumb()))
4007 pItem->SetThumbnailImage(item.GetCachedVideoThumb());
4008 if (!fanart && CFile::Exists(item.GetCachedFanart()))
4009 pItem->SetProperty("fanart_image",item.GetCachedFanart());
4019 // CLog::Log(LOGDEBUG, "%s Time: %d ms", CTimeUtils::GetTimeMS() - time);
4024 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
4029 bool CVideoDatabase::GetMusicVideoAlbumsNav(const CStdString& strBaseDir, CFileItemList& items, int idArtist)
4033 if (NULL == m_pDB.get()) return false;
4034 if (NULL == m_pDS.get()) return false;
4037 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
4039 strSQL=PrepareSQL("select musicvideo.c%02d,musicvideo.idMVideo,actors.strActor,path.strPath from musicvideo join artistlinkmusicvideo on artistlinkmusicvideo.idMVideo=musicvideo.idMVideo join actors on actors.idActor=artistlinkmusicvideo.idArtist join files on files.idFile=musicvideo.idFile join path on path.idPath=files.idPath",VIDEODB_ID_MUSICVIDEO_ALBUM);
4043 strSQL=PrepareSQL("select musicvideo.c%02d,musicvideo.idMVideo,actors.strActor from musicvideo join artistlinkmusicvideo on artistlinkmusicvideo.idMVideo=musicvideo.idMVideo join actors on actors.idActor=artistlinkmusicvideo.idArtist",VIDEODB_ID_MUSICVIDEO_ALBUM);
4046 strSQL += PrepareSQL(" where artistlinkmusicvideo.idArtist=%i",idArtist);
4048 strSQL += PrepareSQL(" group by musicvideo.c%02d",VIDEODB_ID_MUSICVIDEO_ALBUM);
4050 int iRowsFound = RunQuery(strSQL);
4051 if (iRowsFound <= 0)
4052 return iRowsFound == 0;
4054 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
4056 map<int, pair<CStdString,CStdString> > mapAlbums;
4057 map<int, pair<CStdString,CStdString> >::iterator it;
4058 while (!m_pDS->eof())
4060 int lidMVideo = m_pDS->fv(1).get_asInt();
4061 CStdString strAlbum = m_pDS->fv(0).get_asString();
4062 it = mapAlbums.find(lidMVideo);
4063 // was this genre already found?
4064 if (it == mapAlbums.end())
4067 if (g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
4068 mapAlbums.insert(make_pair(lidMVideo, make_pair(strAlbum,m_pDS->fv(2).get_asString())));
4074 for (it=mapAlbums.begin();it != mapAlbums.end();++it)
4076 if (!it->second.first.IsEmpty())
4078 CFileItemPtr pItem(new CFileItem(it->second.first));
4080 strDir.Format("%ld/", it->first);
4081 pItem->m_strPath=strBaseDir + strDir;
4082 pItem->m_bIsFolder=true;
4083 pItem->SetLabelPreformated(true);
4084 if (!items.Contains(pItem->m_strPath))
4086 pItem->GetVideoInfoTag()->m_strArtist = m_pDS->fv(2).get_asString();
4087 CStdString strThumb = CUtil::GetCachedAlbumThumb(pItem->GetLabel(),pItem->GetVideoInfoTag()->m_strArtist);
4088 if (CFile::Exists(strThumb))
4089 pItem->SetThumbnailImage(strThumb);
4097 while (!m_pDS->eof())
4099 if (!m_pDS->fv(0).get_asString().empty())
4101 CFileItemPtr pItem(new CFileItem(m_pDS->fv(0).get_asString()));
4103 strDir.Format("%ld/", m_pDS->fv(1).get_asInt());
4104 pItem->m_strPath=strBaseDir + strDir;
4105 pItem->m_bIsFolder=true;
4106 pItem->SetLabelPreformated(true);
4107 if (!items.Contains(pItem->m_strPath))
4109 pItem->GetVideoInfoTag()->m_strArtist = m_pDS->fv(2).get_asString();
4110 CStdString strThumb = CUtil::GetCachedAlbumThumb(pItem->GetLabel(),m_pDS->fv(2).get_asString());
4111 if (CFile::Exists(strThumb))
4112 pItem->SetThumbnailImage(strThumb);
4121 // CLog::Log(LOGDEBUG, __FUNCTION__" Time: %d ms", CTimeUtils::GetTimeMS() - time);
4126 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
4131 bool CVideoDatabase::GetWritersNav(const CStdString& strBaseDir, CFileItemList& items, int idContent)
4133 return GetPeopleNav(strBaseDir, items, "studio", idContent);
4136 bool CVideoDatabase::GetDirectorsNav(const CStdString& strBaseDir, CFileItemList& items, int idContent)
4138 return GetPeopleNav(strBaseDir, items, "director", idContent);
4141 bool CVideoDatabase::GetActorsNav(const CStdString& strBaseDir, CFileItemList& items, int idContent)
4143 if (GetPeopleNav(strBaseDir, items, (idContent == VIDEODB_CONTENT_MUSICVIDEOS) ? "artist" : "actor", idContent))
4144 { // set thumbs - ideally this should be in the normal thumb setting routines
4145 for (int i = 0; i < items.Size(); i++)
4147 CFileItemPtr pItem = items[i];
4148 if (idContent == VIDEODB_CONTENT_MUSICVIDEOS)
4150 if (CFile::Exists(pItem->GetCachedArtistThumb()))
4151 pItem->SetThumbnailImage(pItem->GetCachedArtistThumb());
4152 pItem->SetIconImage("DefaultArtist.png");
4156 if (CFile::Exists(pItem->GetCachedActorThumb()))
4157 pItem->SetThumbnailImage(pItem->GetCachedActorThumb());
4158 pItem->SetIconImage("DefaultActor.png");
4166 bool CVideoDatabase::GetPeopleNav(const CStdString& strBaseDir, CFileItemList& items, const CStdString &type, int idContent)
4168 if (NULL == m_pDB.get()) return false;
4169 if (NULL == m_pDS.get()) return false;
4173 // TODO: This routine (and probably others at this same level) use playcount as a reference to filter on at a later
4174 // point. This means that we *MUST* filter these levels as you'll get double ups. Ideally we'd allow playcount
4175 // to filter through as we normally do for tvshows to save this happening.
4176 // Also, we apply this same filtering logic to the locked or unlocked paths to prevent these from showing.
4177 // Whether or not this should happen is a tricky one - it complicates all the high level categories (everything
4180 // General routine that the other actor/director/writer routines call
4182 // get primary genres for movies
4184 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
4186 if (idContent == VIDEODB_CONTENT_MOVIES)
4187 strSQL=PrepareSQL("select actors.idActor,actors.strActor,actors.strThumb,path.strPath,files.playCount from actors join %slinkmovie on actors.idActor=%slinkmovie.id%s join movie on %slinkmovie.idMovie=movie.idMovie join files on files.idFile=movie.idFile join path on path.idPath=files.idPath", type.c_str(), type.c_str(), type.c_str(), type.c_str());
4188 else if (idContent == VIDEODB_CONTENT_TVSHOWS)
4189 strSQL=PrepareSQL("select actors.idActor,actors.strActor,actors.strThumb,path.strPath from actors join %slinktvshow on actors.idActor=%slinktvshow.id%s join tvshow on %slinktvshow.idShow = tvshow.idShow join tvshowlinkepisode on tvshowlinkepisode.idShow=tvshow.idShow join episode on episode.idEpisode=tvshowlinkepisode.idEpisode join files on files.idFile=episode.idFile join path on path.idPath = files.idPath", type.c_str(), type.c_str(), type.c_str(), type.c_str());
4190 else if (idContent == VIDEODB_CONTENT_EPISODES)
4191 strSQL=PrepareSQL("select actors.idActor,actors.strActor,actors.strThumb,path.strPath,files.playCount from actors join %slinkepisode on actors.idActor=%slinkepisode.id%s join episode on %slinkepisode.idEpisode = episode.idEpisode join files on files.idFile=episode.idFile join path on path.idPath = files.idPath", type.c_str(), type.c_str(), type.c_str(), type.c_str());
4192 else if (idContent == VIDEODB_CONTENT_MUSICVIDEOS)
4193 strSQL=PrepareSQL("select actors.idActor,actors.strActor,actors.strThumb,path.strPath,files.playCount from actors join %slinkmusicvideo on actors.idActor=%slinkmusicvideo.id%s join musicvideo on %slinkmusicvideo.idMVideo = musicvideo.idMVideo join files on files.idFile=musicvideo.idFile join path on path.idPath = files.idPath", type.c_str(), type.c_str(), type.c_str(), type.c_str());
4197 if (idContent == VIDEODB_CONTENT_MOVIES)
4199 strSQL=PrepareSQL("select actors.idActor,actors.strActor,actors.strThumb,count(1),count(files.playCount) from actors join %slinkmovie on actors.idActor=%slinkmovie.id%s join movie on %slinkmovie.idMovie=movie.idMovie join files on files.idFile=movie.idFile", type.c_str(), type.c_str(), type.c_str(), type.c_str());
4200 strSQL += " group by actors.idActor";
4202 else if (idContent == VIDEODB_CONTENT_TVSHOWS)
4203 strSQL=PrepareSQL("select distinct actors.idActor,actors.strActor,actors.strThumb from actors,%slinktvshow,tvshow where actors.idActor=%slinktvshow.id%s and %slinktvshow.idShow=tvshow.idShow", type.c_str(), type.c_str(), type.c_str(), type.c_str());
4204 else if (idContent == VIDEODB_CONTENT_EPISODES)
4205 strSQL=PrepareSQL("select actors.idActor,actors.strActor,actors.strThumb,count(1),count(files.playCount) from %slinkepisode,actors,episode,files where actors.idActor=%slinkepisode.id%s and %slinkepisode.idEpisode=episode.idEpisode and files.idFile=episode.idFile group by actors.idActor", type.c_str(), type.c_str(), type.c_str(), type.c_str());
4206 else if (idContent == VIDEODB_CONTENT_MUSICVIDEOS)
4208 strSQL=PrepareSQL("select actors.idActor,actors.strActor,actors.strThumb,count(1),count(files.playCount) from actors join %slinkmusicvideo on actors.idActor=%slinkmusicvideo.id%s join musicvideo on %slinkmusicvideo.idMVideo=musicvideo.idMVideo join files on files.idFile=musicvideo.idFile", type.c_str(), type.c_str(), type.c_str(), type.c_str());
4209 strSQL += " group by actors.idActor";
4214 unsigned int time = CTimeUtils::GetTimeMS();
4215 if (!m_pDS->query(strSQL.c_str())) return false;
4216 CLog::Log(LOGDEBUG, "%s - query took %i ms",
4217 __FUNCTION__, CTimeUtils::GetTimeMS() - time); time = CTimeUtils::GetTimeMS();
4218 int iRowsFound = m_pDS->num_rows();
4219 if (iRowsFound == 0)
4225 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
4227 map<int, CActor> mapActors;
4228 map<int, CActor>::iterator it;
4230 while (!m_pDS->eof())
4232 int idActor = m_pDS->fv(0).get_asInt();
4234 actor.name = m_pDS->fv(1).get_asString();
4235 actor.thumb = m_pDS->fv(2).get_asString();
4236 if (idContent != VIDEODB_CONTENT_TVSHOWS)
4237 actor.playcount = m_pDS->fv(3).get_asInt();
4238 it = mapActors.find(idActor);
4239 // is this actor already known?
4240 if (it == mapActors.end())
4243 if (g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
4244 mapActors.insert(pair<int, CActor>(idActor, actor));
4250 for (it=mapActors.begin();it != mapActors.end();++it)
4252 CFileItemPtr pItem(new CFileItem(it->second.name));
4254 strDir.Format("%ld/", it->first);
4255 pItem->m_strPath=strBaseDir + strDir;
4256 pItem->m_bIsFolder=true;
4257 pItem->GetVideoInfoTag()->m_playCount = it->second.playcount;
4258 pItem->GetVideoInfoTag()->m_strPictureURL.ParseString(it->second.thumb);
4264 while (!m_pDS->eof())
4268 CFileItemPtr pItem(new CFileItem(m_pDS->fv(1).get_asString()));
4270 strDir.Format("%ld/", m_pDS->fv(0).get_asInt());
4271 pItem->m_strPath=strBaseDir + strDir;
4272 pItem->m_bIsFolder=true;
4273 pItem->GetVideoInfoTag()->m_strPictureURL.ParseString(m_pDS->fv(2).get_asString());
4274 if (idContent != VIDEODB_CONTENT_TVSHOWS)
4276 // fv(4) is the number of videos watched, fv(3) is the total number. We set the playcount
4277 // only if the number of videos watched is equal to the total number (i.e. every video watched)
4278 pItem->GetVideoInfoTag()->m_playCount = (m_pDS->fv(4).get_asInt() == m_pDS->fv(3).get_asInt()) ? 1 : 0;
4280 if (idContent == VIDEODB_CONTENT_MUSICVIDEOS)
4281 pItem->GetVideoInfoTag()->m_strArtist = pItem->GetLabel();
4288 CLog::Log(LOGERROR, "%s: out of memory - retrieved %i items", __FUNCTION__, items.Size());
4289 return items.Size() > 0;
4294 CLog::Log(LOGDEBUG, "%s item retrieval took %i ms",
4295 __FUNCTION__, CTimeUtils::GetTimeMS() - time); time = CTimeUtils::GetTimeMS();
4302 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
4309 bool CVideoDatabase::GetYearsNav(const CStdString& strBaseDir, CFileItemList& items, int idContent)
4313 if (NULL == m_pDB.get()) return false;
4314 if (NULL == m_pDS.get()) return false;
4317 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
4319 if (idContent == VIDEODB_CONTENT_MOVIES)
4320 strSQL = PrepareSQL("select movie.c%02d,path.strPath,files.playCount from movie join files on files.idFile=movie.idFile join path on files.idPath = path.idPath", VIDEODB_ID_YEAR);
4321 else if (idContent == VIDEODB_CONTENT_TVSHOWS)
4322 strSQL = PrepareSQL("select tvshow.c%02d,path.strPath from tvshow join files on files.idFile=episode.idFile join episode on episode.idEpisode=tvshowlinkepisode.idEpisode join tvshowlinkepisode on tvshow.idShow = tvshowlinkepisode.idShow join path on files.idPath = path.idPath", VIDEODB_ID_TV_PREMIERED);
4323 else if (idContent == VIDEODB_CONTENT_MUSICVIDEOS)
4324 strSQL = PrepareSQL("select musicvideo.c%02d,path.strPath,files.playCount from musicvideo join files on files.idFile=musicvideo.idFile join path on files.idPath = path.idPath", VIDEODB_ID_MUSICVIDEO_YEAR);
4329 if (idContent == VIDEODB_CONTENT_MOVIES)
4331 strSQL = PrepareSQL("select movie.c%02d,count(1),count(files.playCount) from movie join files on files.idFile=movie.idFile", VIDEODB_ID_YEAR);
4332 group = PrepareSQL(" group by movie.c%02d", VIDEODB_ID_YEAR);
4334 else if (idContent == VIDEODB_CONTENT_TVSHOWS)
4335 strSQL = PrepareSQL("select distinct tvshow.c%02d from tvshow", VIDEODB_ID_TV_PREMIERED);
4336 else if (idContent == VIDEODB_CONTENT_MUSICVIDEOS)
4338 strSQL = PrepareSQL("select musicvideo.c%02d,count(1),count(files.playCount) from musicvideo join files on files.idFile=musicvideo.idFile", VIDEODB_ID_MUSICVIDEO_YEAR);
4339 group = PrepareSQL(" group by musicvideo.c%02d", VIDEODB_ID_MUSICVIDEO_YEAR);
4344 int iRowsFound = RunQuery(strSQL);
4345 if (iRowsFound <= 0)
4346 return iRowsFound == 0;
4348 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
4350 map<int, pair<CStdString,int> > mapYears;
4351 map<int, pair<CStdString,int> >::iterator it;
4352 while (!m_pDS->eof())
4355 if (idContent == VIDEODB_CONTENT_TVSHOWS)
4358 time.SetFromDateString(m_pDS->fv(0).get_asString());
4359 lYear = time.GetYear();
4361 else if (idContent == VIDEODB_CONTENT_MOVIES || idContent == VIDEODB_CONTENT_MUSICVIDEOS)
4362 lYear = m_pDS->fv(0).get_asInt();
4363 it = mapYears.find(lYear);
4364 if (it == mapYears.end())
4367 if (g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
4370 year.Format("%d", lYear);
4371 if (idContent == VIDEODB_CONTENT_MOVIES || idContent == VIDEODB_CONTENT_MUSICVIDEOS)
4372 mapYears.insert(pair<int, pair<CStdString,int> >(lYear, pair<CStdString,int>(year,m_pDS->fv(2).get_asInt())));
4374 mapYears.insert(pair<int, pair<CStdString,int> >(lYear, pair<CStdString,int>(year,0)));
4381 for (it=mapYears.begin();it != mapYears.end();++it)
4385 CFileItemPtr pItem(new CFileItem(it->second.first));
4387 strDir.Format("%ld/", it->first);
4388 pItem->m_strPath=strBaseDir + strDir;
4389 pItem->m_bIsFolder=true;
4390 if (idContent == VIDEODB_CONTENT_MOVIES || idContent == VIDEODB_CONTENT_MUSICVIDEOS)
4391 pItem->GetVideoInfoTag()->m_playCount = it->second.second;
4397 while (!m_pDS->eof())
4400 CStdString strLabel;
4401 if (idContent == VIDEODB_CONTENT_TVSHOWS)
4404 time.SetFromDateString(m_pDS->fv(0).get_asString());
4405 lYear = time.GetYear();
4406 strLabel.Format("%i",lYear);
4408 else if (idContent == VIDEODB_CONTENT_MOVIES || idContent == VIDEODB_CONTENT_MUSICVIDEOS)
4410 lYear = m_pDS->fv(0).get_asInt();
4411 strLabel = m_pDS->fv(0).get_asString();
4418 CFileItemPtr pItem(new CFileItem(strLabel));
4420 strDir.Format("%ld/", lYear);
4421 pItem->m_strPath=strBaseDir + strDir;
4422 pItem->m_bIsFolder=true;
4423 if (idContent == VIDEODB_CONTENT_MOVIES || idContent == VIDEODB_CONTENT_MUSICVIDEOS)
4425 // fv(2) is the number of videos watched, fv(1) is the total number. We set the playcount
4426 // only if the number of videos watched is equal to the total number (i.e. every video watched)
4427 pItem->GetVideoInfoTag()->m_playCount = (m_pDS->fv(2).get_asInt() == m_pDS->fv(1).get_asInt()) ? 1 : 0;
4430 // take care of dupes ..
4431 if (!items.Contains(pItem->m_strPath))
4443 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
4448 bool CVideoDatabase::GetStackedTvShowList(int idShow, CStdString& strIn)
4452 if (NULL == m_pDB.get()) return false;
4453 if (NULL == m_pDS.get()) return false;
4455 // look for duplicate show titles and stack them into a list
4458 CStdString strSQL = PrepareSQL("select idShow from tvshow where c00 like (select c00 from tvshow where idShow=%i) order by idShow", idShow);
4459 CLog::Log(LOGDEBUG, "%s query: %s", __FUNCTION__, strSQL.c_str());
4460 if (!m_pDS->query(strSQL.c_str())) return false;
4461 int iRows = m_pDS->num_rows();
4462 if (iRows == 0) return false; // this should never happen!
4464 { // more than one show, so stack them up
4466 while (!m_pDS->eof())
4468 strIn += PrepareSQL("%i,", m_pDS->fv(0).get_asInt());
4471 strIn[strIn.GetLength() - 1] = ')'; // replace last , with )
4478 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
4483 bool CVideoDatabase::GetSeasonsNav(const CStdString& strBaseDir, CFileItemList& items, int idActor, int idDirector, int idGenre, int idYear, int idShow)
4487 if (NULL == m_pDB.get()) return false;
4488 if (NULL == m_pDS.get()) return false;
4490 CStdString strIn = PrepareSQL("= %i", idShow);
4491 GetStackedTvShowList(idShow, strIn);
4493 CStdString strSQL = PrepareSQL("select episode.c%02d,path.strPath,tvshow.c%02d,tvshow.c%02d,tvshow.c%02d,tvshow.c%02d,count(1),count(files.playCount) from episode join tvshowlinkepisode on tvshowlinkepisode.idEpisode=episode.idEpisode join tvshow on tvshow.idShow=tvshowlinkepisode.idShow join files on files.idFile=episode.idFile ", VIDEODB_ID_EPISODE_SEASON, VIDEODB_ID_TV_TITLE, VIDEODB_ID_TV_GENRE, VIDEODB_ID_TV_STUDIOS, VIDEODB_ID_TV_MPAA);
4494 CStdString joins = PrepareSQL(" join tvshowlinkpath on tvshowlinkpath.idShow = tvshow.idShow join path on path.idPath = tvshowlinkpath.idPath where tvshow.idShow %s ", strIn.c_str());
4495 CStdString extraJoins, extraWhere;
4498 extraJoins = "join actorlinktvshow on actorlinktvshow.idShow=tvshow.idShow";
4499 extraWhere = PrepareSQL("and actorlinktvshow.idActor=%i", idActor);
4501 else if (idDirector != -1)
4503 extraJoins = "join directorlinktvshow on directorlinktvshow.idShow=tvshow.idShow";
4504 extraWhere = PrepareSQL("and directorlinktvshow.idDirector=%i",idDirector);
4506 else if (idGenre != -1)
4508 extraJoins = "join genrelinktvshow on genrelinktvshow.idShow=tvshow.idShow";
4509 extraWhere = PrepareSQL("and genrelinktvshow.idGenre=%i", idGenre);
4511 else if (idYear != -1)
4513 extraWhere = PrepareSQL("and tvshow.c%02d like '%%%i%%'", VIDEODB_ID_TV_PREMIERED, idYear);
4515 strSQL += extraJoins + joins + extraWhere + PrepareSQL(" group by episode.c%02d", VIDEODB_ID_EPISODE_SEASON);
4517 int iRowsFound = RunQuery(strSQL);
4518 if (iRowsFound <= 0)
4519 return iRowsFound == 0;
4521 // show titles, studios and mpaa ratings will be the same
4522 CStdString showTitle = m_pDS->fv(2).get_asString();
4523 CStdString showStudio = m_pDS->fv(4).get_asString();
4524 CStdString showMPAARating = m_pDS->fv(5).get_asString();
4526 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
4528 map<int, CSeason> mapSeasons;
4529 map<int, CSeason>::iterator it;
4530 while (!m_pDS->eof())
4532 int iSeason = m_pDS->fv(0).get_asInt();
4533 it = mapSeasons.find(iSeason);
4535 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
4540 if (it == mapSeasons.end())
4543 season.path = m_pDS->fv(1).get_asString();
4544 season.genre = m_pDS->fv(3).get_asString();
4545 season.numEpisodes = m_pDS->fv(6).get_asInt();
4546 season.numWatched = m_pDS->fv(7).get_asInt();
4547 mapSeasons.insert(make_pair(iSeason, season));
4553 for (it=mapSeasons.begin();it != mapSeasons.end();++it)
4555 int iSeason = it->first;
4556 CStdString strLabel;
4558 strLabel = g_localizeStrings.Get(20381);
4560 strLabel.Format(g_localizeStrings.Get(20358),iSeason);
4561 CFileItemPtr pItem(new CFileItem(strLabel));
4563 strDir.Format("%ld/", it->first);
4564 pItem->m_strPath=strBaseDir + strDir;
4565 pItem->m_bIsFolder=true;
4566 pItem->GetVideoInfoTag()->m_strTitle = strLabel;
4567 pItem->GetVideoInfoTag()->m_iSeason = iSeason;
4568 pItem->GetVideoInfoTag()->m_iDbId = idShow;
4569 pItem->GetVideoInfoTag()->m_strPath = it->second.path;
4570 pItem->GetVideoInfoTag()->m_strGenre = it->second.genre;
4571 pItem->GetVideoInfoTag()->m_strStudio = showStudio;
4572 pItem->GetVideoInfoTag()->m_strMPAARating = showMPAARating;
4573 pItem->GetVideoInfoTag()->m_strShowTitle = showTitle;
4574 pItem->GetVideoInfoTag()->m_iEpisode = it->second.numEpisodes;
4575 pItem->SetProperty("totalepisodes", it->second.numEpisodes);
4576 pItem->SetProperty("numepisodes", it->second.numEpisodes); // will be changed later to reflect watchmode setting
4577 pItem->SetProperty("watchedepisodes", it->second.numWatched);
4578 pItem->SetProperty("unwatchedepisodes", it->second.numEpisodes - it->second.numWatched);
4579 pItem->GetVideoInfoTag()->m_playCount = (it->second.numEpisodes == it->second.numWatched) ? 1 : 0;
4580 pItem->SetCachedSeasonThumb();
4581 pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, (pItem->GetVideoInfoTag()->m_playCount > 0) && (pItem->GetVideoInfoTag()->m_iEpisode > 0));
4587 while (!m_pDS->eof())
4589 int iSeason = m_pDS->fv(0).get_asInt();
4590 CStdString strLabel;
4592 strLabel = g_localizeStrings.Get(20381);
4594 strLabel.Format(g_localizeStrings.Get(20358),iSeason);
4595 CFileItemPtr pItem(new CFileItem(strLabel));
4597 strDir.Format("%ld/", iSeason);
4598 pItem->m_strPath=strBaseDir + strDir;
4599 pItem->m_bIsFolder=true;
4600 pItem->GetVideoInfoTag()->m_strTitle = strLabel;
4601 pItem->GetVideoInfoTag()->m_iSeason = iSeason;
4602 pItem->GetVideoInfoTag()->m_iDbId = idShow;
4603 pItem->GetVideoInfoTag()->m_strPath = m_pDS->fv(1).get_asString();
4604 pItem->GetVideoInfoTag()->m_strGenre = m_pDS->fv(3).get_asString();
4605 pItem->GetVideoInfoTag()->m_strStudio = showStudio;
4606 pItem->GetVideoInfoTag()->m_strMPAARating = showMPAARating;
4607 pItem->GetVideoInfoTag()->m_strShowTitle = showTitle;
4608 int totalEpisodes = m_pDS->fv(6).get_asInt();
4609 int watchedEpisodes = m_pDS->fv(7).get_asInt();
4610 pItem->GetVideoInfoTag()->m_iEpisode = totalEpisodes;
4611 pItem->SetProperty("totalepisodes", totalEpisodes);
4612 pItem->SetProperty("numepisodes", totalEpisodes); // will be changed later to reflect watchmode setting
4613 pItem->SetProperty("watchedepisodes", watchedEpisodes);
4614 pItem->SetProperty("unwatchedepisodes", totalEpisodes - watchedEpisodes);
4615 pItem->GetVideoInfoTag()->m_playCount = (totalEpisodes == watchedEpisodes) ? 1 : 0;
4616 pItem->SetCachedSeasonThumb();
4617 pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, (pItem->GetVideoInfoTag()->m_playCount > 0) && (pItem->GetVideoInfoTag()->m_iEpisode > 0));
4623 // now add any linked movies
4624 CStdString where = PrepareSQL("join movielinktvshow on movielinktvshow.idMovie=movieview.idMovie where movielinktvshow.idShow %s", strIn.c_str());
4625 GetMoviesByWhere("videodb://1/2/", where, "", items);
4630 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
4635 bool CVideoDatabase::GetMoviesNav(const CStdString& strBaseDir, CFileItemList& items, int idGenre, int idYear, int idActor, int idDirector, int idStudio, int idCountry, int idSet)
4639 where = PrepareSQL("join genrelinkmovie on genrelinkmovie.idMovie=movieview.idMovie where genrelinkmovie.idGenre=%i", idGenre);
4640 else if (idCountry != -1)
4641 where = PrepareSQL("join countrylinkmovie on countrylinkmovie.idMovie=movieview.idMovie where countrylinkmovie.idCountry=%i", idCountry);
4642 else if (idStudio != -1)
4643 where = PrepareSQL("join studiolinkmovie on studiolinkmovie.idMovie=movieview.idMovie where studiolinkmovie.idStudio=%i", idStudio);
4644 else if (idDirector != -1)
4645 where = PrepareSQL("join directorlinkmovie on directorlinkmovie.idMovie=movieview.idMovie where directorlinkmovie.idDirector=%i", idDirector);
4646 else if (idYear !=-1)
4647 where = PrepareSQL("where c%02d='%i'",VIDEODB_ID_YEAR,idYear);
4648 else if (idActor != -1)
4649 where = PrepareSQL("join actorlinkmovie on actorlinkmovie.idMovie=movieview.idMovie join actors on actors.idActor=actorlinkmovie.idActor where actors.idActor=%i",idActor);
4650 else if (idSet != -1)
4651 where = PrepareSQL("join setlinkmovie on setlinkmovie.idMovie=movieview.idMovie where setlinkmovie.idSet=%u",idSet);
4653 return GetMoviesByWhere(strBaseDir, where, "", items, idSet == -1);
4656 bool CVideoDatabase::GetMoviesByWhere(const CStdString& strBaseDir, const CStdString &where, const CStdString &order, CFileItemList& items, bool fetchSets)
4663 if (NULL == m_pDB.get()) return false;
4664 if (NULL == m_pDS.get()) return false;
4666 CStdString strSQL = "select * from movieview ";
4667 if (fetchSets && !g_guiSettings.GetBool("videolibrary.flattenmoviesets"))
4669 // not getting a set, so grab all sets that match this where clause first
4670 CStdString setsWhere;
4672 setsWhere = " where movie.idMovie in (select movieview.idMovie from movieview " + where + ")";
4673 GetSetsNav("videodb://1/7/", items, VIDEODB_CONTENT_MOVIES, setsWhere);
4675 strSQL += where + PrepareSQL(" and movieview.idMovie NOT in (select idMovie from setlinkmovie)");
4677 strSQL += PrepareSQL("WHERE movieview.idMovie NOT IN (SELECT idMovie FROM setlinkmovie s1 JOIN(SELECT idSet, COUNT(1) AS c FROM setlinkmovie GROUP BY idSet HAVING c>1) s2 ON s2.idSet=s1.idSet)");
4683 strSQL += " " + order;
4685 int iRowsFound = RunQuery(strSQL);
4686 if (iRowsFound <= 0)
4687 return iRowsFound == 0;
4689 // get data from returned rows
4690 items.Reserve(iRowsFound);
4691 while (!m_pDS->eof())
4693 CVideoInfoTag movie = GetDetailsForMovie(m_pDS);
4694 if (g_settings.GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE ||
4695 g_passwordManager.bMasterUser ||
4696 g_passwordManager.IsDatabasePathUnlocked(movie.m_strPath, g_settings.m_videoSources))
4698 CFileItemPtr pItem(new CFileItem(movie));
4699 pItem->m_strPath.Format("%s%ld", strBaseDir.c_str(), movie.m_iDbId);
4700 pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED,movie.m_playCount > 0);
4712 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
4717 bool CVideoDatabase::GetTvShowsNav(const CStdString& strBaseDir, CFileItemList& items, int idGenre, int idYear, int idActor, int idDirector, int idStudio)
4721 where = PrepareSQL("join genrelinktvshow on genrelinktvshow.idShow=tvshow.idShow where genrelinktvshow.idGenre=%i ", idGenre);
4722 else if (idStudio != -1)
4723 where = PrepareSQL("join studiolinktvshow on studiolinktvshow.idShow=tvshow.idShow where studiolinktvshow.idStudio=%i", idStudio);
4724 else if (idDirector != -1)
4725 where = PrepareSQL("join directorlinktvshow on directorlinktvshow.idShow=tvshow.idShow where directorlinktvshow.idDirector=%i", idDirector);
4726 else if (idYear != -1)
4727 where = PrepareSQL("where c%02d like '%%%i%%'", VIDEODB_ID_TV_PREMIERED,idYear);
4728 else if (idActor != -1)
4729 where = PrepareSQL("join actorlinktvshow on actorlinktvshow.idShow=tvshow.idShow join actors on actors.idActor=actorlinktvshow.idActor where actors.idActor=%i",idActor);
4731 return GetTvShowsByWhere(strBaseDir, where, items);
4734 bool CVideoDatabase::GetTvShowsByWhere(const CStdString& strBaseDir, const CStdString &where, CFileItemList& items)
4740 if (NULL == m_pDB.get()) return false;
4741 if (NULL == m_pDS.get()) return false;
4743 int iRowsFound = RunQuery("SELECT * FROM tvshowview " + where);
4744 if (iRowsFound <= 0)
4745 return iRowsFound == 0;
4747 // get data from returned rows
4748 items.Reserve(iRowsFound);
4750 while (!m_pDS->eof())
4752 int idShow = m_pDS->fv("tvshow.idShow").get_asInt();
4753 int numSeasons = m_pDS->fv(VIDEODB_DETAILS_TVSHOW_NUM_SEASONS).get_asInt();
4755 CVideoInfoTag movie = GetDetailsForTvShow(m_pDS, false);
4756 if (!g_advancedSettings.m_bVideoLibraryHideEmptySeries || movie.m_iEpisode > 0)
4758 CFileItemPtr pItem(new CFileItem(movie));
4759 pItem->m_strPath.Format("%s%ld/", strBaseDir.c_str(), idShow);
4760 pItem->m_dateTime.SetFromDateString(movie.m_strPremiered);
4761 pItem->GetVideoInfoTag()->m_iYear = pItem->m_dateTime.GetYear();
4762 pItem->SetProperty("totalseasons", numSeasons);
4763 pItem->SetProperty("totalepisodes", movie.m_iEpisode);
4764 pItem->SetProperty("numepisodes", movie.m_iEpisode); // will be changed later to reflect watchmode setting
4765 pItem->SetProperty("watchedepisodes", movie.m_playCount);
4766 pItem->SetProperty("unwatchedepisodes", movie.m_iEpisode - movie.m_playCount);
4767 pItem->GetVideoInfoTag()->m_playCount = (movie.m_iEpisode == movie.m_playCount) ? 1 : 0;
4768 pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, (pItem->GetVideoInfoTag()->m_playCount > 0) && (pItem->GetVideoInfoTag()->m_iEpisode > 0));
4774 CStdString order(where);
4775 bool maintainOrder = order.ToLower().Find("order by") != -1;
4776 Stack(items, VIDEODB_CONTENT_TVSHOWS, maintainOrder);
4784 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
4789 void CVideoDatabase::Stack(CFileItemList& items, VIDEODB_CONTENT_TYPE type, bool maintainSortOrder /* = false */)
4791 if (maintainSortOrder)
4793 // save current sort order
4794 for (int i = 0; i < items.Size(); i++)
4795 items[i]->m_iprogramCount = i;
4800 case VIDEODB_CONTENT_TVSHOWS:
4803 items.Sort(SORT_METHOD_VIDEO_TITLE, SORT_ORDER_ASC);
4806 while (i < items.Size())
4808 CFileItemPtr pItem = items.Get(i);
4809 CStdString strTitle = pItem->GetVideoInfoTag()->m_strTitle;
4810 CStdString strFanArt = pItem->GetProperty("fanart_image");
4813 bool bStacked = false;
4814 while (j < items.Size())
4816 CFileItemPtr jItem = items.Get(j);
4818 // matching title? append information
4819 if (jItem->GetVideoInfoTag()->m_strTitle.Equals(strTitle))
4821 if (jItem->GetVideoInfoTag()->m_strPremiered !=
4822 pItem->GetVideoInfoTag()->m_strPremiered)
4829 // increment episode counts
4830 pItem->GetVideoInfoTag()->m_iEpisode += jItem->GetVideoInfoTag()->m_iEpisode;
4831 pItem->IncrementProperty("totalepisodes", jItem->GetPropertyInt("totalepisodes"));
4832 pItem->IncrementProperty("numepisodes", jItem->GetPropertyInt("numepisodes")); // will be changed later to reflect watchmode setting
4833 pItem->IncrementProperty("watchedepisodes", jItem->GetPropertyInt("watchedepisodes"));
4834 pItem->IncrementProperty("unwatchedepisodes", jItem->GetPropertyInt("unwatchedepisodes"));
4836 // check for fanart if not already set
4837 if (strFanArt.IsEmpty())
4838 strFanArt = jItem->GetProperty("fanart_image");
4840 // remove duplicate entry
4843 // no match? exit loop
4847 // update playcount and fanart
4850 pItem->GetVideoInfoTag()->m_playCount = (pItem->GetVideoInfoTag()->m_iEpisode == pItem->GetPropertyInt("watchedepisodes")) ? 1 : 0;
4851 pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, (pItem->GetVideoInfoTag()->m_playCount > 0) && (pItem->GetVideoInfoTag()->m_iEpisode > 0));
4852 if (!strFanArt.IsEmpty())
4853 pItem->SetProperty("fanart_image", strFanArt);
4855 // increment i to j which is the next item
4860 // We currently don't stack episodes (No call here in GetEpisodesByWhere()), but this code is left
4861 // so that if we eventually want to stack during scan we can utilize it.
4863 case VIDEODB_CONTENT_EPISODES:
4865 // sort by ShowTitle, Episode, Filename
4866 items.Sort(SORT_METHOD_EPISODE, SORT_ORDER_ASC);
4869 while (i < items.Size())
4871 CFileItemPtr pItem = items.Get(i);
4872 CStdString strPath = pItem->GetVideoInfoTag()->m_strPath;
4873 int iSeason = pItem->GetVideoInfoTag()->m_iSeason;
4874 int iEpisode = pItem->GetVideoInfoTag()->m_iEpisode;
4875 //CStdString strFanArt = pItem->GetProperty("fanart_image");
4877 // do we have a dvd folder, ie foo/VIDEO_TS.IFO or foo/VIDEO_TS/VIDEO_TS.IFO
4878 CStdString strFileNameAndPath = pItem->GetVideoInfoTag()->m_strFileNameAndPath;
4879 bool bDvdFolder = strFileNameAndPath.Right(12).Equals("VIDEO_TS.IFO");
4881 vector<CStdString> paths;
4882 paths.push_back(strFileNameAndPath);
4883 CLog::Log(LOGDEBUG, "Stack episode (%i,%i):[%s]", iSeason, iEpisode, paths[0].c_str());
4886 int iPlayCount = pItem->GetVideoInfoTag()->m_playCount;
4887 while (j < items.Size())
4889 CFileItemPtr jItem = items.Get(j);
4890 const CVideoInfoTag *jTag = jItem->GetVideoInfoTag();
4891 CStdString jFileNameAndPath = jTag->m_strFileNameAndPath;
4893 CLog::Log(LOGDEBUG, " *testing (%i,%i):[%s]", jTag->m_iSeason, jTag->m_iEpisode, jFileNameAndPath.c_str());
4894 // compare path, season, episode
4897 jTag->m_strPath.Equals(strPath) &&
4898 jTag->m_iSeason == iSeason &&
4899 jTag->m_iEpisode == iEpisode
4902 // keep checking to see if this is dvd folder
4905 bDvdFolder = jFileNameAndPath.Right(12).Equals("VIDEO_TS.IFO");
4906 // if we have a dvd folder, we stack differently
4909 // remove all the other items and ONLY show the VIDEO_TS.IFO file
4911 paths.push_back(jFileNameAndPath);
4915 // increment playcount
4916 iPlayCount += jTag->m_playCount;
4918 // episodes dont have fanart yet
4919 //if (strFanArt.IsEmpty())
4920 // strFanArt = jItem->GetProperty("fanart_image");
4922 paths.push_back(jFileNameAndPath);
4926 // remove duplicate entry
4930 // no match? exit loop
4934 // update playcount and fanart if we have a stacked entry
4935 if (paths.size() > 1)
4937 CStackDirectory dir;
4938 CStdString strStack;
4939 dir.ConstructStackPath(paths, strStack);
4940 pItem->GetVideoInfoTag()->m_strFileNameAndPath = strStack;
4941 pItem->GetVideoInfoTag()->m_playCount = iPlayCount;
4942 pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, (pItem->GetVideoInfoTag()->m_playCount > 0) && (pItem->GetVideoInfoTag()->m_iEpisode > 0));
4944 // episodes dont have fanart yet
4945 //if (!strFanArt.IsEmpty())
4946 // pItem->SetProperty("fanart_image", strFanArt);
4948 // increment i to j which is the next item
4954 // stack other types later
4958 if (maintainSortOrder)
4960 // restore original sort order - essential for smartplaylists
4961 items.Sort(SORT_METHOD_PROGRAM_COUNT, SORT_ORDER_ASC);
4965 bool CVideoDatabase::GetEpisodesNav(const CStdString& strBaseDir, CFileItemList& items, int idGenre, int idYear, int idActor, int idDirector, int idShow, int idSeason)
4967 CStdString strIn = PrepareSQL("= %i", idShow);
4968 GetStackedTvShowList(idShow, strIn);
4969 CStdString where = PrepareSQL("where idShow %s",strIn.c_str());
4971 where = PrepareSQL("join genrelinktvshow on genrelinktvshow.idShow=episodeview.idShow where episodeview.idShow=%i and genrelinktvshow.idGenre=%i",idShow,idGenre);
4972 else if (idDirector != -1)
4973 where = PrepareSQL("join directorlinktvshow on directorlinktvshow.idShow=episodeview.idShow where episodeview.idShow=%i and directorlinktvshow.idDirector=%i",idShow,idDirector);
4974 else if (idYear !=-1)
4975 where=PrepareSQL("where idShow=%i and premiered like '%%%i%%'",idShow,idYear);
4976 else if (idActor != -1)
4977 where = PrepareSQL("join actorlinktvshow on actorlinktvshow.idShow=episodeview.idShow where episodeview.idShow=%i and actorlinktvshow.idActor=%i",idShow,idActor);
4981 if (idSeason != 0) // season = 0 indicates a special - we grab all specials here (see below)
4982 where += PrepareSQL(" and (c%02d=%i or (c%02d=0 and (c%02d=0 or c%02d=%i)))",VIDEODB_ID_EPISODE_SEASON,idSeason,VIDEODB_ID_EPISODE_SEASON, VIDEODB_ID_EPISODE_SORTSEASON, VIDEODB_ID_EPISODE_SORTSEASON,idSeason);
4984 where += PrepareSQL(" and c%02d=%i",VIDEODB_ID_EPISODE_SEASON,idSeason);
4987 // we always append show, season + episode in GetEpisodesByWhere
4988 CStdString parent, grandParent;
4989 URIUtils::GetParentPath(strBaseDir,parent);
4990 URIUtils::GetParentPath(parent,grandParent);
4992 bool ret = GetEpisodesByWhere(grandParent, where, items);
4995 { // add any linked movies
4996 CStdString where = PrepareSQL("join movielinktvshow on movielinktvshow.idMovie=movieview.idMovie where movielinktvshow.idShow %s", strIn.c_str());
4997 GetMoviesByWhere("videodb://1/2/", where, "", items);
5002 bool CVideoDatabase::GetEpisodesByWhere(const CStdString& strBaseDir, const CStdString &where, CFileItemList& items, bool appendFullShowPath /* = true */)
5009 if (NULL == m_pDB.get()) return false;
5010 if (NULL == m_pDS.get()) return false;
5012 int iRowsFound = RunQuery("select * from episodeview " + where);
5013 if (iRowsFound <= 0)
5014 return iRowsFound == 0;
5016 // get data from returned rows
5017 items.Reserve(iRowsFound);
5018 while (!m_pDS->eof())
5020 int idEpisode = m_pDS->fv("idEpisode").get_asInt();
5021 int idShow = m_pDS->fv("idShow").get_asInt();
5023 CVideoInfoTag movie = GetDetailsForEpisode(m_pDS);
5024 CFileItemPtr pItem(new CFileItem(movie));
5025 if (appendFullShowPath)
5026 pItem->m_strPath.Format("%s%ld/%ld/%ld",strBaseDir.c_str(), idShow, movie.m_iSeason,idEpisode);
5028 pItem->m_strPath.Format("%s%ld",strBaseDir.c_str(), idEpisode);
5030 pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED,movie.m_playCount > 0);
5031 pItem->m_dateTime.SetFromDateString(movie.m_strFirstAired);
5032 pItem->GetVideoInfoTag()->m_iYear = pItem->m_dateTime.GetYear();
5044 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
5050 bool CVideoDatabase::GetMusicVideosNav(const CStdString& strBaseDir, CFileItemList& items, int idGenre, int idYear, int idArtist, int idDirector, int idStudio, int idAlbum)
5054 where = PrepareSQL("join genrelinkmusicvideo on genrelinkmusicvideo.idMVideo=musicvideoview.idMVideo where genrelinkmusicvideo.idGenre=%i", idGenre);
5055 else if (idStudio != -1)
5056 where = PrepareSQL("join studiolinkmusicvideo on studiolinkmusicvideo.idMVideo=musicvideoview.idMVideo where studiolinkmusicvideo.idStudio=%i", idStudio);
5057 else if (idDirector != -1)
5058 where = PrepareSQL("join directorlinkmusicvideo on directorlinkmusicvideo.idMVideo=musicvideoview.idMVideo where directorlinkmusicvideo.idDirector=%i", idDirector);
5059 else if (idYear !=-1)
5060 where = PrepareSQL("where c%02d='%i'",VIDEODB_ID_MUSICVIDEO_YEAR,idYear);
5061 else if (idArtist != -1)
5062 where = PrepareSQL("join artistlinkmusicvideo on artistlinkmusicvideo.idMVideo=musicvideoview.idMVideo join actors on actors.idActor=artistlinkmusicvideo.idArtist where actors.idActor=%i",idArtist);
5065 CStdString str2 = PrepareSQL(" musicvideoview.c%02d=(select c%02d from musicvideo where idMVideo=%i)",VIDEODB_ID_MUSICVIDEO_ALBUM,VIDEODB_ID_MUSICVIDEO_ALBUM,idAlbum);
5066 if (where.IsEmpty())
5067 where.Format(" %s%s","where",str2.c_str());
5069 where.Format(" %s %s%s",where.Mid(0).c_str(),"and",str2.c_str());
5072 return GetMusicVideosByWhere(strBaseDir, where, items);
5075 bool CVideoDatabase::GetRecentlyAddedMoviesNav(const CStdString& strBaseDir, CFileItemList& items)
5077 CStdString order = PrepareSQL("order by idMovie desc limit %i", g_advancedSettings.m_iVideoLibraryRecentlyAddedItems);
5078 return GetMoviesByWhere(strBaseDir, "", order, items);
5081 bool CVideoDatabase::GetRecentlyAddedEpisodesNav(const CStdString& strBaseDir, CFileItemList& items)
5083 CStdString where = PrepareSQL("order by idEpisode desc limit %i", g_advancedSettings.m_iVideoLibraryRecentlyAddedItems);
5084 return GetEpisodesByWhere(strBaseDir, where, items, false);
5087 bool CVideoDatabase::GetRecentlyAddedMusicVideosNav(const CStdString& strBaseDir, CFileItemList& items)
5089 CStdString where = PrepareSQL("order by idMVideo desc limit %i", g_advancedSettings.m_iVideoLibraryRecentlyAddedItems);
5090 return GetMusicVideosByWhere(strBaseDir, where, items);
5093 CStdString CVideoDatabase::GetGenreById(int id)
5095 return GetSingleValue("genre", "strGenre", PrepareSQL("idGenre=%i", id));
5098 CStdString CVideoDatabase::GetCountryById(int id)
5100 return GetSingleValue("country", "strCountry", PrepareSQL("idCountry=%i", id));
5103 CStdString CVideoDatabase::GetSetById(int id)
5105 return GetSingleValue("sets", "strSet", PrepareSQL("idSet=%i", id));
5108 CStdString CVideoDatabase::GetPersonById(int id)
5110 return GetSingleValue("actors", "strActor", PrepareSQL("idActor=%i", id));
5113 CStdString CVideoDatabase::GetStudioById(int id)
5115 return GetSingleValue("studio", "strStudio", PrepareSQL("idStudio=%i", id));
5118 CStdString CVideoDatabase::GetTvShowTitleById(int id)
5120 return GetSingleValue("tvshow", PrepareSQL("c%02d", VIDEODB_ID_TV_TITLE), PrepareSQL("idShow=%i", id));
5123 CStdString CVideoDatabase::GetMusicVideoAlbumById(int id)
5125 return GetSingleValue("musicvideo", PrepareSQL("c%02d", VIDEODB_ID_MUSICVIDEO_ALBUM), PrepareSQL("idMVideo=%i", id));
5128 bool CVideoDatabase::HasSets() const
5132 if (NULL == m_pDB.get()) return false;
5133 if (NULL == m_pDS.get()) return false;
5135 m_pDS->query( "select idSet from sets" );
5136 bool bResult = (m_pDS->num_rows() > 0);
5142 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
5147 int CVideoDatabase::GetTvShowForEpisode(int idEpisode)
5151 if (NULL == m_pDB.get()) return false;
5152 if (NULL == m_pDS2.get()) return false;
5154 // make sure we use m_pDS2, as this is called in loops using m_pDS
5155 CStdString strSQL=PrepareSQL("select idShow from tvshowlinkepisode where idEpisode=%i", idEpisode);
5156 m_pDS2->query( strSQL.c_str() );
5160 result=m_pDS2->fv(0).get_asInt();
5167 CLog::Log(LOGERROR, "%s (%i) failed", __FUNCTION__, idEpisode);
5172 bool CVideoDatabase::HasContent()
5174 return (HasContent(VIDEODB_CONTENT_MOVIES) ||
5175 HasContent(VIDEODB_CONTENT_TVSHOWS) ||
5176 HasContent(VIDEODB_CONTENT_MUSICVIDEOS));
5179 bool CVideoDatabase::HasContent(VIDEODB_CONTENT_TYPE type)
5181 bool result = false;
5184 if (NULL == m_pDB.get()) return false;
5185 if (NULL == m_pDS.get()) return false;
5188 if (type == VIDEODB_CONTENT_MOVIES)
5189 sql = "select count(1) from movie";
5190 else if (type == VIDEODB_CONTENT_TVSHOWS)
5191 sql = "select count(1) from tvshow";
5192 else if (type == VIDEODB_CONTENT_MUSICVIDEOS)
5193 sql = "select count(1) from musicvideo";
5194 m_pDS->query( sql.c_str() );
5197 result = (m_pDS->fv(0).get_asInt() > 0);
5203 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
5208 int CVideoDatabase::GetMusicVideoCount(const CStdString& strWhere)
5212 if (NULL == m_pDB.get()) return 0;
5213 if (NULL == m_pDS.get()) return 0;
5216 strSQL.Format("select count(1) as nummovies from musicvideoview %s",strWhere.c_str());
5217 m_pDS->query( strSQL.c_str() );
5221 iResult = m_pDS->fv("nummovies").get_asInt();
5228 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
5233 ScraperPtr CVideoDatabase::GetScraperForPath( const CStdString& strPath )
5235 SScanSettings settings;
5236 return GetScraperForPath(strPath, settings);
5239 ScraperPtr CVideoDatabase::GetScraperForPath(const CStdString& strPath, SScanSettings& settings)
5242 return GetScraperForPath(strPath, settings, dummy);
5245 ScraperPtr CVideoDatabase::GetScraperForPath(const CStdString& strPath, SScanSettings& settings, bool& foundDirectly)
5247 foundDirectly = false;
5250 if (strPath.IsEmpty() || !m_pDB.get() || !m_pDS.get()) return ScraperPtr();
5253 CStdString strPath1;
5254 CStdString strPath2(strPath);
5256 if (URIUtils::IsMultiPath(strPath))
5257 strPath2 = CMultiPathDirectory::GetFirstPath(strPath);
5259 URIUtils::GetDirectory(strPath2,strPath1);
5260 int idPath = GetPathId(strPath1);
5264 CStdString strSQL=PrepareSQL("select path.strContent,path.strScraper,path.scanRecursive,path.useFolderNames,path.strSettings,path.noUpdate,path.exclude from path where path.idPath=%i",idPath);
5265 m_pDS->query( strSQL.c_str() );
5269 CONTENT_TYPE content = CONTENT_NONE;
5271 { // path is stored in db
5273 if (m_pDS->fv("path.exclude").get_asBool())
5275 settings.exclude = true;
5277 return ScraperPtr();
5279 settings.exclude = false;
5281 // try and ascertain scraper for this path
5282 CStdString strcontent = m_pDS->fv("path.strContent").get_asString();
5283 strcontent.ToLower();
5284 content = TranslateContent(strcontent);
5286 //FIXME paths stored should not have empty strContent
5287 //assert(content != CONTENT_NONE);
5288 CStdString scraperID = m_pDS->fv("path.strScraper").get_asString();
5291 if (!scraperID.empty() &&
5292 CAddonMgr::Get().GetAddon(scraperID, addon))
5294 scraper = boost::dynamic_pointer_cast<CScraper>(addon->Clone(addon));
5296 return ScraperPtr();
5298 // store this path's content & settings
5299 scraper->SetPathSettings(content, m_pDS->fv("path.strSettings").get_asString());
5300 settings.parent_name = m_pDS->fv("path.useFolderNames").get_asBool();
5301 settings.recurse = m_pDS->fv("path.scanRecursive").get_asInt();
5302 settings.noupdate = m_pDS->fv("path.noUpdate").get_asBool();
5306 if (content == CONTENT_NONE)
5307 { // this path is not saved in db
5308 // we must drill up until a scraper is configured
5309 CStdString strParent;
5310 while (URIUtils::GetParentPath(strPath1, strParent))
5314 CStdString strSQL=PrepareSQL("select path.strContent,path.strScraper,path.scanRecursive,path.useFolderNames,path.strSettings,path.noUpdate from path where strPath like '%s'",strParent.c_str());
5315 m_pDS->query(strSQL.c_str());
5317 CONTENT_TYPE content = CONTENT_NONE;
5321 CStdString strcontent = m_pDS->fv("path.strContent").get_asString();
5322 strcontent.ToLower();
5323 if (strcontent.Equals("none"))
5325 settings.exclude = true;
5331 content = TranslateContent(strcontent);
5334 if (content != CONTENT_NONE &&
5335 CAddonMgr::Get().GetAddon(m_pDS->fv("path.strScraper").get_asString(), addon))
5337 scraper = boost::dynamic_pointer_cast<CScraper>(addon->Clone(addon));
5338 scraper->SetPathSettings(content, m_pDS->fv("path.strSettings").get_asString());
5339 settings.parent_name = m_pDS->fv("path.useFolderNames").get_asBool();
5340 settings.recurse = m_pDS->fv("path.scanRecursive").get_asInt();
5341 settings.noupdate = m_pDS->fv("path.noUpdate").get_asBool();
5342 settings.exclude = false;
5346 strPath1 = strParent;
5351 if (!scraper || scraper->Content() == CONTENT_NONE)
5352 return ScraperPtr();
5354 if (scraper->Content() == CONTENT_TVSHOWS)
5356 settings.recurse = 0;
5357 if(settings.parent_name) // single show
5359 settings.parent_name_root = settings.parent_name = (iFound == 1);
5363 settings.parent_name_root = settings.parent_name = (iFound == 2);
5366 else if (scraper->Content() == CONTENT_MOVIES)
5368 settings.recurse = settings.recurse - (iFound-1);
5369 settings.parent_name_root = settings.parent_name && (!settings.recurse || iFound > 1);
5371 else if (scraper->Content() == CONTENT_MUSICVIDEOS)
5373 settings.recurse = settings.recurse - (iFound-1);
5374 settings.parent_name_root = settings.parent_name && (!settings.recurse || iFound > 1);
5379 return ScraperPtr();
5381 foundDirectly = (iFound == 1);
5386 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
5388 return ScraperPtr();
5391 CStdString CVideoDatabase::GetContentForPath(const CStdString& strPath)
5393 SScanSettings settings;
5394 bool foundDirectly = false;
5395 ScraperPtr scraper = GetScraperForPath(strPath, settings, foundDirectly);
5398 if (scraper->Content() == CONTENT_TVSHOWS && !foundDirectly)
5399 { // check for episodes or seasons (ASSUMPTION: no episodes == seasons (i.e. assume show/season/episodes structure)
5400 CStdString sql = PrepareSQL("select count(1) from episodeview where strPath = '%s' limit 1", strPath.c_str());
5401 m_pDS->query( sql.c_str() );
5402 if (m_pDS->num_rows() && m_pDS->fv(0).get_asInt() > 0)
5406 return TranslateContent(scraper->Content());
5411 void CVideoDatabase::GetMovieGenresByName(const CStdString& strSearch, CFileItemList& items)
5417 if (NULL == m_pDB.get()) return;
5418 if (NULL == m_pDS.get()) return;
5420 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5421 strSQL=PrepareSQL("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.idFile=movie.idFile and path.idPath=files.idPath and genre.strGenre like '%%%s%%'",strSearch.c_str());
5423 strSQL=PrepareSQL("select distinct genre.idGenre,genre.strGenre from genre,genrelinkmovie where genrelinkmovie.idGenre=genre.idGenre and strGenre like '%%%s%%'", strSearch.c_str());
5424 m_pDS->query( strSQL.c_str() );
5426 while (!m_pDS->eof())
5428 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5429 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),
5430 g_settings.m_videoSources))
5436 CFileItemPtr pItem(new CFileItem(m_pDS->fv("genre.strGenre").get_asString()));
5438 strDir.Format("%ld/", m_pDS->fv("genre.idGenre").get_asInt());
5439 pItem->m_strPath="videodb://1/1/"+ strDir;
5440 pItem->m_bIsFolder=true;
5448 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
5452 void CVideoDatabase::GetMovieCountriesByName(const CStdString& strSearch, CFileItemList& items)
5458 if (NULL == m_pDB.get()) return;
5459 if (NULL == m_pDS.get()) return;
5461 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5462 strSQL=PrepareSQL("select country.idCountry,country.strCountry,path.strPath from country,countrylinkmovie,movie,path,files where country.idCountry=countrylinkmovie.idCountry and countrylinkmovie.idMovie=movie.idMovie and files.idFile=movie.idFile and path.idPath=files.idPath and country.strCountry like '%%%s%%'",strSearch.c_str());
5464 strSQL=PrepareSQL("select distinct country.idCountry,country.strCountry from country,countrylinkmovie where countrylinkmovie.idCountry=country.idCountry and strCountry like '%%%s%%'", strSearch.c_str());
5465 m_pDS->query( strSQL.c_str() );
5467 while (!m_pDS->eof())
5469 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5470 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),
5471 g_settings.m_videoSources))
5477 CFileItemPtr pItem(new CFileItem(m_pDS->fv("country.strCountry").get_asString()));
5479 strDir.Format("%ld/", m_pDS->fv("country.idCountry").get_asInt());
5480 pItem->m_strPath="videodb://1/1/"+ strDir;
5481 pItem->m_bIsFolder=true;
5489 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
5493 void CVideoDatabase::GetTvShowGenresByName(const CStdString& strSearch, CFileItemList& items)
5499 if (NULL == m_pDB.get()) return;
5500 if (NULL == m_pDS.get()) return;
5502 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5503 strSQL=PrepareSQL("select genre.idGenre,genre.strGenre,path.strPath from genre,genrelinktvshow,tvshow,path,tvshowlinkpath where genre.idGenre=genrelinktvshow.idGenre and genrelinktvshow.idShow=tvshow.idShow and path.idPath=tvshowlinkpath.idPath and tvshowlinkpath.idShow=tvshow.idShow and genre.strGenre like '%%%s%%'",strSearch.c_str());
5505 strSQL=PrepareSQL("select distinct genre.idGenre,genre.strGenre from genre,genrelinktvshow where genrelinktvshow.idGenre=genre.idGenre and strGenre like '%%%s%%'", strSearch.c_str());
5506 m_pDS->query( strSQL.c_str() );
5508 while (!m_pDS->eof())
5510 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5511 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
5517 CFileItemPtr pItem(new CFileItem(m_pDS->fv("genre.strGenre").get_asString()));
5519 strDir.Format("%ld/", m_pDS->fv("genre.idGenre").get_asInt());
5520 pItem->m_strPath="videodb://2/1/"+ strDir;
5521 pItem->m_bIsFolder=true;
5529 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
5533 void CVideoDatabase::GetMovieActorsByName(const CStdString& strSearch, CFileItemList& items)
5539 if (NULL == m_pDB.get()) return;
5540 if (NULL == m_pDS.get()) return;
5542 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5543 strSQL=PrepareSQL("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.idFile=movie.idFile and files.idPath=path.idPath and actors.strActor like '%%%s%%'",strSearch.c_str());
5545 strSQL=PrepareSQL("select distinct actors.idactor,actors.strActor from actorlinkmovie,actors,movie where actors.idActor=actorlinkmovie.idActor and actorlinkmovie.idMovie=movie.idMovie and actors.strActor like '%%%s%%'",strSearch.c_str());
5546 m_pDS->query( strSQL.c_str() );
5548 while (!m_pDS->eof())
5550 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5551 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
5557 CFileItemPtr pItem(new CFileItem(m_pDS->fv("actors.strActor").get_asString()));
5559 strDir.Format("%ld/", m_pDS->fv("actors.idActor").get_asInt());
5560 pItem->m_strPath="videodb://1/4/"+ strDir;
5561 pItem->m_bIsFolder=true;
5569 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
5573 void CVideoDatabase::GetTvShowsActorsByName(const CStdString& strSearch, CFileItemList& items)
5579 if (NULL == m_pDB.get()) return;
5580 if (NULL == m_pDS.get()) return;
5582 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5583 strSQL=PrepareSQL("select actors.idActor,actors.strActor,path.strPath from actorlinktvshow,actors,tvshow,path,tvshowlinkpath where actors.idActor=actorlinktvshow.idActor and actorlinktvshow.idShow=tvshow.idShow and tvshowlinkpath.idPath=tvshow.idShow and tvshowlinkpath.idPath=path.idPath and actors.strActor like '%%%s%%'",strSearch.c_str());
5585 strSQL=PrepareSQL("select distinct actors.idactor,actors.strActor from actorlinktvshow,actors,tvshow where actors.idActor=actorlinktvshow.idActor and actorlinktvshow.idShow=tvshow.idShow and actors.strActor like '%%%s%%'",strSearch.c_str());
5586 m_pDS->query( strSQL.c_str() );
5588 while (!m_pDS->eof())
5590 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5591 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
5597 CFileItemPtr pItem(new CFileItem(m_pDS->fv("actors.strActor").get_asString()));
5599 strDir.Format("%ld/", m_pDS->fv("actors.idActor").get_asInt());
5600 pItem->m_strPath="videodb://2/4/"+ strDir;
5601 pItem->m_bIsFolder=true;
5609 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
5613 void CVideoDatabase::GetMusicVideoArtistsByName(const CStdString& strSearch, CFileItemList& items)
5619 if (NULL == m_pDB.get()) return;
5620 if (NULL == m_pDS.get()) return;
5623 if (!strSearch.IsEmpty())
5624 strLike = "and actors.strActor like '%%%s%%'";
5625 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5626 strSQL=PrepareSQL("select actors.idactor,actors.strActor,path.strPath from artistlinkmusicvideo,actors,musicvideo,files,path where actors.idActor=artistlinkmusicvideo.idArtist and artistlinkmusicvideo.idMVideo=musicvideo.idMVideo and files.idFile=musicvideo.idFile and files.idPath=path.idPath "+strLike,strSearch.c_str());
5628 strSQL=PrepareSQL("select distinct actors.idactor,actors.strActor from artistlinkmusicvideo,actors where actors.idActor=artistlinkmusicvideo.idArtist "+strLike,strSearch.c_str());
5629 m_pDS->query( strSQL.c_str() );
5631 while (!m_pDS->eof())
5633 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5634 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
5640 CFileItemPtr pItem(new CFileItem(m_pDS->fv("actors.strActor").get_asString()));
5642 strDir.Format("%ld/", m_pDS->fv("actors.idActor").get_asInt());
5643 pItem->m_strPath="videodb://3/4/"+ strDir;
5644 pItem->m_bIsFolder=true;
5652 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
5656 void CVideoDatabase::GetMusicVideoGenresByName(const CStdString& strSearch, CFileItemList& items)
5662 if (NULL == m_pDB.get()) return;
5663 if (NULL == m_pDS.get()) return;
5665 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5666 strSQL=PrepareSQL("select genre.idGenre,genre.strGenre,path.strPath from genre,genrelinkmusicvideo,musicvideo,path,files where genre.idGenre=genrelinkmusicvideo.idGenre and genrelinkmusicvideo.idMVideo = musicvideo.idMVideo and files.idFile=musicvideo.idFile and path.idPath=files.idPath and genre.strGenre like '%%%s%%'",strSearch.c_str());
5668 strSQL=PrepareSQL("select distinct genre.idGenre,genre.strGenre from genre,genrelinkmusicvideo where genrelinkmusicvideo.idGenre=genre.idGenre and genre.strGenre like '%%%s%%'", strSearch.c_str());
5669 m_pDS->query( strSQL.c_str() );
5671 while (!m_pDS->eof())
5673 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5674 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
5680 CFileItemPtr pItem(new CFileItem(m_pDS->fv("genre.strGenre").get_asString()));
5682 strDir.Format("%ld/", m_pDS->fv("genre.idGenre").get_asInt());
5683 pItem->m_strPath="videodb://3/1/"+ strDir;
5684 pItem->m_bIsFolder=true;
5692 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
5696 void CVideoDatabase::GetMusicVideoAlbumsByName(const CStdString& strSearch, CFileItemList& items)
5702 if (NULL == m_pDB.get()) return;
5703 if (NULL == m_pDS.get()) return;
5706 if (!strSearch.IsEmpty())
5708 strLike.Format("and musicvideo.c%02d",VIDEODB_ID_MUSICVIDEO_ALBUM);
5709 strLike += "like '%%s%%%'";
5711 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5712 strSQL=PrepareSQL("select distinct musicvideo.c%02d,musicvideo.idMVideo,path.strPath from musicvideo,files,path where files.idFile=musicvideo.idFile and files.idPath=path.idPath"+strLike,VIDEODB_ID_MUSICVIDEO_ALBUM,strSearch.c_str());
5715 if (!strLike.IsEmpty())
5716 strLike = "where "+strLike.Mid(4);
5717 strSQL=PrepareSQL("select distinct musicvideo.c%02d,musicvideo.idMVideo from musicvideo"+strLike,VIDEODB_ID_MUSICVIDEO_ALBUM,strSearch.c_str());
5719 m_pDS->query( strSQL.c_str() );
5721 while (!m_pDS->eof())
5723 if (m_pDS->fv(0).get_asString().empty())
5729 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5730 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
5736 CFileItemPtr pItem(new CFileItem(m_pDS->fv(0).get_asString()));
5738 strDir.Format("%ld", m_pDS->fv(1).get_asInt());
5739 pItem->m_strPath="videodb://3/2/"+ strDir;
5740 pItem->m_bIsFolder=false;
5748 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
5752 void CVideoDatabase::GetMusicVideosByAlbum(const CStdString& strSearch, CFileItemList& items)
5758 if (NULL == m_pDB.get()) return;
5759 if (NULL == m_pDS.get()) return;
5761 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5762 strSQL = PrepareSQL("select musicvideo.idMVideo,musicvideo.c%02d,musicvideo.c%02d,path.strPath from musicvideo,files,path where files.idFile=musicvideo.idFile and files.idPath=path.idPath and musicvideo.c%02d like '%%%s%%'",VIDEODB_ID_MUSICVIDEO_ALBUM,VIDEODB_ID_MUSICVIDEO_TITLE,VIDEODB_ID_MUSICVIDEO_ALBUM,strSearch.c_str());
5764 strSQL = PrepareSQL("select musicvideo.idmvideo,musicvideo.c%02d,musicvideo.c%02d from musicvideo where musicvideo.c%02d like '%%%s%%'",VIDEODB_ID_MUSICVIDEO_ALBUM,VIDEODB_ID_MUSICVIDEO_TITLE,VIDEODB_ID_MUSICVIDEO_ALBUM,strSearch.c_str());
5765 m_pDS->query( strSQL.c_str() );
5767 while (!m_pDS->eof())
5769 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5770 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
5776 CFileItemPtr pItem(new CFileItem(m_pDS->fv(1).get_asString()+" - "+m_pDS->fv(2).get_asString()));
5778 strDir.Format("3/2/%ld",m_pDS->fv("musicvideo.idMVideo").get_asInt());
5780 pItem->m_strPath="videodb://"+ strDir;
5781 pItem->m_bIsFolder=false;
5789 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
5793 bool CVideoDatabase::GetMusicVideosByWhere(const CStdString &baseDir, const CStdString &whereClause, CFileItemList &items, bool checkLocks /*= true*/)
5797 DWORD time = CTimeUtils::GetTimeMS();
5801 if (NULL == m_pDB.get()) return false;
5802 if (NULL == m_pDS.get()) return false;
5804 // We don't use PrepareSQL here, as the WHERE clause is already formatted.
5805 CStdString strSQL = "select * from musicvideoview " + whereClause;
5806 CLog::Log(LOGDEBUG, "%s query = %s", __FUNCTION__, strSQL.c_str());
5809 if (!m_pDS->query(strSQL.c_str()))
5811 CLog::Log(LOGDEBUG, "%s time for actual SQL query = %d", __FUNCTION__, CTimeUtils::GetTimeMS() - time); time = CTimeUtils::GetTimeMS();
5813 int iRowsFound = m_pDS->num_rows();
5814 if (iRowsFound == 0)
5820 // get data from returned rows
5821 items.Reserve(iRowsFound);
5822 // get songs from returned subtable
5823 while (!m_pDS->eof())
5825 int idMVideo = m_pDS->fv("idMVideo").get_asInt();
5826 CVideoInfoTag musicvideo = GetDetailsForMusicVideo(m_pDS);
5827 if (!checkLocks || g_settings.GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE || g_passwordManager.bMasterUser ||
5828 g_passwordManager.IsDatabasePathUnlocked(musicvideo.m_strPath,g_settings.m_videoSources))
5830 CFileItemPtr item(new CFileItem(musicvideo));
5831 item->m_strPath.Format("%s%ld",baseDir,idMVideo);
5832 item->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED,musicvideo.m_playCount > 0);
5838 CLog::Log(LOGDEBUG, "%s time to retrieve from dataset = %d", __FUNCTION__, CTimeUtils::GetTimeMS() - time); time = CTimeUtils::GetTimeMS();
5846 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, whereClause.c_str());
5851 unsigned int CVideoDatabase::GetMusicVideoIDs(const CStdString& strWhere, vector<pair<int,int> > &songIDs)
5855 if (NULL == m_pDB.get()) return 0;
5856 if (NULL == m_pDS.get()) return 0;
5858 CStdString strSQL = "select distinct idMVideo from musicvideoview " + strWhere;
5859 if (!m_pDS->query(strSQL.c_str())) return 0;
5861 if (m_pDS->num_rows() == 0)
5866 songIDs.reserve(m_pDS->num_rows());
5867 while (!m_pDS->eof())
5869 songIDs.push_back(make_pair<int,int>(2,m_pDS->fv(0).get_asInt()));
5873 return songIDs.size();
5877 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strWhere.c_str());
5882 bool CVideoDatabase::GetRandomMusicVideo(CFileItem* item, int& idSong, const CStdString& strWhere)
5888 int iCount = GetMusicVideoCount(strWhere);
5891 int iRandom = rand() % iCount;
5893 if (NULL == m_pDB.get()) return false;
5894 if (NULL == m_pDS.get()) return false;
5896 // We don't use PrepareSQL here, as the WHERE clause is already formatted.
5898 strSQL.Format("select * from musicvideoview %s order by idMVideo limit 1 offset %i",strWhere.c_str(),iRandom);
5899 CLog::Log(LOGDEBUG, "%s query = %s", __FUNCTION__, strSQL.c_str());
5901 if (!m_pDS->query(strSQL.c_str()))
5903 int iRowsFound = m_pDS->num_rows();
5904 if (iRowsFound != 1)
5909 *item->GetVideoInfoTag() = GetDetailsForMusicVideo(m_pDS);
5910 item->m_strPath.Format("videodb://3/2/%ld",item->GetVideoInfoTag()->m_iDbId);
5911 idSong = m_pDS->fv("idmvideo").get_asInt();
5912 item->SetLabel(item->GetVideoInfoTag()->m_strTitle);
5918 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strWhere.c_str());
5923 int CVideoDatabase::GetMatchingMusicVideo(const CStdString& strArtist, const CStdString& strAlbum, const CStdString& strTitle)
5927 if (NULL == m_pDB.get()) return -1;
5928 if (NULL == m_pDS.get()) return -1;
5931 if (strAlbum.IsEmpty() && strTitle.IsEmpty())
5932 { // we want to return matching artists only
5933 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5934 strSQL=PrepareSQL("select distinct actors.idActor,path.strPath from artistlinkmusicvideo,actors,musicvideo,files,path where actors.idActor=artistlinkmusicvideo.idArtist and artistlinkmusicvideo.idMVideo=musicvideo.idMVideo and files.idFile=musicvideo.idFile and files.idPath=path.idPath and actors.strActor like '%s'",strArtist.c_str());
5936 strSQL=PrepareSQL("select distinct actors.idActor from artistlinkmusicvideo,actors where actors.idActor=artistlinkmusicvideo.idArtist and actors.strActor like '%s'",strArtist.c_str());
5939 { // we want to return the matching musicvideo
5940 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5941 strSQL = PrepareSQL("select musicvideo.idMVideo from musicvideo,files,path,artistlinkmusicvideo,actors where files.idFile=musicvideo.idFile and files.idPath=path.idPath and musicvideo.%c02d like '%s' and musicvideo.%c02d like '%s' and artistlinkmusicvideo.idMVideo=musicvideo.idMVideo and artistlinkmusicvideo.idArtist=actors.idActors and actors.strActor like '%s'",VIDEODB_ID_MUSICVIDEO_ALBUM,strAlbum.c_str(),VIDEODB_ID_MUSICVIDEO_TITLE,strTitle.c_str(),strArtist.c_str());
5943 strSQL = PrepareSQL("select musicvideo.idMVideo from musicvideo join artistlinkmusicvideo on artistlinkmusicvideo.idMVideo=musicvideo.idMVideo join actors on actors.idActor=artistlinkmusicvideo.idArtist where musicvideo.c%02d like '%s' and musicvideo.c%02d like '%s' and actors.strActor like '%s'",VIDEODB_ID_MUSICVIDEO_ALBUM,strAlbum.c_str(),VIDEODB_ID_MUSICVIDEO_TITLE,strTitle.c_str(),strArtist.c_str());
5945 m_pDS->query( strSQL.c_str() );
5950 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5951 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
5957 int lResult = m_pDS->fv(0).get_asInt();
5963 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
5968 void CVideoDatabase::GetMoviesByName(const CStdString& strSearch, CFileItemList& items)
5974 if (NULL == m_pDB.get()) return;
5975 if (NULL == m_pDS.get()) return;
5977 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5978 strSQL = PrepareSQL("select movie.idMovie,movie.c%02d,path.strPath from movie,files,path where files.idFile=movie.idFile and files.idPath=path.idPath and movie.c%02d like '%%%s%%'",VIDEODB_ID_TITLE,VIDEODB_ID_TITLE,strSearch.c_str());
5980 strSQL = PrepareSQL("select movie.idMovie,movie.c%02d from movie where movie.c%02d like '%%%s%%'",VIDEODB_ID_TITLE,VIDEODB_ID_TITLE,strSearch.c_str());
5981 m_pDS->query( strSQL.c_str() );
5983 while (!m_pDS->eof())
5985 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5986 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
5992 int movieId = m_pDS->fv("movie.idMovie").get_asInt();
5993 CStdString strSQL2 = PrepareSQL("select idSet from setlinkmovie where idMovie=%i",movieId);
5994 m_pDS2->query(strSQL2.c_str());
5995 CFileItemPtr pItem(new CFileItem(m_pDS->fv(1).get_asString()));
5997 pItem->m_strPath.Format("videodb://1/2/%i",movieId);
5999 pItem->m_strPath.Format("videodb://1/7/%i/%i",m_pDS2->fv(0).get_asInt(),movieId);
6001 pItem->m_bIsFolder=false;
6010 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
6014 void CVideoDatabase::GetTvShowsByName(const CStdString& strSearch, CFileItemList& items)
6020 if (NULL == m_pDB.get()) return;
6021 if (NULL == m_pDS.get()) return;
6023 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6024 strSQL = PrepareSQL("select tvshow.idShow,tvshow.c%02d,path.strPath from tvshow,path,tvshowlinkpath where tvshowlinkpath.idPath=path.idPath and tvshowlinkpath.idShow=tvshow.idShow and tvshow.c%02d like '%%%s%%'",VIDEODB_ID_TV_TITLE,VIDEODB_ID_TV_TITLE,strSearch.c_str());
6026 strSQL = PrepareSQL("select tvshow.idShow,tvshow.c%02d from tvshow where tvshow.c%02d like '%%%s%%'",VIDEODB_ID_TV_TITLE,VIDEODB_ID_TV_TITLE,strSearch.c_str());
6027 m_pDS->query( strSQL.c_str() );
6029 while (!m_pDS->eof())
6031 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6032 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
6038 CFileItemPtr pItem(new CFileItem(m_pDS->fv(1).get_asString()));
6040 strDir.Format("2/2/%ld/", m_pDS->fv("tvshow.idShow").get_asInt());
6042 pItem->m_strPath="videodb://"+ strDir;
6043 pItem->m_bIsFolder=true;
6044 pItem->GetVideoInfoTag()->m_iDbId = m_pDS->fv("tvshow.idshow").get_asInt();
6052 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
6056 void CVideoDatabase::GetEpisodesByName(const CStdString& strSearch, CFileItemList& items)
6062 if (NULL == m_pDB.get()) return;
6063 if (NULL == m_pDS.get()) return;
6065 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6066 strSQL = PrepareSQL("select episode.idEpisode,episode.c%02d,episode.c%02d,tvshowlinkepisode.idShow,tvshow.c%02d,path.strPath from episode,files,path,tvshowlinkepisode,tvshow where files.idFile=episode.idFile and tvshowlinkepisode.idEpisode=episode.idEpisode and tvshowlinkepisode.idShow=tvshow.idShow and files.idPath=path.idPath and episode.c%02d like '%%%s%%'",VIDEODB_ID_EPISODE_TITLE,VIDEODB_ID_EPISODE_SEASON,VIDEODB_ID_TV_TITLE,VIDEODB_ID_EPISODE_TITLE,strSearch.c_str());
6068 strSQL = PrepareSQL("select episode.idEpisode,episode.c%02d,episode.c%02d,tvshowlinkepisode.idShow,tvshow.c%02d from episode,tvshowlinkepisode,tvshow where tvshowlinkepisode.idEpisode=episode.idEpisode and tvshow.idShow=tvshowlinkepisode.idShow and episode.c%02d like '%%%s%%'",VIDEODB_ID_EPISODE_TITLE,VIDEODB_ID_EPISODE_SEASON,VIDEODB_ID_TV_TITLE,VIDEODB_ID_EPISODE_TITLE,strSearch.c_str());
6069 m_pDS->query( strSQL.c_str() );
6071 while (!m_pDS->eof())
6073 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6074 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
6080 CFileItemPtr pItem(new CFileItem(m_pDS->fv(1).get_asString()+" ("+m_pDS->fv(4).get_asString()+")"));
6081 pItem->m_strPath.Format("videodb://2/2/%ld/%ld/%ld",m_pDS->fv("tvshowlinkepisode.idShow").get_asInt(),m_pDS->fv(2).get_asInt(),m_pDS->fv(0).get_asInt());
6082 pItem->m_bIsFolder=false;
6090 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
6094 void CVideoDatabase::GetMusicVideosByName(const CStdString& strSearch, CFileItemList& items)
6096 // Alternative searching - not quite as fast though due to
6097 // retrieving all information
6098 // CStdString where = PrepareSQL("where c%02d like '%s%%' or c%02d like '%% %s%%'", VIDEODB_ID_MUSICVIDEO_TITLE, strSearch.c_str(), VIDEODB_ID_MUSICVIDEO_TITLE, strSearch.c_str());
6099 // GetMusicVideosByWhere("videodb://3/2/", where, items);
6104 if (NULL == m_pDB.get()) return;
6105 if (NULL == m_pDS.get()) return;
6107 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6108 strSQL = PrepareSQL("select musicvideo.idMVideo,musicvideo.c%02d,path.strPath from musicvideo,files,path where files.idFile=musicvideo.idFile and files.idPath=path.idPath and musicvideo.c%02d like '%%%s%%'",VIDEODB_ID_MUSICVIDEO_TITLE,VIDEODB_ID_MUSICVIDEO_TITLE,strSearch.c_str());
6110 strSQL = PrepareSQL("select musicvideo.idMVideo,musicvideo.c%02d from musicvideo where musicvideo.c%02d like '%%%s%%'",VIDEODB_ID_MUSICVIDEO_TITLE,VIDEODB_ID_MUSICVIDEO_TITLE,strSearch.c_str());
6111 m_pDS->query( strSQL.c_str() );
6113 while (!m_pDS->eof())
6115 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6116 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
6122 CFileItemPtr pItem(new CFileItem(m_pDS->fv(1).get_asString()));
6124 strDir.Format("3/2/%ld",m_pDS->fv("musicvideo.idMVideo").get_asInt());
6126 pItem->m_strPath="videodb://"+ strDir;
6127 pItem->m_bIsFolder=false;
6135 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
6139 void CVideoDatabase::GetEpisodesByPlot(const CStdString& strSearch, CFileItemList& items)
6141 // Alternative searching - not quite as fast though due to
6142 // retrieving all information
6143 // CStdString where = PrepareSQL("where c%02d like '%s%%' or c%02d like '%% %s%%'", VIDEODB_ID_EPISODE_PLOT, strSearch.c_str(), VIDEODB_ID_EPISODE_PLOT, strSearch.c_str());
6144 // where += PrepareSQL("or c%02d like '%s%%' or c%02d like '%% %s%%'", VIDEODB_ID_EPISODE_TITLE, strSearch.c_str(), VIDEODB_ID_EPISODE_TITLE, strSearch.c_str());
6145 // GetEpisodesByWhere("videodb://2/2/", where, items);
6151 if (NULL == m_pDB.get()) return;
6152 if (NULL == m_pDS.get()) return;
6154 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6155 strSQL = PrepareSQL("select episode.idEpisode,episode.c%02d,episode.c%02d,tvshowlinkepisode.idShow,tvshow.c%02d,path.strPath from episode,files,path,tvshowlinkepisode,tvshow where files.idFile=episode.idFile and tvshowlinkepisode.idEpisode=episode.idEpisode and files.idPath=path.idPath and tvshow.idShow=tvshowlinkepisode.idShow and episode.c%02d like '%%%s%%'",VIDEODB_ID_EPISODE_TITLE,VIDEODB_ID_EPISODE_SEASON,VIDEODB_ID_TV_TITLE,VIDEODB_ID_EPISODE_PLOT,strSearch.c_str());
6157 strSQL = PrepareSQL("select episode.idEpisode,episode.c%02d,episode.c%02d,tvshowlinkepisode.idShow,tvshow.c%02d from episode,tvshowlinkepisode,tvshow where tvshowlinkepisode.idEpisode=episode.idEpisode and tvshow.idShow=tvshowlinkepisode.idShow and episode.c%02d like '%%%s%%'",VIDEODB_ID_EPISODE_TITLE,VIDEODB_ID_EPISODE_SEASON,VIDEODB_ID_TV_TITLE,VIDEODB_ID_EPISODE_PLOT,strSearch.c_str());
6158 m_pDS->query( strSQL.c_str() );
6160 while (!m_pDS->eof())
6162 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6163 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
6169 CFileItemPtr pItem(new CFileItem(m_pDS->fv(1).get_asString()+" ("+m_pDS->fv(4).get_asString()+")"));
6170 pItem->m_strPath.Format("videodb://2/2/%ld/%ld/%ld",m_pDS->fv("tvshowlinkepisode.idShow").get_asInt(),m_pDS->fv(2).get_asInt(),m_pDS->fv(0).get_asInt());
6171 pItem->m_bIsFolder=false;
6179 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
6183 void CVideoDatabase::GetMoviesByPlot(const CStdString& strSearch, CFileItemList& items)
6189 if (NULL == m_pDB.get()) return;
6190 if (NULL == m_pDS.get()) return;
6192 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6193 strSQL = PrepareSQL("select movie.idMovie, movie.c%02d, path.strPath from movie,files,path where files.idFile=movie.idFile and files.idPath=path.idPath and (movie.c%02d like '%%%s%%' or movie.c%02d like '%%%s%%' or movie.c%02d like '%%%s%%')",VIDEODB_ID_TITLE,VIDEODB_ID_PLOT,strSearch.c_str(),VIDEODB_ID_PLOTOUTLINE,strSearch.c_str(),VIDEODB_ID_TAGLINE,strSearch.c_str());
6195 strSQL = PrepareSQL("select movie.idMovie, movie.c%02d from movie where (movie.c%02d like '%%%s%%' or movie.c%02d like '%%%s%%' or movie.c%02d like '%%%s%%')",VIDEODB_ID_TITLE,VIDEODB_ID_PLOT,strSearch.c_str(),VIDEODB_ID_PLOTOUTLINE,strSearch.c_str(),VIDEODB_ID_TAGLINE,strSearch.c_str());
6197 m_pDS->query( strSQL.c_str() );
6199 while (!m_pDS->eof())
6201 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6202 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv(2).get_asString()),g_settings.m_videoSources))
6208 CFileItemPtr pItem(new CFileItem(m_pDS->fv(1).get_asString()));
6209 pItem->m_strPath.Format("videodb://1/2/%ld", m_pDS->fv(0).get_asInt());
6210 pItem->m_bIsFolder=false;
6220 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
6224 void CVideoDatabase::GetMovieDirectorsByName(const CStdString& strSearch, CFileItemList& items)
6230 if (NULL == m_pDB.get()) return;
6231 if (NULL == m_pDS.get()) return;
6233 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6234 strSQL = PrepareSQL("select distinct directorlinkmovie.idDirector,actors.strActor,path.strPath from movie,files,path,actors,directorlinkmovie where files.idFile=movie.idFile and files.idPath=path.idPath and directorlinkmovie.idMovie=movie.idMovie and directorlinkmovie.idDirector=actors.idActor and actors.strActor like '%%%s%%'",strSearch.c_str());
6236 strSQL = PrepareSQL("select distinct directorlinkmovie.idDirector,actors.strActor from movie,actors,directorlinkmovie where directorlinkmovie.idMovie=movie.idMovie and directorlinkmovie.idDirector=actors.idActor and actors.strActor like '%%%s%%'",strSearch.c_str());
6238 m_pDS->query( strSQL.c_str() );
6240 while (!m_pDS->eof())
6242 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6243 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
6250 strDir.Format("%ld/", m_pDS->fv("directorlinkmovie.idDirector").get_asInt());
6251 CFileItemPtr pItem(new CFileItem(m_pDS->fv("actors.strActor").get_asString()));
6253 pItem->m_strPath="videodb://1/5/"+ strDir;
6254 pItem->m_bIsFolder=true;
6262 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
6266 void CVideoDatabase::GetTvShowsDirectorsByName(const CStdString& strSearch, CFileItemList& items)
6272 if (NULL == m_pDB.get()) return;
6273 if (NULL == m_pDS.get()) return;
6275 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6276 strSQL = PrepareSQL("select distinct directorlinktvshow.idDirector,actors.strActor,path.strPath from tvshow,path,actors,directorlinktvshow,tvshowlinkpath where tvshowlinkpath.idPath=path.idPath and tvshowlinkpath.idShow=tvshow.idShow and directorlinktvshow.idShow=tvshow.idShow and directorlinktvshow.idDirector=actors.idActor and actors.strActor like '%%%s%%'",strSearch.c_str());
6278 strSQL = PrepareSQL("select distinct directorlinktvshow.idDirector,actors.strActor from tvshow,actors,directorlinktvshow where directorlinktvshow.idShow=tvshow.idShow and directorlinktvshow.idDirector=actors.idActor and actors.strActor like '%%%s%%'",strSearch.c_str());
6280 m_pDS->query( strSQL.c_str() );
6282 while (!m_pDS->eof())
6284 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6285 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
6292 strDir.Format("%ld/", m_pDS->fv("directorlinktvshow.idDirector").get_asInt());
6293 CFileItemPtr pItem(new CFileItem(m_pDS->fv("actors.strActor").get_asString()));
6295 pItem->m_strPath="videodb://2/5/"+ strDir;
6296 pItem->m_bIsFolder=true;
6304 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
6308 void CVideoDatabase::GetMusicVideoDirectorsByName(const CStdString& strSearch, CFileItemList& items)
6314 if (NULL == m_pDB.get()) return;
6315 if (NULL == m_pDS.get()) return;
6317 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6318 strSQL = PrepareSQL("select distinct directorlinkmusicvideo.idDirector,actors.strActor,path.strPath from musicvideo,files,path,actors,directorlinkmusicvideo where files.idFile=musicvideo.idFile and files.idPath=path.idPath and directorlinkmusicvideo.idMVideo=musicvideo.idMVideo and directorlinkmusicvideo.idDirector=actors.idActor and actors.strActor like '%%%s%%'",strSearch.c_str());
6320 strSQL = PrepareSQL("select distinct directorlinkmusicvideo.idDirector,actors.strActor from musicvideo,actors,directorlinkmusicvideo where directorlinkmusicvideo.idMVideo=musicvideo.idMVideo and directorlinkmusicvideo.idDirector=actors.idActor and actors.strActor like '%%%s%%'",strSearch.c_str());
6322 m_pDS->query( strSQL.c_str() );
6324 while (!m_pDS->eof())
6326 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6327 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
6334 strDir.Format("%ld/", m_pDS->fv("directorlinkmusicvideo.idDirector").get_asInt());
6335 CFileItemPtr pItem(new CFileItem(m_pDS->fv("actors.strActor").get_asString()));
6337 pItem->m_strPath="videodb://3/5/"+ strDir;
6338 pItem->m_bIsFolder=true;
6346 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
6350 void CVideoDatabase::CleanDatabase(IVideoInfoScannerObserver* pObserver, const vector<int>* paths)
6352 CGUIDialogProgress *progress=NULL;
6355 if (NULL == m_pDB.get()) return;
6356 if (NULL == m_pDS.get()) return;
6358 unsigned int time = CTimeUtils::GetTimeMS();
6359 CLog::Log(LOGNOTICE, "%s: Starting videodatabase cleanup ..", __FUNCTION__);
6363 // find all the files
6367 if (paths->size() == 0)
6369 RollbackTransaction();
6373 CStdString strPaths;
6374 for (unsigned int i=0;i<paths->size();++i )
6375 strPaths.Format("%s,%i",strPaths.Mid(0).c_str(),paths->at(i));
6376 sql = PrepareSQL("select * from files,path where files.idPath=path.idPath and path.idPath in (%s)",strPaths.Mid(1).c_str());
6379 sql = "select * from files, path where files.idPath = path.idPath";
6381 m_pDS->query(sql.c_str());
6382 if (m_pDS->num_rows() == 0) return;
6386 progress = (CGUIDialogProgress *)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
6389 progress->SetHeading(700);
6390 progress->SetLine(0, "");
6391 progress->SetLine(1, 313);
6392 progress->SetLine(2, 330);
6393 progress->SetPercentage(0);
6394 progress->StartModal();
6395 progress->ShowProgressBar(true);
6400 pObserver->OnDirectoryChanged("");
6401 pObserver->OnSetTitle("");
6402 pObserver->OnSetCurrentProgress(0,1);
6403 pObserver->OnStateChanged(CLEANING_UP_DATABASE);
6406 CStdString filesToDelete = "";
6407 CStdString moviesToDelete = "";
6408 CStdString episodesToDelete = "";
6409 CStdString musicVideosToDelete = "";
6411 std::vector<int> movieIDs;
6412 std::vector<int> episodeIDs;
6413 std::vector<int> musicVideoIDs;
6415 int total = m_pDS->num_rows();
6417 while (!m_pDS->eof())
6419 CStdString path = m_pDS->fv("path.strPath").get_asString();
6420 CStdString fileName = m_pDS->fv("files.strFileName").get_asString();
6421 CStdString fullPath;
6422 ConstructPath(fullPath,path,fileName);
6424 // get the first stacked file
6425 if (URIUtils::IsStack(fullPath))
6426 fullPath = CStackDirectory::GetFirstStackedFile(fullPath);
6428 // check for deletion
6430 VECSOURCES *pShares = g_settings.GetSourcesFromType("video");
6432 // check if we have a internet related file that is part of a media source
6433 if (URIUtils::IsInternetStream(fullPath, true) && CUtil::GetMatchingSource(fullPath, *pShares, bIsSource) > -1)
6435 if (!CFile::Exists(fullPath, false))
6436 filesToDelete += m_pDS->fv("files.idFile").get_asString() + ",";
6440 // remove optical, internet related and non-existing files
6441 // note: this will also remove entries from previously existing media sources
6442 if (URIUtils::IsOnDVD(fullPath) || URIUtils::IsInternetStream(fullPath, true) || !CFile::Exists(fullPath, false))
6443 filesToDelete += m_pDS->fv("files.idFile").get_asString() + ",";
6450 progress->SetPercentage(current * 100 / total);
6451 progress->Progress();
6452 if (progress->IsCanceled())
6461 pObserver->OnSetProgress(current,total);
6468 if ( ! filesToDelete.IsEmpty() )
6470 filesToDelete.TrimRight(",");
6471 // now grab them movies
6472 sql = PrepareSQL("select idMovie from movie where idFile in (%s)",filesToDelete.c_str());
6473 m_pDS->query(sql.c_str());
6474 while (!m_pDS->eof())
6476 movieIDs.push_back(m_pDS->fv(0).get_asInt());
6477 moviesToDelete += m_pDS->fv(0).get_asString() + ",";
6481 // now grab them episodes
6482 sql = PrepareSQL("select idEpisode from episode where idFile in (%s)",filesToDelete.c_str());
6483 m_pDS->query(sql.c_str());
6484 while (!m_pDS->eof())
6486 episodeIDs.push_back(m_pDS->fv(0).get_asInt());
6487 episodesToDelete += m_pDS->fv(0).get_asString() + ",";
6492 // now grab them musicvideos
6493 sql = PrepareSQL("select idMVideo from musicvideo where idFile in (%s)",filesToDelete.c_str());
6494 m_pDS->query(sql.c_str());
6495 while (!m_pDS->eof())
6497 musicVideoIDs.push_back(m_pDS->fv(0).get_asInt());
6498 musicVideosToDelete += m_pDS->fv(0).get_asString() + ",";
6506 progress->SetPercentage(100);
6507 progress->Progress();
6510 if ( ! filesToDelete.IsEmpty() )
6512 filesToDelete = "(" + filesToDelete + ")";
6513 CLog::Log(LOGDEBUG, "%s: Cleaning files table", __FUNCTION__);
6514 sql = "delete from files where idFile in " + filesToDelete;
6515 m_pDS->exec(sql.c_str());
6517 CLog::Log(LOGDEBUG, "%s: Cleaning streamdetails table", __FUNCTION__);
6518 sql = "delete from streamdetails where idFile in " + filesToDelete;
6519 m_pDS->exec(sql.c_str());
6521 CLog::Log(LOGDEBUG, "%s: Cleaning bookmark table", __FUNCTION__);
6522 sql = "delete from bookmark where idFile in " + filesToDelete;
6523 m_pDS->exec(sql.c_str());
6525 CLog::Log(LOGDEBUG, "%s: Cleaning settings table", __FUNCTION__);
6526 sql = "delete from settings where idFile in " + filesToDelete;
6527 m_pDS->exec(sql.c_str());
6529 CLog::Log(LOGDEBUG, "%s: Cleaning stacktimes table", __FUNCTION__);
6530 sql = "delete from stacktimes where idFile in " + filesToDelete;
6531 m_pDS->exec(sql.c_str());
6534 if ( ! moviesToDelete.IsEmpty() )
6536 moviesToDelete = "(" + moviesToDelete.TrimRight(",") + ")";
6538 CLog::Log(LOGDEBUG, "%s: Cleaning movie table", __FUNCTION__);
6539 sql = "delete from movie where idMovie in " + moviesToDelete;
6540 m_pDS->exec(sql.c_str());
6542 CLog::Log(LOGDEBUG, "%s: Cleaning actorlinkmovie table", __FUNCTION__);
6543 sql = "delete from actorlinkmovie where idMovie in " + moviesToDelete;
6544 m_pDS->exec(sql.c_str());
6546 CLog::Log(LOGDEBUG, "%s: Cleaning directorlinkmovie table", __FUNCTION__);
6547 sql = "delete from directorlinkmovie where idMovie in " + moviesToDelete;
6548 m_pDS->exec(sql.c_str());
6550 CLog::Log(LOGDEBUG, "%s: Cleaning writerlinkmovie table", __FUNCTION__);
6551 sql = "delete from writerlinkmovie where idMovie in " + moviesToDelete;
6552 m_pDS->exec(sql.c_str());
6554 CLog::Log(LOGDEBUG, "%s: Cleaning genrelinkmovie table", __FUNCTION__);
6555 sql = "delete from genrelinkmovie where idMovie in " + moviesToDelete;
6556 m_pDS->exec(sql.c_str());
6558 CLog::Log(LOGDEBUG, "%s: Cleaning countrylinkmovie table", __FUNCTION__);
6559 sql = "delete from countrylinkmovie where idMovie in " + moviesToDelete;
6560 m_pDS->exec(sql.c_str());
6562 CLog::Log(LOGDEBUG, "%s: Cleaning studiolinkmovie table", __FUNCTION__);
6563 sql = "delete from studiolinkmovie where idMovie in " + moviesToDelete;
6564 m_pDS->exec(sql.c_str());
6566 CLog::Log(LOGDEBUG, "%s: Cleaning setlinkmovie table", __FUNCTION__);
6567 sql = "delete from setlinkmovie where idMovie in " + moviesToDelete;
6568 m_pDS->exec(sql.c_str());
6571 if ( ! episodesToDelete.IsEmpty() )
6573 episodesToDelete = "(" + episodesToDelete.TrimRight(",") + ")";
6575 CLog::Log(LOGDEBUG, "%s: Cleaning episode table", __FUNCTION__);
6576 sql = "delete from episode where idEpisode in " + episodesToDelete;
6577 m_pDS->exec(sql.c_str());
6579 CLog::Log(LOGDEBUG, "%s: Cleaning actorlinkepisode table", __FUNCTION__);
6580 sql = "delete from actorlinkepisode where idEpisode in " + episodesToDelete;
6581 m_pDS->exec(sql.c_str());
6583 CLog::Log(LOGDEBUG, "%s: Cleaning directorlinkepisode table", __FUNCTION__);
6584 sql = "delete from directorlinkepisode where idEpisode in " + episodesToDelete;
6585 m_pDS->exec(sql.c_str());
6587 CLog::Log(LOGDEBUG, "%s: Cleaning writerlinkepisode table", __FUNCTION__);
6588 sql = "delete from writerlinkepisode where idEpisode in " + episodesToDelete;
6589 m_pDS->exec(sql.c_str());
6591 CLog::Log(LOGDEBUG, "%s: Cleaning tvshowlinkepisode table", __FUNCTION__);
6592 sql = "delete from tvshowlinkepisode where idEpisode in " + episodesToDelete;
6593 m_pDS->exec(sql.c_str());
6596 CLog::Log(LOGDEBUG, "%s: Cleaning paths that don't exist and don't have content set...", __FUNCTION__);
6597 sql = "select * from path where strContent not like ''";
6598 m_pDS->query(sql.c_str());
6600 while (!m_pDS->eof())
6602 if (!CDirectory::Exists(m_pDS->fv("path.strPath").get_asString()))
6603 strIds.Format("%s %i,",strIds.Mid(0),m_pDS->fv("path.idPath").get_asInt()); // mid since we cannot format the same string
6606 if (!strIds.IsEmpty())
6608 strIds.TrimLeft(" ");
6609 strIds.TrimRight(",");
6610 sql = PrepareSQL("delete from path where idPath in (%s)",strIds.c_str());
6611 m_pDS->exec(sql.c_str());
6612 sql = PrepareSQL("delete from tvshowlinkpath where idPath in (%s)",strIds.c_str());
6613 m_pDS->exec(sql.c_str());
6616 CLog::Log(LOGDEBUG, "%s: Cleaning tvshow table", __FUNCTION__);
6617 sql = "delete from tvshow where idShow not in (select idShow from tvshowlinkpath)";
6618 m_pDS->exec(sql.c_str());
6620 std::vector<int> tvshowIDs;
6621 CStdString showsToDelete;
6622 sql = "select tvshow.idShow from tvshow "
6623 "join tvshowlinkpath on tvshow.idShow=tvshowlinkpath.idShow "
6624 "join path on path.idPath=tvshowlinkpath.idPath "
6625 "where tvshow.idShow not in (select idShow from tvshowlinkepisode) "
6626 "and path.strContent=''";
6627 m_pDS->query(sql.c_str());
6628 while (!m_pDS->eof())
6630 tvshowIDs.push_back(m_pDS->fv(0).get_asInt());
6631 showsToDelete += m_pDS->fv(0).get_asString() + ",";
6635 if (!showsToDelete.IsEmpty())
6637 sql = "delete from tvshow where idShow in (" + showsToDelete.TrimRight(",") + ")";
6638 m_pDS->exec(sql.c_str());
6641 CLog::Log(LOGDEBUG, "%s: Cleaning actorlinktvshow table", __FUNCTION__);
6642 sql = "delete from actorlinktvshow where idShow not in (select idShow from tvshow)";
6643 m_pDS->exec(sql.c_str());
6645 CLog::Log(LOGDEBUG, "%s: Cleaning directorlinktvshow table", __FUNCTION__);
6646 sql = "delete from directorlinktvshow where idShow not in (select idShow from tvshow)";
6647 m_pDS->exec(sql.c_str());
6649 CLog::Log(LOGDEBUG, "%s: Cleaning tvshowlinkpath table", __FUNCTION__);
6650 sql = "delete from tvshowlinkpath where idShow not in (select idShow from tvshow)";
6651 m_pDS->exec(sql.c_str());
6653 CLog::Log(LOGDEBUG, "%s: Cleaning genrelinktvshow table", __FUNCTION__);
6654 sql = "delete from genrelinktvshow where idShow not in (select idShow from tvshow)";
6655 m_pDS->exec(sql.c_str());
6657 CLog::Log(LOGDEBUG, "%s: Cleaning movielinktvshow table", __FUNCTION__);
6658 sql = "delete from movielinktvshow where idShow not in (select idShow from tvshow)";
6659 m_pDS->exec(sql.c_str());
6660 sql = "delete from movielinktvshow where idMovie not in (select distinct idMovie from movie)";
6661 m_pDS->exec(sql.c_str());
6663 if ( ! musicVideosToDelete.IsEmpty() )
6665 musicVideosToDelete = "(" + musicVideosToDelete.TrimRight(",") + ")";
6667 CLog::Log(LOGDEBUG, "%s: Cleaning musicvideo table", __FUNCTION__);
6668 sql = "delete from musicvideo where idMVideo in " + musicVideosToDelete;
6669 m_pDS->exec(sql.c_str());
6671 CLog::Log(LOGDEBUG, "%s: Cleaning artistlinkmusicvideo table", __FUNCTION__);
6672 sql = "delete from artistlinkmusicvideo where idMVideo in " + musicVideosToDelete;
6673 m_pDS->exec(sql.c_str());
6675 CLog::Log(LOGDEBUG, "%s: Cleaning directorlinkmusicvideo table" ,__FUNCTION__);
6676 sql = "delete from directorlinkmusicvideo where idMVideo in " + musicVideosToDelete;
6677 m_pDS->exec(sql.c_str());
6679 CLog::Log(LOGDEBUG, "%s: Cleaning genrelinkmusicvideo table" ,__FUNCTION__);
6680 sql = "delete from genrelinkmusicvideo where idMVideo in " + musicVideosToDelete;
6681 m_pDS->exec(sql.c_str());
6683 CLog::Log(LOGDEBUG, "%s: Cleaning studiolinkmusicvideo table", __FUNCTION__);
6684 sql = "delete from studiolinkmusicvideo where idMVideo in " + musicVideosToDelete;
6685 m_pDS->exec(sql.c_str());
6688 CLog::Log(LOGDEBUG, "%s: Cleaning path table", __FUNCTION__);
6689 sql = "delete from path where idPath not in (select distinct idPath from files) and idPath not in (select distinct idPath from tvshowlinkpath) and strContent=''";
6690 m_pDS->exec(sql.c_str());
6692 CLog::Log(LOGDEBUG, "%s: Cleaning genre table", __FUNCTION__);
6693 sql = "delete from genre where idGenre not in (select distinct idGenre from genrelinkmovie) and idGenre not in (select distinct idGenre from genrelinktvshow) and idGenre not in (select distinct idGenre from genrelinkmusicvideo)";
6694 m_pDS->exec(sql.c_str());
6696 CLog::Log(LOGDEBUG, "%s: Cleaning country table", __FUNCTION__);
6697 sql = "delete from country where idCountry not in (select distinct idCountry from countrylinkmovie)";
6698 m_pDS->exec(sql.c_str());
6700 CLog::Log(LOGDEBUG, "%s: Cleaning actor table of actors, directors and writers", __FUNCTION__);
6701 sql = "delete from actors where idActor not in (select distinct idActor from actorlinkmovie) and idActor not in (select distinct idDirector from directorlinkmovie) and idActor not in (select distinct idWriter from writerlinkmovie) and idActor not in (select distinct idActor from actorlinktvshow) and idActor not in (select distinct idActor from actorlinkepisode) and idActor not in (select distinct idDirector from directorlinktvshow) and idActor not in (select distinct idDirector from directorlinkepisode) and idActor not in (select distinct idWriter from writerlinkepisode) and idActor not in (select distinct idArtist from artistlinkmusicvideo) and idActor not in (select distinct idDirector from directorlinkmusicvideo)";
6702 m_pDS->exec(sql.c_str());
6704 CLog::Log(LOGDEBUG, "%s: Cleaning studio table", __FUNCTION__);
6705 sql = "delete from studio where idStudio not in (select distinct idStudio from studiolinkmovie) and idStudio not in (select distinct idStudio from studiolinkmusicvideo) and idStudio not in (select distinct idStudio from studiolinktvshow)";
6706 m_pDS->exec(sql.c_str());
6708 CLog::Log(LOGDEBUG, "%s: Cleaning set table", __FUNCTION__);
6709 sql = "delete from sets where idSet not in (select distinct idSet from setlinkmovie)";
6710 m_pDS->exec(sql.c_str());
6712 CommitTransaction();
6715 pObserver->OnStateChanged(COMPRESSING_DATABASE);
6719 CUtil::DeleteVideoDatabaseDirectoryCache();
6721 time = CTimeUtils::GetTimeMS() - time;
6722 CLog::Log(LOGNOTICE, "%s: Cleaning videodatabase done. Operation took %s", __FUNCTION__, StringUtils::SecondsToTimeString(time / 1000).c_str());
6724 for (unsigned int i = 0; i < movieIDs.size(); i++)
6725 AnnounceRemove("movie", movieIDs[i]);
6727 for (unsigned int i = 0; i < episodeIDs.size(); i++)
6728 AnnounceRemove("episode", episodeIDs[i]);
6730 for (unsigned int i = 0; i < tvshowIDs.size(); i++)
6731 AnnounceRemove("tvshow", tvshowIDs[i]);
6733 for (unsigned int i = 0; i < musicVideoIDs.size(); i++)
6734 AnnounceRemove("musicvideo", musicVideoIDs[i]);
6738 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
6744 void CVideoDatabase::DumpToDummyFiles(const CStdString &path)
6747 CFileItemList items;
6748 GetTvShowsByWhere("videodb://2/2/", "", items);
6749 CStdString showPath = URIUtils::AddFileToFolder(path, "shows");
6750 CDirectory::Create(showPath);
6751 for (int i = 0; i < items.Size(); i++)
6753 // create a folder in this directory
6754 CStdString showName = CUtil::MakeLegalFileName(items[i]->GetVideoInfoTag()->m_strShowTitle);
6755 CStdString TVFolder;
6756 URIUtils::AddFileToFolder(showPath, showName, TVFolder);
6757 if (CDirectory::Create(TVFolder))
6758 { // right - grab the episodes and dump them as well
6759 CFileItemList episodes;
6760 CStdString where = PrepareSQL("where idShow=%i", items[i]->GetVideoInfoTag()->m_iDbId);
6761 GetEpisodesByWhere("videodb://2/2/", where, episodes);
6762 for (int i = 0; i < episodes.Size(); i++)
6764 CVideoInfoTag *tag = episodes[i]->GetVideoInfoTag();
6766 episode.Format("%s.s%02de%02d.avi", showName.c_str(), tag->m_iSeason, tag->m_iEpisode);
6768 CStdString episodePath;
6769 URIUtils::AddFileToFolder(TVFolder, episode, episodePath);
6771 if (file.OpenForWrite(episodePath))
6778 GetMoviesByWhere("videodb://1/2/", "", "", items);
6779 CStdString moviePath = URIUtils::AddFileToFolder(path, "movies");
6780 CDirectory::Create(moviePath);
6781 for (int i = 0; i < items.Size(); i++)
6783 CVideoInfoTag *tag = items[i]->GetVideoInfoTag();
6785 movie.Format("%s.avi", tag->m_strTitle.c_str());
6787 if (file.OpenForWrite(URIUtils::AddFileToFolder(moviePath, movie)))
6792 void CVideoDatabase::ExportToXML(const CStdString &path, bool singleFiles /* = false */, bool images /* = false */, bool actorThumbs /* false */, bool overwrite /*=false*/)
6794 CGUIDialogProgress *progress=NULL;
6797 if (NULL == m_pDB.get()) return;
6798 if (NULL == m_pDS.get()) return;
6799 if (NULL == m_pDS2.get()) return;
6801 // create a 3rd dataset as well as GetEpisodeDetails() etc. uses m_pDS2, and we need to do 3 nested queries on tv shows
6802 auto_ptr<Dataset> pDS;
6803 pDS.reset(m_pDB->CreateDataset());
6804 if (NULL == pDS.get()) return;
6806 auto_ptr<Dataset> pDS2;
6807 pDS2.reset(m_pDB->CreateDataset());
6808 if (NULL == pDS2.get()) return;
6810 // if we're exporting to a single folder, we export thumbs as well
6811 CStdString exportRoot = URIUtils::AddFileToFolder(path, "xbmc_videodb_" + CDateTime::GetCurrentDateTime().GetAsDBDate());
6812 CStdString xmlFile = URIUtils::AddFileToFolder(exportRoot, "videodb.xml");
6813 CStdString actorsDir = URIUtils::AddFileToFolder(exportRoot, "actors");
6814 CStdString moviesDir = URIUtils::AddFileToFolder(exportRoot, "movies");
6815 CStdString musicvideosDir = URIUtils::AddFileToFolder(exportRoot, "musicvideos");
6816 CStdString tvshowsDir = URIUtils::AddFileToFolder(exportRoot, "tvshows");
6822 CDirectory::Remove(exportRoot);
6823 CDirectory::Create(exportRoot);
6824 CDirectory::Create(actorsDir);
6825 CDirectory::Create(moviesDir);
6826 CDirectory::Create(musicvideosDir);
6827 CDirectory::Create(tvshowsDir);
6830 progress = (CGUIDialogProgress *)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
6832 CStdString sql = "select * from movieview";
6834 m_pDS->query(sql.c_str());
6838 progress->SetHeading(647);
6839 progress->SetLine(0, 650);
6840 progress->SetLine(1, "");
6841 progress->SetLine(2, "");
6842 progress->SetPercentage(0);
6843 progress->StartModal();
6844 progress->ShowProgressBar(true);
6847 int total = m_pDS->num_rows();
6850 // create our xml document
6851 TiXmlDocument xmlDoc;
6852 TiXmlDeclaration decl("1.0", "UTF-8", "yes");
6853 xmlDoc.InsertEndChild(decl);
6854 TiXmlNode *pMain = NULL;
6859 TiXmlElement xmlMainElement("videodb");
6860 pMain = xmlDoc.InsertEndChild(xmlMainElement);
6861 XMLUtils::SetInt(pMain,"version", GetExportVersion());
6864 while (!m_pDS->eof())
6866 CVideoInfoTag movie = GetDetailsForMovie(m_pDS, true);
6867 // strip paths to make them relative
6868 if (movie.m_strTrailer.Mid(0,movie.m_strPath.size()).Equals(movie.m_strPath))
6869 movie.m_strTrailer = movie.m_strTrailer.Mid(movie.m_strPath.size());
6870 movie.Save(pMain, "movie", !singleFiles);
6872 // reset old skip state
6877 progress->SetLine(1, movie.m_strTitle);
6878 progress->SetPercentage(current * 100 / total);
6879 progress->Progress();
6880 if (progress->IsCanceled())
6888 CFileItem item(movie.m_strFileNameAndPath,false);
6889 CFileItem saveItem(item);
6892 CStdString strFileName(movie.m_strTitle);
6893 if (movie.m_iYear > 0)
6894 strFileName.AppendFormat("_%i", movie.m_iYear);
6895 saveItem = CFileItem(GetSafeFile(moviesDir, strFileName) + ".avi", false);
6897 if (singleFiles && CUtil::SupportsFileOperations(movie.m_strFileNameAndPath))
6899 if (!item.Exists(false))
6901 CLog::Log(LOGDEBUG, "%s - Not exporting item %s as it does not exist", __FUNCTION__, movie.m_strFileNameAndPath.c_str());
6906 CStdString nfoFile(URIUtils::ReplaceExtension(item.GetTBNFile(), ".nfo"));
6908 if (item.IsOpticalMediaFile())
6910 nfoFile = URIUtils::GetParentFolderURI(nfoFile, true);
6913 if (overwrite || !CFile::Exists(nfoFile, false))
6915 if(!xmlDoc.SaveFile(nfoFile))
6917 CLog::Log(LOGERROR, "%s: Movie nfo export failed! ('%s')", __FUNCTION__, nfoFile.c_str());
6918 bSkip = ExportSkipEntry(nfoFile);
6932 TiXmlDeclaration decl("1.0", "UTF-8", "yes");
6933 xmlDoc.InsertEndChild(decl);
6937 if (images && !bSkip)
6939 CStdString cachedThumb(GetCachedThumb(item));
6940 CStdString savedThumb(saveItem.GetTBNFile());
6941 if (!cachedThumb.IsEmpty() && (overwrite || !CFile::Exists(savedThumb, false)))
6942 if (!CFile::Cache(cachedThumb, savedThumb))
6943 CLog::Log(LOGERROR, "%s: Movie thumb export failed! ('%s' -> '%s')", __FUNCTION__, cachedThumb.c_str(), savedThumb.c_str());
6945 CStdString cachedFanart(item.GetCachedFanart());
6946 CStdString savedFanart(URIUtils::ReplaceExtension(savedThumb, "-fanart.jpg"));
6948 if (CFile::Exists(cachedFanart, false) && (overwrite || !CFile::Exists(savedFanart, false)))
6949 if (!CFile::Cache(cachedFanart, savedFanart))
6950 CLog::Log(LOGERROR, "%s: Movie fanart export failed! ('%s' -> '%s')", __FUNCTION__, cachedFanart.c_str(), savedFanart.c_str());
6953 ExportActorThumbs(actorsDir, movie, singleFiles, overwrite);
6960 // find all musicvideos
6961 sql = "select * from musicvideoview";
6963 m_pDS->query(sql.c_str());
6965 total = m_pDS->num_rows();
6968 while (!m_pDS->eof())
6970 CVideoInfoTag movie = GetDetailsForMusicVideo(m_pDS);
6971 movie.Save(pMain, "musicvideo", !singleFiles);
6973 // reset old skip state
6978 progress->SetLine(1, movie.m_strTitle);
6979 progress->SetPercentage(current * 100 / total);
6980 progress->Progress();
6981 if (progress->IsCanceled())
6989 CFileItem item(movie.m_strFileNameAndPath,false);
6990 CFileItem saveItem(item);
6993 CStdString strFileName(movie.m_strArtist + "." + movie.m_strTitle);
6994 if (movie.m_iYear > 0)
6995 strFileName.AppendFormat("_%i", movie.m_iYear);
6996 saveItem = CFileItem(GetSafeFile(musicvideosDir, strFileName) + ".avi", false);
6998 if (CUtil::SupportsFileOperations(movie.m_strFileNameAndPath) && singleFiles)
7000 if (!item.Exists(false))
7002 CLog::Log(LOGDEBUG, "%s - Not exporting item %s as it does not exist", __FUNCTION__, movie.m_strFileNameAndPath.c_str());
7007 CStdString nfoFile(URIUtils::ReplaceExtension(item.GetTBNFile(), ".nfo"));
7009 if (overwrite || !CFile::Exists(nfoFile, false))
7011 if(!xmlDoc.SaveFile(nfoFile))
7013 CLog::Log(LOGERROR, "%s: Musicvideo nfo export failed! ('%s')", __FUNCTION__, nfoFile.c_str());
7014 bSkip = ExportSkipEntry(nfoFile);
7028 TiXmlDeclaration decl("1.0", "UTF-8", "yes");
7029 xmlDoc.InsertEndChild(decl);
7032 if (images && !bSkip)
7034 CStdString cachedThumb(GetCachedThumb(item));
7035 CStdString savedThumb(saveItem.GetTBNFile());
7036 if (!cachedThumb.IsEmpty() && (overwrite || !CFile::Exists(savedThumb, false)))
7037 if (!CFile::Cache(cachedThumb, savedThumb))
7038 CLog::Log(LOGERROR, "%s: Musicvideo thumb export failed! ('%s' -> '%s')", __FUNCTION__, cachedThumb.c_str(), savedThumb.c_str());
7045 // repeat for all tvshows
7046 sql = "SELECT * FROM tvshowview";
7047 m_pDS->query(sql.c_str());
7049 total = m_pDS->num_rows();
7052 while (!m_pDS->eof())
7054 CVideoInfoTag tvshow = GetDetailsForTvShow(m_pDS, true);
7055 tvshow.Save(pMain, "tvshow", !singleFiles);
7057 // reset old skip state
7062 progress->SetLine(1, tvshow.m_strTitle);
7063 progress->SetPercentage(current * 100 / total);
7064 progress->Progress();
7065 if (progress->IsCanceled())
7074 CFileItem item(tvshow.m_strPath, true);
7075 CFileItem saveItem(item);
7077 saveItem = CFileItem(GetSafeFile(tvshowsDir, tvshow.m_strShowTitle), true);
7078 if (singleFiles && CUtil::SupportsFileOperations(tvshow.m_strPath))
7080 if (!item.Exists(false))
7082 CLog::Log(LOGDEBUG, "%s - Not exporting item %s as it does not exist", __FUNCTION__, tvshow.m_strPath.c_str());
7088 URIUtils::AddFileToFolder(tvshow.m_strPath, "tvshow.nfo", nfoFile);
7090 if (overwrite || !CFile::Exists(nfoFile, false))
7092 if(!xmlDoc.SaveFile(nfoFile))
7094 CLog::Log(LOGERROR, "%s: TVShow nfo export failed! ('%s')", __FUNCTION__, nfoFile.c_str());
7095 bSkip = ExportSkipEntry(nfoFile);
7109 TiXmlDeclaration decl("1.0", "UTF-8", "yes");
7110 xmlDoc.InsertEndChild(decl);
7113 if (images && !bSkip)
7115 CStdString cachedThumb(GetCachedThumb(item));
7116 CStdString savedThumb(saveItem.GetFolderThumb());
7117 if (!cachedThumb.IsEmpty() && (overwrite || !CFile::Exists(savedThumb, false)))
7118 if (!CFile::Cache(cachedThumb, savedThumb))
7119 CLog::Log(LOGERROR, "%s: TVShow thumb export failed! ('%s' -> '%s')", __FUNCTION__, cachedThumb.c_str(), savedThumb.c_str());
7121 CStdString cachedFanart(item.GetCachedFanart());
7122 CStdString savedFanart(saveItem.GetFolderThumb("fanart.jpg"));
7123 if (CFile::Exists(cachedFanart, false) && (overwrite || !CFile::Exists(savedFanart, false)))
7124 if (!CFile::Cache(cachedFanart, savedFanart))
7125 CLog::Log(LOGERROR, "%s: TVShow fanart export failed! ('%s' -> '%s')", __FUNCTION__, cachedFanart.c_str(), savedFanart.c_str());
7128 ExportActorThumbs(actorsDir, tvshow, singleFiles, overwrite);
7130 // now get all available seasons from this show
7131 sql = PrepareSQL("select distinct(c%02d) from episodeview where idShow=%i", VIDEODB_ID_EPISODE_SEASON, tvshow.m_iDbId);
7132 pDS2->query(sql.c_str());
7134 CFileItemList items;
7135 CStdString strDatabasePath;
7136 strDatabasePath.Format("videodb://2/2/%i/",tvshow.m_iDbId);
7138 // add "All Seasons" to list
7140 pItem.reset(new CFileItem(g_localizeStrings.Get(20366)));
7141 pItem->GetVideoInfoTag()->m_iSeason = -1;
7142 pItem->GetVideoInfoTag()->m_strPath = tvshow.m_strPath;
7145 // loop through available season
7146 while (!pDS2->eof())
7148 int iSeason = pDS2->fv(0).get_asInt();
7149 CStdString strLabel;
7151 strLabel = g_localizeStrings.Get(20381);
7153 strLabel.Format(g_localizeStrings.Get(20358),iSeason);
7154 CFileItemPtr pItem(new CFileItem(strLabel));
7155 pItem->GetVideoInfoTag()->m_strTitle = strLabel;
7156 pItem->GetVideoInfoTag()->m_iSeason = iSeason;
7157 pItem->GetVideoInfoTag()->m_strPath = tvshow.m_strPath;
7163 // export season thumbs
7164 for (int i=0;i<items.Size();++i)
7166 CStdString strSeasonThumb, strParent;
7167 int iSeason = items[i]->GetVideoInfoTag()->m_iSeason;
7169 strSeasonThumb = "season-all.tbn";
7170 else if (iSeason == 0)
7171 strSeasonThumb = "season-specials.tbn";
7173 strSeasonThumb.Format("season%02i.tbn",iSeason);
7175 CStdString cachedThumb(items[i]->GetCachedSeasonThumb());
7176 CStdString savedThumb(saveItem.GetFolderThumb(strSeasonThumb));
7178 if (CFile::Exists(cachedThumb, false) && (overwrite || !CFile::Exists(savedThumb, false)))
7179 if (!CFile::Cache(cachedThumb, savedThumb))
7180 CLog::Log(LOGERROR, "%s: TVShow season thumb export failed ('%s' -> '%s')", __FUNCTION__, cachedThumb.c_str(), savedThumb.c_str());
7184 // now save the episodes from this show
7185 sql = PrepareSQL("select * from episodeview where idShow=%i order by strFileName, idEpisode",tvshow.m_iDbId);
7186 pDS->query(sql.c_str());
7187 CStdString showDir(saveItem.m_strPath);
7191 CVideoInfoTag episode = GetDetailsForEpisode(pDS, true);
7193 episode.Save(pMain, "episodedetails", !singleFiles);
7195 episode.Save(pMain->LastChild(), "episodedetails", !singleFiles);
7197 // multi-episode files need dumping to the same XML
7198 while (singleFiles && !pDS->eof() &&
7199 episode.m_iFileId == pDS->fv("idFile").get_asInt())
7201 episode = GetDetailsForEpisode(pDS, true);
7202 episode.Save(pMain, "episodedetails", !singleFiles);
7206 // reset old skip state
7209 CFileItem item(episode.m_strFileNameAndPath, false);
7210 CFileItem saveItem(item);
7214 epName.Format("s%02ie%02i.avi", episode.m_iSeason, episode.m_iEpisode);
7215 saveItem = CFileItem(URIUtils::AddFileToFolder(showDir, epName), false);
7219 if (!item.Exists(false))
7221 CLog::Log(LOGDEBUG, "%s - Not exporting item %s as it does not exist", __FUNCTION__, episode.m_strFileNameAndPath.c_str());
7226 CStdString nfoFile(URIUtils::ReplaceExtension(item.GetTBNFile(), ".nfo"));
7228 if (overwrite || !CFile::Exists(nfoFile, false))
7230 if(!xmlDoc.SaveFile(nfoFile))
7232 CLog::Log(LOGERROR, "%s: Episode nfo export failed! ('%s')", __FUNCTION__, nfoFile.c_str());
7233 bSkip = ExportSkipEntry(nfoFile);
7247 TiXmlDeclaration decl("1.0", "UTF-8", "yes");
7248 xmlDoc.InsertEndChild(decl);
7252 if (images && !bSkip)
7254 CStdString cachedThumb(GetCachedThumb(item));
7255 CStdString savedThumb(saveItem.GetTBNFile());
7256 if (!cachedThumb.IsEmpty() && (overwrite || !CFile::Exists(savedThumb, false)))
7257 if (!CFile::Cache(cachedThumb, savedThumb))
7258 CLog::Log(LOGERROR, "%s: Episode thumb export failed! ('%s' -> '%s')", __FUNCTION__, cachedThumb.c_str(), savedThumb.c_str());
7261 ExportActorThumbs(actorsDir, episode, singleFiles, overwrite);
7270 if (singleFiles && progress)
7272 progress->SetPercentage(100);
7273 progress->Progress();
7278 // now dump path info
7279 set<CStdString> paths;
7281 TiXmlElement xmlPathElement("paths");
7282 TiXmlNode *pPaths = pMain->InsertEndChild(xmlPathElement);
7283 for( set<CStdString>::iterator iter = paths.begin(); iter != paths.end(); ++iter)
7285 bool foundDirectly = false;
7286 SScanSettings settings;
7287 ScraperPtr info = GetScraperForPath(*iter, settings, foundDirectly);
7288 if (info && foundDirectly)
7290 TiXmlElement xmlPathElement2("path");
7291 TiXmlNode *pPath = pPaths->InsertEndChild(xmlPathElement2);
7292 XMLUtils::SetString(pPath,"url", *iter);
7293 XMLUtils::SetInt(pPath,"scanrecursive", settings.recurse);
7294 XMLUtils::SetBoolean(pPath,"usefoldernames", settings.parent_name);
7295 XMLUtils::SetString(pPath,"content", TranslateContent(info->Content()));
7296 XMLUtils::SetString(pPath,"scraperpath", info->ID());
7299 xmlDoc.SaveFile(xmlFile);
7304 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
7311 void CVideoDatabase::ExportActorThumbs(const CStdString &strDir, const CVideoInfoTag &tag, bool singleFiles, bool overwrite /*=false*/)
7313 CStdString strPath(strDir);
7316 strPath = URIUtils::AddFileToFolder(tag.m_strPath, ".actors");
7317 if (!CDirectory::Exists(strPath))
7319 CDirectory::Create(strPath);
7320 CFile::SetHidden(strPath, true);
7324 for (CVideoInfoTag::iCast iter = tag.m_cast.begin();iter != tag.m_cast.end();++iter)
7327 item.SetLabel(iter->strName);
7328 CStdString strThumb = item.GetCachedActorThumb();
7329 if (CFile::Exists(strThumb))
7331 CStdString thumbFile(GetSafeFile(strPath, iter->strName) + ".tbn");
7332 if (overwrite || !CFile::Exists(thumbFile))
7333 if (!CFile::Cache(strThumb, thumbFile))
7334 CLog::Log(LOGERROR, "%s: Actor thumb export failed! ('%s' -> '%s')", __FUNCTION__, strThumb.c_str(), thumbFile.c_str());
7339 CStdString CVideoDatabase::GetCachedThumb(const CFileItem& item) const
7341 CStdString cachedThumb(item.GetCachedVideoThumb());
7342 if (!CFile::Exists(cachedThumb) && g_advancedSettings.m_bVideoLibraryExportAutoThumbs)
7344 CStdString strPath, strFileName;
7345 URIUtils::Split(cachedThumb, strPath, strFileName);
7346 cachedThumb = strPath + "auto-" + strFileName;
7349 if (CFile::Exists(cachedThumb))
7355 bool CVideoDatabase::ExportSkipEntry(const CStdString &nfoFile)
7357 CStdString strParent;
7358 URIUtils::GetParentPath(nfoFile,strParent);
7359 CLog::Log(LOGERROR, "%s: Unable to write to '%s'!", __FUNCTION__, strParent.c_str());
7361 bool bSkip = CGUIDialogYesNo::ShowAndGetInput(g_localizeStrings.Get(647), g_localizeStrings.Get(20302), strParent.c_str(), g_localizeStrings.Get(20303));
7364 CLog::Log(LOGERROR, "%s: Skipping export of '%s' as requested", __FUNCTION__, nfoFile.c_str());
7366 CLog::Log(LOGERROR, "%s: Export failed! Canceling as requested", __FUNCTION__);
7371 void CVideoDatabase::ImportFromXML(const CStdString &path)
7373 CGUIDialogProgress *progress=NULL;
7376 if (NULL == m_pDB.get()) return;
7377 if (NULL == m_pDS.get()) return;
7379 TiXmlDocument xmlDoc;
7380 if (!xmlDoc.LoadFile(URIUtils::AddFileToFolder(path, "videodb.xml")))
7383 TiXmlElement *root = xmlDoc.RootElement();
7386 progress = (CGUIDialogProgress *)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
7389 progress->SetHeading(648);
7390 progress->SetLine(0, 649);
7391 progress->SetLine(1, 330);
7392 progress->SetLine(2, "");
7393 progress->SetPercentage(0);
7394 progress->StartModal();
7395 progress->ShowProgressBar(true);
7399 XMLUtils::GetInt(root, "version", iVersion);
7401 CLog::Log(LOGDEBUG, "%s: Starting import (export version = %i)", __FUNCTION__, iVersion);
7403 TiXmlElement *movie = root->FirstChildElement();
7406 // first count the number of items...
7409 if (strnicmp(movie->Value(), "movie", 5)==0 ||
7410 strnicmp(movie->Value(), "tvshow", 6)==0 ||
7411 strnicmp(movie->Value(), "musicvideo",10)==0 )
7413 movie = movie->NextSiblingElement();
7416 CStdString actorsDir(URIUtils::AddFileToFolder(path, "actors"));
7417 CStdString moviesDir(URIUtils::AddFileToFolder(path, "movies"));
7418 CStdString musicvideosDir(URIUtils::AddFileToFolder(path, "musicvideos"));
7419 CStdString tvshowsDir(URIUtils::AddFileToFolder(path, "tvshows"));
7420 CVideoInfoScanner scanner;
7421 set<CStdString> actors;
7422 movie = root->FirstChildElement();
7426 if (strnicmp(movie->Value(), "movie", 5) == 0)
7429 CFileItem item(info);
7430 scanner.AddVideo(&item,CONTENT_MOVIES);
7431 SetPlayCount(item, info.m_playCount, info.m_lastPlayed);
7432 CStdString strFileName(info.m_strTitle);
7433 if (GetExportVersion() >= 1 && info.m_iYear > 0)
7434 strFileName.AppendFormat("_%i", info.m_iYear);
7435 CStdString file(GetSafeFile(moviesDir, strFileName));
7436 CFile::Cache(file + ".tbn", item.GetCachedVideoThumb());
7437 CFile::Cache(file + "-fanart.jpg", item.GetCachedFanart());
7438 for (CVideoInfoTag::iCast i = info.m_cast.begin(); i != info.m_cast.end(); ++i)
7439 actors.insert(i->strName);
7442 else if (strnicmp(movie->Value(), "musicvideo", 10) == 0)
7445 CFileItem item(info);
7446 scanner.AddVideo(&item,CONTENT_MUSICVIDEOS);
7447 SetPlayCount(item, info.m_playCount, info.m_lastPlayed);
7448 CStdString strFileName(info.m_strArtist + "." + info.m_strTitle);
7449 if (GetExportVersion() >= 1 && info.m_iYear > 0)
7450 strFileName.AppendFormat("_%i", info.m_iYear);
7451 CStdString file(GetSafeFile(musicvideosDir, strFileName));
7452 CFile::Cache(file + ".tbn", item.GetCachedVideoThumb());
7455 else if (strnicmp(movie->Value(), "tvshow", 6) == 0)
7457 // load the TV show in. NOTE: This deletes all episodes under the TV Show, which may not be
7458 // what we desire. It may make better sense to only delete (or even better, update) the show information
7460 URIUtils::AddSlashAtEnd(info.m_strPath);
7461 DeleteTvShow(info.m_strPath);
7462 CFileItem item(info);
7463 int showID = scanner.AddVideo(&item,CONTENT_TVSHOWS);
7465 CStdString showDir(GetSafeFile(tvshowsDir, info.m_strTitle));
7466 CFile::Cache(URIUtils::AddFileToFolder(showDir, "folder.jpg"), item.GetCachedVideoThumb());
7467 CFile::Cache(URIUtils::AddFileToFolder(showDir, "fanart.jpg"), item.GetCachedFanart());
7468 for (CVideoInfoTag::iCast i = info.m_cast.begin(); i != info.m_cast.end(); ++i)
7469 actors.insert(i->strName);
7470 // now load the episodes
7471 TiXmlElement *episode = movie->FirstChildElement("episodedetails");
7474 // no need to delete the episode info, due to the above deletion
7477 CFileItem item(info);
7478 scanner.AddVideo(&item,CONTENT_TVSHOWS,false,showID);
7479 SetPlayCount(item, info.m_playCount, info.m_lastPlayed);
7481 file.Format("s%02ie%02i.tbn", info.m_iSeason, info.m_iEpisode);
7482 CFile::Cache(URIUtils::AddFileToFolder(showDir, file), item.GetCachedVideoThumb());
7483 for (CVideoInfoTag::iCast i = info.m_cast.begin(); i != info.m_cast.end(); ++i)
7484 actors.insert(i->strName);
7485 episode = episode->NextSiblingElement("episodedetails");
7487 // and fetch season thumbs
7488 scanner.FetchSeasonThumbs(showID, showDir, false, true);
7490 else if (strnicmp(movie->Value(), "paths", 5) == 0)
7492 const TiXmlElement* path = movie->FirstChildElement("path");
7496 XMLUtils::GetString(path,"url",strPath);
7499 if (XMLUtils::GetString(path,"content", content))
7500 { // check the scraper exists, if so store the path
7504 if (!XMLUtils::GetString(path,"scraperID",uuid))
7505 { // support pre addons exports
7506 XMLUtils::GetString(path, "scraperpath", uuid);
7507 uuid = URIUtils::GetFileName(uuid);
7510 if (CAddonMgr::Get().GetAddon(uuid, addon))
7512 SScanSettings settings;
7513 ScraperPtr scraper = boost::dynamic_pointer_cast<CScraper>(addon);
7514 // FIXME: scraper settings are not exported?
7515 scraper->SetPathSettings(TranslateContent(content), "");
7516 XMLUtils::GetInt(path,"scanrecursive",settings.recurse);
7517 XMLUtils::GetBoolean(path,"usefoldernames",settings.parent_name);
7518 SetScraperForPath(strPath,scraper,settings);
7521 path = path->NextSiblingElement();
7524 movie = movie->NextSiblingElement();
7525 if (progress && total)
7527 progress->SetPercentage(current * 100 / total);
7528 progress->SetLine(2, info.m_strTitle);
7529 progress->Progress();
7530 if (progress->IsCanceled())
7533 RollbackTransaction();
7538 // cache any actor thumbs
7539 for (set<CStdString>::iterator i = actors.begin(); i != actors.end(); i++)
7543 CStdString savedThumb(GetSafeFile(actorsDir, *i) + ".tbn");
7544 CStdString cachedThumb = item.GetCachedActorThumb();
7545 CFile::Cache(savedThumb, cachedThumb);
7550 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
7556 bool CVideoDatabase::GetArbitraryQuery(const CStdString& strQuery, const CStdString& strOpenRecordSet, const CStdString& strCloseRecordSet,
7557 const CStdString& strOpenRecord, const CStdString& strCloseRecord, const CStdString& strOpenField, const CStdString& strCloseField, CStdString& strResult)
7562 if (NULL == m_pDB.get()) return false;
7563 if (NULL == m_pDS.get()) return false;
7564 CStdString strSQL=strQuery;
7565 if (!m_pDS->query(strSQL.c_str()))
7567 strResult = m_pDB->getErrorMsg();
7570 strResult=strOpenRecordSet;
7571 while (!m_pDS->eof())
7573 strResult += strOpenRecord;
7574 for (int i=0; i<m_pDS->fieldCount(); i++)
7576 strResult += strOpenField + CStdString(m_pDS->fv(i).get_asString()) + strCloseField;
7578 strResult += strCloseRecord;
7581 strResult += strCloseRecordSet;
7587 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
7591 if (NULL == m_pDB.get()) return false;
7592 strResult = m_pDB->getErrorMsg();
7602 bool CVideoDatabase::ArbitraryExec(const CStdString& strExec)
7606 if (NULL == m_pDB.get()) return false;
7607 if (NULL == m_pDS.get()) return false;
7608 CStdString strSQL = strExec;
7609 m_pDS->exec(strSQL.c_str());
7615 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
7620 void CVideoDatabase::ConstructPath(CStdString& strDest, const CStdString& strPath, const CStdString& strFileName)
7622 if (URIUtils::IsStack(strFileName) || URIUtils::IsInArchive(strFileName))
7623 strDest = strFileName;
7625 URIUtils::AddFileToFolder(strPath, strFileName, strDest);
7628 void CVideoDatabase::SplitPath(const CStdString& strFileNameAndPath, CStdString& strPath, CStdString& strFileName)
7630 if (URIUtils::IsStack(strFileNameAndPath) || strFileNameAndPath.Mid(0,6).Equals("rar://") || strFileNameAndPath.Mid(0,6).Equals("zip://"))
7632 URIUtils::GetParentPath(strFileNameAndPath,strPath);
7633 strFileName = strFileNameAndPath;
7636 URIUtils::Split(strFileNameAndPath,strPath, strFileName);
7639 void CVideoDatabase::InvalidatePathHash(const CStdString& strPath)
7641 SScanSettings settings;
7643 ScraperPtr info = GetScraperForPath(strPath,settings,foundDirectly);
7644 SetPathHash(strPath,"");
7647 if (info->Content() == CONTENT_TVSHOWS || (info->Content() == CONTENT_MOVIES && !foundDirectly)) // if we scan by folder name we need to invalidate parent as well
7649 if (info->Content() == CONTENT_TVSHOWS || settings.parent_name_root)
7651 CStdString strParent;
7652 URIUtils::GetParentPath(strPath,strParent);
7653 SetPathHash(strParent,"");
7658 bool CVideoDatabase::CommitTransaction()
7660 if (CDatabase::CommitTransaction())
7661 { // number of items in the db has likely changed, so recalculate
7662 g_infoManager.SetLibraryBool(LIBRARY_HAS_MOVIES, HasContent(VIDEODB_CONTENT_MOVIES));
7663 g_infoManager.SetLibraryBool(LIBRARY_HAS_TVSHOWS, HasContent(VIDEODB_CONTENT_TVSHOWS));
7664 g_infoManager.SetLibraryBool(LIBRARY_HAS_MUSICVIDEOS, HasContent(VIDEODB_CONTENT_MUSICVIDEOS));
7670 void CVideoDatabase::DeleteThumbForItem(const CStdString& strPath, bool bFolder, int idEpisode)
7672 CFileItem item(strPath,bFolder);
7675 item.m_strPath = item.GetVideoInfoTag()->m_strFileNameAndPath;
7676 if (CFile::Exists(item.GetCachedEpisodeThumb()))
7677 CTextureCache::Get().ClearCachedImage(item.GetCachedEpisodeThumb(), true);
7679 CTextureCache::Get().ClearCachedImage(item.GetCachedVideoThumb(), true);
7683 CTextureCache::Get().ClearCachedImage(item.GetCachedVideoThumb(), true);
7684 CTextureCache::Get().ClearCachedImage(item.GetCachedFanart(), true);
7687 // tell our GUI to completely reload all controls (as some of them
7688 // are likely to have had this image in use so will need refreshing)
7689 CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_REFRESH_THUMBS);
7690 g_windowManager.SendThreadMessage(msg);
7693 void CVideoDatabase::SetDetail(const CStdString& strDetail, int id, int field,
7694 VIDEODB_CONTENT_TYPE type)
7698 if (NULL == m_pDB.get()) return;
7699 if (NULL == m_pDS.get()) return;
7701 CStdString strTable, strField;
7702 if (type == VIDEODB_CONTENT_MOVIES)
7705 strField = "idMovie";
7707 if (type == VIDEODB_CONTENT_TVSHOWS)
7709 strTable = "tvshow";
7710 strField = "idShow";
7712 if (type == VIDEODB_CONTENT_MUSICVIDEOS)
7714 strTable = "musicvideo";
7715 strField = "idMVideo";
7718 if (strTable.IsEmpty())
7721 CStdString strSQL = PrepareSQL("update %s set c%02u='%s' where %s=%u",
7722 strTable.c_str(), field, strDetail.c_str(), strField.c_str(), id);
7723 m_pDS->exec(strSQL.c_str());
7727 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
7731 CStdString CVideoDatabase::GetSafeFile(const CStdString &dir, const CStdString &name) const
7733 CStdString safeThumb(name);
7734 safeThumb.Replace(' ', '_');
7735 return URIUtils::AddFileToFolder(dir, CUtil::MakeLegalFileName(safeThumb));
7738 void CVideoDatabase::AnnounceRemove(std::string content, int id)
7741 data["content"] = content;
7742 data[content + "id"] = id;
7743 ANNOUNCEMENT::CAnnouncementManager::Announce(ANNOUNCEMENT::Library, "xbmc", "RemoveVideo", data);
7746 void CVideoDatabase::AnnounceUpdate(std::string content, int id)
7749 data["content"] = content;
7750 data[content + "id"] = id;
7751 ANNOUNCEMENT::CAnnouncementManager::Announce(ANNOUNCEMENT::Library, "xbmc", "UpdateVideo", data);
7754 bool CVideoDatabase::GetItemForPath(const CStdString &content, const CStdString &strPath, CFileItem &item)
7756 CFileItemList items;
7757 CStdString path(strPath);
7759 if(URIUtils::IsMultiPath(path))
7760 path = CMultiPathDirectory::GetFirstPath(path);
7762 if (content == "movies")
7764 CStdString where = PrepareSQL("where c%02d='%s' limit 1", VIDEODB_ID_BASEPATH, path.c_str());
7765 GetMoviesByWhere("", where, "", items);
7767 else if (content == "episodes")
7769 CStdString where = PrepareSQL("where c%02d='%s' limit 1", VIDEODB_ID_EPISODE_BASEPATH, path.c_str());
7770 GetEpisodesByWhere("", where, items);
7772 else if (content == "tvshows")
7774 CStdString where = PrepareSQL("where c%02d='%s' limit 1", VIDEODB_ID_TV_BASEPATH, path.c_str());
7775 GetTvShowsByWhere("", where, items);
7777 else if (content == "musicvideos")
7779 CStdString where = PrepareSQL("where c%02d='%s' limit 1", VIDEODB_ID_MUSICVIDEO_BASEPATH, path.c_str());
7780 GetMusicVideosByWhere("", where, items);
7785 if (item.m_bIsFolder)
7786 item.m_strPath = item.GetVideoInfoTag()->m_strPath;
7788 item.m_strPath = item.GetVideoInfoTag()->m_strFileNameAndPath;