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"
51 #include "dbwrappers/dataset.h"
54 using namespace dbiplus;
55 using namespace XFILE;
56 using namespace VIDEO;
57 using namespace ADDON;
59 //********************************************************************************************************************************
60 CVideoDatabase::CVideoDatabase(void)
64 //********************************************************************************************************************************
65 CVideoDatabase::~CVideoDatabase(void)
68 //********************************************************************************************************************************
69 bool CVideoDatabase::Open()
71 return CDatabase::Open(g_advancedSettings.m_databaseVideo);
74 bool CVideoDatabase::CreateTables()
76 /* indexes should be added on any columns that are used in in */
77 /* a where or a join. primary key on a column is the same as a */
78 /* unique index on that column, so there is no need to add any */
79 /* index if no other columns are refered */
81 /* order of indexes are important, for an index to be considered all */
82 /* columns up to the column in question have to have been specified */
83 /* select * from actorlinkmovie where idMovie = 1, can not take */
84 /* advantage of a index that has been created on ( idGenre, idMovie ) */
85 /*, hower on on ( idMovie, idGenre ) will be considered for use */
90 CDatabase::CreateTables();
92 CLog::Log(LOGINFO, "create bookmark table");
93 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");
94 m_pDS->exec("CREATE INDEX ix_bookmark ON bookmark (idFile)");
96 CLog::Log(LOGINFO, "create settings table");
97 m_pDS->exec("CREATE TABLE settings ( idFile integer, Deinterlace bool,"
98 "ViewMode integer,ZoomAmount float, PixelRatio float, VerticalShift float, AudioStream integer, SubtitleStream integer,"
99 "SubtitleDelay float, SubtitlesOn bool, Brightness float, Contrast float, Gamma float,"
100 "VolumeAmplification float, AudioDelay float, OutputToAllSpeakers bool, ResumeTime integer, Crop bool, CropLeft integer,"
101 "CropRight integer, CropTop integer, CropBottom integer, Sharpness float, NoiseReduction float, NonLinStretch bool, PostProcess bool, ScalingMethod integer)\n");
102 m_pDS->exec("CREATE UNIQUE INDEX ix_settings ON settings ( idFile )\n");
104 CLog::Log(LOGINFO, "create stacktimes table");
105 m_pDS->exec("CREATE TABLE stacktimes (idFile integer, times text)\n");
106 m_pDS->exec("CREATE UNIQUE INDEX ix_stacktimes ON stacktimes ( idFile )\n");
108 CLog::Log(LOGINFO, "create genre table");
109 m_pDS->exec("CREATE TABLE genre ( idGenre integer primary key, strGenre text)\n");
111 CLog::Log(LOGINFO, "create genrelinkmovie table");
112 m_pDS->exec("CREATE TABLE genrelinkmovie ( idGenre integer, idMovie integer)\n");
113 m_pDS->exec("CREATE UNIQUE INDEX ix_genrelinkmovie_1 ON genrelinkmovie ( idGenre, idMovie)\n");
114 m_pDS->exec("CREATE UNIQUE INDEX ix_genrelinkmovie_2 ON genrelinkmovie ( idMovie, idGenre)\n");
116 CLog::Log(LOGINFO, "create country table");
117 m_pDS->exec("CREATE TABLE country ( idCountry integer primary key, strCountry text)\n");
119 CLog::Log(LOGINFO, "create countrylinkmovie table");
120 m_pDS->exec("CREATE TABLE countrylinkmovie ( idCountry integer, idMovie integer)\n");
121 m_pDS->exec("CREATE UNIQUE INDEX ix_countrylinkmovie_1 ON countrylinkmovie ( idCountry, idMovie)\n");
122 m_pDS->exec("CREATE UNIQUE INDEX ix_countrylinkmovie_2 ON countrylinkmovie ( idMovie, idCountry)\n");
124 CLog::Log(LOGINFO, "create movie table");
125 CStdString columns = "CREATE TABLE movie ( idMovie integer primary key, idFile integer";
126 for (int i = 0; i < VIDEODB_MAX_COLUMNS; i++)
129 column.Format(",c%02d text", i);
133 m_pDS->exec(columns.c_str());
134 m_pDS->exec("CREATE UNIQUE INDEX ix_movie_file_1 ON movie (idFile, idMovie)");
135 m_pDS->exec("CREATE UNIQUE INDEX ix_movie_file_2 ON movie (idMovie, idFile)");
137 CLog::Log(LOGINFO, "create actorlinkmovie table");
138 m_pDS->exec("CREATE TABLE actorlinkmovie ( idActor integer, idMovie integer, strRole text, iOrder integer)\n");
139 m_pDS->exec("CREATE UNIQUE INDEX ix_actorlinkmovie_1 ON actorlinkmovie ( idActor, idMovie )\n");
140 m_pDS->exec("CREATE UNIQUE INDEX ix_actorlinkmovie_2 ON actorlinkmovie ( idMovie, idActor )\n");
142 CLog::Log(LOGINFO, "create directorlinkmovie table");
143 m_pDS->exec("CREATE TABLE directorlinkmovie ( idDirector integer, idMovie integer)\n");
144 m_pDS->exec("CREATE UNIQUE INDEX ix_directorlinkmovie_1 ON directorlinkmovie ( idDirector, idMovie )\n");
145 m_pDS->exec("CREATE UNIQUE INDEX ix_directorlinkmovie_2 ON directorlinkmovie ( idMovie, idDirector )\n");
147 CLog::Log(LOGINFO, "create writerlinkmovie table");
148 m_pDS->exec("CREATE TABLE writerlinkmovie ( idWriter integer, idMovie integer)\n");
149 m_pDS->exec("CREATE UNIQUE INDEX ix_writerlinkmovie_1 ON writerlinkmovie ( idWriter, idMovie )\n");
150 m_pDS->exec("CREATE UNIQUE INDEX ix_writerlinkmovie_2 ON writerlinkmovie ( idMovie, idWriter )\n");
152 CLog::Log(LOGINFO, "create actors table");
153 m_pDS->exec("CREATE TABLE actors ( idActor integer primary key, strActor text, strThumb text )\n");
155 CLog::Log(LOGINFO, "create path table");
156 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)");
157 m_pDS->exec("CREATE UNIQUE INDEX ix_path ON path ( strPath(255) )");
159 CLog::Log(LOGINFO, "create files table");
160 m_pDS->exec("CREATE TABLE files ( idFile integer primary key, idPath integer, strFilename text, playCount integer, lastPlayed text)");
161 m_pDS->exec("CREATE UNIQUE INDEX ix_files ON files ( idPath, strFilename(255) )");
163 CLog::Log(LOGINFO, "create tvshow table");
164 columns = "CREATE TABLE tvshow ( idShow integer primary key";
165 for (int i = 0; i < VIDEODB_MAX_COLUMNS; i++)
168 column.Format(",c%02d text", i);
172 m_pDS->exec(columns.c_str());
174 CLog::Log(LOGINFO, "create directorlinktvshow table");
175 m_pDS->exec("CREATE TABLE directorlinktvshow ( idDirector integer, idShow integer)\n");
176 m_pDS->exec("CREATE UNIQUE INDEX ix_directorlinktvshow_1 ON directorlinktvshow ( idDirector, idShow )\n");
177 m_pDS->exec("CREATE UNIQUE INDEX ix_directorlinktvshow_2 ON directorlinktvshow ( idShow, idDirector )\n");
179 CLog::Log(LOGINFO, "create actorlinktvshow table");
180 m_pDS->exec("CREATE TABLE actorlinktvshow ( idActor integer, idShow integer, strRole text, iOrder integer)\n");
181 m_pDS->exec("CREATE UNIQUE INDEX ix_actorlinktvshow_1 ON actorlinktvshow ( idActor, idShow )\n");
182 m_pDS->exec("CREATE UNIQUE INDEX ix_actorlinktvshow_2 ON actorlinktvshow ( idShow, idActor )\n");
184 CLog::Log(LOGINFO, "create studiolinktvshow table");
185 m_pDS->exec("CREATE TABLE studiolinktvshow ( idStudio integer, idShow integer)\n");
186 m_pDS->exec("CREATE UNIQUE INDEX ix_studiolinktvshow_1 ON studiolinktvshow ( idStudio, idShow)\n");
187 m_pDS->exec("CREATE UNIQUE INDEX ix_studiolinktvshow_2 ON studiolinktvshow ( idShow, idStudio)\n");
189 CLog::Log(LOGINFO, "create episode table");
190 columns = "CREATE TABLE episode ( idEpisode integer primary key, idFile integer";
191 for (int i = 0; i < VIDEODB_MAX_COLUMNS; i++)
194 if ( i == VIDEODB_ID_EPISODE_SEASON || i == VIDEODB_ID_EPISODE_EPISODE || i == VIDEODB_ID_EPISODE_BOOKMARK)
195 column.Format(",c%02d varchar(24)", i);
197 column.Format(",c%02d text", i);
202 m_pDS->exec(columns.c_str());
203 m_pDS->exec("CREATE UNIQUE INDEX ix_episode_file_1 on episode (idEpisode, idFile)");
204 m_pDS->exec("CREATE UNIQUE INDEX id_episode_file_2 on episode (idFile, idEpisode)");
205 CStdString createColIndex;
206 createColIndex.Format("CREATE INDEX ix_episode_season_episode on episode (c%02d, c%02d)", VIDEODB_ID_EPISODE_SEASON, VIDEODB_ID_EPISODE_EPISODE);
207 m_pDS->exec(createColIndex.c_str());
208 createColIndex.Format("CREATE INDEX ix_episode_bookmark on episode (c%02d)", VIDEODB_ID_EPISODE_BOOKMARK);
209 m_pDS->exec(createColIndex.c_str());
211 CLog::Log(LOGINFO, "create tvshowlinkepisode table");
212 m_pDS->exec("CREATE TABLE tvshowlinkepisode ( idShow integer, idEpisode integer)\n");
213 m_pDS->exec("CREATE UNIQUE INDEX ix_tvshowlinkepisode_1 ON tvshowlinkepisode ( idShow, idEpisode )\n");
214 m_pDS->exec("CREATE UNIQUE INDEX ix_tvshowlinkepisode_2 ON tvshowlinkepisode ( idEpisode, idShow )\n");
216 CLog::Log(LOGINFO, "create tvshowlinkpath table");
217 m_pDS->exec("CREATE TABLE tvshowlinkpath (idShow integer, idPath integer)\n");
218 m_pDS->exec("CREATE UNIQUE INDEX ix_tvshowlinkpath_1 ON tvshowlinkpath ( idShow, idPath )\n");
219 m_pDS->exec("CREATE UNIQUE INDEX ix_tvshowlinkpath_2 ON tvshowlinkpath ( idPath, idShow )\n");
221 CLog::Log(LOGINFO, "create actorlinkepisode table");
222 m_pDS->exec("CREATE TABLE actorlinkepisode ( idActor integer, idEpisode integer, strRole text, iOrder integer)\n");
223 m_pDS->exec("CREATE UNIQUE INDEX ix_actorlinkepisode_1 ON actorlinkepisode ( idActor, idEpisode )\n");
224 m_pDS->exec("CREATE UNIQUE INDEX ix_actorlinkepisode_2 ON actorlinkepisode ( idEpisode, idActor )\n");
226 CLog::Log(LOGINFO, "create directorlinkepisode table");
227 m_pDS->exec("CREATE TABLE directorlinkepisode ( idDirector integer, idEpisode integer)\n");
228 m_pDS->exec("CREATE UNIQUE INDEX ix_directorlinkepisode_1 ON directorlinkepisode ( idDirector, idEpisode )\n");
229 m_pDS->exec("CREATE UNIQUE INDEX ix_directorlinkepisode_2 ON directorlinkepisode ( idEpisode, idDirector )\n");
231 CLog::Log(LOGINFO, "create writerlinkepisode table");
232 m_pDS->exec("CREATE TABLE writerlinkepisode ( idWriter integer, idEpisode integer)\n");
233 m_pDS->exec("CREATE UNIQUE INDEX ix_writerlinkepisode_1 ON writerlinkepisode ( idWriter, idEpisode )\n");
234 m_pDS->exec("CREATE UNIQUE INDEX ix_writerlinkepisode_2 ON writerlinkepisode ( idEpisode, idWriter )\n");
236 CLog::Log(LOGINFO, "create genrelinktvshow table");
237 m_pDS->exec("CREATE TABLE genrelinktvshow ( idGenre integer, idShow integer)\n");
238 m_pDS->exec("CREATE UNIQUE INDEX ix_genrelinktvshow_1 ON genrelinktvshow ( idGenre, idShow)\n");
239 m_pDS->exec("CREATE UNIQUE INDEX ix_genrelinktvshow_2 ON genrelinktvshow ( idShow, idGenre)\n");
241 CLog::Log(LOGINFO, "create movielinktvshow table");
242 m_pDS->exec("CREATE TABLE movielinktvshow ( idMovie integer, IdShow integer)\n");
243 m_pDS->exec("CREATE UNIQUE INDEX ix_movielinktvshow_1 ON movielinktvshow ( idShow, idMovie)\n");
244 m_pDS->exec("CREATE UNIQUE INDEX ix_movielinktvshow_2 ON movielinktvshow ( idMovie, idShow)\n");
246 CLog::Log(LOGINFO, "create studio table");
247 m_pDS->exec("CREATE TABLE studio ( idStudio integer primary key, strStudio text)\n");
249 CLog::Log(LOGINFO, "create studiolinkmovie table");
250 m_pDS->exec("CREATE TABLE studiolinkmovie ( idStudio integer, idMovie integer)\n");
251 m_pDS->exec("CREATE UNIQUE INDEX ix_studiolinkmovie_1 ON studiolinkmovie ( idStudio, idMovie)\n");
252 m_pDS->exec("CREATE UNIQUE INDEX ix_studiolinkmovie_2 ON studiolinkmovie ( idMovie, idStudio)\n");
254 CLog::Log(LOGINFO, "create musicvideo table");
255 columns = "CREATE TABLE musicvideo ( idMVideo integer primary key, idFile integer";
256 for (int i = 0; i < VIDEODB_MAX_COLUMNS; i++)
259 column.Format(",c%02d text", i);
263 m_pDS->exec(columns.c_str());
268 m_pDS->exec("CREATE UNIQUE INDEX ix_musicvideo_file_1 on musicvideo (idMVideo, idFile)");
269 m_pDS->exec("CREATE UNIQUE INDEX ix_musicvideo_file_2 on musicvideo (idFile, idMVideo)");
271 CLog::Log(LOGINFO, "create artistlinkmusicvideo table");
272 m_pDS->exec("CREATE TABLE artistlinkmusicvideo ( idArtist integer, idMVideo integer)\n");
273 m_pDS->exec("CREATE UNIQUE INDEX ix_artistlinkmusicvideo_1 ON artistlinkmusicvideo ( idArtist, idMVideo)\n");
274 m_pDS->exec("CREATE UNIQUE INDEX ix_artistlinkmusicvideo_2 ON artistlinkmusicvideo ( idMVideo, idArtist)\n");
276 CLog::Log(LOGINFO, "create genrelinkmusicvideo table");
277 m_pDS->exec("CREATE TABLE genrelinkmusicvideo ( idGenre integer, idMVideo integer)\n");
278 m_pDS->exec("CREATE UNIQUE INDEX ix_genrelinkmusicvideo_1 ON genrelinkmusicvideo ( idGenre, idMVideo)\n");
279 m_pDS->exec("CREATE UNIQUE INDEX ix_genrelinkmusicvideo_2 ON genrelinkmusicvideo ( idMVideo, idGenre)\n");
281 CLog::Log(LOGINFO, "create studiolinkmusicvideo table");
282 m_pDS->exec("CREATE TABLE studiolinkmusicvideo ( idStudio integer, idMVideo integer)\n");
283 m_pDS->exec("CREATE UNIQUE INDEX ix_studiolinkmusicvideo_1 ON studiolinkmusicvideo ( idStudio, idMVideo)\n");
284 m_pDS->exec("CREATE UNIQUE INDEX ix_studiolinkmusicvideo_2 ON studiolinkmusicvideo ( idMVideo, idStudio)\n");
286 CLog::Log(LOGINFO, "create directorlinkmusicvideo table");
287 m_pDS->exec("CREATE TABLE directorlinkmusicvideo ( idDirector integer, idMVideo integer)\n");
288 m_pDS->exec("CREATE UNIQUE INDEX ix_directorlinkmusicvideo_1 ON directorlinkmusicvideo ( idDirector, idMVideo )\n");
289 m_pDS->exec("CREATE UNIQUE INDEX ix_directorlinkmusicvideo_2 ON directorlinkmusicvideo ( idMVideo, idDirector )\n");
291 CLog::Log(LOGINFO, "create streaminfo table");
292 m_pDS->exec("CREATE TABLE streamdetails (idFile integer, iStreamType integer, "
293 "strVideoCodec text, fVideoAspect float, iVideoWidth integer, iVideoHeight integer, "
294 "strAudioCodec text, iAudioChannels integer, strAudioLanguage text, strSubtitleLanguage text, iVideoDuration integer)");
295 m_pDS->exec("CREATE INDEX ix_streamdetails ON streamdetails (idFile)");
297 CLog::Log(LOGINFO, "create sets table");
298 m_pDS->exec("CREATE TABLE sets ( idSet integer primary key, strSet text)\n");
300 CLog::Log(LOGINFO, "create setlinkmovie table");
301 m_pDS->exec("CREATE TABLE setlinkmovie ( idSet integer, idMovie integer)\n");
302 m_pDS->exec("CREATE UNIQUE INDEX ix_setlinkmovie_1 ON setlinkmovie ( idSet, idMovie)\n");
303 m_pDS->exec("CREATE UNIQUE INDEX ix_setlinkmovie_2 ON setlinkmovie ( idMovie, idSet)\n");
305 // create basepath indices
306 m_pDS->exec("CREATE INDEX ixMovieBasePath ON movie ( c22(255) )");
307 m_pDS->exec("CREATE INDEX ixMusicVideoBasePath ON musicvideo ( c13(255) )");
308 m_pDS->exec("CREATE INDEX ixEpisodeBasePath ON episode ( c18(255) )");
309 m_pDS->exec("CREATE INDEX ixTVShowBasePath on tvshow ( c16(255) )");
313 CLog::Log(LOGERROR, "%s unable to create tables:%i", __FUNCTION__, (int)GetLastError());
314 RollbackTransaction();
321 void CVideoDatabase::CreateViews()
323 CLog::Log(LOGINFO, "create episodeview");
324 m_pDS->exec("DROP VIEW IF EXISTS episodeview");
325 CStdString episodeview = PrepareSQL("create view episodeview as select episode.*,files.strFileName as strFileName,"
326 "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,"
327 "tvshow.c%02d as premiered, tvshow.c%02d as mpaa from episode "
328 "join files on files.idFile=episode.idFile "
329 "join tvshowlinkepisode on episode.idEpisode=tvshowlinkepisode.idEpisode "
330 "join tvshow on tvshow.idShow=tvshowlinkepisode.idShow "
331 "join path on files.idPath=path.idPath",VIDEODB_ID_TV_TITLE, VIDEODB_ID_TV_STUDIOS, VIDEODB_ID_TV_PREMIERED, VIDEODB_ID_TV_MPAA);
332 m_pDS->exec(episodeview.c_str());
334 CLog::Log(LOGINFO, "create tvshowview");
335 m_pDS->exec("DROP VIEW IF EXISTS tvshowview");
336 CStdString tvshowview = PrepareSQL("CREATE VIEW tvshowview AS SELECT "
338 "path.strPath AS strPath,"
339 " NULLIF(COUNT(episode.c12), 0) AS totalCount,"
340 " COUNT(files.playCount) AS watchedcount,"
341 " NULLIF(COUNT(DISTINCT(episode.c12)), 0) AS totalSeasons "
343 " LEFT JOIN tvshowlinkpath ON"
344 " tvshowlinkpath.idShow=tvshow.idShow"
346 " path.idPath=tvshowlinkpath.idPath"
347 " LEFT JOIN tvshowlinkepisode ON"
348 " tvshowlinkepisode.idShow=tvshow.idShow"
349 " LEFT JOIN episode ON"
350 " episode.idEpisode=tvshowlinkepisode.idEpisode"
351 " LEFT JOIN files ON"
352 " files.idFile=episode.idFile "
353 "GROUP BY tvshow.idShow;");
354 m_pDS->exec(tvshowview.c_str());
356 CLog::Log(LOGINFO, "create musicvideoview");
357 m_pDS->exec("DROP VIEW IF EXISTS musicvideoview");
358 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 "
359 "from musicvideo join files on files.idFile=musicvideo.idFile join path on path.idPath=files.idPath");
361 CLog::Log(LOGINFO, "create movieview");
362 m_pDS->exec("DROP VIEW IF EXISTS movieview");
363 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 "
364 "from movie join files on files.idFile=movie.idFile join path on path.idPath=files.idPath");
367 //********************************************************************************************************************************
368 int CVideoDatabase::GetPathId(const CStdString& strPath)
374 if (NULL == m_pDB.get()) return -1;
375 if (NULL == m_pDS.get()) return -1;
377 CStdString strPath1(strPath);
378 if (URIUtils::IsStack(strPath) || strPath.Mid(0,6).Equals("rar://") || strPath.Mid(0,6).Equals("zip://"))
379 URIUtils::GetParentPath(strPath,strPath1);
381 URIUtils::AddSlashAtEnd(strPath1);
383 strSQL=PrepareSQL("select idPath from path where strPath like '%s'",strPath1.c_str());
384 m_pDS->query(strSQL.c_str());
386 idPath = m_pDS->fv("path.idPath").get_asInt();
393 CLog::Log(LOGERROR, "%s unable to getpath (%s)", __FUNCTION__, strSQL.c_str());
398 bool CVideoDatabase::GetPaths(set<CStdString> &paths)
402 if (NULL == m_pDB.get()) return false;
403 if (NULL == m_pDS.get()) return false;
407 // grab all paths with movie content set
408 if (!m_pDS->query("select strPath,noUpdate from path"
409 " where (strContent = 'movies' or strContent = 'musicvideos')"
410 " and strPath NOT like 'multipath://%%'"
411 " order by strPath"))
414 while (!m_pDS->eof())
416 if (!m_pDS->fv("noUpdate").get_asBool())
417 paths.insert(m_pDS->fv("strPath").get_asString());
422 // then grab all tvshow paths
423 if (!m_pDS->query("select strPath,noUpdate from path"
424 " where ( strContent = 'tvshows'"
425 " or idPath in (select idPath from tvshowlinkpath))"
426 " and strPath NOT like 'multipath://%%'"
427 " order by strPath"))
430 while (!m_pDS->eof())
432 if (!m_pDS->fv("noUpdate").get_asBool())
433 paths.insert(m_pDS->fv("strPath").get_asString());
438 // finally grab all other paths holding a movie which is not a stack or a rar archive
439 // - this isnt perfect but it should do fine in most situations.
440 // reason we need it to hold a movie is stacks from different directories (cdx folders for instance)
441 // not making mistakes must take priority
442 if (!m_pDS->query("select strPath,noUpdate from path"
443 " where idPath in (select idPath from files join movie on movie.idFile=files.idFile)"
444 " and idPath NOT in (select idPath from tvshowlinkpath)"
445 " 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
446 " and idPath NOT in (select idPath from files where strFileName like 'index.bdmv')" // bluray folders get stacked to a single item in parent folder
447 " and strPath NOT like 'multipath://%%'"
448 " and strContent NOT in ('movies', 'tvshows', 'None')" // these have been added above
449 " order by strPath"))
452 while (!m_pDS->eof())
454 if (!m_pDS->fv("noUpdate").get_asBool())
455 paths.insert(m_pDS->fv("strPath").get_asString());
463 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
468 bool CVideoDatabase::GetPathsForTvShow(int idShow, vector<int>& paths)
473 if (NULL == m_pDB.get()) return false;
474 if (NULL == m_pDS.get()) return false;
475 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);
476 m_pDS->query(strSQL.c_str());
477 while (!m_pDS->eof())
479 paths.push_back(m_pDS->fv(0).get_asInt());
487 CLog::Log(LOGERROR, "%s error during query: %s",__FUNCTION__, strSQL.c_str());
492 int CVideoDatabase::RunQuery(const CStdString &sql)
494 unsigned int time = CTimeUtils::GetTimeMS();
496 if (m_pDS->query(sql.c_str()))
498 rows = m_pDS->num_rows();
502 CLog::Log(LOGDEBUG, "%s took %d ms for %d items query: %s", __FUNCTION__, CTimeUtils::GetTimeMS() - time, rows, sql.c_str());
506 bool CVideoDatabase::GetSubPaths(const CStdString &basepath, vector<int>& subpaths)
511 if (!m_pDB.get() || !m_pDS.get())
514 sql = PrepareSQL("SELECT idPath FROM path WHERE strPath LIKE '%s%%'", basepath.c_str());
515 m_pDS->query(sql.c_str());
516 while (!m_pDS->eof())
518 subpaths.push_back(m_pDS->fv(0).get_asInt());
526 CLog::Log(LOGERROR, "%s error during query: %s",__FUNCTION__, sql.c_str());
531 int CVideoDatabase::AddPath(const CStdString& strPath)
537 if (NULL == m_pDB.get()) return -1;
538 if (NULL == m_pDS.get()) return -1;
540 CStdString strPath1(strPath);
541 if (URIUtils::IsStack(strPath) || strPath.Mid(0,6).Equals("rar://") || strPath.Mid(0,6).Equals("zip://"))
542 URIUtils::GetParentPath(strPath,strPath1);
544 URIUtils::AddSlashAtEnd(strPath1);
546 strSQL=PrepareSQL("insert into path (idPath, strPath, strContent, strScraper) values (NULL,'%s','','')", strPath1.c_str());
547 m_pDS->exec(strSQL.c_str());
548 idPath = (int)m_pDS->lastinsertid();
553 CLog::Log(LOGERROR, "%s unable to addpath (%s)", __FUNCTION__, strSQL.c_str());
558 bool CVideoDatabase::GetPathHash(const CStdString &path, CStdString &hash)
562 if (NULL == m_pDB.get()) return false;
563 if (NULL == m_pDS.get()) return false;
565 CStdString strSQL=PrepareSQL("select strHash from path where strPath like '%s'", path.c_str());
566 m_pDS->query(strSQL.c_str());
567 if (m_pDS->num_rows() == 0)
569 hash = m_pDS->fv("strHash").get_asString();
574 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, path.c_str());
580 //********************************************************************************************************************************
581 int CVideoDatabase::AddFile(const CStdString& strFileNameAndPath)
583 CStdString strSQL = "";
587 if (NULL == m_pDB.get()) return -1;
588 if (NULL == m_pDS.get()) return -1;
590 CStdString strFileName, strPath;
591 SplitPath(strFileNameAndPath,strPath,strFileName);
593 int idPath=GetPathId(strPath);
595 idPath = AddPath(strPath);
600 CStdString strSQL=PrepareSQL("select idFile from files where strFileName like '%s' and idPath=%i", strFileName.c_str(),idPath);
602 m_pDS->query(strSQL.c_str());
603 if (m_pDS->num_rows() > 0)
605 idFile = m_pDS->fv("idFile").get_asInt() ;
610 strSQL=PrepareSQL("insert into files (idFile,idPath,strFileName) values(NULL, %i, '%s')", idPath,strFileName.c_str());
611 m_pDS->exec(strSQL.c_str());
612 idFile = (int)m_pDS->lastinsertid();
617 CLog::Log(LOGERROR, "%s unable to addfile (%s)", __FUNCTION__, strSQL.c_str());
622 int CVideoDatabase::AddFile(const CFileItem& item)
624 if (item.IsVideoDb() && item.HasVideoInfoTag())
625 return AddFile(item.GetVideoInfoTag()->m_strFileNameAndPath);
626 return AddFile(item.m_strPath);
629 bool CVideoDatabase::SetPathHash(const CStdString &path, const CStdString &hash)
633 if (NULL == m_pDB.get()) return false;
634 if (NULL == m_pDS.get()) return false;
637 { // this is an empty folder - we need only add it to the path table
638 // if the path actually exists
639 if (!CDirectory::Exists(path))
642 int idPath = GetPathId(path);
644 idPath = AddPath(path);
645 if (idPath < 0) return false;
647 CStdString strSQL=PrepareSQL("update path set strHash='%s' where idPath=%ld", hash.c_str(), idPath);
648 m_pDS->exec(strSQL.c_str());
654 CLog::Log(LOGERROR, "%s (%s, %s) failed", __FUNCTION__, path.c_str(), hash.c_str());
660 bool CVideoDatabase::LinkMovieToTvshow(int idMovie, int idShow, bool bRemove)
664 if (NULL == m_pDB.get()) return false;
665 if (NULL == m_pDS.get()) return false;
667 if (bRemove) // delete link
669 CStdString strSQL=PrepareSQL("delete from movielinktvshow where idMovie=%i and idShow=%i", idMovie, idShow);
670 m_pDS->exec(strSQL.c_str());
674 CStdString strSQL=PrepareSQL("insert into movielinktvshow (idShow,idMovie) values (%i,%i)", idShow,idMovie);
675 m_pDS->exec(strSQL.c_str());
681 CLog::Log(LOGERROR, "%s (%i, %i) failed", __FUNCTION__, idMovie, idShow);
687 bool CVideoDatabase::IsLinkedToTvshow(int idMovie)
691 if (NULL == m_pDB.get()) return false;
692 if (NULL == m_pDS.get()) return false;
694 CStdString strSQL=PrepareSQL("select * from movielinktvshow where idMovie=%i", idMovie);
695 m_pDS->query(strSQL.c_str());
707 CLog::Log(LOGERROR, "%s (%i) failed", __FUNCTION__, idMovie);
713 bool CVideoDatabase::GetLinksToTvShow(int idMovie, vector<int>& ids)
717 if (NULL == m_pDB.get()) return false;
718 if (NULL == m_pDS.get()) return false;
720 CStdString strSQL=PrepareSQL("select * from movielinktvshow where idMovie=%i", idMovie);
721 m_pDS2->query(strSQL.c_str());
722 while (!m_pDS2->eof())
724 ids.push_back(m_pDS2->fv(1).get_asInt());
733 CLog::Log(LOGERROR, "%s (%i) failed", __FUNCTION__, idMovie);
740 //********************************************************************************************************************************
741 int CVideoDatabase::GetFileId(const CStdString& strFilenameAndPath)
745 if (NULL == m_pDB.get()) return -1;
746 if (NULL == m_pDS.get()) return -1;
747 CStdString strPath, strFileName;
748 SplitPath(strFilenameAndPath,strPath,strFileName);
750 int idPath = GetPathId(strPath);
754 strSQL=PrepareSQL("select idFile from files where strFileName like '%s' and idPath=%i", strFileName.c_str(),idPath);
755 m_pDS->query(strSQL.c_str());
756 if (m_pDS->num_rows() > 0)
758 int idFile = m_pDS->fv("files.idFile").get_asInt();
766 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
771 int CVideoDatabase::GetFileId(const CFileItem &item)
773 if (item.IsVideoDb() && item.HasVideoInfoTag())
774 return GetFileId(item.GetVideoInfoTag()->m_strFileNameAndPath);
775 return GetFileId(item.m_strPath);
778 //********************************************************************************************************************************
779 int CVideoDatabase::GetMovieId(const CStdString& strFilenameAndPath)
783 if (NULL == m_pDB.get()) return -1;
784 if (NULL == m_pDS.get()) return -1;
787 // needed for query parameters
788 int idFile = GetFileId(strFilenameAndPath);
794 SplitPath(strFilenameAndPath,strPath,strFile);
796 // have to join movieinfo table for correct results
797 idPath = GetPathId(strPath);
798 if (idPath < 0 && strPath != strFilenameAndPath)
802 if (idFile == -1 && strPath != strFilenameAndPath)
807 strSQL=PrepareSQL("select idMovie from movie join files on files.idFile=movie.idFile where files.idPath=%i",idPath);
809 strSQL=PrepareSQL("select idMovie from movie where idFile=%i", idFile);
811 CLog::Log(LOGDEBUG, "%s (%s), query = %s", __FUNCTION__, strFilenameAndPath.c_str(), strSQL.c_str());
812 m_pDS->query(strSQL.c_str());
813 if (m_pDS->num_rows() > 0)
814 idMovie = m_pDS->fv("idMovie").get_asInt();
821 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
826 int CVideoDatabase::GetTvShowId(const CStdString& strPath)
830 if (NULL == m_pDB.get()) return -1;
831 if (NULL == m_pDS.get()) return -1;
834 // have to join movieinfo table for correct results
835 int idPath = GetPathId(strPath);
840 CStdString strPath1=strPath;
841 CStdString strParent;
844 strSQL=PrepareSQL("select idShow from tvshowlinkpath where tvshowlinkpath.idPath=%i",idPath);
845 m_pDS->query(strSQL);
849 while (iFound == 0 && URIUtils::GetParentPath(strPath1, strParent))
851 strSQL=PrepareSQL("select idShow from path,tvshowlinkpath where tvshowlinkpath.idPath=path.idPath and strPath like '%s'",strParent.c_str());
852 m_pDS->query(strSQL.c_str());
855 int idShow = m_pDS->fv("idShow").get_asInt();
859 strPath1 = strParent;
862 if (m_pDS->num_rows() > 0)
863 idTvShow = m_pDS->fv("idShow").get_asInt();
870 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strPath.c_str());
875 int CVideoDatabase::GetEpisodeId(const CStdString& strFilenameAndPath, int idEpisode, int idSeason) // input value is episode/season number hint - for multiparters
879 if (NULL == m_pDB.get()) return -1;
880 if (NULL == m_pDS.get()) return -1;
882 // need this due to the nested GetEpisodeInfo query
883 auto_ptr<Dataset> pDS;
884 pDS.reset(m_pDB->CreateDataset());
885 if (NULL == pDS.get()) return -1;
887 int idFile = GetFileId(strFilenameAndPath);
891 CStdString strSQL=PrepareSQL("select idEpisode from episode where idFile=%i", idFile);
893 CLog::Log(LOGDEBUG, "%s (%s), query = %s", __FUNCTION__, strFilenameAndPath.c_str(), strSQL.c_str());
894 pDS->query(strSQL.c_str());
895 if (pDS->num_rows() > 0)
898 idEpisode = pDS->fv("episode.idEpisode").get_asInt();
899 else // use the hint!
904 int idTmpEpisode = pDS->fv("episode.idEpisode").get_asInt();
905 GetEpisodeInfo(strFilenameAndPath,tag,idTmpEpisode);
906 if (tag.m_iEpisode == idEpisode && (idSeason == -1 || tag.m_iSeason == idSeason)) {
907 // match on the episode hint, and there's no season hint or a season hint match
908 idEpisode = idTmpEpisode;
926 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
931 int CVideoDatabase::GetMusicVideoId(const CStdString& strFilenameAndPath)
935 if (NULL == m_pDB.get()) return -1;
936 if (NULL == m_pDS.get()) return -1;
938 int idFile = GetFileId(strFilenameAndPath);
942 CStdString strSQL=PrepareSQL("select idMVideo from musicvideo where idFile=%i", idFile);
944 CLog::Log(LOGDEBUG, "%s (%s), query = %s", __FUNCTION__, strFilenameAndPath.c_str(), strSQL.c_str());
945 m_pDS->query(strSQL.c_str());
947 if (m_pDS->num_rows() > 0)
948 idMVideo = m_pDS->fv("idMVideo").get_asInt();
955 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
960 //********************************************************************************************************************************
961 int CVideoDatabase::AddMovie(const CStdString& strFilenameAndPath)
965 if (NULL == m_pDB.get()) return -1;
966 if (NULL == m_pDS.get()) return -1;
968 int idMovie = GetMovieId(strFilenameAndPath);
971 int idFile = AddFile(strFilenameAndPath);
974 CStdString strSQL=PrepareSQL("insert into movie (idMovie, idFile) values (NULL, %i)", idFile);
975 m_pDS->exec(strSQL.c_str());
976 idMovie = (int)m_pDS->lastinsertid();
977 // CommitTransaction();
984 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
989 int CVideoDatabase::AddTvShow(const CStdString& strPath)
993 if (NULL == m_pDB.get()) return -1;
994 if (NULL == m_pDS.get()) return -1;
996 CStdString strSQL=PrepareSQL("select tvshowlinkpath.idShow from path,tvshowlinkpath where path.strPath like '%s' and path.idPath=tvshowlinkpath.idPath",strPath.c_str());
997 m_pDS->query(strSQL.c_str());
998 if (m_pDS->num_rows() != 0)
999 return m_pDS->fv("tvshowlinkpath.idShow").get_asInt();
1001 strSQL=PrepareSQL("insert into tvshow (idShow) values (NULL)");
1002 m_pDS->exec(strSQL.c_str());
1003 int idTvShow = (int)m_pDS->lastinsertid();
1005 int idPath = GetPathId(strPath);
1007 idPath = AddPath(strPath);
1008 strSQL=PrepareSQL("insert into tvshowlinkpath values (%i,%i)",idTvShow,idPath);
1009 m_pDS->exec(strSQL.c_str());
1011 // CommitTransaction();
1017 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strPath.c_str());
1022 //********************************************************************************************************************************
1023 int CVideoDatabase::AddEpisode(int idShow, const CStdString& strFilenameAndPath)
1027 if (NULL == m_pDB.get()) return -1;
1028 if (NULL == m_pDS.get()) return -1;
1030 int idFile = AddFile(strFilenameAndPath);
1034 CStdString strSQL=PrepareSQL("insert into episode (idEpisode, idFile) values (NULL, %i)", idFile);
1035 m_pDS->exec(strSQL.c_str());
1036 int idEpisode = (int)m_pDS->lastinsertid();
1038 strSQL=PrepareSQL("insert into tvshowlinkepisode (idShow,idEpisode) values (%i,%i)",idShow,idEpisode);
1039 m_pDS->exec(strSQL.c_str());
1041 // CommitTransaction();
1047 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
1052 int CVideoDatabase::AddMusicVideo(const CStdString& strFilenameAndPath)
1056 if (NULL == m_pDB.get()) return -1;
1057 if (NULL == m_pDS.get()) return -1;
1059 int idMVideo = GetMusicVideoId(strFilenameAndPath);
1062 int idFile = AddFile(strFilenameAndPath);
1065 CStdString strSQL=PrepareSQL("insert into musicvideo (idMVideo, idFile) values (NULL, %i)", idFile);
1066 m_pDS->exec(strSQL.c_str());
1067 idMVideo = (int)m_pDS->lastinsertid();
1074 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
1079 //********************************************************************************************************************************
1080 int CVideoDatabase::AddToTable(const CStdString& table, const CStdString& firstField, const CStdString& secondField, const CStdString& value)
1084 if (NULL == m_pDB.get()) return -1;
1085 if (NULL == m_pDS.get()) return -1;
1087 CStdString strSQL = PrepareSQL("select %s from %s where %s like '%s'", firstField.c_str(), table.c_str(), secondField.c_str(), value.c_str());
1088 m_pDS->query(strSQL.c_str());
1089 if (m_pDS->num_rows() == 0)
1092 // doesnt exists, add it
1093 strSQL = PrepareSQL("insert into %s (%s, %s) values( NULL, '%s')", table.c_str(), firstField.c_str(), secondField.c_str(), value.c_str());
1094 m_pDS->exec(strSQL.c_str());
1095 int id = (int)m_pDS->lastinsertid();
1100 int id = m_pDS->fv(firstField).get_asInt();
1107 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, value.c_str() );
1113 int CVideoDatabase::AddSet(const CStdString& strSet)
1115 return AddToTable("sets", "idSet", "strSet", strSet);
1118 int CVideoDatabase::AddGenre(const CStdString& strGenre)
1120 return AddToTable("genre", "idGenre", "strGenre", strGenre);
1123 int CVideoDatabase::AddStudio(const CStdString& strStudio)
1125 return AddToTable("studio", "idStudio", "strStudio", strStudio);
1128 //********************************************************************************************************************************
1129 int CVideoDatabase::AddCountry(const CStdString& strCountry)
1131 return AddToTable("country", "idCountry", "strCountry", strCountry);
1134 int CVideoDatabase::AddActor(const CStdString& strActor, const CStdString& strThumb)
1138 if (NULL == m_pDB.get()) return -1;
1139 if (NULL == m_pDS.get()) return -1;
1140 CStdString strSQL=PrepareSQL("select idActor from actors where strActor like '%s'", strActor.c_str());
1141 m_pDS->query(strSQL.c_str());
1142 if (m_pDS->num_rows() == 0)
1145 // doesnt exists, add it
1146 strSQL=PrepareSQL("insert into actors (idActor, strActor, strThumb) values( NULL, '%s','%s')", strActor.c_str(),strThumb.c_str());
1147 m_pDS->exec(strSQL.c_str());
1148 int idActor = (int)m_pDS->lastinsertid();
1153 const field_value value = m_pDS->fv("idActor");
1154 int idActor = value.get_asInt() ;
1155 // update the thumb url's
1156 if (!strThumb.IsEmpty())
1157 strSQL=PrepareSQL("update actors set strThumb='%s' where idActor=%i",strThumb.c_str(),idActor);
1165 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strActor.c_str() );
1172 void CVideoDatabase::AddLinkToActor(const char *table, int actorID, const char *secondField, int secondID, const CStdString &role, int order)
1176 if (NULL == m_pDB.get()) return ;
1177 if (NULL == m_pDS.get()) return ;
1179 CStdString strSQL=PrepareSQL("select * from %s where idActor=%i and %s=%i", table, actorID, secondField, secondID);
1180 m_pDS->query(strSQL.c_str());
1181 if (m_pDS->num_rows() == 0)
1183 // doesnt exists, add it
1184 strSQL=PrepareSQL("insert into %s (idActor, %s, strRole, iOrder) values(%i,%i,'%s',%i)", table, secondField, actorID, secondID, role.c_str(), order);
1185 m_pDS->exec(strSQL.c_str());
1191 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
1195 void CVideoDatabase::AddToLinkTable(const char *table, const char *firstField, int firstID, const char *secondField, int secondID)
1199 if (NULL == m_pDB.get()) return ;
1200 if (NULL == m_pDS.get()) return ;
1202 CStdString strSQL=PrepareSQL("select * from %s where %s=%i and %s=%i", table, firstField, firstID, secondField, secondID);
1203 m_pDS->query(strSQL.c_str());
1204 if (m_pDS->num_rows() == 0)
1206 // doesnt exists, add it
1207 strSQL=PrepareSQL("insert into %s (%s,%s) values(%i,%i)", table, firstField, secondField, firstID, secondID);
1208 m_pDS->exec(strSQL.c_str());
1214 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
1219 void CVideoDatabase::AddSetToMovie(int idMovie, int idSet)
1221 AddToLinkTable("setlinkmovie", "idSet", idSet, "idMovie", idMovie);
1225 void CVideoDatabase::AddActorToMovie(int idMovie, int idActor, const CStdString& strRole, int order)
1227 AddLinkToActor("actorlinkmovie", idActor, "idMovie", idMovie, strRole, order);
1230 void CVideoDatabase::AddActorToTvShow(int idTvShow, int idActor, const CStdString& strRole, int order)
1232 AddLinkToActor("actorlinktvshow", idActor, "idShow", idTvShow, strRole, order);
1235 void CVideoDatabase::AddActorToEpisode(int idEpisode, int idActor, const CStdString& strRole, int order)
1237 AddLinkToActor("actorlinkepisode", idActor, "idEpisode", idEpisode, strRole, order);
1240 void CVideoDatabase::AddArtistToMusicVideo(int idMVideo, int idArtist)
1242 AddToLinkTable("artistlinkmusicvideo", "idArtist", idArtist, "idMVideo", idMVideo);
1245 //****Directors + Writers****
1246 void CVideoDatabase::AddDirectorToMovie(int idMovie, int idDirector)
1248 AddToLinkTable("directorlinkmovie", "idDirector", idDirector, "idMovie", idMovie);
1251 void CVideoDatabase::AddDirectorToTvShow(int idTvShow, int idDirector)
1253 AddToLinkTable("directorlinktvshow", "idDirector", idDirector, "idShow", idTvShow);
1256 void CVideoDatabase::AddWriterToEpisode(int idEpisode, int idWriter)
1258 AddToLinkTable("writerlinkepisode", "idWriter", idWriter, "idEpisode", idEpisode);
1261 void CVideoDatabase::AddWriterToMovie(int idMovie, int idWriter)
1263 AddToLinkTable("writerlinkmovie", "idWriter", idWriter, "idMovie", idMovie);
1266 void CVideoDatabase::AddDirectorToEpisode(int idEpisode, int idDirector)
1268 AddToLinkTable("directorlinkepisode", "idDirector", idDirector, "idEpisode", idEpisode);
1271 void CVideoDatabase::AddDirectorToMusicVideo(int idMVideo, int idDirector)
1273 AddToLinkTable("directorlinkmusicvideo", "idDirector", idDirector, "idMVideo", idMVideo);
1277 void CVideoDatabase::AddStudioToMovie(int idMovie, int idStudio)
1279 AddToLinkTable("studiolinkmovie", "idStudio", idStudio, "idMovie", idMovie);
1282 void CVideoDatabase::AddStudioToTvShow(int idTvShow, int idStudio)
1284 AddToLinkTable("studiolinktvshow", "idStudio", idStudio, "idShow", idTvShow);
1287 void CVideoDatabase::AddStudioToMusicVideo(int idMVideo, int idStudio)
1289 AddToLinkTable("studiolinkmusicvideo", "idStudio", idStudio, "idMVideo", idMVideo);
1293 void CVideoDatabase::AddGenreToMovie(int idMovie, int idGenre)
1295 AddToLinkTable("genrelinkmovie", "idGenre", idGenre, "idMovie", idMovie);
1298 void CVideoDatabase::AddGenreToTvShow(int idTvShow, int idGenre)
1300 AddToLinkTable("genrelinktvshow", "idGenre", idGenre, "idShow", idTvShow);
1303 void CVideoDatabase::AddGenreToMusicVideo(int idMVideo, int idGenre)
1305 AddToLinkTable("genrelinkmusicvideo", "idGenre", idGenre, "idMVideo", idMVideo);
1309 void CVideoDatabase::AddCountryToMovie(int idMovie, int idCountry)
1311 AddToLinkTable("countrylinkmovie", "idCountry", idCountry, "idMovie", idMovie);
1314 //********************************************************************************************************************************
1315 bool CVideoDatabase::HasMovieInfo(const CStdString& strFilenameAndPath)
1319 if (NULL == m_pDB.get()) return false;
1320 if (NULL == m_pDS.get()) return false;
1321 int idMovie = GetMovieId(strFilenameAndPath);
1322 return (idMovie > 0); // index of zero is also invalid
1327 // get title. if no title, the id was "deleted" for in-place update
1328 CVideoInfoTag details;
1329 GetMovieInfo(strFilenameAndPath, details, idMovie);
1330 if (!details.m_strTitle.IsEmpty()) return true;
1336 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
1341 bool CVideoDatabase::HasTvShowInfo(const CStdString& strPath)
1345 if (NULL == m_pDB.get()) return false;
1346 if (NULL == m_pDS.get()) return false;
1347 int idTvShow = GetTvShowId(strPath);
1348 return (idTvShow > 0); // index of zero is also invalid
1353 // get title. if no title, the id was "deleted" for in-place update
1354 CVideoInfoTag details;
1355 GetTvShowInfo(strPath, details, idTvShow);
1356 if (!details.m_strTitle.IsEmpty()) return true;
1362 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strPath.c_str());
1367 bool CVideoDatabase::HasEpisodeInfo(const CStdString& strFilenameAndPath)
1371 if (NULL == m_pDB.get()) return false;
1372 if (NULL == m_pDS.get()) return false;
1373 int idEpisode = GetEpisodeId(strFilenameAndPath);
1374 return (idEpisode > 0); // index of zero is also invalid
1379 // get title. if no title, the id was "deleted" for in-place update
1380 CVideoInfoTag details;
1381 GetEpisodeInfo(strFilenameAndPath, details, idEpisode);
1382 if (!details.m_strTitle.IsEmpty()) return true;
1388 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
1393 bool CVideoDatabase::HasMusicVideoInfo(const CStdString& strFilenameAndPath)
1397 if (NULL == m_pDB.get()) return false;
1398 if (NULL == m_pDS.get()) return false;
1399 int idMVideo = GetMusicVideoId(strFilenameAndPath);
1400 return (idMVideo > 0); // index of zero is also invalid
1405 // get title. if no title, the id was "deleted" for in-place update
1406 CVideoInfoTag details;
1407 GetMusicVideoInfo(strFilenameAndPath, details, idMVideo);
1408 if (!details.m_strTitle.IsEmpty()) return true;
1414 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
1419 void CVideoDatabase::DeleteDetailsForTvShow(const CStdString& strPath)
1420 {// TODO: merge into DeleteTvShow
1423 if (NULL == m_pDB.get()) return ;
1424 if (NULL == m_pDS.get()) return ;
1426 int idTvShow = GetTvShowId(strPath);
1427 if ( idTvShow < 0) return ;
1429 CFileItemList items;
1430 CStdString strPath2;
1431 strPath2.Format("videodb://2/2/%i/",idTvShow);
1432 GetSeasonsNav(strPath2,items,-1,-1,-1,-1,idTvShow);
1433 for( int i=0;i<items.Size();++i )
1434 CTextureCache::Get().ClearCachedImage(items[i]->GetCachedSeasonThumb(), true);
1435 DeleteThumbForItem(strPath,true);
1438 strSQL=PrepareSQL("delete from genrelinktvshow where idShow=%i", idTvShow);
1439 m_pDS->exec(strSQL.c_str());
1441 strSQL=PrepareSQL("delete from actorlinktvshow where idShow=%i", idTvShow);
1442 m_pDS->exec(strSQL.c_str());
1444 strSQL=PrepareSQL("delete from directorlinktvshow where idShow=%i", idTvShow);
1445 m_pDS->exec(strSQL.c_str());
1447 strSQL=PrepareSQL("delete from studiolinktvshow where idShow=%i", idTvShow);
1448 m_pDS->exec(strSQL.c_str());
1450 // remove all info other than the id
1451 // we do this due to the way we have the link between the file + movie tables.
1453 strSQL = "update tvshow set ";
1454 for (int iType = VIDEODB_ID_TV_MIN + 1; iType < VIDEODB_ID_TV_MAX; iType++)
1457 column.Format("c%02d=NULL,", iType);
1460 strSQL = strSQL.Mid(0, strSQL.size() - 1) + PrepareSQL(" where idShow=%i", idTvShow);
1461 m_pDS->exec(strSQL.c_str());
1465 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strPath.c_str());
1469 //********************************************************************************************************************************
1470 void CVideoDatabase::GetMoviesByActor(const CStdString& strActor, CFileItemList& items)
1472 CStdString where = PrepareSQL("join actorlinkmovie on actorlinkmovie.idMovie=movieview.idMovie "
1473 "join actors on actors.idActor=actorlinkmovie.idActor "
1474 "where actors.strActor='%s'", strActor.c_str());
1475 GetMoviesByWhere("videodb://1/2/", where, "", items);
1478 void CVideoDatabase::GetTvShowsByActor(const CStdString& strActor, CFileItemList& items)
1480 CStdString where = PrepareSQL("join actorlinktvshow on actorlinktvshow.idShow=tvshowview.idShow "
1481 "join actors on actors.idActor=actorlinktvshow.idActor "
1482 "where actors.strActor='%s'", strActor.c_str());
1483 GetTvShowsByWhere("videodb://2/2/", where, items);
1486 void CVideoDatabase::GetEpisodesByActor(const CStdString& strActor, CFileItemList& items)
1488 CStdString where = PrepareSQL("join actorlinkepisode on actorlinkepisode.idEpisode=episodeview.idEpisode "
1489 "join actors on actors.idActor=actorlinkepisode.idActor "
1490 "where actors.strActor='%s'", strActor.c_str());
1491 GetEpisodesByWhere("videodb://2/2/", where, items);
1494 void CVideoDatabase::GetMusicVideosByArtist(const CStdString& strArtist, CFileItemList& items)
1499 if (NULL == m_pDB.get()) return ;
1500 if (NULL == m_pDS.get()) return ;
1503 if (strArtist.IsEmpty()) // TODO: SMARTPLAYLISTS what is this here for???
1504 strSQL=PrepareSQL("select distinct * from musicvideoview join artistlinkmusicvideo on artistlinkmusicvideo.idMVideo=musicvideoview.idMVideo join actors on actors.idActor=artistlinkmusicvideo.idArtist");
1506 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());
1507 m_pDS->query( strSQL.c_str() );
1509 while (!m_pDS->eof())
1511 CVideoInfoTag tag = GetDetailsForMusicVideo(m_pDS);
1512 CFileItemPtr pItem(new CFileItem(tag));
1513 pItem->SetLabel(tag.m_strArtist);
1521 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strArtist.c_str());
1525 //********************************************************************************************************************************
1526 void CVideoDatabase::GetMovieInfo(const CStdString& strFilenameAndPath, CVideoInfoTag& details, int idMovie /* = -1 */)
1530 // TODO: Optimize this - no need for all the queries!
1532 idMovie = GetMovieId(strFilenameAndPath);
1533 if (idMovie < 0) return ;
1535 CStdString sql = PrepareSQL("select * from movieview where idMovie=%i", idMovie);
1536 if (!m_pDS->query(sql.c_str()))
1538 details = GetDetailsForMovie(m_pDS, true);
1542 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
1546 //********************************************************************************************************************************
1547 void CVideoDatabase::GetTvShowInfo(const CStdString& strPath, CVideoInfoTag& details, int idTvShow /* = -1 */)
1552 idTvShow = GetTvShowId(strPath);
1553 if (idTvShow < 0) return ;
1555 CStdString sql = PrepareSQL("SELECT * FROM tvshowview WHERE idShow=%i", idTvShow);
1556 if (!m_pDS->query(sql.c_str()))
1558 details = GetDetailsForTvShow(m_pDS, true);
1562 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strPath.c_str());
1566 bool CVideoDatabase::GetEpisodeInfo(const CStdString& strFilenameAndPath, CVideoInfoTag& details, int idEpisode /* = -1 */)
1570 // TODO: Optimize this - no need for all the queries!
1572 idEpisode = GetEpisodeId(strFilenameAndPath);
1573 if (idEpisode < 0) return false;
1575 CStdString sql = PrepareSQL("select * from episodeview where idEpisode=%i",idEpisode);
1576 if (!m_pDS->query(sql.c_str()))
1578 details = GetDetailsForEpisode(m_pDS, true);
1583 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
1588 void CVideoDatabase::GetMusicVideoInfo(const CStdString& strFilenameAndPath, CVideoInfoTag& details, int idMVideo /* = -1 */)
1592 // TODO: Optimize this - no need for all the queries!
1594 idMVideo = GetMusicVideoId(strFilenameAndPath);
1595 if (idMVideo < 0) return ;
1597 CStdString sql = PrepareSQL("select * from musicvideoview where idMVideo=%i", idMVideo);
1598 if (!m_pDS->query(sql.c_str()))
1600 details = GetDetailsForMusicVideo(m_pDS);
1604 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
1608 void CVideoDatabase::AddGenreAndDirectorsAndStudios(const CVideoInfoTag& details, vector<int>& vecDirectors, vector<int>& vecGenres, vector<int>& vecStudios)
1610 // add all directors
1611 if (!details.m_strDirector.IsEmpty())
1613 CStdStringArray directors;
1614 StringUtils::SplitString(details.m_strDirector, g_advancedSettings.m_videoItemSeparator, directors);
1615 for (unsigned int i = 0; i < directors.size(); i++)
1617 CStdString strDirector(directors[i]);
1619 int idDirector = AddActor(strDirector,"");
1620 vecDirectors.push_back(idDirector);
1625 if (!details.m_strGenre.IsEmpty())
1627 CStdStringArray genres;
1628 StringUtils::SplitString(details.m_strGenre, g_advancedSettings.m_videoItemSeparator, genres);
1629 for (unsigned int i = 0; i < genres.size(); i++)
1631 CStdString strGenre(genres[i]);
1633 int idGenre = AddGenre(strGenre);
1634 vecGenres.push_back(idGenre);
1638 if (!details.m_strStudio.IsEmpty())
1640 CStdStringArray studios;
1641 StringUtils::SplitString(details.m_strStudio, g_advancedSettings.m_videoItemSeparator, studios);
1642 for (unsigned int i = 0; i < studios.size(); i++)
1644 CStdString strStudio(studios[i]);
1646 int idStudio = AddStudio(strStudio);
1647 vecStudios.push_back(idStudio);
1652 CStdString CVideoDatabase::GetValueString(const CVideoInfoTag &details, int min, int max, const SDbTableOffsets *offsets) const
1655 for (int i = min + 1; i < max; ++i)
1657 switch (offsets[i].type)
1659 case VIDEODB_TYPE_STRING:
1660 sql += PrepareSQL("c%02d='%s',", i, ((CStdString*)(((char*)&details)+offsets[i].offset))->c_str());
1662 case VIDEODB_TYPE_INT:
1663 sql += PrepareSQL("c%02d='%i',", i, *(int*)(((char*)&details)+offsets[i].offset));
1665 case VIDEODB_TYPE_COUNT:
1667 int value = *(int*)(((char*)&details)+offsets[i].offset);
1669 sql += PrepareSQL("c%02d=%i,", i, value);
1671 sql += PrepareSQL("c%02d=NULL,", i);
1674 case VIDEODB_TYPE_BOOL:
1675 sql += PrepareSQL("c%02d='%s',", i, *(bool*)(((char*)&details)+offsets[i].offset)?"true":"false");
1677 case VIDEODB_TYPE_FLOAT:
1678 sql += PrepareSQL("c%02d='%f',", i, *(float*)(((char*)&details)+offsets[i].offset));
1686 //********************************************************************************************************************************
1687 int CVideoDatabase::SetDetailsForMovie(const CStdString& strFilenameAndPath, const CVideoInfoTag& details)
1691 CVideoInfoTag info = details;
1693 int idMovie = GetMovieId(strFilenameAndPath);
1695 DeleteMovie(strFilenameAndPath, true); // true to keep the table entry
1699 idMovie = AddMovie(strFilenameAndPath);
1702 CommitTransaction();
1706 vector<int> vecDirectors;
1707 vector<int> vecGenres;
1708 vector<int> vecStudios;
1709 AddGenreAndDirectorsAndStudios(info,vecDirectors,vecGenres,vecStudios);
1711 for (unsigned int i = 0; i < vecGenres.size(); ++i)
1712 AddGenreToMovie(idMovie, vecGenres[i]);
1714 for (unsigned int i = 0; i < vecDirectors.size(); ++i)
1715 AddDirectorToMovie(idMovie, vecDirectors[i]);
1717 for (unsigned int i = 0; i < vecStudios.size(); ++i)
1718 AddStudioToMovie(idMovie, vecStudios[i]);
1721 if (!info.m_strWritingCredits.IsEmpty())
1723 CStdStringArray writers;
1724 StringUtils::SplitString(info.m_strWritingCredits, g_advancedSettings.m_videoItemSeparator, writers);
1725 for (unsigned int i = 0; i < writers.size(); i++)
1727 CStdString writer(writers[i]);
1729 int idWriter = AddActor(writer,"");
1730 AddWriterToMovie(idMovie, idWriter );
1736 for (CVideoInfoTag::iCast it = info.m_cast.begin(); it != info.m_cast.end(); ++it)
1738 int idActor = AddActor(it->strName,it->thumbUrl.m_xml);
1739 AddActorToMovie(idMovie, idActor, it->strRole, order++);
1743 if (!info.m_strSet.IsEmpty())
1745 CStdStringArray sets;
1746 StringUtils::SplitString(info.m_strSet, g_advancedSettings.m_videoItemSeparator, sets);
1747 for (unsigned int i = 0; i < sets.size(); i++)
1749 CStdString set(sets[i]);
1751 int idSet = AddSet(set);
1752 AddSetToMovie(idMovie, idSet);
1757 if (!info.m_strCountry.IsEmpty())
1759 CStdStringArray countries;
1760 StringUtils::SplitString(info.m_strCountry, g_advancedSettings.m_videoItemSeparator, countries);
1761 for (unsigned int i = 0; i < countries.size(); i++)
1763 CStdString country(countries[i]);
1765 int idCountry = AddCountry(country);
1766 AddCountryToMovie(idMovie, idCountry);
1770 if (details.HasStreamDetails())
1771 SetStreamDetailsForFileId(details.m_streamDetails, GetFileId(strFilenameAndPath));
1773 // update our movie table (we know it was added already above)
1774 // and insert the new row
1775 CStdString sql = "update movie set " + GetValueString(info, VIDEODB_ID_MIN, VIDEODB_ID_MAX, DbMovieOffsets);
1776 sql += PrepareSQL(" where idMovie=%i", idMovie);
1777 m_pDS->exec(sql.c_str());
1778 CommitTransaction();
1780 AnnounceUpdate("movie", idMovie);
1786 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
1791 int CVideoDatabase::SetDetailsForTvShow(const CStdString& strPath, const CVideoInfoTag& details)
1795 if (!m_pDB.get() || !m_pDS.get())
1797 CLog::Log(LOGERROR, "%s: called without database open", __FUNCTION__);
1803 int idTvShow = GetTvShowId(strPath);
1805 idTvShow = AddTvShow(strPath);
1807 vector<int> vecDirectors;
1808 vector<int> vecGenres;
1809 vector<int> vecStudios;
1810 AddGenreAndDirectorsAndStudios(details,vecDirectors,vecGenres,vecStudios);
1814 for (CVideoInfoTag::iCast it = details.m_cast.begin(); it != details.m_cast.end(); ++it)
1816 int idActor = AddActor(it->strName,it->thumbUrl.m_xml);
1817 AddActorToTvShow(idTvShow, idActor, it->strRole, order++);
1821 for (i = 0; i < vecGenres.size(); ++i)
1823 AddGenreToTvShow(idTvShow, vecGenres[i]);
1826 for (i = 0; i < vecDirectors.size(); ++i)
1828 AddDirectorToTvShow(idTvShow, vecDirectors[i]);
1831 for (i = 0; i < vecStudios.size(); ++i)
1833 AddStudioToTvShow(idTvShow, vecStudios[i]);
1836 // and insert the new row
1837 CStdString sql = "update tvshow set " + GetValueString(details, VIDEODB_ID_TV_MIN, VIDEODB_ID_TV_MAX, DbTvShowOffsets);
1838 sql += PrepareSQL("where idShow=%i", idTvShow);
1839 m_pDS->exec(sql.c_str());
1840 CommitTransaction();
1842 AnnounceUpdate("tvshow", idTvShow);
1848 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strPath.c_str());
1854 int CVideoDatabase::SetDetailsForEpisode(const CStdString& strFilenameAndPath, const CVideoInfoTag& details, int idShow, int idEpisode)
1859 if (idEpisode == -1)
1861 idEpisode = GetEpisodeId(strFilenameAndPath);
1863 DeleteEpisode(strFilenameAndPath,idEpisode);
1865 idEpisode = AddEpisode(idShow,strFilenameAndPath);
1868 CommitTransaction();
1873 vector<int> vecDirectors;
1874 vector<int> vecGenres;
1875 vector<int> vecStudios;
1876 AddGenreAndDirectorsAndStudios(details,vecDirectors,vecGenres,vecStudios);
1880 for (CVideoInfoTag::iCast it = details.m_cast.begin(); it != details.m_cast.end(); ++it)
1882 int idActor = AddActor(it->strName,it->thumbUrl.m_xml);
1883 AddActorToEpisode(idEpisode, idActor, it->strRole, order++);
1887 if (!details.m_strWritingCredits.IsEmpty())
1889 CStdStringArray writers;
1890 StringUtils::SplitString(details.m_strWritingCredits, g_advancedSettings.m_videoItemSeparator, writers);
1891 for (unsigned int i = 0; i < writers.size(); i++)
1893 CStdString writer(writers[i]);
1895 int idWriter = AddActor(writer,"");
1896 AddWriterToEpisode(idEpisode, idWriter );
1900 for (unsigned int i = 0; i < vecDirectors.size(); ++i)
1902 AddDirectorToEpisode(idEpisode, vecDirectors[i]);
1905 if (details.HasStreamDetails())
1907 if (details.m_iFileId != -1)
1908 SetStreamDetailsForFileId(details.m_streamDetails, details.m_iFileId);
1910 SetStreamDetailsForFile(details.m_streamDetails, strFilenameAndPath);
1913 // and insert the new row
1914 CStdString sql = "update episode set " + GetValueString(details, VIDEODB_ID_EPISODE_MIN, VIDEODB_ID_EPISODE_MAX, DbEpisodeOffsets);
1915 sql += PrepareSQL("where idEpisode=%i", idEpisode);
1916 m_pDS->exec(sql.c_str());
1917 CommitTransaction();
1919 AnnounceUpdate("episode", idEpisode);
1925 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
1930 int CVideoDatabase::SetDetailsForMusicVideo(const CStdString& strFilenameAndPath, const CVideoInfoTag& details)
1936 int idMVideo = GetMusicVideoId(strFilenameAndPath);
1939 DeleteMusicVideo(strFilenameAndPath);
1941 idMVideo = AddMusicVideo(strFilenameAndPath);
1944 CommitTransaction();
1948 vector<int> vecDirectors;
1949 vector<int> vecGenres;
1950 vector<int> vecStudios;
1951 AddGenreAndDirectorsAndStudios(details,vecDirectors,vecGenres,vecStudios);
1954 if (!details.m_strArtist.IsEmpty())
1956 CStdStringArray vecArtists;
1957 StringUtils::SplitString(details.m_strArtist, g_advancedSettings.m_videoItemSeparator, vecArtists);
1958 for (unsigned int i = 0; i < vecArtists.size(); i++)
1960 CStdString artist = vecArtists[i];
1962 int idArtist = AddActor(artist,"");
1963 AddArtistToMusicVideo(idMVideo, idArtist);
1968 for (i = 0; i < vecGenres.size(); ++i)
1970 AddGenreToMusicVideo(idMVideo, vecGenres[i]);
1973 for (i = 0; i < vecDirectors.size(); ++i)
1975 AddDirectorToMusicVideo(idMVideo, vecDirectors[i]);
1978 for (i = 0; i < vecStudios.size(); ++i)
1980 AddStudioToMusicVideo(idMVideo, vecStudios[i]);
1983 if (details.HasStreamDetails())
1984 SetStreamDetailsForFileId(details.m_streamDetails, GetFileId(strFilenameAndPath));
1986 // update our movie table (we know it was added already above)
1987 // and insert the new row
1988 CStdString sql = "update musicvideo set " + GetValueString(details, VIDEODB_ID_MUSICVIDEO_MIN, VIDEODB_ID_MUSICVIDEO_MAX, DbMusicVideoOffsets);
1989 sql += PrepareSQL(" where idMVideo=%i", idMVideo);
1990 m_pDS->exec(sql.c_str());
1991 CommitTransaction();
1993 AnnounceUpdate("musicvideo", idMVideo);
1999 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
2004 void CVideoDatabase::SetStreamDetailsForFile(const CStreamDetails& details, const CStdString &strFileNameAndPath)
2006 // AddFile checks to make sure the file isn't already in the DB first
2007 int idFile = AddFile(strFileNameAndPath);
2010 SetStreamDetailsForFileId(details, idFile);
2013 void CVideoDatabase::SetStreamDetailsForFileId(const CStreamDetails& details, int idFile)
2021 m_pDS->exec(PrepareSQL("DELETE FROM streamdetails WHERE idFile = %i", idFile));
2023 for (int i=1; i<=details.GetVideoStreamCount(); i++)
2025 m_pDS->exec(PrepareSQL("INSERT INTO streamdetails "
2026 "(idFile, iStreamType, strVideoCodec, fVideoAspect, iVideoWidth, iVideoHeight, iVideoDuration) "
2027 "VALUES (%i,%i,'%s',%f,%i,%i,%i)",
2028 idFile, (int)CStreamDetail::VIDEO,
2029 details.GetVideoCodec(i).c_str(), details.GetVideoAspect(i),
2030 details.GetVideoWidth(i), details.GetVideoHeight(i), details.GetVideoDuration(i)));
2032 for (int i=1; i<=details.GetAudioStreamCount(); i++)
2034 m_pDS->exec(PrepareSQL("INSERT INTO streamdetails "
2035 "(idFile, iStreamType, strAudioCodec, iAudioChannels, strAudioLanguage) "
2036 "VALUES (%i,%i,'%s',%i,'%s')",
2037 idFile, (int)CStreamDetail::AUDIO,
2038 details.GetAudioCodec(i).c_str(), details.GetAudioChannels(i),
2039 details.GetAudioLanguage(i).c_str()));
2041 for (int i=1; i<=details.GetSubtitleStreamCount(); i++)
2043 m_pDS->exec(PrepareSQL("INSERT INTO streamdetails "
2044 "(idFile, iStreamType, strSubtitleLanguage) "
2045 "VALUES (%i,%i,'%s')",
2046 idFile, (int)CStreamDetail::SUBTITLE,
2047 details.GetSubtitleLanguage(i).c_str()));
2050 CommitTransaction();
2054 RollbackTransaction();
2055 CLog::Log(LOGERROR, "%s (%i) failed", __FUNCTION__, idFile);
2059 //********************************************************************************************************************************
2060 void CVideoDatabase::GetFilePathById(int idMovie, CStdString &filePath, VIDEODB_CONTENT_TYPE iType)
2064 if (NULL == m_pDB.get()) return ;
2065 if (NULL == m_pDS.get()) return ;
2067 if (idMovie < 0) return ;
2070 if (iType == VIDEODB_CONTENT_MOVIES)
2071 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 );
2072 if (iType == VIDEODB_CONTENT_EPISODES)
2073 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 );
2074 if (iType == VIDEODB_CONTENT_TVSHOWS)
2075 strSQL=PrepareSQL("select path.strPath from path,tvshowlinkpath where path.idPath=tvshowlinkpath.idPath and tvshowlinkpath.idShow=%i", idMovie );
2076 if (iType ==VIDEODB_CONTENT_MUSICVIDEOS)
2077 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 );
2079 m_pDS->query( strSQL.c_str() );
2082 if (iType != VIDEODB_CONTENT_TVSHOWS)
2084 CStdString fileName = m_pDS->fv("files.strFilename").get_asString();
2085 ConstructPath(filePath,m_pDS->fv("path.strPath").get_asString(),fileName);
2088 filePath = m_pDS->fv("path.strPath").get_asString();
2094 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
2098 //********************************************************************************************************************************
2099 void CVideoDatabase::GetBookMarksForFile(const CStdString& strFilenameAndPath, VECBOOKMARKS& bookmarks, CBookmark::EType type /*= CBookmark::STANDARD*/, bool bAppend)
2103 int idFile = GetFileId(strFilenameAndPath);
2104 if (idFile < 0) return ;
2106 bookmarks.erase(bookmarks.begin(), bookmarks.end());
2107 if (NULL == m_pDB.get()) return ;
2108 if (NULL == m_pDS.get()) return ;
2110 CStdString strSQL=PrepareSQL("select * from bookmark where idFile=%i and type=%i order by timeInSeconds", idFile, (int)type);
2111 m_pDS->query( strSQL.c_str() );
2112 while (!m_pDS->eof())
2115 bookmark.timeInSeconds = m_pDS->fv("timeInSeconds").get_asDouble();
2116 bookmark.totalTimeInSeconds = m_pDS->fv("totalTimeInSeconds").get_asDouble();
2117 bookmark.thumbNailImage = m_pDS->fv("thumbNailImage").get_asString();
2118 bookmark.playerState = m_pDS->fv("playerState").get_asString();
2119 bookmark.player = m_pDS->fv("player").get_asString();
2120 bookmark.type = type;
2121 if (type == CBookmark::EPISODE)
2123 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);
2124 m_pDS2->query(strSQL2.c_str());
2125 bookmark.episodeNumber = m_pDS2->fv(0).get_asInt();
2126 bookmark.seasonNumber = m_pDS2->fv(1).get_asInt();
2129 bookmarks.push_back(bookmark);
2132 //sort(bookmarks.begin(), bookmarks.end(), SortBookmarks);
2137 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
2141 bool CVideoDatabase::GetResumeBookMark(const CStdString& strFilenameAndPath, CBookmark &bookmark)
2143 VECBOOKMARKS bookmarks;
2144 GetBookMarksForFile(strFilenameAndPath, bookmarks, CBookmark::RESUME);
2145 if (bookmarks.size() > 0)
2147 bookmark = bookmarks[0];
2153 void CVideoDatabase::DeleteResumeBookMark(const CStdString &strFilenameAndPath)
2155 if (!m_pDB.get() || !m_pDS.get())
2158 int fileID = GetFileId(strFilenameAndPath);
2164 CStdString sql = PrepareSQL("delete from bookmark where idFile=%i and type=%i", fileID, CBookmark::RESUME);
2165 m_pDS->exec(sql.c_str());
2169 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
2173 void CVideoDatabase::GetEpisodesByFile(const CStdString& strFilenameAndPath, vector<CVideoInfoTag>& episodes)
2177 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);
2178 m_pDS->query(strSQL.c_str());
2179 while (!m_pDS->eof())
2181 episodes.push_back(GetDetailsForEpisode(m_pDS));
2188 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
2192 //********************************************************************************************************************************
2193 void CVideoDatabase::AddBookMarkToFile(const CStdString& strFilenameAndPath, const CBookmark &bookmark, CBookmark::EType type /*= CBookmark::STANDARD*/)
2197 int idFile = AddFile(strFilenameAndPath);
2200 if (NULL == m_pDB.get()) return ;
2201 if (NULL == m_pDS.get()) return ;
2205 if (type == CBookmark::RESUME) // get the same resume mark bookmark each time type
2207 strSQL=PrepareSQL("select idBookmark from bookmark where idFile=%i and type=1", idFile);
2209 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
2211 /* get a bookmark within the same time as previous */
2212 double mintime = bookmark.timeInSeconds - 0.5f;
2213 double maxtime = bookmark.timeInSeconds + 0.5f;
2214 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());
2217 if (type != CBookmark::EPISODE)
2220 m_pDS->query( strSQL.c_str() );
2221 if (m_pDS->num_rows() != 0)
2222 idBookmark = m_pDS->get_field_value("idBookmark").get_asInt();
2225 // update or insert depending if it existed before
2226 if (idBookmark >= 0 )
2227 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);
2229 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);
2231 m_pDS->exec(strSQL.c_str());
2235 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
2239 void CVideoDatabase::ClearBookMarkOfFile(const CStdString& strFilenameAndPath, CBookmark& bookmark, CBookmark::EType type /*= CBookmark::STANDARD*/)
2243 int idFile = GetFileId(strFilenameAndPath);
2244 if (idFile < 0) return ;
2245 if (NULL == m_pDB.get()) return ;
2246 if (NULL == m_pDS.get()) return ;
2248 /* a litle bit uggly, we clear first bookmark that is within one second of given */
2249 /* should be no problem since we never add bookmarks that are closer than that */
2250 double mintime = bookmark.timeInSeconds - 0.5f;
2251 double maxtime = bookmark.timeInSeconds + 0.5f;
2252 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);
2254 m_pDS->query( strSQL.c_str() );
2255 if (m_pDS->num_rows() != 0)
2257 int idBookmark = m_pDS->get_field_value("idBookmark").get_asInt();
2258 strSQL=PrepareSQL("delete from bookmark where idBookmark=%i",idBookmark);
2259 m_pDS->exec(strSQL.c_str());
2260 if (type == CBookmark::EPISODE)
2262 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);
2263 m_pDS->exec(strSQL.c_str());
2271 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
2275 //********************************************************************************************************************************
2276 void CVideoDatabase::ClearBookMarksOfFile(const CStdString& strFilenameAndPath, CBookmark::EType type /*= CBookmark::STANDARD*/)
2280 int idFile = GetFileId(strFilenameAndPath);
2281 if (idFile < 0) return ;
2282 if (NULL == m_pDB.get()) return ;
2283 if (NULL == m_pDS.get()) return ;
2285 CStdString strSQL=PrepareSQL("delete from bookmark where idFile=%i and type=%i", idFile, (int)type);
2286 m_pDS->exec(strSQL.c_str());
2287 if (type == CBookmark::EPISODE)
2289 strSQL=PrepareSQL("update episode set c%02d=-1 where idFile=%i", VIDEODB_ID_EPISODE_BOOKMARK, idFile);
2290 m_pDS->exec(strSQL.c_str());
2295 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
2300 bool CVideoDatabase::GetBookMarkForEpisode(const CVideoInfoTag& tag, CBookmark& bookmark)
2304 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);
2305 m_pDS->query( strSQL.c_str() );
2308 bookmark.timeInSeconds = m_pDS->fv("timeInSeconds").get_asDouble();
2309 bookmark.totalTimeInSeconds = m_pDS->fv("totalTimeInSeconds").get_asDouble();
2310 bookmark.thumbNailImage = m_pDS->fv("thumbNailImage").get_asString();
2311 bookmark.playerState = m_pDS->fv("playerState").get_asString();
2312 bookmark.player = m_pDS->fv("player").get_asString();
2313 bookmark.type = (CBookmark::EType)m_pDS->fv("type").get_asInt();
2324 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
2330 void CVideoDatabase::AddBookMarkForEpisode(const CVideoInfoTag& tag, const CBookmark& bookmark)
2334 int idFile = GetFileId(tag.m_strFileNameAndPath);
2335 // delete the current episode for the selected episode number
2336 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);
2337 m_pDS->exec(strSQL.c_str());
2339 AddBookMarkToFile(tag.m_strFileNameAndPath, bookmark, CBookmark::EPISODE);
2340 int idBookmark = (int)m_pDS->lastinsertid();
2341 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);
2342 m_pDS->exec(strSQL.c_str());
2346 CLog::Log(LOGERROR, "%s (%i) failed", __FUNCTION__, tag.m_iDbId);
2350 void CVideoDatabase::DeleteBookMarkForEpisode(const CVideoInfoTag& tag)
2354 CStdString strSQL = PrepareSQL("delete from bookmark where idBookmark in (select c%02d from episode where idEpisode=%i)", VIDEODB_ID_EPISODE_BOOKMARK, tag.m_iDbId);
2355 m_pDS->exec(strSQL.c_str());
2356 strSQL = PrepareSQL("update episode set c%02d=-1 where idEpisode=%i", VIDEODB_ID_EPISODE_BOOKMARK, tag.m_iDbId);
2357 m_pDS->exec(strSQL.c_str());
2361 CLog::Log(LOGERROR, "%s (%i) failed", __FUNCTION__, tag.m_iDbId);
2365 //********************************************************************************************************************************
2366 void CVideoDatabase::DeleteMovie(const CStdString& strFilenameAndPath, bool bKeepId /* = false */, bool bKeepThumb /* = false */)
2370 if (NULL == m_pDB.get()) return ;
2371 if (NULL == m_pDS.get()) return ;
2372 int idMovie = GetMovieId(strFilenameAndPath);
2381 strSQL=PrepareSQL("delete from genrelinkmovie where idMovie=%i", idMovie);
2382 m_pDS->exec(strSQL.c_str());
2384 strSQL=PrepareSQL("delete from actorlinkmovie where idMovie=%i", idMovie);
2385 m_pDS->exec(strSQL.c_str());
2387 strSQL=PrepareSQL("delete from directorlinkmovie where idMovie=%i", idMovie);
2388 m_pDS->exec(strSQL.c_str());
2390 strSQL=PrepareSQL("delete from studiolinkmovie where idMovie=%i", idMovie);
2391 m_pDS->exec(strSQL.c_str());
2393 strSQL=PrepareSQL("delete from setlinkmovie where idMovie=%i", idMovie);
2394 m_pDS->exec(strSQL.c_str());
2396 strSQL=PrepareSQL("delete from countrylinkmovie where idMovie=%i", idMovie);
2397 m_pDS->exec(strSQL.c_str());
2400 DeleteThumbForItem(strFilenameAndPath,false);
2402 DeleteStreamDetails(GetFileId(strFilenameAndPath));
2404 // keep the movie table entry, linking to tv shows, and bookmarks
2405 // so we can update the data in place
2406 // the ancilliary tables are still purged
2409 ClearBookMarksOfFile(strFilenameAndPath);
2411 strSQL=PrepareSQL("delete from movie where idMovie=%i", idMovie);
2412 m_pDS->exec(strSQL.c_str());
2414 strSQL=PrepareSQL("delete from movielinktvshow where idMovie=%i", idMovie);
2415 m_pDS->exec(strSQL.c_str());
2422 strSQL=PrepareSQL("update movie set c%02d=NULL where idMovie=%i", VIDEODB_ID_TITLE, idMovie);
2423 m_pDS->exec(strSQL.c_str());
2427 CStdString strPath, strFileName;
2428 SplitPath(strFilenameAndPath,strPath,strFileName);
2429 InvalidatePathHash(strPath);
2430 CommitTransaction();
2433 AnnounceRemove("movie", idMovie);
2437 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
2441 void CVideoDatabase::DeleteTvShow(const CStdString& strPath, bool bKeepId /* = false */, bool bKeepThumb /* = false */)
2446 if (NULL == m_pDB.get()) return ;
2447 if (NULL == m_pDS.get()) return ;
2448 idTvShow = GetTvShowId(strPath);
2456 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);
2457 m_pDS2->query(strSQL.c_str());
2458 while (!m_pDS2->eof())
2460 CStdString strFilenameAndPath;
2461 CStdString strPath = m_pDS2->fv("path.strPath").get_asString();
2462 CStdString strFileName = m_pDS2->fv("files.strFilename").get_asString();
2463 ConstructPath(strFilenameAndPath, strPath, strFileName);
2464 DeleteEpisode(strFilenameAndPath, m_pDS2->fv(0).get_asInt(), bKeepId);
2468 strSQL=PrepareSQL("delete from genrelinktvshow where idShow=%i", idTvShow);
2469 m_pDS->exec(strSQL.c_str());
2471 strSQL=PrepareSQL("delete from actorlinktvshow where idShow=%i", idTvShow);
2472 m_pDS->exec(strSQL.c_str());
2474 strSQL=PrepareSQL("delete from directorlinktvshow where idShow=%i", idTvShow);
2475 m_pDS->exec(strSQL.c_str());
2477 strSQL=PrepareSQL("delete from tvshowlinkpath where idShow=%i", idTvShow);
2478 m_pDS->exec(strSQL.c_str());
2480 strSQL=PrepareSQL("delete from studiolinktvshow where idShow=%i", idTvShow);
2481 m_pDS->exec(strSQL.c_str());
2484 DeleteThumbForItem(strPath,true);
2486 // keep tvshow table and movielink table so we can update data in place
2489 strSQL=PrepareSQL("delete from tvshow where idShow=%i", idTvShow);
2490 m_pDS->exec(strSQL.c_str());
2492 strSQL=PrepareSQL("delete from movielinktvshow where idShow=%i", idTvShow);
2493 m_pDS->exec(strSQL.c_str());
2496 InvalidatePathHash(strPath);
2498 CommitTransaction();
2501 AnnounceRemove("tvshow", idTvShow);
2505 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strPath.c_str());
2509 void CVideoDatabase::DeleteEpisode(const CStdString& strFilenameAndPath, int idEpisode, bool bKeepId /* = false */, bool bKeepThumb /* = false */)
2513 if (NULL == m_pDB.get()) return ;
2514 if (NULL == m_pDS.get()) return ;
2517 idEpisode = GetEpisodeId(strFilenameAndPath);
2525 strSQL=PrepareSQL("delete from actorlinkepisode where idEpisode=%i", idEpisode);
2526 m_pDS->exec(strSQL.c_str());
2528 strSQL=PrepareSQL("delete from directorlinkepisode where idEpisode=%i", idEpisode);
2529 m_pDS->exec(strSQL.c_str());
2531 strSQL=PrepareSQL("select tvshowlinkepisode.idShow from tvshowlinkepisode where idEpisode=%i",idEpisode);
2532 m_pDS->query(strSQL.c_str());
2534 strSQL=PrepareSQL("delete from tvshowlinkepisode where idEpisode=%i", idEpisode);
2535 m_pDS->exec(strSQL.c_str());
2538 DeleteThumbForItem(strFilenameAndPath, false, idEpisode);
2540 DeleteStreamDetails(GetFileId(strFilenameAndPath));
2542 // keep episode table entry and bookmarks so we can update the data in place
2543 // the ancilliary tables are still purged
2546 ClearBookMarksOfFile(strFilenameAndPath);
2548 strSQL=PrepareSQL("delete from episode where idEpisode=%i", idEpisode);
2549 m_pDS->exec(strSQL.c_str());
2553 AnnounceRemove("episode", idEpisode);
2557 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
2561 void CVideoDatabase::DeleteMusicVideo(const CStdString& strFilenameAndPath, bool bKeepId /* = false */, bool bKeepThumb /* = false */)
2565 if (NULL == m_pDB.get()) return ;
2566 if (NULL == m_pDS.get()) return ;
2567 int idMVideo = GetMusicVideoId(strFilenameAndPath);
2576 strSQL=PrepareSQL("delete from genrelinkmusicvideo where idMVideo=%i", idMVideo);
2577 m_pDS->exec(strSQL.c_str());
2579 strSQL=PrepareSQL("delete from artistlinkmusicvideo where idMVideo=%i", idMVideo);
2580 m_pDS->exec(strSQL.c_str());
2582 strSQL=PrepareSQL("delete from directorlinkmusicvideo where idMVideo=%i", idMVideo);
2583 m_pDS->exec(strSQL.c_str());
2585 strSQL=PrepareSQL("delete from studiolinkmusicvideo where idMVideo=%i", idMVideo);
2586 m_pDS->exec(strSQL.c_str());
2589 DeleteThumbForItem(strFilenameAndPath,false);
2591 DeleteStreamDetails(GetFileId(strFilenameAndPath));
2593 // keep the music video table entry and bookmarks so we can update data in place
2594 // the ancilliary tables are still purged
2597 ClearBookMarksOfFile(strFilenameAndPath);
2599 strSQL=PrepareSQL("delete from musicvideo where idMVideo=%i", idMVideo);
2600 m_pDS->exec(strSQL.c_str());
2607 strSQL=PrepareSQL("update musicvideo set c%02d=NULL where idMVideo=%i", VIDEODB_ID_MUSICVIDEO_TITLE, idMVideo);
2608 m_pDS->exec(strSQL.c_str());
2612 CStdString strPath, strFileName;
2613 SplitPath(strFilenameAndPath,strPath,strFileName);
2614 InvalidatePathHash(strPath);
2615 CommitTransaction();
2618 AnnounceRemove("musicvideo", idMVideo);
2622 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
2626 void CVideoDatabase::DeleteStreamDetails(int idFile)
2628 m_pDS->exec(PrepareSQL("delete from streamdetails where idFile=%i", idFile));
2631 void CVideoDatabase::DeleteSet(int idSet)
2635 if (NULL == m_pDB.get()) return ;
2636 if (NULL == m_pDS.get()) return ;
2639 strSQL=PrepareSQL("delete from sets where idSet=%i", idSet);
2640 m_pDS->exec(strSQL.c_str());
2641 strSQL=PrepareSQL("delete from setlinkmovie where idSet=%i", idSet);
2642 m_pDS->exec(strSQL.c_str());
2646 CLog::Log(LOGERROR, "%s (%i) failed", __FUNCTION__, idSet);
2650 void CVideoDatabase::GetDetailsFromDB(auto_ptr<Dataset> &pDS, int min, int max, const SDbTableOffsets *offsets, CVideoInfoTag &details, int idxOffset)
2652 for (int i = min + 1; i < max; i++)
2654 switch (offsets[i].type)
2656 case VIDEODB_TYPE_STRING:
2657 *(CStdString*)(((char*)&details)+offsets[i].offset) = pDS->fv(i+idxOffset).get_asString();
2659 case VIDEODB_TYPE_INT:
2660 case VIDEODB_TYPE_COUNT:
2661 *(int*)(((char*)&details)+offsets[i].offset) = pDS->fv(i+idxOffset).get_asInt();
2663 case VIDEODB_TYPE_BOOL:
2664 *(bool*)(((char*)&details)+offsets[i].offset) = pDS->fv(i+idxOffset).get_asBool();
2666 case VIDEODB_TYPE_FLOAT:
2667 *(float*)(((char*)&details)+offsets[i].offset) = pDS->fv(i+idxOffset).get_asFloat();
2673 DWORD movieTime = 0;
2676 CVideoInfoTag CVideoDatabase::GetDetailsByTypeAndId(VIDEODB_CONTENT_TYPE type, int id)
2678 CVideoInfoTag details;
2683 case VIDEODB_CONTENT_MOVIES:
2684 GetMovieInfo("", details, id);
2686 case VIDEODB_CONTENT_TVSHOWS:
2687 GetTvShowInfo("", details, id);
2689 case VIDEODB_CONTENT_EPISODES:
2690 GetEpisodeInfo("", details, id);
2692 case VIDEODB_CONTENT_MUSICVIDEOS:
2693 GetMusicVideoInfo("", details, id);
2701 bool CVideoDatabase::GetStreamDetails(CVideoInfoTag& tag) const
2703 if (tag.m_iFileId < 0)
2706 bool retVal = false;
2708 dbiplus::Dataset *pDS = m_pDB->CreateDataset();
2709 CStdString strSQL = PrepareSQL("SELECT * FROM streamdetails WHERE idFile = %i", tag.m_iFileId);
2712 CStreamDetails& details = tag.m_streamDetails;
2716 CStreamDetail::StreamType e = (CStreamDetail::StreamType)pDS->fv(1).get_asInt();
2719 case CStreamDetail::VIDEO:
2721 CStreamDetailVideo *p = new CStreamDetailVideo();
2722 p->m_strCodec = pDS->fv(2).get_asString();
2723 p->m_fAspect = pDS->fv(3).get_asFloat();
2724 p->m_iWidth = pDS->fv(4).get_asInt();
2725 p->m_iHeight = pDS->fv(5).get_asInt();
2726 p->m_iDuration = pDS->fv(10).get_asInt();
2727 details.AddStream(p);
2731 case CStreamDetail::AUDIO:
2733 CStreamDetailAudio *p = new CStreamDetailAudio();
2734 p->m_strCodec = pDS->fv(6).get_asString();
2735 if (pDS->fv(7).get_isNull())
2736 p->m_iChannels = -1;
2738 p->m_iChannels = pDS->fv(7).get_asInt();
2739 p->m_strLanguage = pDS->fv(8).get_asString();
2740 details.AddStream(p);
2744 case CStreamDetail::SUBTITLE:
2746 CStreamDetailSubtitle *p = new CStreamDetailSubtitle();
2747 p->m_strLanguage = pDS->fv(9).get_asString();
2748 details.AddStream(p);
2758 details.DetermineBestStreams();
2760 if (details.GetVideoDuration() > 0)
2761 tag.m_strRuntime.Format("%i", details.GetVideoDuration() / 60 );
2766 CVideoInfoTag CVideoDatabase::GetDetailsForMovie(auto_ptr<Dataset> &pDS, bool needsCast /* = false */)
2768 CVideoInfoTag details;
2771 DWORD time = CTimeUtils::GetTimeMS();
2772 int idMovie = pDS->fv(0).get_asInt();
2774 GetDetailsFromDB(pDS, VIDEODB_ID_MIN, VIDEODB_ID_MAX, DbMovieOffsets, details);
2776 details.m_iDbId = idMovie;
2777 GetCommonDetails(pDS, details);
2778 movieTime += CTimeUtils::GetTimeMS() - time; time = CTimeUtils::GetTimeMS();
2780 GetStreamDetails(details);
2784 // create cast string
2785 CStdString strSQL = PrepareSQL("SELECT actors.strActor,actorlinkmovie.strRole,actors.strThumb FROM actorlinkmovie,actors WHERE actorlinkmovie.idMovie=%i AND actorlinkmovie.idActor=actors.idActor ORDER BY actorlinkmovie.iOrder",idMovie);
2786 m_pDS2->query(strSQL.c_str());
2787 while (!m_pDS2->eof())
2790 info.strName = m_pDS2->fv("actors.strActor").get_asString();
2791 info.strRole = m_pDS2->fv("actorlinkmovie.strRole").get_asString();
2792 info.thumbUrl.ParseString(m_pDS2->fv("actors.strThumb").get_asString());
2793 details.m_cast.push_back(info);
2796 castTime += CTimeUtils::GetTimeMS() - time; time = CTimeUtils::GetTimeMS();
2797 details.m_strPictureURL.Parse();
2799 // create sets string
2800 strSQL = PrepareSQL("SELECT sets.strSet FROM sets,setlinkmovie WHERE setlinkmovie.idMovie=%i AND setlinkmovie.idSet=sets.idSet ORDER BY sets.idSet",idMovie);
2801 m_pDS2->query(strSQL.c_str());
2802 while (!m_pDS2->eof())
2804 CStdString setName = m_pDS2->fv("sets.strSet").get_asString();
2805 if (!details.m_strSet.IsEmpty())
2806 details.m_strSet += g_advancedSettings.m_videoItemSeparator;
2807 details.m_strSet += setName;
2811 // create tvshowlink string
2813 GetLinksToTvShow(idMovie,links);
2814 for (unsigned int i=0;i<links.size();++i)
2816 strSQL = PrepareSQL("select c%02d from tvshow where idShow=%i",
2817 VIDEODB_ID_TV_TITLE,links[i]);
2818 m_pDS2->query(strSQL.c_str());
2821 if (!details.m_strShowLink.IsEmpty())
2822 details.m_strShowLink += g_advancedSettings.m_videoItemSeparator;
2823 details.m_strShowLink += m_pDS2->fv(0).get_asString();
2831 CVideoInfoTag CVideoDatabase::GetDetailsForTvShow(auto_ptr<Dataset> &pDS, bool needsCast /* = false */)
2833 CVideoInfoTag details;
2836 DWORD time = CTimeUtils::GetTimeMS();
2837 int idTvShow = pDS->fv(0).get_asInt();
2839 GetDetailsFromDB(pDS, VIDEODB_ID_TV_MIN, VIDEODB_ID_TV_MAX, DbTvShowOffsets, details, 1);
2840 details.m_iDbId = idTvShow;
2841 details.m_strPath = pDS->fv(VIDEODB_DETAILS_TVSHOW_PATH).get_asString();
2842 details.m_iEpisode = m_pDS->fv(VIDEODB_DETAILS_TVSHOW_NUM_EPISODES).get_asInt();
2843 details.m_playCount = m_pDS->fv(VIDEODB_DETAILS_TVSHOW_NUM_WATCHED).get_asInt();
2844 details.m_strShowTitle = details.m_strTitle;
2846 movieTime += CTimeUtils::GetTimeMS() - time; time = CTimeUtils::GetTimeMS();
2850 // create cast string
2851 CStdString strSQL = PrepareSQL("select actors.strActor,actorlinktvshow.strRole,actors.strThumb from actorlinktvshow,actors where actorlinktvshow.idShow=%i and actorlinktvshow.idActor = actors.idActor ORDER BY actorlinktvshow.iOrder",idTvShow);
2852 m_pDS2->query(strSQL.c_str());
2853 while (!m_pDS2->eof())
2856 info.strName = m_pDS2->fv("actors.strActor").get_asString();
2857 info.strRole = m_pDS2->fv("actorlinktvshow.strRole").get_asString();
2858 info.thumbUrl.ParseString(m_pDS2->fv("actors.strThumb").get_asString());
2859 details.m_cast.push_back(info);
2862 castTime += CTimeUtils::GetTimeMS() - time; time = CTimeUtils::GetTimeMS();
2863 details.m_strPictureURL.Parse();
2868 CVideoInfoTag CVideoDatabase::GetDetailsForEpisode(auto_ptr<Dataset> &pDS, bool needsCast /* = false */)
2870 CVideoInfoTag details;
2873 DWORD time = CTimeUtils::GetTimeMS();
2874 int idEpisode = pDS->fv(0).get_asInt();
2876 GetDetailsFromDB(pDS, VIDEODB_ID_EPISODE_MIN, VIDEODB_ID_EPISODE_MAX, DbEpisodeOffsets, details);
2877 details.m_iDbId = idEpisode;
2878 GetCommonDetails(pDS, details);
2879 movieTime += CTimeUtils::GetTimeMS() - time; time = CTimeUtils::GetTimeMS();
2881 details.m_strMPAARating = pDS->fv(VIDEODB_DETAILS_EPISODE_TVSHOW_MPAA).get_asString();
2882 details.m_strShowTitle = pDS->fv(VIDEODB_DETAILS_EPISODE_TVSHOW_NAME).get_asString();
2883 details.m_strStudio = pDS->fv(VIDEODB_DETAILS_EPISODE_TVSHOW_STUDIO).get_asString();
2884 details.m_strPremiered = pDS->fv(VIDEODB_DETAILS_EPISODE_TVSHOW_AIRED).get_asString();
2886 GetStreamDetails(details);
2891 set<int>::iterator it;
2893 // create cast string
2894 CStdString strSQL = PrepareSQL("select actors.idActor,actors.strActor,actorlinkepisode.strRole,actors.strThumb from actorlinkepisode,actors where actorlinkepisode.idEpisode=%i and actorlinkepisode.idActor = actors.idActor ORDER BY actorlinkepisode.iOrder",idEpisode);
2895 m_pDS2->query(strSQL.c_str());
2896 bool showCast=false;
2897 while (!m_pDS2->eof() || !showCast)
2901 int idActor = m_pDS2->fv("actors.idActor").get_asInt();
2902 it = actors.find(idActor);
2904 if (it == actors.end())
2907 info.strName = m_pDS2->fv("actors.strActor").get_asString();
2908 info.strRole = m_pDS2->fv("actorlinkepisode.strRole").get_asString();
2909 info.thumbUrl.ParseString(m_pDS2->fv("actors.strThumb").get_asString());
2910 details.m_cast.push_back(info);
2911 actors.insert(idActor);
2915 if (m_pDS2->eof() && !showCast)
2918 int idShow = GetTvShowForEpisode(details.m_iDbId);
2921 strSQL = PrepareSQL("select actors.idActor,actors.strActor,actorlinktvshow.strRole,actors.strThumb from actorlinktvshow,actors where actorlinktvshow.idShow=%i and actorlinktvshow.idActor = actors.idActor ORDER BY actorlinktvshow.iOrder",idShow);
2922 m_pDS2->query(strSQL.c_str());
2926 castTime += CTimeUtils::GetTimeMS() - time; time = CTimeUtils::GetTimeMS();
2927 details.m_strPictureURL.Parse();
2928 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);
2929 m_pDS2->query(strSQL.c_str());
2931 details.m_fEpBookmark = m_pDS2->fv("bookmark.timeInSeconds").get_asFloat();
2937 CVideoInfoTag CVideoDatabase::GetDetailsForMusicVideo(auto_ptr<Dataset> &pDS)
2939 CVideoInfoTag details;
2942 DWORD time = CTimeUtils::GetTimeMS();
2943 int idMovie = pDS->fv(0).get_asInt();
2945 GetDetailsFromDB(pDS, VIDEODB_ID_MUSICVIDEO_MIN, VIDEODB_ID_MUSICVIDEO_MAX, DbMusicVideoOffsets, details);
2946 details.m_iDbId = idMovie;
2947 GetCommonDetails(pDS, details);
2948 movieTime += CTimeUtils::GetTimeMS() - time; time = CTimeUtils::GetTimeMS();
2950 GetStreamDetails(details);
2952 details.m_strPictureURL.Parse();
2956 void CVideoDatabase::GetCommonDetails(auto_ptr<Dataset> &pDS, CVideoInfoTag &details)
2958 details.m_iFileId = pDS->fv(VIDEODB_DETAILS_FILEID).get_asInt();
2959 details.m_strPath = pDS->fv(VIDEODB_DETAILS_PATH).get_asString();
2960 CStdString strFileName = pDS->fv(VIDEODB_DETAILS_FILE).get_asString();
2961 ConstructPath(details.m_strFileNameAndPath,details.m_strPath,strFileName);
2962 details.m_playCount = pDS->fv(VIDEODB_DETAILS_PLAYCOUNT).get_asInt();
2963 details.m_lastPlayed = pDS->fv(VIDEODB_DETAILS_LASTPLAYED).get_asString();
2966 /// \brief GetVideoSettings() obtains any saved video settings for the current file.
2967 /// \retval Returns true if the settings exist, false otherwise.
2968 bool CVideoDatabase::GetVideoSettings(const CStdString &strFilenameAndPath, CVideoSettings &settings)
2972 // obtain the FileID (if it exists)
2973 #ifdef NEW_VIDEODB_METHODS
2974 if (NULL == m_pDB.get()) return false;
2975 if (NULL == m_pDS.get()) return false;
2976 CStdString strPath, strFileName;
2977 URIUtils::Split(strFilenameAndPath, strPath, strFileName);
2978 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());
2980 int idFile = GetFileId(strFilenameAndPath);
2981 if (idFile < 0) return false;
2982 if (NULL == m_pDB.get()) return false;
2983 if (NULL == m_pDS.get()) return false;
2984 // ok, now obtain the settings for this file
2985 CStdString strSQL=PrepareSQL("select * from settings where settings.idFile = '%i'", idFile);
2987 m_pDS->query( strSQL.c_str() );
2988 if (m_pDS->num_rows() > 0)
2989 { // get the video settings info
2990 settings.m_AudioDelay = m_pDS->fv("AudioDelay").get_asFloat();
2991 settings.m_AudioStream = m_pDS->fv("AudioStream").get_asInt();
2992 settings.m_Brightness = m_pDS->fv("Brightness").get_asFloat();
2993 settings.m_Contrast = m_pDS->fv("Contrast").get_asFloat();
2994 settings.m_CustomPixelRatio = m_pDS->fv("PixelRatio").get_asFloat();
2995 settings.m_CustomNonLinStretch = m_pDS->fv("NonLinStretch").get_asBool();
2996 settings.m_NoiseReduction = m_pDS->fv("NoiseReduction").get_asFloat();
2997 settings.m_PostProcess = m_pDS->fv("PostProcess").get_asBool();
2998 settings.m_Sharpness = m_pDS->fv("Sharpness").get_asFloat();
2999 settings.m_CustomZoomAmount = m_pDS->fv("ZoomAmount").get_asFloat();
3000 settings.m_CustomVerticalShift = m_pDS->fv("VerticalShift").get_asFloat();
3001 settings.m_Gamma = m_pDS->fv("Gamma").get_asFloat();
3002 settings.m_SubtitleDelay = m_pDS->fv("SubtitleDelay").get_asFloat();
3003 settings.m_SubtitleOn = m_pDS->fv("SubtitlesOn").get_asBool();
3004 settings.m_SubtitleStream = m_pDS->fv("SubtitleStream").get_asInt();
3005 settings.m_ViewMode = m_pDS->fv("ViewMode").get_asInt();
3006 settings.m_ResumeTime = m_pDS->fv("ResumeTime").get_asInt();
3007 settings.m_Crop = m_pDS->fv("Crop").get_asBool();
3008 settings.m_CropLeft = m_pDS->fv("CropLeft").get_asInt();
3009 settings.m_CropRight = m_pDS->fv("CropRight").get_asInt();
3010 settings.m_CropTop = m_pDS->fv("CropTop").get_asInt();
3011 settings.m_CropBottom = m_pDS->fv("CropBottom").get_asInt();
3012 settings.m_InterlaceMethod = (EINTERLACEMETHOD)m_pDS->fv("Deinterlace").get_asInt();
3013 settings.m_VolumeAmplification = m_pDS->fv("VolumeAmplification").get_asFloat();
3014 settings.m_OutputToAllSpeakers = m_pDS->fv("OutputToAllSpeakers").get_asBool();
3015 settings.m_ScalingMethod = (ESCALINGMETHOD)m_pDS->fv("ScalingMethod").get_asInt();
3016 settings.m_SubtitleCached = false;
3024 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
3029 /// \brief Sets the settings for a particular video file
3030 void CVideoDatabase::SetVideoSettings(const CStdString& strFilenameAndPath, const CVideoSettings &setting)
3034 if (NULL == m_pDB.get()) return ;
3035 if (NULL == m_pDS.get()) return ;
3036 int idFile = AddFile(strFilenameAndPath);
3040 strSQL.Format("select * from settings where idFile=%i", idFile);
3041 m_pDS->query( strSQL.c_str() );
3042 if (m_pDS->num_rows() > 0)
3046 strSQL=PrepareSQL("update settings set Deinterlace=%i,ViewMode=%i,ZoomAmount=%f,PixelRatio=%f,VerticalShift=%f,"
3047 "AudioStream=%i,SubtitleStream=%i,SubtitleDelay=%f,SubtitlesOn=%i,Brightness=%f,Contrast=%f,Gamma=%f,"
3048 "VolumeAmplification=%f,AudioDelay=%f,OutputToAllSpeakers=%i,Sharpness=%f,NoiseReduction=%f,NonLinStretch=%i,PostProcess=%i,ScalingMethod=%i,",
3049 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,
3051 setting.m_Brightness, setting.m_Contrast, setting.m_Gamma, setting.m_VolumeAmplification, setting.m_AudioDelay,
3052 setting.m_OutputToAllSpeakers,setting.m_Sharpness,setting.m_NoiseReduction,setting.m_CustomNonLinStretch,setting.m_PostProcess,setting.m_ScalingMethod);
3054 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);
3056 m_pDS->exec(strSQL.c_str());
3062 strSQL= "INSERT INTO settings (idFile,Deinterlace,ViewMode,ZoomAmount,PixelRatio, VerticalShift, "
3063 "AudioStream,SubtitleStream,SubtitleDelay,SubtitlesOn,Brightness,"
3064 "Contrast,Gamma,VolumeAmplification,AudioDelay,OutputToAllSpeakers,"
3065 "ResumeTime,Crop,CropLeft,CropRight,CropTop,CropBottom,"
3066 "Sharpness,NoiseReduction,NonLinStretch,PostProcess,ScalingMethod) "
3068 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,%i)",
3069 idFile, setting.m_InterlaceMethod, setting.m_ViewMode, setting.m_CustomZoomAmount, setting.m_CustomPixelRatio, setting.m_CustomVerticalShift,
3070 setting.m_AudioStream, setting.m_SubtitleStream, setting.m_SubtitleDelay, setting.m_SubtitleOn, setting.m_Brightness,
3071 setting.m_Contrast, setting.m_Gamma, setting.m_VolumeAmplification, setting.m_AudioDelay, setting.m_OutputToAllSpeakers,
3072 setting.m_ResumeTime, setting.m_Crop, setting.m_CropLeft, setting.m_CropRight, setting.m_CropTop, setting.m_CropBottom,
3073 setting.m_Sharpness, setting.m_NoiseReduction, setting.m_CustomNonLinStretch, setting.m_PostProcess, setting.m_ScalingMethod);
3074 m_pDS->exec(strSQL.c_str());
3079 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strFilenameAndPath.c_str());
3083 /// \brief GetStackTimes() obtains any saved video times for the stacked file
3084 /// \retval Returns true if the stack times exist, false otherwise.
3085 bool CVideoDatabase::GetStackTimes(const CStdString &filePath, vector<int> ×)
3089 // obtain the FileID (if it exists)
3090 int idFile = GetFileId(filePath);
3091 if (idFile < 0) return false;
3092 if (NULL == m_pDB.get()) return false;
3093 if (NULL == m_pDS.get()) return false;
3094 // ok, now obtain the settings for this file
3095 CStdString strSQL=PrepareSQL("select times from stacktimes where idFile=%i\n", idFile);
3096 m_pDS->query( strSQL.c_str() );
3097 if (m_pDS->num_rows() > 0)
3098 { // get the video settings info
3099 CStdStringArray timeString;
3101 StringUtils::SplitString(m_pDS->fv("times").get_asString(), ",", timeString);
3103 for (unsigned int i = 0; i < timeString.size(); i++)
3105 times.push_back(atoi(timeString[i].c_str()));
3106 timeTotal += atoi(timeString[i].c_str());
3109 return (timeTotal > 0);
3115 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
3120 /// \brief Sets the stack times for a particular video file
3121 void CVideoDatabase::SetStackTimes(const CStdString& filePath, vector<int> ×)
3125 if (NULL == m_pDB.get()) return ;
3126 if (NULL == m_pDS.get()) return ;
3127 int idFile = AddFile(filePath);
3131 // delete any existing items
3132 m_pDS->exec( PrepareSQL("delete from stacktimes where idFile=%i", idFile) );
3135 CStdString timeString;
3136 timeString.Format("%i", times[0]);
3137 for (unsigned int i = 1; i < times.size(); i++)
3140 time.Format(",%i", times[i]);
3143 m_pDS->exec( PrepareSQL("insert into stacktimes (idFile,times) values (%i,'%s')\n", idFile, timeString.c_str()) );
3147 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, filePath.c_str());
3151 void CVideoDatabase::RemoveContentForPath(const CStdString& strPath, CGUIDialogProgress *progress /* = NULL */)
3153 if(URIUtils::IsMultiPath(strPath))
3155 vector<CStdString> paths;
3156 CMultiPathDirectory::GetPaths(strPath, paths);
3158 for(unsigned i=0;i<paths.size();i++)
3159 RemoveContentForPath(paths[i], progress);
3164 if (NULL == m_pDB.get()) return ;
3165 if (NULL == m_pDS.get()) return ;
3167 auto_ptr<Dataset> pDS(m_pDB->CreateDataset());
3168 CStdString strPath1(strPath);
3169 CStdString strSQL = PrepareSQL("select idPath,strContent,strPath from path where strPath like '%%%s%%'",strPath1.c_str());
3170 progress = (CGUIDialogProgress *)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
3171 pDS->query(strSQL.c_str());
3174 progress->SetHeading(700);
3175 progress->SetLine(0, "");
3176 progress->SetLine(1, 313);
3177 progress->SetLine(2, 330);
3178 progress->SetPercentage(0);
3179 progress->StartModal();
3180 progress->ShowProgressBar(true);
3183 int iMax = pDS->num_rows();
3186 bool bMvidsChecked=false;
3189 progress->SetPercentage((int)((float)(iCurr++)/iMax*100.f));
3190 progress->Progress();
3192 int idPath = pDS->fv("path.idPath").get_asInt();
3193 CStdString strCurrPath = pDS->fv("path.strPath").get_asString();
3194 if (HasTvShowInfo(strCurrPath))
3195 DeleteTvShow(strCurrPath);
3198 strSQL=PrepareSQL("select files.strFilename from files join movie on movie.idFile=files.idFile where files.idPath=%i",idPath);
3199 m_pDS2->query(strSQL.c_str());
3202 strSQL=PrepareSQL("select files.strFilename from files join musicvideo on musicvideo.idFile=files.idFile where files.idPath=%i",idPath);
3203 m_pDS2->query(strSQL.c_str());
3204 bMvidsChecked = true;
3206 while (!m_pDS2->eof())
3208 CStdString strMoviePath;
3209 CStdString strFileName = m_pDS2->fv("files.strFilename").get_asString();
3210 ConstructPath(strMoviePath, strCurrPath, strFileName);
3211 if (HasMovieInfo(strMoviePath))
3212 DeleteMovie(strMoviePath);
3213 if (HasMusicVideoInfo(strMoviePath))
3214 DeleteMusicVideo(strMoviePath);
3216 if (m_pDS2->eof() && !bMvidsChecked)
3218 strSQL=PrepareSQL("select files.strFilename from files join musicvideo on musicvideo.idFile=files.idFile where files.idPath=%i",idPath);
3219 m_pDS2->query(strSQL.c_str());
3220 bMvidsChecked = true;
3227 strSQL = PrepareSQL("update path set strContent = '', strScraper='', strHash='',strSettings='',useFolderNames=0,scanRecursive=0 where strPath like '%%%s%%'",strPath1.c_str());
3228 pDS->exec(strSQL.c_str());
3232 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strPath.c_str());
3238 void CVideoDatabase::SetScraperForPath(const CStdString& filePath, const ScraperPtr& scraper, const VIDEO::SScanSettings& settings)
3240 // if we have a multipath, set scraper for all contained paths too
3241 if(URIUtils::IsMultiPath(filePath))
3243 vector<CStdString> paths;
3244 CMultiPathDirectory::GetPaths(filePath, paths);
3246 for(unsigned i=0;i<paths.size();i++)
3247 SetScraperForPath(paths[i],scraper,settings);
3252 if (NULL == m_pDB.get()) return ;
3253 if (NULL == m_pDS.get()) return ;
3254 int idPath = GetPathId(filePath);
3256 { // no path found - we have to add one
3257 idPath = AddPath(filePath);
3258 if (idPath < 0) return ;
3263 if (settings.exclude)
3264 { //NB See note in ::GetScraperForPath about strContent=='none'
3265 strSQL=PrepareSQL("update path set strContent='', strScraper='', scanRecursive=0, useFolderNames=0, strSettings='', noUpdate=0 , exclude=1 where idPath=%i", idPath);
3268 { // catch clearing content, but not excluding
3269 strSQL=PrepareSQL("update path set strContent='', strScraper='', scanRecursive=0, useFolderNames=0, strSettings='', noUpdate=0, exclude=0 where idPath=%i", idPath);
3273 CStdString content = TranslateContent(scraper->Content());
3274 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);
3276 m_pDS->exec(strSQL.c_str());
3280 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, filePath.c_str());
3284 bool CVideoDatabase::ScraperInUse(const CStdString &scraperID) const
3288 if (NULL == m_pDB.get()) return false;
3289 if (NULL == m_pDS.get()) return false;
3291 CStdString sql = PrepareSQL("select count(1) from path where strScraper='%s'", scraperID.c_str());
3292 if (!m_pDS->query(sql.c_str()) || m_pDS->num_rows() == 0)
3294 bool found = m_pDS->fv(0).get_asInt() > 0;
3300 CLog::Log(LOGERROR, "%s(%s) failed", __FUNCTION__, scraperID.c_str());
3305 bool CVideoDatabase::UpdateOldVersion(int iVersion)
3313 m_pDS->exec("alter table settings add NonLinStretch bool");
3317 m_pDS->exec("alter table path add exclude bool");
3322 CStdString columnsSelect, columns;
3323 for (int i = 0; i < 21; i++)
3326 column.Format(",c%02d", i);
3327 columnsSelect += column;
3328 columns += column + " text";
3332 m_pDS->exec(PrepareSQL("CREATE TABLE movienew ( idMovie integer primary key, idFile integer%s)", columns.c_str()));
3333 m_pDS->exec(PrepareSQL("INSERT INTO movienew select idMovie,idFile%s from movie", columnsSelect.c_str()));
3334 m_pDS->exec("DROP TABLE movie");
3335 m_pDS->exec("ALTER TABLE movienew RENAME TO movie");
3337 m_pDS->exec("CREATE UNIQUE INDEX ix_movie_file_1 ON movie (idFile, idMovie)");
3338 m_pDS->exec("CREATE UNIQUE INDEX ix_movie_file_2 ON movie (idMovie, idFile)");
3341 m_pDS->exec(PrepareSQL("CREATE TABLE episodenew ( idEpisode integer primary key, idFile integer%s)", columns.c_str()));
3342 m_pDS->exec(PrepareSQL("INSERT INTO episodenew select idEpisode,idFile%s from episode", columnsSelect.c_str()));
3343 m_pDS->exec("DROP TABLE episode");
3344 m_pDS->exec("ALTER TABLE episodenew RENAME TO episode");
3346 m_pDS->exec("CREATE UNIQUE INDEX ix_episode_file_1 on episode (idEpisode, idFile)");
3347 m_pDS->exec("CREATE UNIQUE INDEX id_episode_file_2 on episode (idFile, idEpisode)");
3348 m_pDS->exec(PrepareSQL("CREATE INDEX ix_episode_season_episode on episode (c%02d, c%02d)", VIDEODB_ID_EPISODE_SEASON, VIDEODB_ID_EPISODE_EPISODE));
3349 m_pDS->exec(PrepareSQL("CREATE INDEX ix_episode_bookmark on episode (c%02d)", VIDEODB_ID_EPISODE_BOOKMARK));
3352 m_pDS->exec(PrepareSQL("CREATE TABLE musicvideonew ( idMVideo integer primary key, idFile integer%s)", columns.c_str()));
3353 m_pDS->exec(PrepareSQL("INSERT INTO musicvideonew select idMVideo,idFile%s from musicvideo", columnsSelect.c_str()));
3354 m_pDS->exec("DROP TABLE musicvideo");
3355 m_pDS->exec("ALTER TABLE musicvideonew RENAME TO musicvideo");
3357 m_pDS->exec("CREATE UNIQUE INDEX ix_musicvideo_file_1 on musicvideo (idMVideo, idFile)");
3358 m_pDS->exec("CREATE UNIQUE INDEX ix_musicvideo_file_2 on musicvideo (idFile, idMVideo)");
3362 m_pDS->exec("ALTER table movie add c21 text");
3363 m_pDS->exec("ALTER table episode add c21 text");
3364 m_pDS->exec("ALTER table musicvideo add c21 text");
3365 m_pDS->exec("ALTER table tvshow add c21 text");
3367 CLog::Log(LOGINFO, "create country table");
3368 m_pDS->exec("CREATE TABLE country ( idCountry integer primary key, strCountry text)\n");
3370 CLog::Log(LOGINFO, "create countrylinkmovie table");
3371 m_pDS->exec("CREATE TABLE countrylinkmovie ( idCountry integer, idMovie integer)\n");
3372 m_pDS->exec("CREATE UNIQUE INDEX ix_countrylinkmovie_1 ON countrylinkmovie ( idCountry, idMovie)\n");
3373 m_pDS->exec("CREATE UNIQUE INDEX ix_countrylinkmovie_2 ON countrylinkmovie ( idMovie, idCountry)\n");
3376 { // update for old scrapers
3377 m_pDS->query("select idPath,strScraper from path");
3378 set<CStdString> scrapers;
3379 while (!m_pDS->eof())
3381 // translate the addon
3382 CStdString scraperID = ADDON::UpdateVideoScraper(m_pDS->fv(1).get_asString());
3383 if (!scraperID.IsEmpty())
3385 scrapers.insert(scraperID);
3386 CStdString update = PrepareSQL("update path set strScraper='%s' where idPath=%i", scraperID.c_str(), m_pDS->fv(0).get_asInt());
3387 m_pDS2->exec(update);
3392 // ensure these scrapers are installed
3393 CAddonInstaller::Get().InstallFromXBMCRepo(scrapers);
3397 m_pDS->exec("DELETE FROM streamdetails");
3398 m_pDS->exec("ALTER table streamdetails add iVideoDuration integer");
3402 m_pDS->exec("ALTER table settings add PostProcess bool");
3406 m_pDS->exec("DELETE FROM streamdetails"); //Roll the stream details as changed from minutes to seconds
3410 m_pDS->exec("ALTER table settings add VerticalShift float");
3414 // only if MySQL is used and default character set is not utf8
3415 // string data needs to be converted to proper utf8
3416 CStdString charset = m_pDS->getDatabase()->getDefaultCharset();
3417 if (!m_sqlite && !charset.empty() && charset != "utf8")
3419 map<CStdString, CStdStringArray> tables;
3420 map<CStdString, CStdStringArray>::iterator itt;
3421 CStdStringArray::iterator itc;
3423 // columns that need to be converted
3425 CStdStringArray c_columns;
3426 for (int i = 0; i < 22; i++)
3429 c.Format("c%02d", i);
3430 c_columns.push_back(c);
3433 tables.insert(pair<CStdString, CStdStringArray> ("episode", c_columns));
3434 tables.insert(pair<CStdString, CStdStringArray> ("movie", c_columns));
3435 tables.insert(pair<CStdString, CStdStringArray> ("musicvideo", c_columns));
3436 tables.insert(pair<CStdString, CStdStringArray> ("tvshow", c_columns));
3440 c1.push_back("strRole");
3441 tables.insert(pair<CStdString, CStdStringArray> ("actorlinkepisode", c1));
3442 tables.insert(pair<CStdString, CStdStringArray> ("actorlinkmovie", c1));
3443 tables.insert(pair<CStdString, CStdStringArray> ("actorlinktvshow", c1));
3447 c2.push_back("strActor");
3448 tables.insert(pair<CStdString, CStdStringArray> ("actors", c2));
3451 c3.push_back("strCountry");
3452 tables.insert(pair<CStdString, CStdStringArray> ("country", c3));
3455 c4.push_back("strFilename");
3456 tables.insert(pair<CStdString, CStdStringArray> ("files", c4));
3459 c5.push_back("strGenre");
3460 tables.insert(pair<CStdString, CStdStringArray> ("genre", c5));
3463 c6.push_back("strSet");
3464 tables.insert(pair<CStdString, CStdStringArray> ("sets", c6));
3467 c7.push_back("strStudio");
3468 tables.insert(pair<CStdString, CStdStringArray> ("studio", c7));
3470 for (itt = tables.begin(); itt != tables.end(); ++itt)
3473 q = PrepareSQL("UPDATE `%s` SET", itt->first.c_str());
3474 for (itc = itt->second.begin(); itc != itt->second.end(); ++itc)
3476 q += PrepareSQL(" `%s` = CONVERT(CAST(CONVERT(`%s` USING %s) AS BINARY) USING utf8)",
3477 itc->c_str(), itc->c_str(), charset.c_str());
3478 if (*itc != itt->second.back())
3489 m_pDS->exec("ALTER table movie add c22 text");
3490 m_pDS->exec("ALTER table episode add c22 text");
3491 m_pDS->exec("ALTER table musicvideo add c22 text");
3492 m_pDS->exec("ALTER table tvshow add c22 text");
3493 // Now update our tables
3494 UpdateBasePath("movie", "idMovie", VIDEODB_ID_BASEPATH);
3495 UpdateBasePath("musicvideo", "idMVideo", VIDEODB_ID_MUSICVIDEO_BASEPATH);
3496 UpdateBasePath("episode", "idEpisode", VIDEODB_ID_EPISODE_BASEPATH);
3497 UpdateBasePath("tvshow", "idShow", VIDEODB_ID_TV_BASEPATH, true);
3500 { // add indices for dir entry lookups
3501 m_pDS->exec("CREATE INDEX ixMovieBasePath ON movie ( c22(255) )");
3502 m_pDS->exec("CREATE INDEX ixMusicVideoBasePath ON musicvideo ( c13(255) )");
3503 m_pDS->exec("CREATE INDEX ixEpisodeBasePath ON episode ( c18(255) )");
3504 m_pDS->exec("CREATE INDEX ixTVShowBasePath ON tvshow ( c16(255) )");
3512 m_pDS->exec("ALTER table settings add ScalingMethod integer");
3513 m_pDS->exec(PrepareSQL("UPDATE settings set ScalingMethod=%i", g_settings.m_defaultVideoSettings.m_ScalingMethod));
3517 // Add iOrder fields to actorlink* tables to be able to list
3518 // actors by importance
3519 m_pDS->exec("ALTER TABLE actorlinkmovie ADD iOrder integer");
3520 m_pDS->exec("ALTER TABLE actorlinktvshow ADD iOrder integer");
3521 m_pDS->exec("ALTER TABLE actorlinkepisode ADD iOrder integer");
3526 CLog::Log(LOGERROR, "Error attempting to update the database version!");
3527 RollbackTransaction();
3530 CommitTransaction();
3534 void CVideoDatabase::UpdateBasePath(const char *table, const char *id, int column, bool shows)
3538 query = PrepareSQL("SELECT idShow,path.strPath from tvshowlinkpath join path on tvshowlinkpath.idPath=path.idPath");
3540 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);
3542 map<CStdString, bool> paths;
3543 m_pDS2->query(query.c_str());
3544 while (!m_pDS2->eof())
3546 CStdString path(m_pDS2->fv(1).get_asString());
3547 map<CStdString, bool>::iterator i = paths.find(path);
3548 if (i == paths.end())
3550 SScanSettings settings;
3551 bool foundDirectly = false;
3552 ScraperPtr scraper = GetScraperForPath(path, settings, foundDirectly);
3553 if (scraper && scraper->Content() == CONTENT_TVSHOWS && !shows)
3554 paths.insert(make_pair(path, false)); // episodes
3556 paths.insert(make_pair(path, settings.parent_name_root)); // shows, movies, musicvids
3557 i = paths.find(path);
3559 CStdString filename;
3561 ConstructPath(filename, path, m_pDS2->fv(2).get_asString());
3564 CFileItem item(filename, shows);
3565 path = item.GetBaseMoviePath(i->second);
3566 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());
3567 m_pDS->exec(sql.c_str());
3573 int CVideoDatabase::GetPlayCount(const CFileItem &item)
3575 int id = GetFileId(item);
3577 return 0; // not in db, so not watched
3582 if (NULL == m_pDB.get()) return -1;
3583 if (NULL == m_pDS.get()) return -1;
3585 CStdString strSQL = PrepareSQL("select playCount from files WHERE idFile=%i", id);
3587 if (m_pDS->query(strSQL.c_str()))
3589 // there should only ever be one row returned
3590 if (m_pDS->num_rows() == 1)
3591 count = m_pDS->fv(0).get_asInt();
3598 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
3603 void CVideoDatabase::UpdateFanart(const CFileItem &item, VIDEODB_CONTENT_TYPE type)
3605 if (NULL == m_pDB.get()) return;
3606 if (NULL == m_pDS.get()) return;
3607 if (!item.HasVideoInfoTag() || item.GetVideoInfoTag()->m_iDbId < 0) return;
3610 if (type == VIDEODB_CONTENT_TVSHOWS)
3611 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);
3612 else if (type == VIDEODB_CONTENT_MOVIES)
3613 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);
3617 m_pDS->exec(exec.c_str());
3619 if (type == VIDEODB_CONTENT_TVSHOWS)
3620 AnnounceUpdate("tvshow", item.GetVideoInfoTag()->m_iDbId);
3621 else if (type == VIDEODB_CONTENT_MOVIES)
3622 AnnounceUpdate("movie", item.GetVideoInfoTag()->m_iDbId);
3626 CLog::Log(LOGERROR, "%s - error updating fanart for %s", __FUNCTION__, item.m_strPath.c_str());
3630 void CVideoDatabase::SetPlayCount(const CFileItem &item, int count, const CStdString &date)
3632 int id = AddFile(item);
3636 // and mark as watched
3639 if (NULL == m_pDB.get()) return ;
3640 if (NULL == m_pDS.get()) return ;
3646 strSQL = PrepareSQL("update files set playCount=%i,lastPlayed='%s' where idFile=%i", count, CDateTime::GetCurrentDateTime().GetAsDBDateTime().c_str(), id);
3648 strSQL = PrepareSQL("update files set playCount=%i,lastPlayed='%s' where idFile=%i", count, date.c_str(), id);
3653 strSQL = PrepareSQL("update files set playCount=NULL,lastPlayed=NULL where idFile=%i", id);
3655 strSQL = PrepareSQL("update files set playCount=NULL,lastPlayed='%s' where idFile=%i", date.c_str(), id);
3658 m_pDS->exec(strSQL.c_str());
3661 data["playcount"] = count;
3662 ANNOUNCEMENT::CAnnouncementManager::Announce(ANNOUNCEMENT::Library, "xbmc", "NewPlayCount", CFileItemPtr(new CFileItem(item)), data);
3666 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
3670 void CVideoDatabase::IncrementPlayCount(const CFileItem &item)
3672 SetPlayCount(item, GetPlayCount(item) + 1);
3675 void CVideoDatabase::UpdateLastPlayed(const CFileItem &item)
3677 SetPlayCount(item, GetPlayCount(item), CDateTime::GetCurrentDateTime().GetAsDBDateTime());
3680 void CVideoDatabase::UpdateMovieTitle(int idMovie, const CStdString& strNewMovieTitle, VIDEODB_CONTENT_TYPE iType)
3684 if (NULL == m_pDB.get()) return ;
3685 if (NULL == m_pDS.get()) return ;
3688 if (iType == VIDEODB_CONTENT_MOVIES)
3690 CLog::Log(LOGINFO, "Changing Movie:id:%i New Title:%s", idMovie, strNewMovieTitle.c_str());
3691 strSQL = PrepareSQL("UPDATE movie SET c%02d='%s' WHERE idMovie=%i", VIDEODB_ID_TITLE, strNewMovieTitle.c_str(), idMovie );
3694 else if (iType == VIDEODB_CONTENT_EPISODES)
3696 CLog::Log(LOGINFO, "Changing Episode:id:%i New Title:%s", idMovie, strNewMovieTitle.c_str());
3697 strSQL = PrepareSQL("UPDATE episode SET c%02d='%s' WHERE idEpisode=%i", VIDEODB_ID_EPISODE_TITLE, strNewMovieTitle.c_str(), idMovie );
3698 content = "episode";
3700 else if (iType == VIDEODB_CONTENT_TVSHOWS)
3702 CLog::Log(LOGINFO, "Changing TvShow:id:%i New Title:%s", idMovie, strNewMovieTitle.c_str());
3703 strSQL = PrepareSQL("UPDATE tvshow SET c%02d='%s' WHERE idShow=%i", VIDEODB_ID_TV_TITLE, strNewMovieTitle.c_str(), idMovie );
3706 else if (iType == VIDEODB_CONTENT_MUSICVIDEOS)
3708 CLog::Log(LOGINFO, "Changing MusicVideo:id:%i New Title:%s", idMovie, strNewMovieTitle.c_str());
3709 strSQL = PrepareSQL("UPDATE musicvideo SET c%02d='%s' WHERE idMVideo=%i", VIDEODB_ID_MUSICVIDEO_TITLE, strNewMovieTitle.c_str(), idMovie );
3710 content = "musicvideo";
3712 else if (iType == VIDEODB_CONTENT_MOVIE_SETS)
3714 CLog::Log(LOGINFO, "Changing Movie set:id:%i New Title:%s", idMovie, strNewMovieTitle.c_str());
3715 strSQL = PrepareSQL("UPDATE sets SET strSet='%s' WHERE idSet=%i", strNewMovieTitle.c_str(), idMovie );
3717 m_pDS->exec(strSQL.c_str());
3719 if (content.size() > 0)
3720 AnnounceUpdate(content, idMovie);
3724 CLog::Log(LOGERROR, "%s (int idMovie, const CStdString& strNewMovieTitle) failed on MovieID:%i and Title:%s", __FUNCTION__, idMovie, strNewMovieTitle.c_str());
3728 /// \brief EraseVideoSettings() Erases the videoSettings table and reconstructs it
3729 void CVideoDatabase::EraseVideoSettings()
3733 CLog::Log(LOGINFO, "Deleting settings information for all movies");
3734 m_pDS->exec("delete from settings");
3738 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
3742 bool CVideoDatabase::GetGenresNav(const CStdString& strBaseDir, CFileItemList& items, int idContent)
3744 return GetNavCommon(strBaseDir, items, "genre", idContent);
3747 bool CVideoDatabase::GetCountriesNav(const CStdString& strBaseDir, CFileItemList& items, int idContent)
3749 return GetNavCommon(strBaseDir, items, "country", idContent);
3752 bool CVideoDatabase::GetStudiosNav(const CStdString& strBaseDir, CFileItemList& items, int idContent)
3754 return GetNavCommon(strBaseDir, items, "studio", idContent);
3757 bool CVideoDatabase::GetNavCommon(const CStdString& strBaseDir, CFileItemList& items, const CStdString &type, int idContent)
3761 if (NULL == m_pDB.get()) return false;
3762 if (NULL == m_pDS.get()) return false;
3765 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
3767 if (idContent == VIDEODB_CONTENT_MOVIES)
3768 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",
3769 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());
3770 else if (idContent == VIDEODB_CONTENT_TVSHOWS) //this will not get tvshows with 0 episodes
3771 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",
3772 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());
3773 else if (idContent == VIDEODB_CONTENT_MUSICVIDEOS)
3774 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",
3775 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());
3779 if (idContent == VIDEODB_CONTENT_MOVIES)
3780 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",
3781 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());
3782 else if (idContent == VIDEODB_CONTENT_TVSHOWS)
3783 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",
3784 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());
3785 else if (idContent == VIDEODB_CONTENT_MUSICVIDEOS)
3786 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",
3787 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());
3790 int iRowsFound = RunQuery(strSQL);
3791 if (iRowsFound <= 0)
3792 return iRowsFound == 0;
3794 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
3796 map<int, pair<CStdString,int> > mapItems;
3797 map<int, pair<CStdString,int> >::iterator it;
3798 while (!m_pDS->eof())
3800 int id = m_pDS->fv(0).get_asInt();
3801 CStdString str = m_pDS->fv(1).get_asString();
3803 // was this already found?
3804 it = mapItems.find(id);
3805 if (it == mapItems.end())
3808 if (g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv(2).get_asString()),g_settings.m_videoSources))
3810 if (idContent == VIDEODB_CONTENT_MOVIES || idContent == VIDEODB_CONTENT_MUSICVIDEOS)
3811 mapItems.insert(pair<int, pair<CStdString,int> >(id, pair<CStdString,int>(str,m_pDS->fv(3).get_asInt()))); //fv(3) is file.playCount
3812 else if (idContent == VIDEODB_CONTENT_TVSHOWS)
3813 mapItems.insert(pair<int, pair<CStdString,int> >(id, pair<CStdString,int>(str,0)));
3820 for (it = mapItems.begin(); it != mapItems.end(); ++it)
3822 CFileItemPtr pItem(new CFileItem(it->second.first));
3824 strDir.Format("%ld/", it->first);
3825 pItem->m_strPath = strBaseDir + strDir;
3826 pItem->m_bIsFolder = true;
3827 if (idContent == VIDEODB_CONTENT_MOVIES || idContent == VIDEODB_CONTENT_MUSICVIDEOS)
3828 pItem->GetVideoInfoTag()->m_playCount = it->second.second;
3829 if (!items.Contains(pItem->m_strPath))
3831 pItem->SetLabelPreformated(true);
3838 while (!m_pDS->eof())
3840 CFileItemPtr pItem(new CFileItem(m_pDS->fv(1).get_asString()));
3842 strDir.Format("%ld/", m_pDS->fv(0).get_asInt());
3843 pItem->m_strPath = strBaseDir + strDir;
3844 pItem->m_bIsFolder = true;
3845 pItem->SetLabelPreformated(true);
3846 if (idContent == VIDEODB_CONTENT_MOVIES || idContent == VIDEODB_CONTENT_MUSICVIDEOS)
3847 { // fv(3) is the number of videos watched, fv(2) is the total number. We set the playcount
3848 // only if the number of videos watched is equal to the total number (i.e. every video watched)
3849 pItem->GetVideoInfoTag()->m_playCount = (m_pDS->fv(3).get_asInt() == m_pDS->fv(2).get_asInt()) ? 1 : 0;
3860 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
3865 bool CVideoDatabase::GetSetsNav(const CStdString& strBaseDir, CFileItemList& items, int idContent, const CStdString &where)
3869 if (NULL == m_pDB.get()) return false;
3870 if (NULL == m_pDS.get()) return false;
3872 // get primary sets for movies
3874 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
3876 if (idContent == VIDEODB_CONTENT_MOVIES)
3877 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");
3883 if (idContent == VIDEODB_CONTENT_MOVIES)
3885 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 ");
3886 group = " GROUP BY sets.idSet HAVING c>1";
3892 int iRowsFound = RunQuery(strSQL);
3893 if (iRowsFound <= 0)
3894 return iRowsFound == 0;
3896 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
3898 map<int, pair<CStdString,int> > mapSets;
3899 map<int, pair<CStdString,int> >::iterator it;
3900 while (!m_pDS->eof())
3902 int idSet = m_pDS->fv("sets.idSet").get_asInt();
3903 CStdString strSet = m_pDS->fv("sets.strSet").get_asString();
3904 it = mapSets.find(idSet);
3905 // was this set already found?
3906 if (it == mapSets.end())
3909 if (g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
3911 if (idContent == VIDEODB_CONTENT_MOVIES || idContent == VIDEODB_CONTENT_MUSICVIDEOS)
3912 mapSets.insert(pair<int, pair<CStdString,int> >(idSet, pair<CStdString,int>(strSet,m_pDS->fv(3).get_asInt())));
3914 mapSets.insert(pair<int, pair<CStdString,int> >(idSet, pair<CStdString,int>(strSet,0)));
3921 for (it=mapSets.begin();it != mapSets.end();++it)
3923 CFileItemPtr pItem(new CFileItem(it->second.first));
3925 strDir.Format("%ld/", it->first);
3926 pItem->m_strPath=strBaseDir + strDir;
3927 pItem->m_bIsFolder=true;
3928 if (idContent == VIDEODB_CONTENT_MOVIES || idContent == VIDEODB_CONTENT_MUSICVIDEOS)
3930 pItem->GetVideoInfoTag()->m_playCount = it->second.second;
3931 pItem->GetVideoInfoTag()->m_strTitle = pItem->GetLabel();
3933 if (!items.Contains(pItem->m_strPath))
3935 pItem->SetLabelPreformated(true);
3942 while (!m_pDS->eof())
3944 CFileItemPtr pItem(new CFileItem(m_pDS->fv("sets.strSet").get_asString()));
3946 strDir.Format("%ld/", m_pDS->fv("sets.idSet").get_asInt());
3947 pItem->m_strPath=strBaseDir + strDir;
3948 pItem->m_bIsFolder=true;
3949 pItem->SetLabelPreformated(true);
3950 if (idContent == VIDEODB_CONTENT_MOVIES || idContent==VIDEODB_CONTENT_MUSICVIDEOS)
3952 // fv(3) is the number of videos watched, fv(2) is the total number. We set the playcount
3953 // only if the number of videos watched is equal to the total number (i.e. every video watched)
3954 pItem->GetVideoInfoTag()->m_playCount = (m_pDS->fv(3).get_asInt() == m_pDS->fv(2).get_asInt()) ? 1 : 0;
3955 pItem->GetVideoInfoTag()->m_strTitle = pItem->GetLabel();
3957 bool thumb=false,fanart=false;
3958 if (CFile::Exists(pItem->GetCachedVideoThumb()))
3960 pItem->SetThumbnailImage(pItem->GetCachedVideoThumb());
3963 if (CFile::Exists(pItem->GetCachedFanart()))
3965 pItem->SetProperty("fanart_image",pItem->GetCachedFanart());
3968 if (!thumb || !fanart) // use the first item's thumb
3970 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());
3971 m_pDS2->query(strSQL.c_str());
3975 ConstructPath(path,m_pDS2->fv(0).get_asString(),m_pDS2->fv(1).get_asString());
3976 CFileItem item(path,false);
3977 if (!thumb && CFile::Exists(item.GetCachedVideoThumb()))
3978 pItem->SetThumbnailImage(item.GetCachedVideoThumb());
3979 if (!fanart && CFile::Exists(item.GetCachedFanart()))
3980 pItem->SetProperty("fanart_image",item.GetCachedFanart());
3990 // CLog::Log(LOGDEBUG, "%s Time: %d ms", CTimeUtils::GetTimeMS() - time);
3995 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
4000 bool CVideoDatabase::GetMusicVideoAlbumsNav(const CStdString& strBaseDir, CFileItemList& items, int idArtist)
4004 if (NULL == m_pDB.get()) return false;
4005 if (NULL == m_pDS.get()) return false;
4008 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
4010 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);
4014 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);
4017 strSQL += PrepareSQL(" where artistlinkmusicvideo.idArtist=%i",idArtist);
4019 strSQL += PrepareSQL(" group by musicvideo.c%02d",VIDEODB_ID_MUSICVIDEO_ALBUM);
4021 int iRowsFound = RunQuery(strSQL);
4022 if (iRowsFound <= 0)
4023 return iRowsFound == 0;
4025 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
4027 map<int, pair<CStdString,CStdString> > mapAlbums;
4028 map<int, pair<CStdString,CStdString> >::iterator it;
4029 while (!m_pDS->eof())
4031 int lidMVideo = m_pDS->fv(1).get_asInt();
4032 CStdString strAlbum = m_pDS->fv(0).get_asString();
4033 it = mapAlbums.find(lidMVideo);
4034 // was this genre already found?
4035 if (it == mapAlbums.end())
4038 if (g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
4039 mapAlbums.insert(make_pair(lidMVideo, make_pair(strAlbum,m_pDS->fv(2).get_asString())));
4045 for (it=mapAlbums.begin();it != mapAlbums.end();++it)
4047 if (!it->second.first.IsEmpty())
4049 CFileItemPtr pItem(new CFileItem(it->second.first));
4051 strDir.Format("%ld/", it->first);
4052 pItem->m_strPath=strBaseDir + strDir;
4053 pItem->m_bIsFolder=true;
4054 pItem->SetLabelPreformated(true);
4055 if (!items.Contains(pItem->m_strPath))
4057 pItem->GetVideoInfoTag()->m_strArtist = m_pDS->fv(2).get_asString();
4058 CStdString strThumb = CUtil::GetCachedAlbumThumb(pItem->GetLabel(),pItem->GetVideoInfoTag()->m_strArtist);
4059 if (CFile::Exists(strThumb))
4060 pItem->SetThumbnailImage(strThumb);
4068 while (!m_pDS->eof())
4070 if (!m_pDS->fv(0).get_asString().empty())
4072 CFileItemPtr pItem(new CFileItem(m_pDS->fv(0).get_asString()));
4074 strDir.Format("%ld/", m_pDS->fv(1).get_asInt());
4075 pItem->m_strPath=strBaseDir + strDir;
4076 pItem->m_bIsFolder=true;
4077 pItem->SetLabelPreformated(true);
4078 if (!items.Contains(pItem->m_strPath))
4080 pItem->GetVideoInfoTag()->m_strArtist = m_pDS->fv(2).get_asString();
4081 CStdString strThumb = CUtil::GetCachedAlbumThumb(pItem->GetLabel(),m_pDS->fv(2).get_asString());
4082 if (CFile::Exists(strThumb))
4083 pItem->SetThumbnailImage(strThumb);
4092 // CLog::Log(LOGDEBUG, __FUNCTION__" Time: %d ms", CTimeUtils::GetTimeMS() - time);
4097 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
4102 bool CVideoDatabase::GetWritersNav(const CStdString& strBaseDir, CFileItemList& items, int idContent)
4104 return GetPeopleNav(strBaseDir, items, "studio", idContent);
4107 bool CVideoDatabase::GetDirectorsNav(const CStdString& strBaseDir, CFileItemList& items, int idContent)
4109 return GetPeopleNav(strBaseDir, items, "director", idContent);
4112 bool CVideoDatabase::GetActorsNav(const CStdString& strBaseDir, CFileItemList& items, int idContent)
4114 if (GetPeopleNav(strBaseDir, items, (idContent == VIDEODB_CONTENT_MUSICVIDEOS) ? "artist" : "actor", idContent))
4115 { // set thumbs - ideally this should be in the normal thumb setting routines
4116 for (int i = 0; i < items.Size(); i++)
4118 CFileItemPtr pItem = items[i];
4119 if (idContent == VIDEODB_CONTENT_MUSICVIDEOS)
4121 if (CFile::Exists(pItem->GetCachedArtistThumb()))
4122 pItem->SetThumbnailImage(pItem->GetCachedArtistThumb());
4123 pItem->SetIconImage("DefaultArtist.png");
4127 if (CFile::Exists(pItem->GetCachedActorThumb()))
4128 pItem->SetThumbnailImage(pItem->GetCachedActorThumb());
4129 pItem->SetIconImage("DefaultActor.png");
4137 bool CVideoDatabase::GetPeopleNav(const CStdString& strBaseDir, CFileItemList& items, const CStdString &type, int idContent)
4139 if (NULL == m_pDB.get()) return false;
4140 if (NULL == m_pDS.get()) return false;
4144 // TODO: This routine (and probably others at this same level) use playcount as a reference to filter on at a later
4145 // point. This means that we *MUST* filter these levels as you'll get double ups. Ideally we'd allow playcount
4146 // to filter through as we normally do for tvshows to save this happening.
4147 // Also, we apply this same filtering logic to the locked or unlocked paths to prevent these from showing.
4148 // Whether or not this should happen is a tricky one - it complicates all the high level categories (everything
4151 // General routine that the other actor/director/writer routines call
4153 // get primary genres for movies
4155 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
4157 if (idContent == VIDEODB_CONTENT_MOVIES)
4158 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());
4159 else if (idContent == VIDEODB_CONTENT_TVSHOWS)
4160 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());
4161 else if (idContent == VIDEODB_CONTENT_EPISODES)
4162 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());
4163 else if (idContent == VIDEODB_CONTENT_MUSICVIDEOS)
4164 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());
4168 if (idContent == VIDEODB_CONTENT_MOVIES)
4170 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());
4171 strSQL += " group by actors.idActor";
4173 else if (idContent == VIDEODB_CONTENT_TVSHOWS)
4174 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());
4175 else if (idContent == VIDEODB_CONTENT_EPISODES)
4176 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());
4177 else if (idContent == VIDEODB_CONTENT_MUSICVIDEOS)
4179 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());
4180 strSQL += " group by actors.idActor";
4185 unsigned int time = CTimeUtils::GetTimeMS();
4186 if (!m_pDS->query(strSQL.c_str())) return false;
4187 CLog::Log(LOGDEBUG, "%s - query took %i ms",
4188 __FUNCTION__, CTimeUtils::GetTimeMS() - time); time = CTimeUtils::GetTimeMS();
4189 int iRowsFound = m_pDS->num_rows();
4190 if (iRowsFound == 0)
4196 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
4198 map<int, CActor> mapActors;
4199 map<int, CActor>::iterator it;
4201 while (!m_pDS->eof())
4203 int idActor = m_pDS->fv(0).get_asInt();
4205 actor.name = m_pDS->fv(1).get_asString();
4206 actor.thumb = m_pDS->fv(2).get_asString();
4207 if (idContent != VIDEODB_CONTENT_TVSHOWS)
4208 actor.playcount = m_pDS->fv(3).get_asInt();
4209 it = mapActors.find(idActor);
4210 // is this actor already known?
4211 if (it == mapActors.end())
4214 if (g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
4215 mapActors.insert(pair<int, CActor>(idActor, actor));
4221 for (it=mapActors.begin();it != mapActors.end();++it)
4223 CFileItemPtr pItem(new CFileItem(it->second.name));
4225 strDir.Format("%ld/", it->first);
4226 pItem->m_strPath=strBaseDir + strDir;
4227 pItem->m_bIsFolder=true;
4228 pItem->GetVideoInfoTag()->m_playCount = it->second.playcount;
4229 pItem->GetVideoInfoTag()->m_strPictureURL.ParseString(it->second.thumb);
4235 while (!m_pDS->eof())
4239 CFileItemPtr pItem(new CFileItem(m_pDS->fv(1).get_asString()));
4241 strDir.Format("%ld/", m_pDS->fv(0).get_asInt());
4242 pItem->m_strPath=strBaseDir + strDir;
4243 pItem->m_bIsFolder=true;
4244 pItem->GetVideoInfoTag()->m_strPictureURL.ParseString(m_pDS->fv(2).get_asString());
4245 if (idContent != VIDEODB_CONTENT_TVSHOWS)
4247 // fv(4) is the number of videos watched, fv(3) is the total number. We set the playcount
4248 // only if the number of videos watched is equal to the total number (i.e. every video watched)
4249 pItem->GetVideoInfoTag()->m_playCount = (m_pDS->fv(4).get_asInt() == m_pDS->fv(3).get_asInt()) ? 1 : 0;
4251 if (idContent == VIDEODB_CONTENT_MUSICVIDEOS)
4252 pItem->GetVideoInfoTag()->m_strArtist = pItem->GetLabel();
4259 CLog::Log(LOGERROR, "%s: out of memory - retrieved %i items", __FUNCTION__, items.Size());
4260 return items.Size() > 0;
4265 CLog::Log(LOGDEBUG, "%s item retrieval took %i ms",
4266 __FUNCTION__, CTimeUtils::GetTimeMS() - time); time = CTimeUtils::GetTimeMS();
4273 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
4280 bool CVideoDatabase::GetYearsNav(const CStdString& strBaseDir, CFileItemList& items, int idContent)
4284 if (NULL == m_pDB.get()) return false;
4285 if (NULL == m_pDS.get()) return false;
4288 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
4290 if (idContent == VIDEODB_CONTENT_MOVIES)
4291 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);
4292 else if (idContent == VIDEODB_CONTENT_TVSHOWS)
4293 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);
4294 else if (idContent == VIDEODB_CONTENT_MUSICVIDEOS)
4295 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);
4300 if (idContent == VIDEODB_CONTENT_MOVIES)
4302 strSQL = PrepareSQL("select movie.c%02d,count(1),count(files.playCount) from movie join files on files.idFile=movie.idFile", VIDEODB_ID_YEAR);
4303 group = PrepareSQL(" group by movie.c%02d", VIDEODB_ID_YEAR);
4305 else if (idContent == VIDEODB_CONTENT_TVSHOWS)
4306 strSQL = PrepareSQL("select distinct tvshow.c%02d from tvshow", VIDEODB_ID_TV_PREMIERED);
4307 else if (idContent == VIDEODB_CONTENT_MUSICVIDEOS)
4309 strSQL = PrepareSQL("select musicvideo.c%02d,count(1),count(files.playCount) from musicvideo join files on files.idFile=musicvideo.idFile", VIDEODB_ID_MUSICVIDEO_YEAR);
4310 group = PrepareSQL(" group by musicvideo.c%02d", VIDEODB_ID_MUSICVIDEO_YEAR);
4315 int iRowsFound = RunQuery(strSQL);
4316 if (iRowsFound <= 0)
4317 return iRowsFound == 0;
4319 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
4321 map<int, pair<CStdString,int> > mapYears;
4322 map<int, pair<CStdString,int> >::iterator it;
4323 while (!m_pDS->eof())
4326 if (idContent == VIDEODB_CONTENT_TVSHOWS)
4329 time.SetFromDateString(m_pDS->fv(0).get_asString());
4330 lYear = time.GetYear();
4332 else if (idContent == VIDEODB_CONTENT_MOVIES || idContent == VIDEODB_CONTENT_MUSICVIDEOS)
4333 lYear = m_pDS->fv(0).get_asInt();
4334 it = mapYears.find(lYear);
4335 if (it == mapYears.end())
4338 if (g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
4341 year.Format("%d", lYear);
4342 if (idContent == VIDEODB_CONTENT_MOVIES || idContent == VIDEODB_CONTENT_MUSICVIDEOS)
4343 mapYears.insert(pair<int, pair<CStdString,int> >(lYear, pair<CStdString,int>(year,m_pDS->fv(2).get_asInt())));
4345 mapYears.insert(pair<int, pair<CStdString,int> >(lYear, pair<CStdString,int>(year,0)));
4352 for (it=mapYears.begin();it != mapYears.end();++it)
4356 CFileItemPtr pItem(new CFileItem(it->second.first));
4358 strDir.Format("%ld/", it->first);
4359 pItem->m_strPath=strBaseDir + strDir;
4360 pItem->m_bIsFolder=true;
4361 if (idContent == VIDEODB_CONTENT_MOVIES || idContent == VIDEODB_CONTENT_MUSICVIDEOS)
4362 pItem->GetVideoInfoTag()->m_playCount = it->second.second;
4368 while (!m_pDS->eof())
4371 CStdString strLabel;
4372 if (idContent == VIDEODB_CONTENT_TVSHOWS)
4375 time.SetFromDateString(m_pDS->fv(0).get_asString());
4376 lYear = time.GetYear();
4377 strLabel.Format("%i",lYear);
4379 else if (idContent == VIDEODB_CONTENT_MOVIES || idContent == VIDEODB_CONTENT_MUSICVIDEOS)
4381 lYear = m_pDS->fv(0).get_asInt();
4382 strLabel = m_pDS->fv(0).get_asString();
4389 CFileItemPtr pItem(new CFileItem(strLabel));
4391 strDir.Format("%ld/", lYear);
4392 pItem->m_strPath=strBaseDir + strDir;
4393 pItem->m_bIsFolder=true;
4394 if (idContent == VIDEODB_CONTENT_MOVIES || idContent == VIDEODB_CONTENT_MUSICVIDEOS)
4396 // fv(2) is the number of videos watched, fv(1) is the total number. We set the playcount
4397 // only if the number of videos watched is equal to the total number (i.e. every video watched)
4398 pItem->GetVideoInfoTag()->m_playCount = (m_pDS->fv(2).get_asInt() == m_pDS->fv(1).get_asInt()) ? 1 : 0;
4401 // take care of dupes ..
4402 if (!items.Contains(pItem->m_strPath))
4414 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
4419 bool CVideoDatabase::GetStackedTvShowList(int idShow, CStdString& strIn)
4423 if (NULL == m_pDB.get()) return false;
4424 if (NULL == m_pDS.get()) return false;
4426 // look for duplicate show titles and stack them into a list
4429 CStdString strSQL = PrepareSQL("select idShow from tvshow where c00 like (select c00 from tvshow where idShow=%i) order by idShow", idShow);
4430 CLog::Log(LOGDEBUG, "%s query: %s", __FUNCTION__, strSQL.c_str());
4431 if (!m_pDS->query(strSQL.c_str())) return false;
4432 int iRows = m_pDS->num_rows();
4433 if (iRows == 0) return false; // this should never happen!
4435 { // more than one show, so stack them up
4437 while (!m_pDS->eof())
4439 strIn += PrepareSQL("%i,", m_pDS->fv(0).get_asInt());
4442 strIn[strIn.GetLength() - 1] = ')'; // replace last , with )
4449 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
4454 bool CVideoDatabase::GetSeasonsNav(const CStdString& strBaseDir, CFileItemList& items, int idActor, int idDirector, int idGenre, int idYear, int idShow)
4458 if (NULL == m_pDB.get()) return false;
4459 if (NULL == m_pDS.get()) return false;
4461 CStdString strIn = PrepareSQL("= %i", idShow);
4462 GetStackedTvShowList(idShow, strIn);
4464 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);
4465 CStdString joins = PrepareSQL(" join tvshowlinkpath on tvshowlinkpath.idShow = tvshow.idShow join path on path.idPath = tvshowlinkpath.idPath where tvshow.idShow %s ", strIn.c_str());
4466 CStdString extraJoins, extraWhere;
4469 extraJoins = "join actorlinktvshow on actorlinktvshow.idShow=tvshow.idShow";
4470 extraWhere = PrepareSQL("and actorlinktvshow.idActor=%i", idActor);
4472 else if (idDirector != -1)
4474 extraJoins = "join directorlinktvshow on directorlinktvshow.idShow=tvshow.idShow";
4475 extraWhere = PrepareSQL("and directorlinktvshow.idDirector=%i",idDirector);
4477 else if (idGenre != -1)
4479 extraJoins = "join genrelinktvshow on genrelinktvshow.idShow=tvshow.idShow";
4480 extraWhere = PrepareSQL("and genrelinktvshow.idGenre=%i", idGenre);
4482 else if (idYear != -1)
4484 extraWhere = PrepareSQL("and tvshow.c%02d like '%%%i%%'", VIDEODB_ID_TV_PREMIERED, idYear);
4486 strSQL += extraJoins + joins + extraWhere + PrepareSQL(" group by episode.c%02d", VIDEODB_ID_EPISODE_SEASON);
4488 int iRowsFound = RunQuery(strSQL);
4489 if (iRowsFound <= 0)
4490 return iRowsFound == 0;
4492 // show titles, studios and mpaa ratings will be the same
4493 CStdString showTitle = m_pDS->fv(2).get_asString();
4494 CStdString showStudio = m_pDS->fv(4).get_asString();
4495 CStdString showMPAARating = m_pDS->fv(5).get_asString();
4497 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
4499 map<int, CSeason> mapSeasons;
4500 map<int, CSeason>::iterator it;
4501 while (!m_pDS->eof())
4503 int iSeason = m_pDS->fv(0).get_asInt();
4504 it = mapSeasons.find(iSeason);
4506 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
4511 if (it == mapSeasons.end())
4514 season.path = m_pDS->fv(1).get_asString();
4515 season.genre = m_pDS->fv(3).get_asString();
4516 season.numEpisodes = m_pDS->fv(6).get_asInt();
4517 season.numWatched = m_pDS->fv(7).get_asInt();
4518 mapSeasons.insert(make_pair(iSeason, season));
4524 for (it=mapSeasons.begin();it != mapSeasons.end();++it)
4526 int iSeason = it->first;
4527 CStdString strLabel;
4529 strLabel = g_localizeStrings.Get(20381);
4531 strLabel.Format(g_localizeStrings.Get(20358),iSeason);
4532 CFileItemPtr pItem(new CFileItem(strLabel));
4534 strDir.Format("%ld/", it->first);
4535 pItem->m_strPath=strBaseDir + strDir;
4536 pItem->m_bIsFolder=true;
4537 pItem->GetVideoInfoTag()->m_strTitle = strLabel;
4538 pItem->GetVideoInfoTag()->m_iSeason = iSeason;
4539 pItem->GetVideoInfoTag()->m_iDbId = idShow;
4540 pItem->GetVideoInfoTag()->m_strPath = it->second.path;
4541 pItem->GetVideoInfoTag()->m_strGenre = it->second.genre;
4542 pItem->GetVideoInfoTag()->m_strStudio = showStudio;
4543 pItem->GetVideoInfoTag()->m_strMPAARating = showMPAARating;
4544 pItem->GetVideoInfoTag()->m_strShowTitle = showTitle;
4545 pItem->GetVideoInfoTag()->m_iEpisode = it->second.numEpisodes;
4546 pItem->SetProperty("totalepisodes", it->second.numEpisodes);
4547 pItem->SetProperty("numepisodes", it->second.numEpisodes); // will be changed later to reflect watchmode setting
4548 pItem->SetProperty("watchedepisodes", it->second.numWatched);
4549 pItem->SetProperty("unwatchedepisodes", it->second.numEpisodes - it->second.numWatched);
4550 pItem->GetVideoInfoTag()->m_playCount = (it->second.numEpisodes == it->second.numWatched) ? 1 : 0;
4551 pItem->SetCachedSeasonThumb();
4552 pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, (pItem->GetVideoInfoTag()->m_playCount > 0) && (pItem->GetVideoInfoTag()->m_iEpisode > 0));
4558 while (!m_pDS->eof())
4560 int iSeason = m_pDS->fv(0).get_asInt();
4561 CStdString strLabel;
4563 strLabel = g_localizeStrings.Get(20381);
4565 strLabel.Format(g_localizeStrings.Get(20358),iSeason);
4566 CFileItemPtr pItem(new CFileItem(strLabel));
4568 strDir.Format("%ld/", iSeason);
4569 pItem->m_strPath=strBaseDir + strDir;
4570 pItem->m_bIsFolder=true;
4571 pItem->GetVideoInfoTag()->m_strTitle = strLabel;
4572 pItem->GetVideoInfoTag()->m_iSeason = iSeason;
4573 pItem->GetVideoInfoTag()->m_iDbId = idShow;
4574 pItem->GetVideoInfoTag()->m_strPath = m_pDS->fv(1).get_asString();
4575 pItem->GetVideoInfoTag()->m_strGenre = m_pDS->fv(3).get_asString();
4576 pItem->GetVideoInfoTag()->m_strStudio = showStudio;
4577 pItem->GetVideoInfoTag()->m_strMPAARating = showMPAARating;
4578 pItem->GetVideoInfoTag()->m_strShowTitle = showTitle;
4579 int totalEpisodes = m_pDS->fv(6).get_asInt();
4580 int watchedEpisodes = m_pDS->fv(7).get_asInt();
4581 pItem->GetVideoInfoTag()->m_iEpisode = totalEpisodes;
4582 pItem->SetProperty("totalepisodes", totalEpisodes);
4583 pItem->SetProperty("numepisodes", totalEpisodes); // will be changed later to reflect watchmode setting
4584 pItem->SetProperty("watchedepisodes", watchedEpisodes);
4585 pItem->SetProperty("unwatchedepisodes", totalEpisodes - watchedEpisodes);
4586 pItem->GetVideoInfoTag()->m_playCount = (totalEpisodes == watchedEpisodes) ? 1 : 0;
4587 pItem->SetCachedSeasonThumb();
4588 pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, (pItem->GetVideoInfoTag()->m_playCount > 0) && (pItem->GetVideoInfoTag()->m_iEpisode > 0));
4594 // now add any linked movies
4595 CStdString where = PrepareSQL("join movielinktvshow on movielinktvshow.idMovie=movieview.idMovie where movielinktvshow.idShow %s", strIn.c_str());
4596 GetMoviesByWhere("videodb://1/2/", where, "", items);
4601 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
4606 bool CVideoDatabase::GetMoviesNav(const CStdString& strBaseDir, CFileItemList& items, int idGenre, int idYear, int idActor, int idDirector, int idStudio, int idCountry, int idSet)
4610 where = PrepareSQL("join genrelinkmovie on genrelinkmovie.idMovie=movieview.idMovie where genrelinkmovie.idGenre=%i", idGenre);
4611 else if (idCountry != -1)
4612 where = PrepareSQL("join countrylinkmovie on countrylinkmovie.idMovie=movieview.idMovie where countrylinkmovie.idCountry=%i", idCountry);
4613 else if (idStudio != -1)
4614 where = PrepareSQL("join studiolinkmovie on studiolinkmovie.idMovie=movieview.idMovie where studiolinkmovie.idStudio=%i", idStudio);
4615 else if (idDirector != -1)
4616 where = PrepareSQL("join directorlinkmovie on directorlinkmovie.idMovie=movieview.idMovie where directorlinkmovie.idDirector=%i", idDirector);
4617 else if (idYear !=-1)
4618 where = PrepareSQL("where c%02d='%i'",VIDEODB_ID_YEAR,idYear);
4619 else if (idActor != -1)
4620 where = PrepareSQL("join actorlinkmovie on actorlinkmovie.idMovie=movieview.idMovie join actors on actors.idActor=actorlinkmovie.idActor where actors.idActor=%i",idActor);
4621 else if (idSet != -1)
4622 where = PrepareSQL("join setlinkmovie on setlinkmovie.idMovie=movieview.idMovie where setlinkmovie.idSet=%u",idSet);
4624 return GetMoviesByWhere(strBaseDir, where, "", items, idSet == -1);
4627 bool CVideoDatabase::GetMoviesByWhere(const CStdString& strBaseDir, const CStdString &where, const CStdString &order, CFileItemList& items, bool fetchSets)
4634 if (NULL == m_pDB.get()) return false;
4635 if (NULL == m_pDS.get()) return false;
4637 CStdString strSQL = "select * from movieview ";
4638 if (fetchSets && !g_guiSettings.GetBool("videolibrary.flattenmoviesets"))
4640 // not getting a set, so grab all sets that match this where clause first
4641 CStdString setsWhere;
4643 setsWhere = " where movie.idMovie in (select movieview.idMovie from movieview " + where + ")";
4644 GetSetsNav("videodb://1/7/", items, VIDEODB_CONTENT_MOVIES, setsWhere);
4646 strSQL += where + PrepareSQL(" and movieview.idMovie NOT in (select idMovie from setlinkmovie)");
4648 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)");
4654 strSQL += " " + order;
4656 int iRowsFound = RunQuery(strSQL);
4657 if (iRowsFound <= 0)
4658 return iRowsFound == 0;
4660 // get data from returned rows
4661 items.Reserve(iRowsFound);
4662 while (!m_pDS->eof())
4664 CVideoInfoTag movie = GetDetailsForMovie(m_pDS);
4665 if (g_settings.GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE ||
4666 g_passwordManager.bMasterUser ||
4667 g_passwordManager.IsDatabasePathUnlocked(movie.m_strPath, g_settings.m_videoSources))
4669 CFileItemPtr pItem(new CFileItem(movie));
4670 pItem->m_strPath.Format("%s%ld", strBaseDir.c_str(), movie.m_iDbId);
4671 pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED,movie.m_playCount > 0);
4683 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
4688 bool CVideoDatabase::GetTvShowsNav(const CStdString& strBaseDir, CFileItemList& items, int idGenre, int idYear, int idActor, int idDirector, int idStudio)
4692 where = PrepareSQL("join genrelinktvshow on genrelinktvshow.idShow=tvshowview.idShow where genrelinktvshow.idGenre=%i ", idGenre);
4693 else if (idStudio != -1)
4694 where = PrepareSQL("join studiolinktvshow on studiolinktvshow.idShow=tvshowview.idShow where studiolinktvshow.idStudio=%i", idStudio);
4695 else if (idDirector != -1)
4696 where = PrepareSQL("join directorlinktvshow on directorlinktvshow.idShow=tvshowview.idShow where directorlinktvshow.idDirector=%i", idDirector);
4697 else if (idYear != -1)
4698 where = PrepareSQL("where c%02d like '%%%i%%'", VIDEODB_ID_TV_PREMIERED,idYear);
4699 else if (idActor != -1)
4700 where = PrepareSQL("join actorlinktvshow on actorlinktvshow.idShow=tvshowview.idShow join actors on actors.idActor=actorlinktvshow.idActor where actors.idActor=%i",idActor);
4702 return GetTvShowsByWhere(strBaseDir, where, items);
4705 bool CVideoDatabase::GetTvShowsByWhere(const CStdString& strBaseDir, const CStdString &where, CFileItemList& items)
4711 if (NULL == m_pDB.get()) return false;
4712 if (NULL == m_pDS.get()) return false;
4714 int iRowsFound = RunQuery("SELECT * FROM tvshowview " + where);
4715 if (iRowsFound <= 0)
4716 return iRowsFound == 0;
4718 // get data from returned rows
4719 items.Reserve(iRowsFound);
4721 while (!m_pDS->eof())
4723 int idShow = m_pDS->fv("tvshow.idShow").get_asInt();
4724 int numSeasons = m_pDS->fv(VIDEODB_DETAILS_TVSHOW_NUM_SEASONS).get_asInt();
4726 CVideoInfoTag movie = GetDetailsForTvShow(m_pDS, false);
4727 if (!g_advancedSettings.m_bVideoLibraryHideEmptySeries || movie.m_iEpisode > 0)
4729 CFileItemPtr pItem(new CFileItem(movie));
4730 pItem->m_strPath.Format("%s%ld/", strBaseDir.c_str(), idShow);
4731 pItem->m_dateTime.SetFromDateString(movie.m_strPremiered);
4732 pItem->GetVideoInfoTag()->m_iYear = pItem->m_dateTime.GetYear();
4733 pItem->SetProperty("totalseasons", numSeasons);
4734 pItem->SetProperty("totalepisodes", movie.m_iEpisode);
4735 pItem->SetProperty("numepisodes", movie.m_iEpisode); // will be changed later to reflect watchmode setting
4736 pItem->SetProperty("watchedepisodes", movie.m_playCount);
4737 pItem->SetProperty("unwatchedepisodes", movie.m_iEpisode - movie.m_playCount);
4738 pItem->GetVideoInfoTag()->m_playCount = (movie.m_iEpisode == movie.m_playCount) ? 1 : 0;
4739 pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, (pItem->GetVideoInfoTag()->m_playCount > 0) && (pItem->GetVideoInfoTag()->m_iEpisode > 0));
4745 CStdString order(where);
4746 bool maintainOrder = order.ToLower().Find("order by") != -1;
4747 Stack(items, VIDEODB_CONTENT_TVSHOWS, maintainOrder);
4755 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
4760 void CVideoDatabase::Stack(CFileItemList& items, VIDEODB_CONTENT_TYPE type, bool maintainSortOrder /* = false */)
4762 if (maintainSortOrder)
4764 // save current sort order
4765 for (int i = 0; i < items.Size(); i++)
4766 items[i]->m_iprogramCount = i;
4771 case VIDEODB_CONTENT_TVSHOWS:
4774 items.Sort(SORT_METHOD_VIDEO_TITLE, SORT_ORDER_ASC);
4777 while (i < items.Size())
4779 CFileItemPtr pItem = items.Get(i);
4780 CStdString strTitle = pItem->GetVideoInfoTag()->m_strTitle;
4781 CStdString strFanArt = pItem->GetProperty("fanart_image");
4784 bool bStacked = false;
4785 while (j < items.Size())
4787 CFileItemPtr jItem = items.Get(j);
4789 // matching title? append information
4790 if (jItem->GetVideoInfoTag()->m_strTitle.Equals(strTitle))
4792 if (jItem->GetVideoInfoTag()->m_strPremiered !=
4793 pItem->GetVideoInfoTag()->m_strPremiered)
4800 // increment episode counts
4801 pItem->GetVideoInfoTag()->m_iEpisode += jItem->GetVideoInfoTag()->m_iEpisode;
4802 pItem->IncrementProperty("totalepisodes", jItem->GetPropertyInt("totalepisodes"));
4803 pItem->IncrementProperty("numepisodes", jItem->GetPropertyInt("numepisodes")); // will be changed later to reflect watchmode setting
4804 pItem->IncrementProperty("watchedepisodes", jItem->GetPropertyInt("watchedepisodes"));
4805 pItem->IncrementProperty("unwatchedepisodes", jItem->GetPropertyInt("unwatchedepisodes"));
4807 // check for fanart if not already set
4808 if (strFanArt.IsEmpty())
4809 strFanArt = jItem->GetProperty("fanart_image");
4811 // remove duplicate entry
4814 // no match? exit loop
4818 // update playcount and fanart
4821 pItem->GetVideoInfoTag()->m_playCount = (pItem->GetVideoInfoTag()->m_iEpisode == pItem->GetPropertyInt("watchedepisodes")) ? 1 : 0;
4822 pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, (pItem->GetVideoInfoTag()->m_playCount > 0) && (pItem->GetVideoInfoTag()->m_iEpisode > 0));
4823 if (!strFanArt.IsEmpty())
4824 pItem->SetProperty("fanart_image", strFanArt);
4826 // increment i to j which is the next item
4831 // We currently don't stack episodes (No call here in GetEpisodesByWhere()), but this code is left
4832 // so that if we eventually want to stack during scan we can utilize it.
4834 case VIDEODB_CONTENT_EPISODES:
4836 // sort by ShowTitle, Episode, Filename
4837 items.Sort(SORT_METHOD_EPISODE, SORT_ORDER_ASC);
4840 while (i < items.Size())
4842 CFileItemPtr pItem = items.Get(i);
4843 CStdString strPath = pItem->GetVideoInfoTag()->m_strPath;
4844 int iSeason = pItem->GetVideoInfoTag()->m_iSeason;
4845 int iEpisode = pItem->GetVideoInfoTag()->m_iEpisode;
4846 //CStdString strFanArt = pItem->GetProperty("fanart_image");
4848 // do we have a dvd folder, ie foo/VIDEO_TS.IFO or foo/VIDEO_TS/VIDEO_TS.IFO
4849 CStdString strFileNameAndPath = pItem->GetVideoInfoTag()->m_strFileNameAndPath;
4850 bool bDvdFolder = strFileNameAndPath.Right(12).Equals("VIDEO_TS.IFO");
4852 vector<CStdString> paths;
4853 paths.push_back(strFileNameAndPath);
4854 CLog::Log(LOGDEBUG, "Stack episode (%i,%i):[%s]", iSeason, iEpisode, paths[0].c_str());
4857 int iPlayCount = pItem->GetVideoInfoTag()->m_playCount;
4858 while (j < items.Size())
4860 CFileItemPtr jItem = items.Get(j);
4861 const CVideoInfoTag *jTag = jItem->GetVideoInfoTag();
4862 CStdString jFileNameAndPath = jTag->m_strFileNameAndPath;
4864 CLog::Log(LOGDEBUG, " *testing (%i,%i):[%s]", jTag->m_iSeason, jTag->m_iEpisode, jFileNameAndPath.c_str());
4865 // compare path, season, episode
4868 jTag->m_strPath.Equals(strPath) &&
4869 jTag->m_iSeason == iSeason &&
4870 jTag->m_iEpisode == iEpisode
4873 // keep checking to see if this is dvd folder
4876 bDvdFolder = jFileNameAndPath.Right(12).Equals("VIDEO_TS.IFO");
4877 // if we have a dvd folder, we stack differently
4880 // remove all the other items and ONLY show the VIDEO_TS.IFO file
4882 paths.push_back(jFileNameAndPath);
4886 // increment playcount
4887 iPlayCount += jTag->m_playCount;
4889 // episodes dont have fanart yet
4890 //if (strFanArt.IsEmpty())
4891 // strFanArt = jItem->GetProperty("fanart_image");
4893 paths.push_back(jFileNameAndPath);
4897 // remove duplicate entry
4901 // no match? exit loop
4905 // update playcount and fanart if we have a stacked entry
4906 if (paths.size() > 1)
4908 CStackDirectory dir;
4909 CStdString strStack;
4910 dir.ConstructStackPath(paths, strStack);
4911 pItem->GetVideoInfoTag()->m_strFileNameAndPath = strStack;
4912 pItem->GetVideoInfoTag()->m_playCount = iPlayCount;
4913 pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, (pItem->GetVideoInfoTag()->m_playCount > 0) && (pItem->GetVideoInfoTag()->m_iEpisode > 0));
4915 // episodes dont have fanart yet
4916 //if (!strFanArt.IsEmpty())
4917 // pItem->SetProperty("fanart_image", strFanArt);
4919 // increment i to j which is the next item
4925 // stack other types later
4929 if (maintainSortOrder)
4931 // restore original sort order - essential for smartplaylists
4932 items.Sort(SORT_METHOD_PROGRAM_COUNT, SORT_ORDER_ASC);
4936 bool CVideoDatabase::GetEpisodesNav(const CStdString& strBaseDir, CFileItemList& items, int idGenre, int idYear, int idActor, int idDirector, int idShow, int idSeason)
4938 CStdString strIn = PrepareSQL("= %i", idShow);
4939 GetStackedTvShowList(idShow, strIn);
4940 CStdString where = PrepareSQL("where idShow %s",strIn.c_str());
4942 where = PrepareSQL("join genrelinktvshow on genrelinktvshow.idShow=episodeview.idShow where episodeview.idShow=%i and genrelinktvshow.idGenre=%i",idShow,idGenre);
4943 else if (idDirector != -1)
4944 where = PrepareSQL("join directorlinktvshow on directorlinktvshow.idShow=episodeview.idShow where episodeview.idShow=%i and directorlinktvshow.idDirector=%i",idShow,idDirector);
4945 else if (idYear !=-1)
4946 where=PrepareSQL("where idShow=%i and premiered like '%%%i%%'",idShow,idYear);
4947 else if (idActor != -1)
4948 where = PrepareSQL("join actorlinktvshow on actorlinktvshow.idShow=episodeview.idShow where episodeview.idShow=%i and actorlinktvshow.idActor=%i",idShow,idActor);
4952 if (idSeason != 0) // season = 0 indicates a special - we grab all specials here (see below)
4953 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);
4955 where += PrepareSQL(" and c%02d=%i",VIDEODB_ID_EPISODE_SEASON,idSeason);
4958 // we always append show, season + episode in GetEpisodesByWhere
4959 CStdString parent, grandParent;
4960 URIUtils::GetParentPath(strBaseDir,parent);
4961 URIUtils::GetParentPath(parent,grandParent);
4963 bool ret = GetEpisodesByWhere(grandParent, where, items);
4966 { // add any linked movies
4967 CStdString where = PrepareSQL("join movielinktvshow on movielinktvshow.idMovie=movieview.idMovie where movielinktvshow.idShow %s", strIn.c_str());
4968 GetMoviesByWhere("videodb://1/2/", where, "", items);
4973 bool CVideoDatabase::GetEpisodesByWhere(const CStdString& strBaseDir, const CStdString &where, CFileItemList& items, bool appendFullShowPath /* = true */)
4980 if (NULL == m_pDB.get()) return false;
4981 if (NULL == m_pDS.get()) return false;
4983 int iRowsFound = RunQuery("select * from episodeview " + where);
4984 if (iRowsFound <= 0)
4985 return iRowsFound == 0;
4987 // get data from returned rows
4988 items.Reserve(iRowsFound);
4989 while (!m_pDS->eof())
4991 int idEpisode = m_pDS->fv("idEpisode").get_asInt();
4992 int idShow = m_pDS->fv("idShow").get_asInt();
4994 CVideoInfoTag movie = GetDetailsForEpisode(m_pDS);
4995 CFileItemPtr pItem(new CFileItem(movie));
4996 if (appendFullShowPath)
4997 pItem->m_strPath.Format("%s%ld/%ld/%ld",strBaseDir.c_str(), idShow, movie.m_iSeason,idEpisode);
4999 pItem->m_strPath.Format("%s%ld",strBaseDir.c_str(), idEpisode);
5001 pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED,movie.m_playCount > 0);
5002 pItem->m_dateTime.SetFromDateString(movie.m_strFirstAired);
5003 pItem->GetVideoInfoTag()->m_iYear = pItem->m_dateTime.GetYear();
5015 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
5021 bool CVideoDatabase::GetMusicVideosNav(const CStdString& strBaseDir, CFileItemList& items, int idGenre, int idYear, int idArtist, int idDirector, int idStudio, int idAlbum)
5025 where = PrepareSQL("join genrelinkmusicvideo on genrelinkmusicvideo.idMVideo=musicvideoview.idMVideo where genrelinkmusicvideo.idGenre=%i", idGenre);
5026 else if (idStudio != -1)
5027 where = PrepareSQL("join studiolinkmusicvideo on studiolinkmusicvideo.idMVideo=musicvideoview.idMVideo where studiolinkmusicvideo.idStudio=%i", idStudio);
5028 else if (idDirector != -1)
5029 where = PrepareSQL("join directorlinkmusicvideo on directorlinkmusicvideo.idMVideo=musicvideoview.idMVideo where directorlinkmusicvideo.idDirector=%i", idDirector);
5030 else if (idYear !=-1)
5031 where = PrepareSQL("where c%02d='%i'",VIDEODB_ID_MUSICVIDEO_YEAR,idYear);
5032 else if (idArtist != -1)
5033 where = PrepareSQL("join artistlinkmusicvideo on artistlinkmusicvideo.idMVideo=musicvideoview.idMVideo join actors on actors.idActor=artistlinkmusicvideo.idArtist where actors.idActor=%i",idArtist);
5036 CStdString str2 = PrepareSQL(" musicvideoview.c%02d=(select c%02d from musicvideo where idMVideo=%i)",VIDEODB_ID_MUSICVIDEO_ALBUM,VIDEODB_ID_MUSICVIDEO_ALBUM,idAlbum);
5037 if (where.IsEmpty())
5038 where.Format(" %s%s","where",str2.c_str());
5040 where.Format(" %s %s%s",where.Mid(0).c_str(),"and",str2.c_str());
5043 return GetMusicVideosByWhere(strBaseDir, where, items);
5046 bool CVideoDatabase::GetRecentlyAddedMoviesNav(const CStdString& strBaseDir, CFileItemList& items)
5048 CStdString order = PrepareSQL("order by idMovie desc limit %i", g_advancedSettings.m_iVideoLibraryRecentlyAddedItems);
5049 return GetMoviesByWhere(strBaseDir, "", order, items);
5052 bool CVideoDatabase::GetRecentlyAddedEpisodesNav(const CStdString& strBaseDir, CFileItemList& items)
5054 CStdString where = PrepareSQL("order by idEpisode desc limit %i", g_advancedSettings.m_iVideoLibraryRecentlyAddedItems);
5055 return GetEpisodesByWhere(strBaseDir, where, items, false);
5058 bool CVideoDatabase::GetRecentlyAddedMusicVideosNav(const CStdString& strBaseDir, CFileItemList& items)
5060 CStdString where = PrepareSQL("order by idMVideo desc limit %i", g_advancedSettings.m_iVideoLibraryRecentlyAddedItems);
5061 return GetMusicVideosByWhere(strBaseDir, where, items);
5064 CStdString CVideoDatabase::GetGenreById(int id)
5066 return GetSingleValue("genre", "strGenre", PrepareSQL("idGenre=%i", id));
5069 CStdString CVideoDatabase::GetCountryById(int id)
5071 return GetSingleValue("country", "strCountry", PrepareSQL("idCountry=%i", id));
5074 CStdString CVideoDatabase::GetSetById(int id)
5076 return GetSingleValue("sets", "strSet", PrepareSQL("idSet=%i", id));
5079 CStdString CVideoDatabase::GetPersonById(int id)
5081 return GetSingleValue("actors", "strActor", PrepareSQL("idActor=%i", id));
5084 CStdString CVideoDatabase::GetStudioById(int id)
5086 return GetSingleValue("studio", "strStudio", PrepareSQL("idStudio=%i", id));
5089 CStdString CVideoDatabase::GetTvShowTitleById(int id)
5091 return GetSingleValue("tvshow", PrepareSQL("c%02d", VIDEODB_ID_TV_TITLE), PrepareSQL("idShow=%i", id));
5094 CStdString CVideoDatabase::GetMusicVideoAlbumById(int id)
5096 return GetSingleValue("musicvideo", PrepareSQL("c%02d", VIDEODB_ID_MUSICVIDEO_ALBUM), PrepareSQL("idMVideo=%i", id));
5099 bool CVideoDatabase::HasSets() const
5103 if (NULL == m_pDB.get()) return false;
5104 if (NULL == m_pDS.get()) return false;
5106 m_pDS->query( "select idSet from sets" );
5107 bool bResult = (m_pDS->num_rows() > 0);
5113 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
5118 int CVideoDatabase::GetTvShowForEpisode(int idEpisode)
5122 if (NULL == m_pDB.get()) return false;
5123 if (NULL == m_pDS2.get()) return false;
5125 // make sure we use m_pDS2, as this is called in loops using m_pDS
5126 CStdString strSQL=PrepareSQL("select idShow from tvshowlinkepisode where idEpisode=%i", idEpisode);
5127 m_pDS2->query( strSQL.c_str() );
5131 result=m_pDS2->fv(0).get_asInt();
5138 CLog::Log(LOGERROR, "%s (%i) failed", __FUNCTION__, idEpisode);
5143 bool CVideoDatabase::HasContent()
5145 return (HasContent(VIDEODB_CONTENT_MOVIES) ||
5146 HasContent(VIDEODB_CONTENT_TVSHOWS) ||
5147 HasContent(VIDEODB_CONTENT_MUSICVIDEOS));
5150 bool CVideoDatabase::HasContent(VIDEODB_CONTENT_TYPE type)
5152 bool result = false;
5155 if (NULL == m_pDB.get()) return false;
5156 if (NULL == m_pDS.get()) return false;
5159 if (type == VIDEODB_CONTENT_MOVIES)
5160 sql = "select count(1) from movie";
5161 else if (type == VIDEODB_CONTENT_TVSHOWS)
5162 sql = "select count(1) from tvshow";
5163 else if (type == VIDEODB_CONTENT_MUSICVIDEOS)
5164 sql = "select count(1) from musicvideo";
5165 m_pDS->query( sql.c_str() );
5168 result = (m_pDS->fv(0).get_asInt() > 0);
5174 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
5179 int CVideoDatabase::GetMusicVideoCount(const CStdString& strWhere)
5183 if (NULL == m_pDB.get()) return 0;
5184 if (NULL == m_pDS.get()) return 0;
5187 strSQL.Format("select count(1) as nummovies from musicvideoview %s",strWhere.c_str());
5188 m_pDS->query( strSQL.c_str() );
5192 iResult = m_pDS->fv("nummovies").get_asInt();
5199 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
5204 ScraperPtr CVideoDatabase::GetScraperForPath( const CStdString& strPath )
5206 SScanSettings settings;
5207 return GetScraperForPath(strPath, settings);
5210 ScraperPtr CVideoDatabase::GetScraperForPath(const CStdString& strPath, SScanSettings& settings)
5213 return GetScraperForPath(strPath, settings, dummy);
5216 ScraperPtr CVideoDatabase::GetScraperForPath(const CStdString& strPath, SScanSettings& settings, bool& foundDirectly)
5218 foundDirectly = false;
5221 if (strPath.IsEmpty() || !m_pDB.get() || !m_pDS.get()) return ScraperPtr();
5224 CStdString strPath1;
5225 CStdString strPath2(strPath);
5227 if (URIUtils::IsMultiPath(strPath))
5228 strPath2 = CMultiPathDirectory::GetFirstPath(strPath);
5230 URIUtils::GetDirectory(strPath2,strPath1);
5231 int idPath = GetPathId(strPath1);
5235 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);
5236 m_pDS->query( strSQL.c_str() );
5240 CONTENT_TYPE content = CONTENT_NONE;
5242 { // path is stored in db
5244 if (m_pDS->fv("path.exclude").get_asBool())
5246 settings.exclude = true;
5248 return ScraperPtr();
5250 settings.exclude = false;
5252 // try and ascertain scraper for this path
5253 CStdString strcontent = m_pDS->fv("path.strContent").get_asString();
5254 strcontent.ToLower();
5255 content = TranslateContent(strcontent);
5257 //FIXME paths stored should not have empty strContent
5258 //assert(content != CONTENT_NONE);
5259 CStdString scraperID = m_pDS->fv("path.strScraper").get_asString();
5262 if (!scraperID.empty() &&
5263 CAddonMgr::Get().GetAddon(scraperID, addon))
5265 scraper = boost::dynamic_pointer_cast<CScraper>(addon->Clone(addon));
5267 return ScraperPtr();
5269 // store this path's content & settings
5270 scraper->SetPathSettings(content, m_pDS->fv("path.strSettings").get_asString());
5271 settings.parent_name = m_pDS->fv("path.useFolderNames").get_asBool();
5272 settings.recurse = m_pDS->fv("path.scanRecursive").get_asInt();
5273 settings.noupdate = m_pDS->fv("path.noUpdate").get_asBool();
5277 if (content == CONTENT_NONE)
5278 { // this path is not saved in db
5279 // we must drill up until a scraper is configured
5280 CStdString strParent;
5281 while (URIUtils::GetParentPath(strPath1, strParent))
5285 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());
5286 m_pDS->query(strSQL.c_str());
5288 CONTENT_TYPE content = CONTENT_NONE;
5292 CStdString strcontent = m_pDS->fv("path.strContent").get_asString();
5293 strcontent.ToLower();
5294 if (strcontent.Equals("none"))
5296 settings.exclude = true;
5302 content = TranslateContent(strcontent);
5305 if (content != CONTENT_NONE &&
5306 CAddonMgr::Get().GetAddon(m_pDS->fv("path.strScraper").get_asString(), addon))
5308 scraper = boost::dynamic_pointer_cast<CScraper>(addon->Clone(addon));
5309 scraper->SetPathSettings(content, m_pDS->fv("path.strSettings").get_asString());
5310 settings.parent_name = m_pDS->fv("path.useFolderNames").get_asBool();
5311 settings.recurse = m_pDS->fv("path.scanRecursive").get_asInt();
5312 settings.noupdate = m_pDS->fv("path.noUpdate").get_asBool();
5313 settings.exclude = false;
5317 strPath1 = strParent;
5322 if (!scraper || scraper->Content() == CONTENT_NONE)
5323 return ScraperPtr();
5325 if (scraper->Content() == CONTENT_TVSHOWS)
5327 settings.recurse = 0;
5328 if(settings.parent_name) // single show
5330 settings.parent_name_root = settings.parent_name = (iFound == 1);
5334 settings.parent_name_root = settings.parent_name = (iFound == 2);
5337 else if (scraper->Content() == CONTENT_MOVIES)
5339 settings.recurse = settings.recurse - (iFound-1);
5340 settings.parent_name_root = settings.parent_name && (!settings.recurse || iFound > 1);
5342 else if (scraper->Content() == CONTENT_MUSICVIDEOS)
5344 settings.recurse = settings.recurse - (iFound-1);
5345 settings.parent_name_root = settings.parent_name && (!settings.recurse || iFound > 1);
5350 return ScraperPtr();
5352 foundDirectly = (iFound == 1);
5357 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
5359 return ScraperPtr();
5362 CStdString CVideoDatabase::GetContentForPath(const CStdString& strPath)
5364 SScanSettings settings;
5365 bool foundDirectly = false;
5366 ScraperPtr scraper = GetScraperForPath(strPath, settings, foundDirectly);
5369 if (scraper->Content() == CONTENT_TVSHOWS && !foundDirectly)
5370 { // check for episodes or seasons (ASSUMPTION: no episodes == seasons (i.e. assume show/season/episodes structure)
5371 CStdString sql = PrepareSQL("select count(1) from episodeview where strPath = '%s' limit 1", strPath.c_str());
5372 m_pDS->query( sql.c_str() );
5373 if (m_pDS->num_rows() && m_pDS->fv(0).get_asInt() > 0)
5377 return TranslateContent(scraper->Content());
5382 void CVideoDatabase::GetMovieGenresByName(const CStdString& strSearch, CFileItemList& items)
5388 if (NULL == m_pDB.get()) return;
5389 if (NULL == m_pDS.get()) return;
5391 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5392 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());
5394 strSQL=PrepareSQL("select distinct genre.idGenre,genre.strGenre from genre,genrelinkmovie where genrelinkmovie.idGenre=genre.idGenre and strGenre like '%%%s%%'", strSearch.c_str());
5395 m_pDS->query( strSQL.c_str() );
5397 while (!m_pDS->eof())
5399 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5400 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),
5401 g_settings.m_videoSources))
5407 CFileItemPtr pItem(new CFileItem(m_pDS->fv("genre.strGenre").get_asString()));
5409 strDir.Format("%ld/", m_pDS->fv("genre.idGenre").get_asInt());
5410 pItem->m_strPath="videodb://1/1/"+ strDir;
5411 pItem->m_bIsFolder=true;
5419 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
5423 void CVideoDatabase::GetMovieCountriesByName(const CStdString& strSearch, CFileItemList& items)
5429 if (NULL == m_pDB.get()) return;
5430 if (NULL == m_pDS.get()) return;
5432 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5433 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());
5435 strSQL=PrepareSQL("select distinct country.idCountry,country.strCountry from country,countrylinkmovie where countrylinkmovie.idCountry=country.idCountry and strCountry like '%%%s%%'", strSearch.c_str());
5436 m_pDS->query( strSQL.c_str() );
5438 while (!m_pDS->eof())
5440 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5441 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),
5442 g_settings.m_videoSources))
5448 CFileItemPtr pItem(new CFileItem(m_pDS->fv("country.strCountry").get_asString()));
5450 strDir.Format("%ld/", m_pDS->fv("country.idCountry").get_asInt());
5451 pItem->m_strPath="videodb://1/1/"+ strDir;
5452 pItem->m_bIsFolder=true;
5460 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
5464 void CVideoDatabase::GetTvShowGenresByName(const CStdString& strSearch, CFileItemList& items)
5470 if (NULL == m_pDB.get()) return;
5471 if (NULL == m_pDS.get()) return;
5473 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5474 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());
5476 strSQL=PrepareSQL("select distinct genre.idGenre,genre.strGenre from genre,genrelinktvshow where genrelinktvshow.idGenre=genre.idGenre and strGenre like '%%%s%%'", strSearch.c_str());
5477 m_pDS->query( strSQL.c_str() );
5479 while (!m_pDS->eof())
5481 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5482 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
5488 CFileItemPtr pItem(new CFileItem(m_pDS->fv("genre.strGenre").get_asString()));
5490 strDir.Format("%ld/", m_pDS->fv("genre.idGenre").get_asInt());
5491 pItem->m_strPath="videodb://2/1/"+ strDir;
5492 pItem->m_bIsFolder=true;
5500 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
5504 void CVideoDatabase::GetMovieActorsByName(const CStdString& strSearch, CFileItemList& items)
5510 if (NULL == m_pDB.get()) return;
5511 if (NULL == m_pDS.get()) return;
5513 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5514 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());
5516 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());
5517 m_pDS->query( strSQL.c_str() );
5519 while (!m_pDS->eof())
5521 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5522 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
5528 CFileItemPtr pItem(new CFileItem(m_pDS->fv("actors.strActor").get_asString()));
5530 strDir.Format("%ld/", m_pDS->fv("actors.idActor").get_asInt());
5531 pItem->m_strPath="videodb://1/4/"+ strDir;
5532 pItem->m_bIsFolder=true;
5540 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
5544 void CVideoDatabase::GetTvShowsActorsByName(const CStdString& strSearch, CFileItemList& items)
5550 if (NULL == m_pDB.get()) return;
5551 if (NULL == m_pDS.get()) return;
5553 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5554 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());
5556 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());
5557 m_pDS->query( strSQL.c_str() );
5559 while (!m_pDS->eof())
5561 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5562 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
5568 CFileItemPtr pItem(new CFileItem(m_pDS->fv("actors.strActor").get_asString()));
5570 strDir.Format("%ld/", m_pDS->fv("actors.idActor").get_asInt());
5571 pItem->m_strPath="videodb://2/4/"+ strDir;
5572 pItem->m_bIsFolder=true;
5580 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
5584 void CVideoDatabase::GetMusicVideoArtistsByName(const CStdString& strSearch, CFileItemList& items)
5590 if (NULL == m_pDB.get()) return;
5591 if (NULL == m_pDS.get()) return;
5594 if (!strSearch.IsEmpty())
5595 strLike = "and actors.strActor like '%%%s%%'";
5596 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5597 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());
5599 strSQL=PrepareSQL("select distinct actors.idActor,actors.strActor from artistlinkmusicvideo,actors where actors.idActor=artistlinkmusicvideo.idArtist "+strLike,strSearch.c_str());
5600 m_pDS->query( strSQL.c_str() );
5602 while (!m_pDS->eof())
5604 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5605 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
5611 CFileItemPtr pItem(new CFileItem(m_pDS->fv("actors.strActor").get_asString()));
5613 strDir.Format("%ld/", m_pDS->fv("actors.idActor").get_asInt());
5614 pItem->m_strPath="videodb://3/4/"+ strDir;
5615 pItem->m_bIsFolder=true;
5623 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
5627 void CVideoDatabase::GetMusicVideoGenresByName(const CStdString& strSearch, CFileItemList& items)
5633 if (NULL == m_pDB.get()) return;
5634 if (NULL == m_pDS.get()) return;
5636 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5637 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());
5639 strSQL=PrepareSQL("select distinct genre.idGenre,genre.strGenre from genre,genrelinkmusicvideo where genrelinkmusicvideo.idGenre=genre.idGenre and genre.strGenre like '%%%s%%'", strSearch.c_str());
5640 m_pDS->query( strSQL.c_str() );
5642 while (!m_pDS->eof())
5644 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5645 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
5651 CFileItemPtr pItem(new CFileItem(m_pDS->fv("genre.strGenre").get_asString()));
5653 strDir.Format("%ld/", m_pDS->fv("genre.idGenre").get_asInt());
5654 pItem->m_strPath="videodb://3/1/"+ strDir;
5655 pItem->m_bIsFolder=true;
5663 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
5667 void CVideoDatabase::GetMusicVideoAlbumsByName(const CStdString& strSearch, CFileItemList& items)
5673 if (NULL == m_pDB.get()) return;
5674 if (NULL == m_pDS.get()) return;
5677 if (!strSearch.IsEmpty())
5679 strLike.Format("and musicvideo.c%02d",VIDEODB_ID_MUSICVIDEO_ALBUM);
5680 strLike += "like '%%s%%%'";
5682 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5683 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());
5686 if (!strLike.IsEmpty())
5687 strLike = "where "+strLike.Mid(4);
5688 strSQL=PrepareSQL("select distinct musicvideo.c%02d,musicvideo.idMVideo from musicvideo"+strLike,VIDEODB_ID_MUSICVIDEO_ALBUM,strSearch.c_str());
5690 m_pDS->query( strSQL.c_str() );
5692 while (!m_pDS->eof())
5694 if (m_pDS->fv(0).get_asString().empty())
5700 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5701 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
5707 CFileItemPtr pItem(new CFileItem(m_pDS->fv(0).get_asString()));
5709 strDir.Format("%ld", m_pDS->fv(1).get_asInt());
5710 pItem->m_strPath="videodb://3/2/"+ strDir;
5711 pItem->m_bIsFolder=false;
5719 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
5723 void CVideoDatabase::GetMusicVideosByAlbum(const CStdString& strSearch, CFileItemList& items)
5729 if (NULL == m_pDB.get()) return;
5730 if (NULL == m_pDS.get()) return;
5732 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5733 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());
5735 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());
5736 m_pDS->query( strSQL.c_str() );
5738 while (!m_pDS->eof())
5740 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5741 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
5747 CFileItemPtr pItem(new CFileItem(m_pDS->fv(1).get_asString()+" - "+m_pDS->fv(2).get_asString()));
5749 strDir.Format("3/2/%ld",m_pDS->fv("musicvideo.idMVideo").get_asInt());
5751 pItem->m_strPath="videodb://"+ strDir;
5752 pItem->m_bIsFolder=false;
5760 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
5764 bool CVideoDatabase::GetMusicVideosByWhere(const CStdString &baseDir, const CStdString &whereClause, CFileItemList &items, bool checkLocks /*= true*/)
5768 DWORD time = CTimeUtils::GetTimeMS();
5772 if (NULL == m_pDB.get()) return false;
5773 if (NULL == m_pDS.get()) return false;
5775 // We don't use PrepareSQL here, as the WHERE clause is already formatted.
5776 CStdString strSQL = "select * from musicvideoview " + whereClause;
5777 CLog::Log(LOGDEBUG, "%s query = %s", __FUNCTION__, strSQL.c_str());
5780 if (!m_pDS->query(strSQL.c_str()))
5782 CLog::Log(LOGDEBUG, "%s time for actual SQL query = %d", __FUNCTION__, CTimeUtils::GetTimeMS() - time); time = CTimeUtils::GetTimeMS();
5784 int iRowsFound = m_pDS->num_rows();
5785 if (iRowsFound == 0)
5791 // get data from returned rows
5792 items.Reserve(iRowsFound);
5793 // get songs from returned subtable
5794 while (!m_pDS->eof())
5796 int idMVideo = m_pDS->fv("idMVideo").get_asInt();
5797 CVideoInfoTag musicvideo = GetDetailsForMusicVideo(m_pDS);
5798 if (!checkLocks || g_settings.GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE || g_passwordManager.bMasterUser ||
5799 g_passwordManager.IsDatabasePathUnlocked(musicvideo.m_strPath,g_settings.m_videoSources))
5801 CFileItemPtr item(new CFileItem(musicvideo));
5802 item->m_strPath.Format("%s%ld",baseDir,idMVideo);
5803 item->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED,musicvideo.m_playCount > 0);
5809 CLog::Log(LOGDEBUG, "%s time to retrieve from dataset = %d", __FUNCTION__, CTimeUtils::GetTimeMS() - time); time = CTimeUtils::GetTimeMS();
5817 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, whereClause.c_str());
5822 unsigned int CVideoDatabase::GetMusicVideoIDs(const CStdString& strWhere, vector<pair<int,int> > &songIDs)
5826 if (NULL == m_pDB.get()) return 0;
5827 if (NULL == m_pDS.get()) return 0;
5829 CStdString strSQL = "select distinct idMVideo from musicvideoview " + strWhere;
5830 if (!m_pDS->query(strSQL.c_str())) return 0;
5832 if (m_pDS->num_rows() == 0)
5837 songIDs.reserve(m_pDS->num_rows());
5838 while (!m_pDS->eof())
5840 songIDs.push_back(make_pair<int,int>(2,m_pDS->fv(0).get_asInt()));
5844 return songIDs.size();
5848 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strWhere.c_str());
5853 bool CVideoDatabase::GetRandomMusicVideo(CFileItem* item, int& idSong, const CStdString& strWhere)
5859 int iCount = GetMusicVideoCount(strWhere);
5862 int iRandom = rand() % iCount;
5864 if (NULL == m_pDB.get()) return false;
5865 if (NULL == m_pDS.get()) return false;
5867 // We don't use PrepareSQL here, as the WHERE clause is already formatted.
5869 strSQL.Format("select * from musicvideoview %s order by idMVideo limit 1 offset %i",strWhere.c_str(),iRandom);
5870 CLog::Log(LOGDEBUG, "%s query = %s", __FUNCTION__, strSQL.c_str());
5872 if (!m_pDS->query(strSQL.c_str()))
5874 int iRowsFound = m_pDS->num_rows();
5875 if (iRowsFound != 1)
5880 *item->GetVideoInfoTag() = GetDetailsForMusicVideo(m_pDS);
5881 item->m_strPath.Format("videodb://3/2/%ld",item->GetVideoInfoTag()->m_iDbId);
5882 idSong = m_pDS->fv("idMVideo").get_asInt();
5883 item->SetLabel(item->GetVideoInfoTag()->m_strTitle);
5889 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strWhere.c_str());
5894 int CVideoDatabase::GetMatchingMusicVideo(const CStdString& strArtist, const CStdString& strAlbum, const CStdString& strTitle)
5898 if (NULL == m_pDB.get()) return -1;
5899 if (NULL == m_pDS.get()) return -1;
5902 if (strAlbum.IsEmpty() && strTitle.IsEmpty())
5903 { // we want to return matching artists only
5904 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5905 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());
5907 strSQL=PrepareSQL("select distinct actors.idActor from artistlinkmusicvideo,actors where actors.idActor=artistlinkmusicvideo.idArtist and actors.strActor like '%s'",strArtist.c_str());
5910 { // we want to return the matching musicvideo
5911 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5912 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());
5914 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());
5916 m_pDS->query( strSQL.c_str() );
5921 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5922 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
5928 int lResult = m_pDS->fv(0).get_asInt();
5934 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
5939 void CVideoDatabase::GetMoviesByName(const CStdString& strSearch, CFileItemList& items)
5945 if (NULL == m_pDB.get()) return;
5946 if (NULL == m_pDS.get()) return;
5948 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5949 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());
5951 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());
5952 m_pDS->query( strSQL.c_str() );
5954 while (!m_pDS->eof())
5956 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5957 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
5963 int movieId = m_pDS->fv("movie.idMovie").get_asInt();
5964 CStdString strSQL2 = PrepareSQL("select idSet from setlinkmovie where idMovie=%i",movieId);
5965 m_pDS2->query(strSQL2.c_str());
5966 CFileItemPtr pItem(new CFileItem(m_pDS->fv(1).get_asString()));
5968 pItem->m_strPath.Format("videodb://1/2/%i",movieId);
5970 pItem->m_strPath.Format("videodb://1/7/%i/%i",m_pDS2->fv(0).get_asInt(),movieId);
5972 pItem->m_bIsFolder=false;
5981 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
5985 void CVideoDatabase::GetTvShowsByName(const CStdString& strSearch, CFileItemList& items)
5991 if (NULL == m_pDB.get()) return;
5992 if (NULL == m_pDS.get()) return;
5994 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
5995 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());
5997 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());
5998 m_pDS->query( strSQL.c_str() );
6000 while (!m_pDS->eof())
6002 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6003 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
6009 CFileItemPtr pItem(new CFileItem(m_pDS->fv(1).get_asString()));
6011 strDir.Format("2/2/%ld/", m_pDS->fv("tvshow.idShow").get_asInt());
6013 pItem->m_strPath="videodb://"+ strDir;
6014 pItem->m_bIsFolder=true;
6015 pItem->GetVideoInfoTag()->m_iDbId = m_pDS->fv("tvshow.idShow").get_asInt();
6023 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
6027 void CVideoDatabase::GetEpisodesByName(const CStdString& strSearch, CFileItemList& items)
6033 if (NULL == m_pDB.get()) return;
6034 if (NULL == m_pDS.get()) return;
6036 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6037 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());
6039 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());
6040 m_pDS->query( strSQL.c_str() );
6042 while (!m_pDS->eof())
6044 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6045 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
6051 CFileItemPtr pItem(new CFileItem(m_pDS->fv(1).get_asString()+" ("+m_pDS->fv(4).get_asString()+")"));
6052 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());
6053 pItem->m_bIsFolder=false;
6061 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
6065 void CVideoDatabase::GetMusicVideosByName(const CStdString& strSearch, CFileItemList& items)
6067 // Alternative searching - not quite as fast though due to
6068 // retrieving all information
6069 // 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());
6070 // GetMusicVideosByWhere("videodb://3/2/", where, items);
6075 if (NULL == m_pDB.get()) return;
6076 if (NULL == m_pDS.get()) return;
6078 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6079 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());
6081 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());
6082 m_pDS->query( strSQL.c_str() );
6084 while (!m_pDS->eof())
6086 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6087 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
6093 CFileItemPtr pItem(new CFileItem(m_pDS->fv(1).get_asString()));
6095 strDir.Format("3/2/%ld",m_pDS->fv("musicvideo.idMVideo").get_asInt());
6097 pItem->m_strPath="videodb://"+ strDir;
6098 pItem->m_bIsFolder=false;
6106 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
6110 void CVideoDatabase::GetEpisodesByPlot(const CStdString& strSearch, CFileItemList& items)
6112 // Alternative searching - not quite as fast though due to
6113 // retrieving all information
6114 // 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());
6115 // 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());
6116 // GetEpisodesByWhere("videodb://2/2/", where, items);
6122 if (NULL == m_pDB.get()) return;
6123 if (NULL == m_pDS.get()) return;
6125 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6126 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());
6128 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());
6129 m_pDS->query( strSQL.c_str() );
6131 while (!m_pDS->eof())
6133 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6134 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
6140 CFileItemPtr pItem(new CFileItem(m_pDS->fv(1).get_asString()+" ("+m_pDS->fv(4).get_asString()+")"));
6141 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());
6142 pItem->m_bIsFolder=false;
6150 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
6154 void CVideoDatabase::GetMoviesByPlot(const CStdString& strSearch, CFileItemList& items)
6160 if (NULL == m_pDB.get()) return;
6161 if (NULL == m_pDS.get()) return;
6163 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6164 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());
6166 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());
6168 m_pDS->query( strSQL.c_str() );
6170 while (!m_pDS->eof())
6172 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6173 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv(2).get_asString()),g_settings.m_videoSources))
6179 CFileItemPtr pItem(new CFileItem(m_pDS->fv(1).get_asString()));
6180 pItem->m_strPath.Format("videodb://1/2/%ld", m_pDS->fv(0).get_asInt());
6181 pItem->m_bIsFolder=false;
6191 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
6195 void CVideoDatabase::GetMovieDirectorsByName(const CStdString& strSearch, CFileItemList& items)
6201 if (NULL == m_pDB.get()) return;
6202 if (NULL == m_pDS.get()) return;
6204 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6205 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());
6207 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());
6209 m_pDS->query( strSQL.c_str() );
6211 while (!m_pDS->eof())
6213 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6214 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
6221 strDir.Format("%ld/", m_pDS->fv("directorlinkmovie.idDirector").get_asInt());
6222 CFileItemPtr pItem(new CFileItem(m_pDS->fv("actors.strActor").get_asString()));
6224 pItem->m_strPath="videodb://1/5/"+ strDir;
6225 pItem->m_bIsFolder=true;
6233 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
6237 void CVideoDatabase::GetTvShowsDirectorsByName(const CStdString& strSearch, CFileItemList& items)
6243 if (NULL == m_pDB.get()) return;
6244 if (NULL == m_pDS.get()) return;
6246 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6247 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());
6249 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());
6251 m_pDS->query( strSQL.c_str() );
6253 while (!m_pDS->eof())
6255 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6256 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
6263 strDir.Format("%ld/", m_pDS->fv("directorlinktvshow.idDirector").get_asInt());
6264 CFileItemPtr pItem(new CFileItem(m_pDS->fv("actors.strActor").get_asString()));
6266 pItem->m_strPath="videodb://2/5/"+ strDir;
6267 pItem->m_bIsFolder=true;
6275 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
6279 void CVideoDatabase::GetMusicVideoDirectorsByName(const CStdString& strSearch, CFileItemList& items)
6285 if (NULL == m_pDB.get()) return;
6286 if (NULL == m_pDS.get()) return;
6288 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6289 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());
6291 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());
6293 m_pDS->query( strSQL.c_str() );
6295 while (!m_pDS->eof())
6297 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
6298 if (!g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("path.strPath").get_asString()),g_settings.m_videoSources))
6305 strDir.Format("%ld/", m_pDS->fv("directorlinkmusicvideo.idDirector").get_asInt());
6306 CFileItemPtr pItem(new CFileItem(m_pDS->fv("actors.strActor").get_asString()));
6308 pItem->m_strPath="videodb://3/5/"+ strDir;
6309 pItem->m_bIsFolder=true;
6317 CLog::Log(LOGERROR, "%s (%s) failed", __FUNCTION__, strSQL.c_str());
6321 void CVideoDatabase::CleanDatabase(IVideoInfoScannerObserver* pObserver, const vector<int>* paths)
6323 CGUIDialogProgress *progress=NULL;
6326 if (NULL == m_pDB.get()) return;
6327 if (NULL == m_pDS.get()) return;
6329 unsigned int time = CTimeUtils::GetTimeMS();
6330 CLog::Log(LOGNOTICE, "%s: Starting videodatabase cleanup ..", __FUNCTION__);
6334 // find all the files
6338 if (paths->size() == 0)
6340 RollbackTransaction();
6344 CStdString strPaths;
6345 for (unsigned int i=0;i<paths->size();++i )
6346 strPaths.Format("%s,%i",strPaths.Mid(0).c_str(),paths->at(i));
6347 sql = PrepareSQL("select * from files,path where files.idPath=path.idPath and path.idPath in (%s)",strPaths.Mid(1).c_str());
6350 sql = "select * from files, path where files.idPath = path.idPath";
6352 m_pDS->query(sql.c_str());
6353 if (m_pDS->num_rows() == 0) return;
6357 progress = (CGUIDialogProgress *)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
6360 progress->SetHeading(700);
6361 progress->SetLine(0, "");
6362 progress->SetLine(1, 313);
6363 progress->SetLine(2, 330);
6364 progress->SetPercentage(0);
6365 progress->StartModal();
6366 progress->ShowProgressBar(true);
6371 pObserver->OnDirectoryChanged("");
6372 pObserver->OnSetTitle("");
6373 pObserver->OnSetCurrentProgress(0,1);
6374 pObserver->OnStateChanged(CLEANING_UP_DATABASE);
6377 CStdString filesToDelete = "";
6378 CStdString moviesToDelete = "";
6379 CStdString episodesToDelete = "";
6380 CStdString musicVideosToDelete = "";
6382 std::vector<int> movieIDs;
6383 std::vector<int> episodeIDs;
6384 std::vector<int> musicVideoIDs;
6386 int total = m_pDS->num_rows();
6388 while (!m_pDS->eof())
6390 CStdString path = m_pDS->fv("path.strPath").get_asString();
6391 CStdString fileName = m_pDS->fv("files.strFileName").get_asString();
6392 CStdString fullPath;
6393 ConstructPath(fullPath,path,fileName);
6395 // get the first stacked file
6396 if (URIUtils::IsStack(fullPath))
6397 fullPath = CStackDirectory::GetFirstStackedFile(fullPath);
6399 // check for deletion
6401 VECSOURCES *pShares = g_settings.GetSourcesFromType("video");
6403 // check if we have a internet related file that is part of a media source
6404 if (URIUtils::IsInternetStream(fullPath, true) && CUtil::GetMatchingSource(fullPath, *pShares, bIsSource) > -1)
6406 if (!CFile::Exists(fullPath, false))
6407 filesToDelete += m_pDS->fv("files.idFile").get_asString() + ",";
6411 // remove optical, internet related and non-existing files
6412 // note: this will also remove entries from previously existing media sources
6413 if (URIUtils::IsOnDVD(fullPath) || URIUtils::IsInternetStream(fullPath, true) || !CFile::Exists(fullPath, false))
6414 filesToDelete += m_pDS->fv("files.idFile").get_asString() + ",";
6421 progress->SetPercentage(current * 100 / total);
6422 progress->Progress();
6423 if (progress->IsCanceled())
6432 pObserver->OnSetProgress(current,total);
6439 if ( ! filesToDelete.IsEmpty() )
6441 filesToDelete.TrimRight(",");
6442 // now grab them movies
6443 sql = PrepareSQL("select idMovie from movie where idFile in (%s)",filesToDelete.c_str());
6444 m_pDS->query(sql.c_str());
6445 while (!m_pDS->eof())
6447 movieIDs.push_back(m_pDS->fv(0).get_asInt());
6448 moviesToDelete += m_pDS->fv(0).get_asString() + ",";
6452 // now grab them episodes
6453 sql = PrepareSQL("select idEpisode from episode where idFile in (%s)",filesToDelete.c_str());
6454 m_pDS->query(sql.c_str());
6455 while (!m_pDS->eof())
6457 episodeIDs.push_back(m_pDS->fv(0).get_asInt());
6458 episodesToDelete += m_pDS->fv(0).get_asString() + ",";
6463 // now grab them musicvideos
6464 sql = PrepareSQL("select idMVideo from musicvideo where idFile in (%s)",filesToDelete.c_str());
6465 m_pDS->query(sql.c_str());
6466 while (!m_pDS->eof())
6468 musicVideoIDs.push_back(m_pDS->fv(0).get_asInt());
6469 musicVideosToDelete += m_pDS->fv(0).get_asString() + ",";
6477 progress->SetPercentage(100);
6478 progress->Progress();
6481 if ( ! filesToDelete.IsEmpty() )
6483 filesToDelete = "(" + filesToDelete + ")";
6484 CLog::Log(LOGDEBUG, "%s: Cleaning files table", __FUNCTION__);
6485 sql = "delete from files where idFile in " + filesToDelete;
6486 m_pDS->exec(sql.c_str());
6488 CLog::Log(LOGDEBUG, "%s: Cleaning streamdetails table", __FUNCTION__);
6489 sql = "delete from streamdetails where idFile in " + filesToDelete;
6490 m_pDS->exec(sql.c_str());
6492 CLog::Log(LOGDEBUG, "%s: Cleaning bookmark table", __FUNCTION__);
6493 sql = "delete from bookmark where idFile in " + filesToDelete;
6494 m_pDS->exec(sql.c_str());
6496 CLog::Log(LOGDEBUG, "%s: Cleaning settings table", __FUNCTION__);
6497 sql = "delete from settings where idFile in " + filesToDelete;
6498 m_pDS->exec(sql.c_str());
6500 CLog::Log(LOGDEBUG, "%s: Cleaning stacktimes table", __FUNCTION__);
6501 sql = "delete from stacktimes where idFile in " + filesToDelete;
6502 m_pDS->exec(sql.c_str());
6505 if ( ! moviesToDelete.IsEmpty() )
6507 moviesToDelete = "(" + moviesToDelete.TrimRight(",") + ")";
6509 CLog::Log(LOGDEBUG, "%s: Cleaning movie table", __FUNCTION__);
6510 sql = "delete from movie where idMovie in " + moviesToDelete;
6511 m_pDS->exec(sql.c_str());
6513 CLog::Log(LOGDEBUG, "%s: Cleaning actorlinkmovie table", __FUNCTION__);
6514 sql = "delete from actorlinkmovie where idMovie in " + moviesToDelete;
6515 m_pDS->exec(sql.c_str());
6517 CLog::Log(LOGDEBUG, "%s: Cleaning directorlinkmovie table", __FUNCTION__);
6518 sql = "delete from directorlinkmovie where idMovie in " + moviesToDelete;
6519 m_pDS->exec(sql.c_str());
6521 CLog::Log(LOGDEBUG, "%s: Cleaning writerlinkmovie table", __FUNCTION__);
6522 sql = "delete from writerlinkmovie where idMovie in " + moviesToDelete;
6523 m_pDS->exec(sql.c_str());
6525 CLog::Log(LOGDEBUG, "%s: Cleaning genrelinkmovie table", __FUNCTION__);
6526 sql = "delete from genrelinkmovie where idMovie in " + moviesToDelete;
6527 m_pDS->exec(sql.c_str());
6529 CLog::Log(LOGDEBUG, "%s: Cleaning countrylinkmovie table", __FUNCTION__);
6530 sql = "delete from countrylinkmovie where idMovie in " + moviesToDelete;
6531 m_pDS->exec(sql.c_str());
6533 CLog::Log(LOGDEBUG, "%s: Cleaning studiolinkmovie table", __FUNCTION__);
6534 sql = "delete from studiolinkmovie where idMovie in " + moviesToDelete;
6535 m_pDS->exec(sql.c_str());
6537 CLog::Log(LOGDEBUG, "%s: Cleaning setlinkmovie table", __FUNCTION__);
6538 sql = "delete from setlinkmovie where idMovie in " + moviesToDelete;
6539 m_pDS->exec(sql.c_str());
6542 if ( ! episodesToDelete.IsEmpty() )
6544 episodesToDelete = "(" + episodesToDelete.TrimRight(",") + ")";
6546 CLog::Log(LOGDEBUG, "%s: Cleaning episode table", __FUNCTION__);
6547 sql = "delete from episode where idEpisode in " + episodesToDelete;
6548 m_pDS->exec(sql.c_str());
6550 CLog::Log(LOGDEBUG, "%s: Cleaning actorlinkepisode table", __FUNCTION__);
6551 sql = "delete from actorlinkepisode where idEpisode in " + episodesToDelete;
6552 m_pDS->exec(sql.c_str());
6554 CLog::Log(LOGDEBUG, "%s: Cleaning directorlinkepisode table", __FUNCTION__);
6555 sql = "delete from directorlinkepisode where idEpisode in " + episodesToDelete;
6556 m_pDS->exec(sql.c_str());
6558 CLog::Log(LOGDEBUG, "%s: Cleaning writerlinkepisode table", __FUNCTION__);
6559 sql = "delete from writerlinkepisode where idEpisode in " + episodesToDelete;
6560 m_pDS->exec(sql.c_str());
6562 CLog::Log(LOGDEBUG, "%s: Cleaning tvshowlinkepisode table", __FUNCTION__);
6563 sql = "delete from tvshowlinkepisode where idEpisode in " + episodesToDelete;
6564 m_pDS->exec(sql.c_str());
6567 CLog::Log(LOGDEBUG, "%s: Cleaning paths that don't exist and don't have content set...", __FUNCTION__);
6568 sql = "select * from path where strContent not like ''";
6569 m_pDS->query(sql.c_str());
6571 while (!m_pDS->eof())
6573 if (!CDirectory::Exists(m_pDS->fv("path.strPath").get_asString()))
6574 strIds.Format("%s %i,",strIds.Mid(0),m_pDS->fv("path.idPath").get_asInt()); // mid since we cannot format the same string
6577 if (!strIds.IsEmpty())
6579 strIds.TrimLeft(" ");
6580 strIds.TrimRight(",");
6581 sql = PrepareSQL("delete from path where idPath in (%s)",strIds.c_str());
6582 m_pDS->exec(sql.c_str());
6583 sql = PrepareSQL("delete from tvshowlinkpath where idPath in (%s)",strIds.c_str());
6584 m_pDS->exec(sql.c_str());
6587 CLog::Log(LOGDEBUG, "%s: Cleaning tvshow table", __FUNCTION__);
6588 sql = "delete from tvshow where idShow not in (select idShow from tvshowlinkpath)";
6589 m_pDS->exec(sql.c_str());
6591 std::vector<int> tvshowIDs;
6592 CStdString showsToDelete;
6593 sql = "select tvshow.idShow from tvshow "
6594 "join tvshowlinkpath on tvshow.idShow=tvshowlinkpath.idShow "
6595 "join path on path.idPath=tvshowlinkpath.idPath "
6596 "where tvshow.idShow not in (select idShow from tvshowlinkepisode) "
6597 "and path.strContent=''";
6598 m_pDS->query(sql.c_str());
6599 while (!m_pDS->eof())
6601 tvshowIDs.push_back(m_pDS->fv(0).get_asInt());
6602 showsToDelete += m_pDS->fv(0).get_asString() + ",";
6606 if (!showsToDelete.IsEmpty())
6608 sql = "delete from tvshow where idShow in (" + showsToDelete.TrimRight(",") + ")";
6609 m_pDS->exec(sql.c_str());
6612 CLog::Log(LOGDEBUG, "%s: Cleaning actorlinktvshow table", __FUNCTION__);
6613 sql = "delete from actorlinktvshow where idShow not in (select idShow from tvshow)";
6614 m_pDS->exec(sql.c_str());
6616 CLog::Log(LOGDEBUG, "%s: Cleaning directorlinktvshow table", __FUNCTION__);
6617 sql = "delete from directorlinktvshow where idShow not in (select idShow from tvshow)";
6618 m_pDS->exec(sql.c_str());
6620 CLog::Log(LOGDEBUG, "%s: Cleaning tvshowlinkpath table", __FUNCTION__);
6621 sql = "delete from tvshowlinkpath where idShow not in (select idShow from tvshow)";
6622 m_pDS->exec(sql.c_str());
6624 CLog::Log(LOGDEBUG, "%s: Cleaning genrelinktvshow table", __FUNCTION__);
6625 sql = "delete from genrelinktvshow where idShow not in (select idShow from tvshow)";
6626 m_pDS->exec(sql.c_str());
6628 CLog::Log(LOGDEBUG, "%s: Cleaning movielinktvshow table", __FUNCTION__);
6629 sql = "delete from movielinktvshow where idShow not in (select idShow from tvshow)";
6630 m_pDS->exec(sql.c_str());
6631 sql = "delete from movielinktvshow where idMovie not in (select distinct idMovie from movie)";
6632 m_pDS->exec(sql.c_str());
6634 if ( ! musicVideosToDelete.IsEmpty() )
6636 musicVideosToDelete = "(" + musicVideosToDelete.TrimRight(",") + ")";
6638 CLog::Log(LOGDEBUG, "%s: Cleaning musicvideo table", __FUNCTION__);
6639 sql = "delete from musicvideo where idMVideo in " + musicVideosToDelete;
6640 m_pDS->exec(sql.c_str());
6642 CLog::Log(LOGDEBUG, "%s: Cleaning artistlinkmusicvideo table", __FUNCTION__);
6643 sql = "delete from artistlinkmusicvideo where idMVideo in " + musicVideosToDelete;
6644 m_pDS->exec(sql.c_str());
6646 CLog::Log(LOGDEBUG, "%s: Cleaning directorlinkmusicvideo table" ,__FUNCTION__);
6647 sql = "delete from directorlinkmusicvideo where idMVideo in " + musicVideosToDelete;
6648 m_pDS->exec(sql.c_str());
6650 CLog::Log(LOGDEBUG, "%s: Cleaning genrelinkmusicvideo table" ,__FUNCTION__);
6651 sql = "delete from genrelinkmusicvideo where idMVideo in " + musicVideosToDelete;
6652 m_pDS->exec(sql.c_str());
6654 CLog::Log(LOGDEBUG, "%s: Cleaning studiolinkmusicvideo table", __FUNCTION__);
6655 sql = "delete from studiolinkmusicvideo where idMVideo in " + musicVideosToDelete;
6656 m_pDS->exec(sql.c_str());
6659 CLog::Log(LOGDEBUG, "%s: Cleaning path table", __FUNCTION__);
6660 sql = "delete from path where idPath not in (select distinct idPath from files) and idPath not in (select distinct idPath from tvshowlinkpath) and strContent=''";
6661 m_pDS->exec(sql.c_str());
6663 CLog::Log(LOGDEBUG, "%s: Cleaning genre table", __FUNCTION__);
6664 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)";
6665 m_pDS->exec(sql.c_str());
6667 CLog::Log(LOGDEBUG, "%s: Cleaning country table", __FUNCTION__);
6668 sql = "delete from country where idCountry not in (select distinct idCountry from countrylinkmovie)";
6669 m_pDS->exec(sql.c_str());
6671 CLog::Log(LOGDEBUG, "%s: Cleaning actor table of actors, directors and writers", __FUNCTION__);
6672 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)";
6673 m_pDS->exec(sql.c_str());
6675 CLog::Log(LOGDEBUG, "%s: Cleaning studio table", __FUNCTION__);
6676 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)";
6677 m_pDS->exec(sql.c_str());
6679 CLog::Log(LOGDEBUG, "%s: Cleaning set table", __FUNCTION__);
6680 sql = "delete from sets where idSet not in (select distinct idSet from setlinkmovie)";
6681 m_pDS->exec(sql.c_str());
6683 CommitTransaction();
6686 pObserver->OnStateChanged(COMPRESSING_DATABASE);
6690 CUtil::DeleteVideoDatabaseDirectoryCache();
6692 time = CTimeUtils::GetTimeMS() - time;
6693 CLog::Log(LOGNOTICE, "%s: Cleaning videodatabase done. Operation took %s", __FUNCTION__, StringUtils::SecondsToTimeString(time / 1000).c_str());
6695 for (unsigned int i = 0; i < movieIDs.size(); i++)
6696 AnnounceRemove("movie", movieIDs[i]);
6698 for (unsigned int i = 0; i < episodeIDs.size(); i++)
6699 AnnounceRemove("episode", episodeIDs[i]);
6701 for (unsigned int i = 0; i < tvshowIDs.size(); i++)
6702 AnnounceRemove("tvshow", tvshowIDs[i]);
6704 for (unsigned int i = 0; i < musicVideoIDs.size(); i++)
6705 AnnounceRemove("musicvideo", musicVideoIDs[i]);
6709 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
6715 void CVideoDatabase::DumpToDummyFiles(const CStdString &path)
6718 CFileItemList items;
6719 GetTvShowsByWhere("videodb://2/2/", "", items);
6720 CStdString showPath = URIUtils::AddFileToFolder(path, "shows");
6721 CDirectory::Create(showPath);
6722 for (int i = 0; i < items.Size(); i++)
6724 // create a folder in this directory
6725 CStdString showName = CUtil::MakeLegalFileName(items[i]->GetVideoInfoTag()->m_strShowTitle);
6726 CStdString TVFolder;
6727 URIUtils::AddFileToFolder(showPath, showName, TVFolder);
6728 if (CDirectory::Create(TVFolder))
6729 { // right - grab the episodes and dump them as well
6730 CFileItemList episodes;
6731 CStdString where = PrepareSQL("where idShow=%i", items[i]->GetVideoInfoTag()->m_iDbId);
6732 GetEpisodesByWhere("videodb://2/2/", where, episodes);
6733 for (int i = 0; i < episodes.Size(); i++)
6735 CVideoInfoTag *tag = episodes[i]->GetVideoInfoTag();
6737 episode.Format("%s.s%02de%02d.avi", showName.c_str(), tag->m_iSeason, tag->m_iEpisode);
6739 CStdString episodePath;
6740 URIUtils::AddFileToFolder(TVFolder, episode, episodePath);
6742 if (file.OpenForWrite(episodePath))
6749 GetMoviesByWhere("videodb://1/2/", "", "", items);
6750 CStdString moviePath = URIUtils::AddFileToFolder(path, "movies");
6751 CDirectory::Create(moviePath);
6752 for (int i = 0; i < items.Size(); i++)
6754 CVideoInfoTag *tag = items[i]->GetVideoInfoTag();
6756 movie.Format("%s.avi", tag->m_strTitle.c_str());
6758 if (file.OpenForWrite(URIUtils::AddFileToFolder(moviePath, movie)))
6763 void CVideoDatabase::ExportToXML(const CStdString &path, bool singleFiles /* = false */, bool images /* = false */, bool actorThumbs /* false */, bool overwrite /*=false*/)
6765 CGUIDialogProgress *progress=NULL;
6768 if (NULL == m_pDB.get()) return;
6769 if (NULL == m_pDS.get()) return;
6770 if (NULL == m_pDS2.get()) return;
6772 // create a 3rd dataset as well as GetEpisodeDetails() etc. uses m_pDS2, and we need to do 3 nested queries on tv shows
6773 auto_ptr<Dataset> pDS;
6774 pDS.reset(m_pDB->CreateDataset());
6775 if (NULL == pDS.get()) return;
6777 auto_ptr<Dataset> pDS2;
6778 pDS2.reset(m_pDB->CreateDataset());
6779 if (NULL == pDS2.get()) return;
6781 // if we're exporting to a single folder, we export thumbs as well
6782 CStdString exportRoot = URIUtils::AddFileToFolder(path, "xbmc_videodb_" + CDateTime::GetCurrentDateTime().GetAsDBDate());
6783 CStdString xmlFile = URIUtils::AddFileToFolder(exportRoot, "videodb.xml");
6784 CStdString actorsDir = URIUtils::AddFileToFolder(exportRoot, "actors");
6785 CStdString moviesDir = URIUtils::AddFileToFolder(exportRoot, "movies");
6786 CStdString musicvideosDir = URIUtils::AddFileToFolder(exportRoot, "musicvideos");
6787 CStdString tvshowsDir = URIUtils::AddFileToFolder(exportRoot, "tvshows");
6793 CDirectory::Remove(exportRoot);
6794 CDirectory::Create(exportRoot);
6795 CDirectory::Create(actorsDir);
6796 CDirectory::Create(moviesDir);
6797 CDirectory::Create(musicvideosDir);
6798 CDirectory::Create(tvshowsDir);
6801 progress = (CGUIDialogProgress *)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
6803 CStdString sql = "select * from movieview";
6805 m_pDS->query(sql.c_str());
6809 progress->SetHeading(647);
6810 progress->SetLine(0, 650);
6811 progress->SetLine(1, "");
6812 progress->SetLine(2, "");
6813 progress->SetPercentage(0);
6814 progress->StartModal();
6815 progress->ShowProgressBar(true);
6818 int total = m_pDS->num_rows();
6821 // create our xml document
6822 TiXmlDocument xmlDoc;
6823 TiXmlDeclaration decl("1.0", "UTF-8", "yes");
6824 xmlDoc.InsertEndChild(decl);
6825 TiXmlNode *pMain = NULL;
6830 TiXmlElement xmlMainElement("videodb");
6831 pMain = xmlDoc.InsertEndChild(xmlMainElement);
6832 XMLUtils::SetInt(pMain,"version", GetExportVersion());
6835 while (!m_pDS->eof())
6837 CVideoInfoTag movie = GetDetailsForMovie(m_pDS, true);
6838 // strip paths to make them relative
6839 if (movie.m_strTrailer.Mid(0,movie.m_strPath.size()).Equals(movie.m_strPath))
6840 movie.m_strTrailer = movie.m_strTrailer.Mid(movie.m_strPath.size());
6841 movie.Save(pMain, "movie", !singleFiles);
6843 // reset old skip state
6848 progress->SetLine(1, movie.m_strTitle);
6849 progress->SetPercentage(current * 100 / total);
6850 progress->Progress();
6851 if (progress->IsCanceled())
6859 CFileItem item(movie.m_strFileNameAndPath,false);
6860 CFileItem saveItem(item);
6863 CStdString strFileName(movie.m_strTitle);
6864 if (movie.m_iYear > 0)
6865 strFileName.AppendFormat("_%i", movie.m_iYear);
6866 saveItem = CFileItem(GetSafeFile(moviesDir, strFileName) + ".avi", false);
6868 if (singleFiles && CUtil::SupportsFileOperations(movie.m_strFileNameAndPath))
6870 if (!item.Exists(false))
6872 CLog::Log(LOGDEBUG, "%s - Not exporting item %s as it does not exist", __FUNCTION__, movie.m_strFileNameAndPath.c_str());
6877 CStdString nfoFile(URIUtils::ReplaceExtension(item.GetTBNFile(), ".nfo"));
6879 if (item.IsOpticalMediaFile())
6881 nfoFile = URIUtils::GetParentFolderURI(nfoFile, true);
6884 if (overwrite || !CFile::Exists(nfoFile, false))
6886 if(!xmlDoc.SaveFile(nfoFile))
6888 CLog::Log(LOGERROR, "%s: Movie nfo export failed! ('%s')", __FUNCTION__, nfoFile.c_str());
6889 bSkip = ExportSkipEntry(nfoFile);
6903 TiXmlDeclaration decl("1.0", "UTF-8", "yes");
6904 xmlDoc.InsertEndChild(decl);
6908 if (images && !bSkip)
6910 CStdString cachedThumb(GetCachedThumb(item));
6911 CStdString savedThumb(saveItem.GetTBNFile());
6912 if (!cachedThumb.IsEmpty() && (overwrite || !CFile::Exists(savedThumb, false)))
6913 if (!CFile::Cache(cachedThumb, savedThumb))
6914 CLog::Log(LOGERROR, "%s: Movie thumb export failed! ('%s' -> '%s')", __FUNCTION__, cachedThumb.c_str(), savedThumb.c_str());
6916 CStdString cachedFanart(item.GetCachedFanart());
6917 CStdString savedFanart(URIUtils::ReplaceExtension(savedThumb, "-fanart.jpg"));
6919 if (CFile::Exists(cachedFanart, false) && (overwrite || !CFile::Exists(savedFanart, false)))
6920 if (!CFile::Cache(cachedFanart, savedFanart))
6921 CLog::Log(LOGERROR, "%s: Movie fanart export failed! ('%s' -> '%s')", __FUNCTION__, cachedFanart.c_str(), savedFanart.c_str());
6924 ExportActorThumbs(actorsDir, movie, singleFiles, overwrite);
6931 // find all musicvideos
6932 sql = "select * from musicvideoview";
6934 m_pDS->query(sql.c_str());
6936 total = m_pDS->num_rows();
6939 while (!m_pDS->eof())
6941 CVideoInfoTag movie = GetDetailsForMusicVideo(m_pDS);
6942 movie.Save(pMain, "musicvideo", !singleFiles);
6944 // reset old skip state
6949 progress->SetLine(1, movie.m_strTitle);
6950 progress->SetPercentage(current * 100 / total);
6951 progress->Progress();
6952 if (progress->IsCanceled())
6960 CFileItem item(movie.m_strFileNameAndPath,false);
6961 CFileItem saveItem(item);
6964 CStdString strFileName(movie.m_strArtist + "." + movie.m_strTitle);
6965 if (movie.m_iYear > 0)
6966 strFileName.AppendFormat("_%i", movie.m_iYear);
6967 saveItem = CFileItem(GetSafeFile(musicvideosDir, strFileName) + ".avi", false);
6969 if (CUtil::SupportsFileOperations(movie.m_strFileNameAndPath) && singleFiles)
6971 if (!item.Exists(false))
6973 CLog::Log(LOGDEBUG, "%s - Not exporting item %s as it does not exist", __FUNCTION__, movie.m_strFileNameAndPath.c_str());
6978 CStdString nfoFile(URIUtils::ReplaceExtension(item.GetTBNFile(), ".nfo"));
6980 if (overwrite || !CFile::Exists(nfoFile, false))
6982 if(!xmlDoc.SaveFile(nfoFile))
6984 CLog::Log(LOGERROR, "%s: Musicvideo nfo export failed! ('%s')", __FUNCTION__, nfoFile.c_str());
6985 bSkip = ExportSkipEntry(nfoFile);
6999 TiXmlDeclaration decl("1.0", "UTF-8", "yes");
7000 xmlDoc.InsertEndChild(decl);
7003 if (images && !bSkip)
7005 CStdString cachedThumb(GetCachedThumb(item));
7006 CStdString savedThumb(saveItem.GetTBNFile());
7007 if (!cachedThumb.IsEmpty() && (overwrite || !CFile::Exists(savedThumb, false)))
7008 if (!CFile::Cache(cachedThumb, savedThumb))
7009 CLog::Log(LOGERROR, "%s: Musicvideo thumb export failed! ('%s' -> '%s')", __FUNCTION__, cachedThumb.c_str(), savedThumb.c_str());
7016 // repeat for all tvshows
7017 sql = "SELECT * FROM tvshowview";
7018 m_pDS->query(sql.c_str());
7020 total = m_pDS->num_rows();
7023 while (!m_pDS->eof())
7025 CVideoInfoTag tvshow = GetDetailsForTvShow(m_pDS, true);
7026 tvshow.Save(pMain, "tvshow", !singleFiles);
7028 // reset old skip state
7033 progress->SetLine(1, tvshow.m_strTitle);
7034 progress->SetPercentage(current * 100 / total);
7035 progress->Progress();
7036 if (progress->IsCanceled())
7045 CFileItem item(tvshow.m_strPath, true);
7046 CFileItem saveItem(item);
7048 saveItem = CFileItem(GetSafeFile(tvshowsDir, tvshow.m_strShowTitle), true);
7049 if (singleFiles && CUtil::SupportsFileOperations(tvshow.m_strPath))
7051 if (!item.Exists(false))
7053 CLog::Log(LOGDEBUG, "%s - Not exporting item %s as it does not exist", __FUNCTION__, tvshow.m_strPath.c_str());
7059 URIUtils::AddFileToFolder(tvshow.m_strPath, "tvshow.nfo", nfoFile);
7061 if (overwrite || !CFile::Exists(nfoFile, false))
7063 if(!xmlDoc.SaveFile(nfoFile))
7065 CLog::Log(LOGERROR, "%s: TVShow nfo export failed! ('%s')", __FUNCTION__, nfoFile.c_str());
7066 bSkip = ExportSkipEntry(nfoFile);
7080 TiXmlDeclaration decl("1.0", "UTF-8", "yes");
7081 xmlDoc.InsertEndChild(decl);
7084 if (images && !bSkip)
7086 CStdString cachedThumb(GetCachedThumb(item));
7087 CStdString savedThumb(saveItem.GetFolderThumb());
7088 if (!cachedThumb.IsEmpty() && (overwrite || !CFile::Exists(savedThumb, false)))
7089 if (!CFile::Cache(cachedThumb, savedThumb))
7090 CLog::Log(LOGERROR, "%s: TVShow thumb export failed! ('%s' -> '%s')", __FUNCTION__, cachedThumb.c_str(), savedThumb.c_str());
7092 CStdString cachedFanart(item.GetCachedFanart());
7093 CStdString savedFanart(saveItem.GetFolderThumb("fanart.jpg"));
7094 if (CFile::Exists(cachedFanart, false) && (overwrite || !CFile::Exists(savedFanart, false)))
7095 if (!CFile::Cache(cachedFanart, savedFanart))
7096 CLog::Log(LOGERROR, "%s: TVShow fanart export failed! ('%s' -> '%s')", __FUNCTION__, cachedFanart.c_str(), savedFanart.c_str());
7099 ExportActorThumbs(actorsDir, tvshow, singleFiles, overwrite);
7101 // now get all available seasons from this show
7102 sql = PrepareSQL("select distinct(c%02d) from episodeview where idShow=%i", VIDEODB_ID_EPISODE_SEASON, tvshow.m_iDbId);
7103 pDS2->query(sql.c_str());
7105 CFileItemList items;
7106 CStdString strDatabasePath;
7107 strDatabasePath.Format("videodb://2/2/%i/",tvshow.m_iDbId);
7109 // add "All Seasons" to list
7111 pItem.reset(new CFileItem(g_localizeStrings.Get(20366)));
7112 pItem->GetVideoInfoTag()->m_iSeason = -1;
7113 pItem->GetVideoInfoTag()->m_strPath = tvshow.m_strPath;
7116 // loop through available season
7117 while (!pDS2->eof())
7119 int iSeason = pDS2->fv(0).get_asInt();
7120 CStdString strLabel;
7122 strLabel = g_localizeStrings.Get(20381);
7124 strLabel.Format(g_localizeStrings.Get(20358),iSeason);
7125 CFileItemPtr pItem(new CFileItem(strLabel));
7126 pItem->GetVideoInfoTag()->m_strTitle = strLabel;
7127 pItem->GetVideoInfoTag()->m_iSeason = iSeason;
7128 pItem->GetVideoInfoTag()->m_strPath = tvshow.m_strPath;
7134 // export season thumbs
7135 for (int i=0;i<items.Size();++i)
7137 CStdString strSeasonThumb, strParent;
7138 int iSeason = items[i]->GetVideoInfoTag()->m_iSeason;
7140 strSeasonThumb = "season-all.tbn";
7141 else if (iSeason == 0)
7142 strSeasonThumb = "season-specials.tbn";
7144 strSeasonThumb.Format("season%02i.tbn",iSeason);
7146 CStdString cachedThumb(items[i]->GetCachedSeasonThumb());
7147 CStdString savedThumb(saveItem.GetFolderThumb(strSeasonThumb));
7149 if (CFile::Exists(cachedThumb, false) && (overwrite || !CFile::Exists(savedThumb, false)))
7150 if (!CFile::Cache(cachedThumb, savedThumb))
7151 CLog::Log(LOGERROR, "%s: TVShow season thumb export failed ('%s' -> '%s')", __FUNCTION__, cachedThumb.c_str(), savedThumb.c_str());
7155 // now save the episodes from this show
7156 sql = PrepareSQL("select * from episodeview where idShow=%i order by strFileName, idEpisode",tvshow.m_iDbId);
7157 pDS->query(sql.c_str());
7158 CStdString showDir(saveItem.m_strPath);
7162 CVideoInfoTag episode = GetDetailsForEpisode(pDS, true);
7164 episode.Save(pMain, "episodedetails", !singleFiles);
7166 episode.Save(pMain->LastChild(), "episodedetails", !singleFiles);
7168 // multi-episode files need dumping to the same XML
7169 while (singleFiles && !pDS->eof() &&
7170 episode.m_iFileId == pDS->fv("idFile").get_asInt())
7172 episode = GetDetailsForEpisode(pDS, true);
7173 episode.Save(pMain, "episodedetails", !singleFiles);
7177 // reset old skip state
7180 CFileItem item(episode.m_strFileNameAndPath, false);
7181 CFileItem saveItem(item);
7185 epName.Format("s%02ie%02i.avi", episode.m_iSeason, episode.m_iEpisode);
7186 saveItem = CFileItem(URIUtils::AddFileToFolder(showDir, epName), false);
7190 if (!item.Exists(false))
7192 CLog::Log(LOGDEBUG, "%s - Not exporting item %s as it does not exist", __FUNCTION__, episode.m_strFileNameAndPath.c_str());
7197 CStdString nfoFile(URIUtils::ReplaceExtension(item.GetTBNFile(), ".nfo"));
7199 if (overwrite || !CFile::Exists(nfoFile, false))
7201 if(!xmlDoc.SaveFile(nfoFile))
7203 CLog::Log(LOGERROR, "%s: Episode nfo export failed! ('%s')", __FUNCTION__, nfoFile.c_str());
7204 bSkip = ExportSkipEntry(nfoFile);
7218 TiXmlDeclaration decl("1.0", "UTF-8", "yes");
7219 xmlDoc.InsertEndChild(decl);
7223 if (images && !bSkip)
7225 CStdString cachedThumb(GetCachedThumb(item));
7226 CStdString savedThumb(saveItem.GetTBNFile());
7227 if (!cachedThumb.IsEmpty() && (overwrite || !CFile::Exists(savedThumb, false)))
7228 if (!CFile::Cache(cachedThumb, savedThumb))
7229 CLog::Log(LOGERROR, "%s: Episode thumb export failed! ('%s' -> '%s')", __FUNCTION__, cachedThumb.c_str(), savedThumb.c_str());
7232 ExportActorThumbs(actorsDir, episode, singleFiles, overwrite);
7241 if (singleFiles && progress)
7243 progress->SetPercentage(100);
7244 progress->Progress();
7249 // now dump path info
7250 set<CStdString> paths;
7252 TiXmlElement xmlPathElement("paths");
7253 TiXmlNode *pPaths = pMain->InsertEndChild(xmlPathElement);
7254 for( set<CStdString>::iterator iter = paths.begin(); iter != paths.end(); ++iter)
7256 bool foundDirectly = false;
7257 SScanSettings settings;
7258 ScraperPtr info = GetScraperForPath(*iter, settings, foundDirectly);
7259 if (info && foundDirectly)
7261 TiXmlElement xmlPathElement2("path");
7262 TiXmlNode *pPath = pPaths->InsertEndChild(xmlPathElement2);
7263 XMLUtils::SetString(pPath,"url", *iter);
7264 XMLUtils::SetInt(pPath,"scanrecursive", settings.recurse);
7265 XMLUtils::SetBoolean(pPath,"usefoldernames", settings.parent_name);
7266 XMLUtils::SetString(pPath,"content", TranslateContent(info->Content()));
7267 XMLUtils::SetString(pPath,"scraperpath", info->ID());
7270 xmlDoc.SaveFile(xmlFile);
7275 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
7282 void CVideoDatabase::ExportActorThumbs(const CStdString &strDir, const CVideoInfoTag &tag, bool singleFiles, bool overwrite /*=false*/)
7284 CStdString strPath(strDir);
7287 strPath = URIUtils::AddFileToFolder(tag.m_strPath, ".actors");
7288 if (!CDirectory::Exists(strPath))
7290 CDirectory::Create(strPath);
7291 CFile::SetHidden(strPath, true);
7295 for (CVideoInfoTag::iCast iter = tag.m_cast.begin();iter != tag.m_cast.end();++iter)
7298 item.SetLabel(iter->strName);
7299 CStdString strThumb = item.GetCachedActorThumb();
7300 if (CFile::Exists(strThumb))
7302 CStdString thumbFile(GetSafeFile(strPath, iter->strName) + ".tbn");
7303 if (overwrite || !CFile::Exists(thumbFile))
7304 if (!CFile::Cache(strThumb, thumbFile))
7305 CLog::Log(LOGERROR, "%s: Actor thumb export failed! ('%s' -> '%s')", __FUNCTION__, strThumb.c_str(), thumbFile.c_str());
7310 CStdString CVideoDatabase::GetCachedThumb(const CFileItem& item) const
7312 CStdString cachedThumb(item.GetCachedVideoThumb());
7313 if (!CFile::Exists(cachedThumb) && g_advancedSettings.m_bVideoLibraryExportAutoThumbs)
7315 CStdString strPath, strFileName;
7316 URIUtils::Split(cachedThumb, strPath, strFileName);
7317 cachedThumb = strPath + "auto-" + strFileName;
7320 if (CFile::Exists(cachedThumb))
7326 bool CVideoDatabase::ExportSkipEntry(const CStdString &nfoFile)
7328 CStdString strParent;
7329 URIUtils::GetParentPath(nfoFile,strParent);
7330 CLog::Log(LOGERROR, "%s: Unable to write to '%s'!", __FUNCTION__, strParent.c_str());
7332 bool bSkip = CGUIDialogYesNo::ShowAndGetInput(g_localizeStrings.Get(647), g_localizeStrings.Get(20302), strParent.c_str(), g_localizeStrings.Get(20303));
7335 CLog::Log(LOGERROR, "%s: Skipping export of '%s' as requested", __FUNCTION__, nfoFile.c_str());
7337 CLog::Log(LOGERROR, "%s: Export failed! Canceling as requested", __FUNCTION__);
7342 void CVideoDatabase::ImportFromXML(const CStdString &path)
7344 CGUIDialogProgress *progress=NULL;
7347 if (NULL == m_pDB.get()) return;
7348 if (NULL == m_pDS.get()) return;
7350 TiXmlDocument xmlDoc;
7351 if (!xmlDoc.LoadFile(URIUtils::AddFileToFolder(path, "videodb.xml")))
7354 TiXmlElement *root = xmlDoc.RootElement();
7357 progress = (CGUIDialogProgress *)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
7360 progress->SetHeading(648);
7361 progress->SetLine(0, 649);
7362 progress->SetLine(1, 330);
7363 progress->SetLine(2, "");
7364 progress->SetPercentage(0);
7365 progress->StartModal();
7366 progress->ShowProgressBar(true);
7370 XMLUtils::GetInt(root, "version", iVersion);
7372 CLog::Log(LOGDEBUG, "%s: Starting import (export version = %i)", __FUNCTION__, iVersion);
7374 TiXmlElement *movie = root->FirstChildElement();
7377 // first count the number of items...
7380 if (strnicmp(movie->Value(), "movie", 5)==0 ||
7381 strnicmp(movie->Value(), "tvshow", 6)==0 ||
7382 strnicmp(movie->Value(), "musicvideo",10)==0 )
7384 movie = movie->NextSiblingElement();
7387 CStdString actorsDir(URIUtils::AddFileToFolder(path, "actors"));
7388 CStdString moviesDir(URIUtils::AddFileToFolder(path, "movies"));
7389 CStdString musicvideosDir(URIUtils::AddFileToFolder(path, "musicvideos"));
7390 CStdString tvshowsDir(URIUtils::AddFileToFolder(path, "tvshows"));
7391 CVideoInfoScanner scanner;
7392 set<CStdString> actors;
7393 movie = root->FirstChildElement();
7397 if (strnicmp(movie->Value(), "movie", 5) == 0)
7400 CFileItem item(info);
7401 scanner.AddVideo(&item,CONTENT_MOVIES);
7402 SetPlayCount(item, info.m_playCount, info.m_lastPlayed);
7403 CStdString strFileName(info.m_strTitle);
7404 if (GetExportVersion() >= 1 && info.m_iYear > 0)
7405 strFileName.AppendFormat("_%i", info.m_iYear);
7406 CStdString file(GetSafeFile(moviesDir, strFileName));
7407 CFile::Cache(file + ".tbn", item.GetCachedVideoThumb());
7408 CFile::Cache(file + "-fanart.jpg", item.GetCachedFanart());
7409 for (CVideoInfoTag::iCast i = info.m_cast.begin(); i != info.m_cast.end(); ++i)
7410 actors.insert(i->strName);
7413 else if (strnicmp(movie->Value(), "musicvideo", 10) == 0)
7416 CFileItem item(info);
7417 scanner.AddVideo(&item,CONTENT_MUSICVIDEOS);
7418 SetPlayCount(item, info.m_playCount, info.m_lastPlayed);
7419 CStdString strFileName(info.m_strArtist + "." + info.m_strTitle);
7420 if (GetExportVersion() >= 1 && info.m_iYear > 0)
7421 strFileName.AppendFormat("_%i", info.m_iYear);
7422 CStdString file(GetSafeFile(musicvideosDir, strFileName));
7423 CFile::Cache(file + ".tbn", item.GetCachedVideoThumb());
7426 else if (strnicmp(movie->Value(), "tvshow", 6) == 0)
7428 // load the TV show in. NOTE: This deletes all episodes under the TV Show, which may not be
7429 // what we desire. It may make better sense to only delete (or even better, update) the show information
7431 URIUtils::AddSlashAtEnd(info.m_strPath);
7432 DeleteTvShow(info.m_strPath);
7433 CFileItem item(info);
7434 int showID = scanner.AddVideo(&item,CONTENT_TVSHOWS);
7436 CStdString showDir(GetSafeFile(tvshowsDir, info.m_strTitle));
7437 CFile::Cache(URIUtils::AddFileToFolder(showDir, "folder.jpg"), item.GetCachedVideoThumb());
7438 CFile::Cache(URIUtils::AddFileToFolder(showDir, "fanart.jpg"), item.GetCachedFanart());
7439 for (CVideoInfoTag::iCast i = info.m_cast.begin(); i != info.m_cast.end(); ++i)
7440 actors.insert(i->strName);
7441 // now load the episodes
7442 TiXmlElement *episode = movie->FirstChildElement("episodedetails");
7445 // no need to delete the episode info, due to the above deletion
7448 CFileItem item(info);
7449 scanner.AddVideo(&item,CONTENT_TVSHOWS,false,showID);
7450 SetPlayCount(item, info.m_playCount, info.m_lastPlayed);
7452 file.Format("s%02ie%02i.tbn", info.m_iSeason, info.m_iEpisode);
7453 CFile::Cache(URIUtils::AddFileToFolder(showDir, file), item.GetCachedVideoThumb());
7454 for (CVideoInfoTag::iCast i = info.m_cast.begin(); i != info.m_cast.end(); ++i)
7455 actors.insert(i->strName);
7456 episode = episode->NextSiblingElement("episodedetails");
7458 // and fetch season thumbs
7459 scanner.FetchSeasonThumbs(showID, showDir, false, true);
7461 else if (strnicmp(movie->Value(), "paths", 5) == 0)
7463 const TiXmlElement* path = movie->FirstChildElement("path");
7467 XMLUtils::GetString(path,"url",strPath);
7470 if (XMLUtils::GetString(path,"content", content))
7471 { // check the scraper exists, if so store the path
7475 if (!XMLUtils::GetString(path,"scraperID",uuid))
7476 { // support pre addons exports
7477 XMLUtils::GetString(path, "scraperpath", uuid);
7478 uuid = URIUtils::GetFileName(uuid);
7481 if (CAddonMgr::Get().GetAddon(uuid, addon))
7483 SScanSettings settings;
7484 ScraperPtr scraper = boost::dynamic_pointer_cast<CScraper>(addon);
7485 // FIXME: scraper settings are not exported?
7486 scraper->SetPathSettings(TranslateContent(content), "");
7487 XMLUtils::GetInt(path,"scanrecursive",settings.recurse);
7488 XMLUtils::GetBoolean(path,"usefoldernames",settings.parent_name);
7489 SetScraperForPath(strPath,scraper,settings);
7492 path = path->NextSiblingElement();
7495 movie = movie->NextSiblingElement();
7496 if (progress && total)
7498 progress->SetPercentage(current * 100 / total);
7499 progress->SetLine(2, info.m_strTitle);
7500 progress->Progress();
7501 if (progress->IsCanceled())
7504 RollbackTransaction();
7509 // cache any actor thumbs
7510 for (set<CStdString>::iterator i = actors.begin(); i != actors.end(); i++)
7514 CStdString savedThumb(GetSafeFile(actorsDir, *i) + ".tbn");
7515 CStdString cachedThumb = item.GetCachedActorThumb();
7516 CFile::Cache(savedThumb, cachedThumb);
7521 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
7527 bool CVideoDatabase::GetArbitraryQuery(const CStdString& strQuery, const CStdString& strOpenRecordSet, const CStdString& strCloseRecordSet,
7528 const CStdString& strOpenRecord, const CStdString& strCloseRecord, const CStdString& strOpenField, const CStdString& strCloseField, CStdString& strResult)
7533 if (NULL == m_pDB.get()) return false;
7534 if (NULL == m_pDS.get()) return false;
7535 CStdString strSQL=strQuery;
7536 if (!m_pDS->query(strSQL.c_str()))
7538 strResult = m_pDB->getErrorMsg();
7541 strResult=strOpenRecordSet;
7542 while (!m_pDS->eof())
7544 strResult += strOpenRecord;
7545 for (int i=0; i<m_pDS->fieldCount(); i++)
7547 strResult += strOpenField + CStdString(m_pDS->fv(i).get_asString()) + strCloseField;
7549 strResult += strCloseRecord;
7552 strResult += strCloseRecordSet;
7558 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
7562 if (NULL == m_pDB.get()) return false;
7563 strResult = m_pDB->getErrorMsg();
7573 bool CVideoDatabase::ArbitraryExec(const CStdString& strExec)
7577 if (NULL == m_pDB.get()) return false;
7578 if (NULL == m_pDS.get()) return false;
7579 CStdString strSQL = strExec;
7580 m_pDS->exec(strSQL.c_str());
7586 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
7591 void CVideoDatabase::ConstructPath(CStdString& strDest, const CStdString& strPath, const CStdString& strFileName)
7593 if (URIUtils::IsStack(strFileName) || URIUtils::IsInArchive(strFileName))
7594 strDest = strFileName;
7596 URIUtils::AddFileToFolder(strPath, strFileName, strDest);
7599 void CVideoDatabase::SplitPath(const CStdString& strFileNameAndPath, CStdString& strPath, CStdString& strFileName)
7601 if (URIUtils::IsStack(strFileNameAndPath) || strFileNameAndPath.Mid(0,6).Equals("rar://") || strFileNameAndPath.Mid(0,6).Equals("zip://"))
7603 URIUtils::GetParentPath(strFileNameAndPath,strPath);
7604 strFileName = strFileNameAndPath;
7607 URIUtils::Split(strFileNameAndPath,strPath, strFileName);
7610 void CVideoDatabase::InvalidatePathHash(const CStdString& strPath)
7612 SScanSettings settings;
7614 ScraperPtr info = GetScraperForPath(strPath,settings,foundDirectly);
7615 SetPathHash(strPath,"");
7618 if (info->Content() == CONTENT_TVSHOWS || (info->Content() == CONTENT_MOVIES && !foundDirectly)) // if we scan by folder name we need to invalidate parent as well
7620 if (info->Content() == CONTENT_TVSHOWS || settings.parent_name_root)
7622 CStdString strParent;
7623 URIUtils::GetParentPath(strPath,strParent);
7624 SetPathHash(strParent,"");
7629 bool CVideoDatabase::CommitTransaction()
7631 if (CDatabase::CommitTransaction())
7632 { // number of items in the db has likely changed, so recalculate
7633 g_infoManager.SetLibraryBool(LIBRARY_HAS_MOVIES, HasContent(VIDEODB_CONTENT_MOVIES));
7634 g_infoManager.SetLibraryBool(LIBRARY_HAS_TVSHOWS, HasContent(VIDEODB_CONTENT_TVSHOWS));
7635 g_infoManager.SetLibraryBool(LIBRARY_HAS_MUSICVIDEOS, HasContent(VIDEODB_CONTENT_MUSICVIDEOS));
7641 void CVideoDatabase::DeleteThumbForItem(const CStdString& strPath, bool bFolder, int idEpisode)
7643 CFileItem item(strPath,bFolder);
7646 item.m_strPath = item.GetVideoInfoTag()->m_strFileNameAndPath;
7647 if (CFile::Exists(item.GetCachedEpisodeThumb()))
7648 CTextureCache::Get().ClearCachedImage(item.GetCachedEpisodeThumb(), true);
7650 CTextureCache::Get().ClearCachedImage(item.GetCachedVideoThumb(), true);
7654 CTextureCache::Get().ClearCachedImage(item.GetCachedVideoThumb(), true);
7655 CTextureCache::Get().ClearCachedImage(item.GetCachedFanart(), true);
7658 // tell our GUI to completely reload all controls (as some of them
7659 // are likely to have had this image in use so will need refreshing)
7660 CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_REFRESH_THUMBS);
7661 g_windowManager.SendThreadMessage(msg);
7664 void CVideoDatabase::SetDetail(const CStdString& strDetail, int id, int field,
7665 VIDEODB_CONTENT_TYPE type)
7669 if (NULL == m_pDB.get()) return;
7670 if (NULL == m_pDS.get()) return;
7672 CStdString strTable, strField;
7673 if (type == VIDEODB_CONTENT_MOVIES)
7676 strField = "idMovie";
7678 if (type == VIDEODB_CONTENT_TVSHOWS)
7680 strTable = "tvshow";
7681 strField = "idShow";
7683 if (type == VIDEODB_CONTENT_MUSICVIDEOS)
7685 strTable = "musicvideo";
7686 strField = "idMVideo";
7689 if (strTable.IsEmpty())
7692 CStdString strSQL = PrepareSQL("update %s set c%02u='%s' where %s=%u",
7693 strTable.c_str(), field, strDetail.c_str(), strField.c_str(), id);
7694 m_pDS->exec(strSQL.c_str());
7698 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
7702 CStdString CVideoDatabase::GetSafeFile(const CStdString &dir, const CStdString &name) const
7704 CStdString safeThumb(name);
7705 safeThumb.Replace(' ', '_');
7706 return URIUtils::AddFileToFolder(dir, CUtil::MakeLegalFileName(safeThumb));
7709 void CVideoDatabase::AnnounceRemove(std::string content, int id)
7712 data["content"] = content;
7713 data[content + "id"] = id;
7714 ANNOUNCEMENT::CAnnouncementManager::Announce(ANNOUNCEMENT::Library, "xbmc", "RemoveVideo", data);
7717 void CVideoDatabase::AnnounceUpdate(std::string content, int id)
7720 data["content"] = content;
7721 data[content + "id"] = id;
7722 ANNOUNCEMENT::CAnnouncementManager::Announce(ANNOUNCEMENT::Library, "xbmc", "UpdateVideo", data);
7725 bool CVideoDatabase::GetItemForPath(const CStdString &content, const CStdString &strPath, CFileItem &item)
7727 CFileItemList items;
7728 CStdString path(strPath);
7730 if(URIUtils::IsMultiPath(path))
7731 path = CMultiPathDirectory::GetFirstPath(path);
7733 if (content == "movies")
7735 CStdString where = PrepareSQL("where c%02d='%s' limit 1", VIDEODB_ID_BASEPATH, path.c_str());
7736 GetMoviesByWhere("", where, "", items);
7738 else if (content == "episodes")
7740 CStdString where = PrepareSQL("where c%02d='%s' limit 1", VIDEODB_ID_EPISODE_BASEPATH, path.c_str());
7741 GetEpisodesByWhere("", where, items);
7743 else if (content == "tvshows")
7745 CStdString where = PrepareSQL("where c%02d='%s' limit 1", VIDEODB_ID_TV_BASEPATH, path.c_str());
7746 GetTvShowsByWhere("", where, items);
7748 else if (content == "musicvideos")
7750 CStdString where = PrepareSQL("where c%02d='%s' limit 1", VIDEODB_ID_MUSICVIDEO_BASEPATH, path.c_str());
7751 GetMusicVideosByWhere("", where, items);
7756 if (item.m_bIsFolder)
7757 item.m_strPath = item.GetVideoInfoTag()->m_strPath;
7759 item.m_strPath = item.GetVideoInfoTag()->m_strFileNameAndPath;