2 * Copyright (C) 2005-2013 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, see
17 * <http://www.gnu.org/licenses/>.
21 #include "VideoLibrary.h"
22 #include "ApplicationMessenger.h"
23 #include "TextureDatabase.h"
25 #include "utils/StringUtils.h"
26 #include "utils/URIUtils.h"
27 #include "video/VideoDatabase.h"
29 using namespace JSONRPC;
31 JSONRPC_STATUS CVideoLibrary::GetMovies(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
33 CVideoDatabase videodatabase;
34 if (!videodatabase.Open())
37 SortDescription sorting;
38 ParseLimits(parameterObject, sorting.limitStart, sorting.limitEnd);
39 if (!ParseSorting(parameterObject, sorting.sortBy, sorting.sortOrder, sorting.sortAttributes))
43 videoUrl.FromString("videodb://movies/titles/");
44 int genreID = -1, year = -1, setID = 0;
45 const CVariant &filter = parameterObject["filter"];
46 if (filter.isMember("genreid"))
47 genreID = (int)filter["genreid"].asInteger();
48 else if (filter.isMember("genre"))
49 videoUrl.AddOption("genre", filter["genre"].asString());
50 else if (filter.isMember("year"))
51 year = (int)filter["year"].asInteger();
52 else if (filter.isMember("actor"))
53 videoUrl.AddOption("actor", filter["actor"].asString());
54 else if (filter.isMember("director"))
55 videoUrl.AddOption("director", filter["director"].asString());
56 else if (filter.isMember("studio"))
57 videoUrl.AddOption("studio", filter["studio"].asString());
58 else if (filter.isMember("country"))
59 videoUrl.AddOption("country", filter["country"].asString());
60 else if (filter.isMember("setid"))
61 setID = (int)filter["setid"].asInteger();
62 else if (filter.isMember("set"))
63 videoUrl.AddOption("set", filter["set"].asString());
64 else if (filter.isMember("tag"))
65 videoUrl.AddOption("tag", filter["tag"].asString());
66 else if (filter.isObject())
69 if (!GetXspFiltering("movies", filter, xsp))
72 videoUrl.AddOption("xsp", xsp);
75 // setID must not be -1 otherwise GetMoviesNav() will return sets
80 if (!videodatabase.GetMoviesNav(videoUrl.ToString(), items, genreID, year, -1, -1, -1, -1, setID, -1, sorting))
83 return GetAdditionalMovieDetails(parameterObject, items, result, videodatabase, false);
86 JSONRPC_STATUS CVideoLibrary::GetMovieDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
88 int id = (int)parameterObject["movieid"].asInteger();
90 CVideoDatabase videodatabase;
91 if (!videodatabase.Open())
95 if (!videodatabase.GetMovieInfo("", infos, id) || infos.m_iDbId <= 0)
98 HandleFileItem("movieid", true, "moviedetails", CFileItemPtr(new CFileItem(infos)), parameterObject, parameterObject["properties"], result, false);
102 JSONRPC_STATUS CVideoLibrary::GetMovieSets(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
104 CVideoDatabase videodatabase;
105 if (!videodatabase.Open())
106 return InternalError;
109 if (!videodatabase.GetSetsNav("videodb://movies/sets/", items, VIDEODB_CONTENT_MOVIES))
110 return InternalError;
112 HandleFileItemList("setid", false, "sets", items, parameterObject, result);
116 JSONRPC_STATUS CVideoLibrary::GetMovieSetDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
118 int id = (int)parameterObject["setid"].asInteger();
120 CVideoDatabase videodatabase;
121 if (!videodatabase.Open())
122 return InternalError;
124 // Get movie set details
126 if (!videodatabase.GetSetInfo(id, infos) || infos.m_iDbId <= 0)
127 return InvalidParams;
129 HandleFileItem("setid", false, "setdetails", CFileItemPtr(new CFileItem(infos)), parameterObject, parameterObject["properties"], result, false);
131 // Get movies from the set
133 if (!videodatabase.GetMoviesNav("videodb://movies/titles/", items, -1, -1, -1, -1, -1, -1, id))
134 return InternalError;
136 return GetAdditionalMovieDetails(parameterObject["movies"], items, result["setdetails"], videodatabase, true);
139 JSONRPC_STATUS CVideoLibrary::GetTVShows(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
141 CVideoDatabase videodatabase;
142 if (!videodatabase.Open())
143 return InternalError;
145 SortDescription sorting;
146 ParseLimits(parameterObject, sorting.limitStart, sorting.limitEnd);
147 if (!ParseSorting(parameterObject, sorting.sortBy, sorting.sortOrder, sorting.sortAttributes))
148 return InvalidParams;
150 CVideoDbUrl videoUrl;
151 videoUrl.FromString("videodb://tvshows/titles/");
152 int genreID = -1, year = -1;
153 const CVariant &filter = parameterObject["filter"];
154 if (filter.isMember("genreid"))
155 genreID = (int)filter["genreid"].asInteger();
156 else if (filter.isMember("genre"))
157 videoUrl.AddOption("genre", filter["genre"].asString());
158 else if (filter.isMember("year"))
159 year = (int)filter["year"].asInteger();
160 else if (filter.isMember("actor"))
161 videoUrl.AddOption("actor", filter["actor"].asString());
162 else if (filter.isMember("studio"))
163 videoUrl.AddOption("studio", filter["studio"].asString());
164 else if (filter.isMember("tag"))
165 videoUrl.AddOption("tag", filter["tag"].asString());
166 else if (filter.isObject())
169 if (!GetXspFiltering("tvshows", filter, xsp))
170 return InvalidParams;
172 videoUrl.AddOption("xsp", xsp);
176 if (!videodatabase.GetTvShowsNav(videoUrl.ToString(), items, genreID, year, -1, -1, -1, -1, sorting))
177 return InvalidParams;
179 bool additionalInfo = false;
180 for (CVariant::const_iterator_array itr = parameterObject["properties"].begin_array(); itr != parameterObject["properties"].end_array(); itr++)
182 CStdString fieldValue = itr->asString();
183 if (fieldValue == "cast" || fieldValue == "tag")
184 additionalInfo = true;
189 for (int index = 0; index < items.Size(); index++)
190 videodatabase.GetTvShowInfo("", *(items[index]->GetVideoInfoTag()), items[index]->GetVideoInfoTag()->m_iDbId);
193 int size = items.Size();
194 if (items.HasProperty("total") && items.GetProperty("total").asInteger() > size)
195 size = (int)items.GetProperty("total").asInteger();
196 HandleFileItemList("tvshowid", true, "tvshows", items, parameterObject, result, size, false);
201 JSONRPC_STATUS CVideoLibrary::GetTVShowDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
203 CVideoDatabase videodatabase;
204 if (!videodatabase.Open())
205 return InternalError;
207 int id = (int)parameterObject["tvshowid"].asInteger();
210 if (!videodatabase.GetTvShowInfo("", infos, id) || infos.m_iDbId <= 0)
211 return InvalidParams;
213 HandleFileItem("tvshowid", true, "tvshowdetails", CFileItemPtr(new CFileItem(infos)), parameterObject, parameterObject["properties"], result, false);
217 JSONRPC_STATUS CVideoLibrary::GetSeasons(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
219 CVideoDatabase videodatabase;
220 if (!videodatabase.Open())
221 return InternalError;
223 int tvshowID = (int)parameterObject["tvshowid"].asInteger();
225 CStdString strPath = StringUtils::Format("videodb://tvshows/titles/%i/", tvshowID);
227 if (!videodatabase.GetSeasonsNav(strPath, items, -1, -1, -1, -1, tvshowID, false))
228 return InternalError;
230 HandleFileItemList("seasonid", false, "seasons", items, parameterObject, result);
234 JSONRPC_STATUS CVideoLibrary::GetSeasonDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
236 CVideoDatabase videodatabase;
237 if (!videodatabase.Open())
238 return InternalError;
240 int id = (int)parameterObject["seasonid"].asInteger();
243 if (!videodatabase.GetSeasonInfo(id, infos) ||
244 infos.m_iDbId <= 0 || infos.m_iIdShow <= 0)
245 return InvalidParams;
247 CFileItemPtr pItem = CFileItemPtr(new CFileItem(infos));
248 HandleFileItem("seasonid", false, "seasondetails", pItem, parameterObject, parameterObject["properties"], result, false);
252 JSONRPC_STATUS CVideoLibrary::GetEpisodes(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
254 CVideoDatabase videodatabase;
255 if (!videodatabase.Open())
256 return InternalError;
258 SortDescription sorting;
259 ParseLimits(parameterObject, sorting.limitStart, sorting.limitEnd);
260 if (!ParseSorting(parameterObject, sorting.sortBy, sorting.sortOrder, sorting.sortAttributes))
261 return InvalidParams;
263 int tvshowID = (int)parameterObject["tvshowid"].asInteger();
264 int season = (int)parameterObject["season"].asInteger();
266 CStdString strPath = StringUtils::Format("videodb://tvshows/titles/%i/%i/", tvshowID, season);
268 CVideoDbUrl videoUrl;
269 videoUrl.FromString(strPath);
270 const CVariant &filter = parameterObject["filter"];
271 if (filter.isMember("genreid"))
272 videoUrl.AddOption("genreid", (int)filter["genreid"].asInteger());
273 else if (filter.isMember("genre"))
274 videoUrl.AddOption("genre", filter["genre"].asString());
275 else if (filter.isMember("year"))
276 videoUrl.AddOption("year", (int)filter["year"].asInteger());
277 else if (filter.isMember("actor"))
278 videoUrl.AddOption("actor", filter["actor"].asString());
279 else if (filter.isMember("director"))
280 videoUrl.AddOption("director", filter["director"].asString());
281 else if (filter.isObject())
284 if (!GetXspFiltering("episodes", filter, xsp))
285 return InvalidParams;
287 videoUrl.AddOption("xsp", xsp);
290 if (tvshowID <= 0 && (season > 0 || videoUrl.HasOption("genreid") || videoUrl.HasOption("genre") || videoUrl.HasOption("actor")))
291 return InvalidParams;
295 videoUrl.AddOption("tvshowid", tvshowID);
297 videoUrl.AddOption("season", season);
301 if (!videodatabase.GetEpisodesByWhere(videoUrl.ToString(), CDatabase::Filter(), items, false, sorting))
302 return InvalidParams;
304 return GetAdditionalEpisodeDetails(parameterObject, items, result, videodatabase, false);
307 JSONRPC_STATUS CVideoLibrary::GetEpisodeDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
309 CVideoDatabase videodatabase;
310 if (!videodatabase.Open())
311 return InternalError;
313 int id = (int)parameterObject["episodeid"].asInteger();
316 if (!videodatabase.GetEpisodeInfo("", infos, id) || infos.m_iDbId <= 0)
317 return InvalidParams;
319 CFileItemPtr pItem = CFileItemPtr(new CFileItem(infos));
320 // We need to set the correct base path to get the valid fanart
321 int tvshowid = infos.m_iIdShow;
323 tvshowid = videodatabase.GetTvShowForEpisode(id);
325 CStdString basePath = StringUtils::Format("videodb://tvshows/titles/%ld/%ld/%ld", tvshowid, infos.m_iSeason, id);
326 pItem->SetPath(basePath);
328 HandleFileItem("episodeid", true, "episodedetails", pItem, parameterObject, parameterObject["properties"], result, false);
332 JSONRPC_STATUS CVideoLibrary::GetMusicVideos(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
334 CVideoDatabase videodatabase;
335 if (!videodatabase.Open())
336 return InternalError;
338 SortDescription sorting;
339 ParseLimits(parameterObject, sorting.limitStart, sorting.limitEnd);
340 if (!ParseSorting(parameterObject, sorting.sortBy, sorting.sortOrder, sorting.sortAttributes))
341 return InvalidParams;
343 CVideoDbUrl videoUrl;
344 videoUrl.FromString("videodb://musicvideos/titles/");
345 int genreID = -1, year = -1;
346 const CVariant &filter = parameterObject["filter"];
347 if (filter.isMember("artist"))
348 videoUrl.AddOption("artist", filter["artist"].asString());
349 else if (filter.isMember("genreid"))
350 genreID = (int)filter["genreid"].asInteger();
351 else if (filter.isMember("genre"))
352 videoUrl.AddOption("genre", filter["genre"].asString());
353 else if (filter.isMember("year"))
354 year = (int)filter["year"].asInteger();
355 else if (filter.isMember("director"))
356 videoUrl.AddOption("director", filter["director"].asString());
357 else if (filter.isMember("studio"))
358 videoUrl.AddOption("studio", filter["studio"].asString());
359 else if (filter.isMember("tag"))
360 videoUrl.AddOption("tag", filter["tag"].asString());
361 else if (filter.isObject())
364 if (!GetXspFiltering("musicvideos", filter, xsp))
365 return InvalidParams;
367 videoUrl.AddOption("xsp", xsp);
371 if (!videodatabase.GetMusicVideosNav(videoUrl.ToString(), items, genreID, year, -1, -1, -1, -1, -1, sorting))
372 return InternalError;
374 return GetAdditionalMusicVideoDetails(parameterObject, items, result, videodatabase, false);
377 JSONRPC_STATUS CVideoLibrary::GetMusicVideoDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
379 CVideoDatabase videodatabase;
380 if (!videodatabase.Open())
381 return InternalError;
383 int id = (int)parameterObject["musicvideoid"].asInteger();
386 if (!videodatabase.GetMusicVideoInfo("", infos, id) || infos.m_iDbId <= 0)
387 return InvalidParams;
389 HandleFileItem("musicvideoid", true, "musicvideodetails", CFileItemPtr(new CFileItem(infos)), parameterObject, parameterObject["properties"], result, false);
393 JSONRPC_STATUS CVideoLibrary::GetRecentlyAddedMovies(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
395 CVideoDatabase videodatabase;
396 if (!videodatabase.Open())
397 return InternalError;
400 if (!videodatabase.GetRecentlyAddedMoviesNav("videodb://recentlyaddedmovies/", items))
401 return InternalError;
403 return GetAdditionalMovieDetails(parameterObject, items, result, videodatabase, true);
406 JSONRPC_STATUS CVideoLibrary::GetRecentlyAddedEpisodes(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
408 CVideoDatabase videodatabase;
409 if (!videodatabase.Open())
410 return InternalError;
413 if (!videodatabase.GetRecentlyAddedEpisodesNav("videodb://recentlyaddedepisodes/", items))
414 return InternalError;
416 return GetAdditionalEpisodeDetails(parameterObject, items, result, videodatabase, true);
419 JSONRPC_STATUS CVideoLibrary::GetRecentlyAddedMusicVideos(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
421 CVideoDatabase videodatabase;
422 if (!videodatabase.Open())
423 return InternalError;
426 if (!videodatabase.GetRecentlyAddedMusicVideosNav("videodb://recentlyaddedmusicvideos/", items))
427 return InternalError;
429 return GetAdditionalMusicVideoDetails(parameterObject, items, result, videodatabase, true);
432 JSONRPC_STATUS CVideoLibrary::GetGenres(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
434 CStdString media = parameterObject["type"].asString();
435 media = media.ToLower();
438 CStdString strPath = "videodb://";
439 /* select which video content to get genres from*/
440 if (media.Equals("movie"))
442 idContent = VIDEODB_CONTENT_MOVIES;
445 else if (media.Equals("tvshow"))
447 idContent = VIDEODB_CONTENT_TVSHOWS;
448 strPath += "tvshows";
450 else if (media.Equals("musicvideo"))
452 idContent = VIDEODB_CONTENT_MUSICVIDEOS;
453 strPath += "musicvideos";
455 strPath += "/genres/";
457 CVideoDatabase videodatabase;
458 if (!videodatabase.Open())
459 return InternalError;
462 if (!videodatabase.GetGenresNav(strPath, items, idContent))
463 return InternalError;
465 /* need to set strTitle in each item*/
466 for (unsigned int i = 0; i < (unsigned int)items.Size(); i++)
467 items[i]->GetVideoInfoTag()->m_strTitle = items[i]->GetLabel();
469 HandleFileItemList("genreid", false, "genres", items, parameterObject, result);
473 JSONRPC_STATUS CVideoLibrary::SetMovieDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
475 int id = (int)parameterObject["movieid"].asInteger();
477 CVideoDatabase videodatabase;
478 if (!videodatabase.Open())
479 return InternalError;
482 if (!videodatabase.GetMovieInfo("", infos, id) || infos.m_iDbId <= 0)
483 return InvalidParams;
486 std::map<std::string, std::string> artwork;
487 videodatabase.GetArtForItem(infos.m_iDbId, infos.m_type, artwork);
489 int playcount = infos.m_playCount;
490 CDateTime lastPlayed = infos.m_lastPlayed;
492 std::set<std::string> removedArtwork;
493 UpdateVideoTag(parameterObject, infos, artwork, removedArtwork);
495 // we need to manually remove tags/taglinks for now because they aren't replaced
496 // due to scrapers not supporting them
497 videodatabase.RemoveTagsFromItem(id, "movie");
499 if (videodatabase.SetDetailsForMovie(infos.m_strFileNameAndPath, infos, artwork, id) <= 0)
500 return InternalError;
502 if (!videodatabase.RemoveArtForItem(infos.m_iDbId, "movie", removedArtwork))
503 return InternalError;
505 if (playcount != infos.m_playCount || lastPlayed != infos.m_lastPlayed)
507 // restore original playcount or the new one won't be announced
508 int newPlaycount = infos.m_playCount;
509 infos.m_playCount = playcount;
510 videodatabase.SetPlayCount(CFileItem(infos), newPlaycount, infos.m_lastPlayed.IsValid() ? infos.m_lastPlayed : CDateTime::GetCurrentDateTime());
513 UpdateResumePoint(parameterObject, infos, videodatabase);
515 CJSONRPCUtils::NotifyItemUpdated();
519 JSONRPC_STATUS CVideoLibrary::SetMovieSetDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
521 int id = (int)parameterObject["setid"].asInteger();
523 CVideoDatabase videodatabase;
524 if (!videodatabase.Open())
525 return InternalError;
528 videodatabase.GetSetInfo(id, infos);
529 if (infos.m_iDbId <= 0)
531 videodatabase.Close();
532 return InvalidParams;
536 std::map<std::string, std::string> artwork;
537 videodatabase.GetArtForItem(infos.m_iDbId, infos.m_type, artwork);
539 std::set<std::string> removedArtwork;
540 UpdateVideoTag(parameterObject, infos, artwork, removedArtwork);
542 if (videodatabase.SetDetailsForMovieSet(infos, artwork, id) <= 0)
543 return InternalError;
545 if (!videodatabase.RemoveArtForItem(infos.m_iDbId, "set", removedArtwork))
546 return InternalError;
548 CJSONRPCUtils::NotifyItemUpdated();
552 JSONRPC_STATUS CVideoLibrary::SetTVShowDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
554 int id = (int)parameterObject["tvshowid"].asInteger();
556 CVideoDatabase videodatabase;
557 if (!videodatabase.Open())
558 return InternalError;
561 if (!videodatabase.GetTvShowInfo("", infos, id) || infos.m_iDbId <= 0)
562 return InvalidParams;
565 std::map<std::string, std::string> artwork;
566 videodatabase.GetArtForItem(infos.m_iDbId, infos.m_type, artwork);
568 std::map<int, std::map<std::string, std::string> > seasonArt;
569 videodatabase.GetTvShowSeasonArt(infos.m_iDbId, seasonArt);
571 int playcount = infos.m_playCount;
572 CDateTime lastPlayed = infos.m_lastPlayed;
574 std::set<std::string> removedArtwork;
575 UpdateVideoTag(parameterObject, infos, artwork, removedArtwork);
577 // we need to manually remove tags/taglinks for now because they aren't replaced
578 // due to scrapers not supporting them
579 videodatabase.RemoveTagsFromItem(id, "tvshow");
581 if (videodatabase.SetDetailsForTvShow(infos.m_strFileNameAndPath, infos, artwork, seasonArt, id) <= 0)
582 return InternalError;
584 if (!videodatabase.RemoveArtForItem(infos.m_iDbId, "tvshow", removedArtwork))
585 return InternalError;
587 if (playcount != infos.m_playCount || lastPlayed != infos.m_lastPlayed)
589 // restore original playcount or the new one won't be announced
590 int newPlaycount = infos.m_playCount;
591 infos.m_playCount = playcount;
592 videodatabase.SetPlayCount(CFileItem(infos), newPlaycount, infos.m_lastPlayed.IsValid() ? infos.m_lastPlayed : CDateTime::GetCurrentDateTime());
595 CJSONRPCUtils::NotifyItemUpdated();
599 JSONRPC_STATUS CVideoLibrary::SetSeasonDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
601 int id = (int)parameterObject["seasonid"].asInteger();
603 CVideoDatabase videodatabase;
604 if (!videodatabase.Open())
605 return InternalError;
608 videodatabase.GetSeasonInfo(id, infos);
609 if (infos.m_iDbId <= 0 || infos.m_iIdShow <= 0)
611 videodatabase.Close();
612 return InvalidParams;
616 std::map<std::string, std::string> artwork;
617 videodatabase.GetArtForItem(infos.m_iDbId, infos.m_type, artwork);
619 std::set<std::string> removedArtwork;
620 UpdateVideoTag(parameterObject, infos, artwork, removedArtwork);
622 if (videodatabase.SetDetailsForSeason(infos, artwork, infos.m_iIdShow, id) <= 0)
623 return InternalError;
625 if (!videodatabase.RemoveArtForItem(infos.m_iDbId, "season", removedArtwork))
626 return InternalError;
628 CJSONRPCUtils::NotifyItemUpdated();
632 JSONRPC_STATUS CVideoLibrary::SetEpisodeDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
634 int id = (int)parameterObject["episodeid"].asInteger();
636 CVideoDatabase videodatabase;
637 if (!videodatabase.Open())
638 return InternalError;
641 videodatabase.GetEpisodeInfo("", infos, id);
642 if (infos.m_iDbId <= 0)
644 videodatabase.Close();
645 return InvalidParams;
648 int tvshowid = videodatabase.GetTvShowForEpisode(id);
651 videodatabase.Close();
652 return InvalidParams;
656 std::map<std::string, std::string> artwork;
657 videodatabase.GetArtForItem(infos.m_iDbId, infos.m_type, artwork);
659 int playcount = infos.m_playCount;
660 CDateTime lastPlayed = infos.m_lastPlayed;
662 std::set<std::string> removedArtwork;
663 UpdateVideoTag(parameterObject, infos, artwork, removedArtwork);
665 if (videodatabase.SetDetailsForEpisode(infos.m_strFileNameAndPath, infos, artwork, tvshowid, id) <= 0)
666 return InternalError;
668 if (!videodatabase.RemoveArtForItem(infos.m_iDbId, "episode", removedArtwork))
669 return InternalError;
671 if (playcount != infos.m_playCount || lastPlayed != infos.m_lastPlayed)
673 // restore original playcount or the new one won't be announced
674 int newPlaycount = infos.m_playCount;
675 infos.m_playCount = playcount;
676 videodatabase.SetPlayCount(CFileItem(infos), newPlaycount, infos.m_lastPlayed.IsValid() ? infos.m_lastPlayed : CDateTime::GetCurrentDateTime());
679 UpdateResumePoint(parameterObject, infos, videodatabase);
681 CJSONRPCUtils::NotifyItemUpdated();
685 JSONRPC_STATUS CVideoLibrary::SetMusicVideoDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
687 int id = (int)parameterObject["musicvideoid"].asInteger();
689 CVideoDatabase videodatabase;
690 if (!videodatabase.Open())
691 return InternalError;
694 videodatabase.GetMusicVideoInfo("", infos, id);
695 if (infos.m_iDbId <= 0)
697 videodatabase.Close();
698 return InvalidParams;
702 std::map<std::string, std::string> artwork;
703 videodatabase.GetArtForItem(infos.m_iDbId, infos.m_type, artwork);
705 int playcount = infos.m_playCount;
706 CDateTime lastPlayed = infos.m_lastPlayed;
708 std::set<std::string> removedArtwork;
709 UpdateVideoTag(parameterObject, infos, artwork, removedArtwork);
711 // we need to manually remove tags/taglinks for now because they aren't replaced
712 // due to scrapers not supporting them
713 videodatabase.RemoveTagsFromItem(id, "musicvideo");
715 if (videodatabase.SetDetailsForMusicVideo(infos.m_strFileNameAndPath, infos, artwork, id) <= 0)
716 return InternalError;
718 if (!videodatabase.RemoveArtForItem(infos.m_iDbId, "musicvideo", removedArtwork))
719 return InternalError;
721 if (playcount != infos.m_playCount || lastPlayed != infos.m_lastPlayed)
723 // restore original playcount or the new one won't be announced
724 int newPlaycount = infos.m_playCount;
725 infos.m_playCount = playcount;
726 videodatabase.SetPlayCount(CFileItem(infos), newPlaycount, infos.m_lastPlayed.IsValid() ? infos.m_lastPlayed : CDateTime::GetCurrentDateTime());
729 UpdateResumePoint(parameterObject, infos, videodatabase);
731 CJSONRPCUtils::NotifyItemUpdated();
735 JSONRPC_STATUS CVideoLibrary::RemoveMovie(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
737 return RemoveVideo(parameterObject);
740 JSONRPC_STATUS CVideoLibrary::RemoveTVShow(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
742 return RemoveVideo(parameterObject);
745 JSONRPC_STATUS CVideoLibrary::RemoveEpisode(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
747 return RemoveVideo(parameterObject);
750 JSONRPC_STATUS CVideoLibrary::RemoveMusicVideo(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
752 return RemoveVideo(parameterObject);
755 JSONRPC_STATUS CVideoLibrary::Scan(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
757 std::string directory = parameterObject["directory"].asString();
759 if (directory.empty())
760 cmd = "updatelibrary(video)";
762 cmd = StringUtils::Format("updatelibrary(video, %s)", StringUtils::Paramify(directory).c_str());
764 CApplicationMessenger::Get().ExecBuiltIn(cmd);
768 JSONRPC_STATUS CVideoLibrary::Export(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
771 if (parameterObject["options"].isMember("path"))
772 cmd = StringUtils::Format("exportlibrary(video, false, %s)", StringUtils::Paramify(parameterObject["options"]["path"].asString()).c_str());
774 cmd = StringUtils::Format("exportlibrary(video, true, %s, %s, %s)",
775 parameterObject["options"]["images"].asBoolean() ? "true" : "false",
776 parameterObject["options"]["overwrite"].asBoolean() ? "true" : "false",
777 parameterObject["options"]["actorthumbs"].asBoolean() ? "true" : "false");
779 CApplicationMessenger::Get().ExecBuiltIn(cmd);
783 JSONRPC_STATUS CVideoLibrary::Clean(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
785 CApplicationMessenger::Get().ExecBuiltIn("cleanlibrary(video)");
789 bool CVideoLibrary::FillFileItem(const CStdString &strFilename, CFileItemPtr &item, const CVariant ¶meterObject /* = CVariant(CVariant::VariantTypeArray) */)
791 CVideoDatabase videodatabase;
792 if (strFilename.empty())
796 if (videodatabase.Open())
798 CVideoInfoTag details;
799 if (videodatabase.LoadVideoInfo(strFilename, details))
801 item->SetFromVideoInfoTag(details);
806 if (item->GetLabel().empty())
808 item->SetLabel(CUtil::GetTitleFromPath(strFilename, false));
809 if (item->GetLabel().empty())
810 item->SetLabel(URIUtils::GetFileName(strFilename));
816 bool CVideoLibrary::FillFileItemList(const CVariant ¶meterObject, CFileItemList &list)
818 CVideoDatabase videodatabase;
819 if (!videodatabase.Open())
822 CStdString file = parameterObject["file"].asString();
823 int movieID = (int)parameterObject["movieid"].asInteger(-1);
824 int episodeID = (int)parameterObject["episodeid"].asInteger(-1);
825 int musicVideoID = (int)parameterObject["musicvideoid"].asInteger(-1);
827 bool success = false;
828 CFileItemPtr fileItem(new CFileItem());
829 if (FillFileItem(file, fileItem))
837 CVideoInfoTag details;
838 videodatabase.GetMovieInfo("", details, movieID);
839 if (!details.IsEmpty())
841 list.Add(CFileItemPtr(new CFileItem(details)));
847 CVideoInfoTag details;
848 if (videodatabase.GetEpisodeInfo("", details, episodeID) && !details.IsEmpty())
850 list.Add(CFileItemPtr(new CFileItem(details)));
854 if (musicVideoID > 0)
856 CVideoInfoTag details;
857 videodatabase.GetMusicVideoInfo("", details, musicVideoID);
858 if (!details.IsEmpty())
860 list.Add(CFileItemPtr(new CFileItem(details)));
868 JSONRPC_STATUS CVideoLibrary::GetAdditionalMovieDetails(const CVariant ¶meterObject, CFileItemList &items, CVariant &result, CVideoDatabase &videodatabase, bool limit /* = true */)
870 if (!videodatabase.Open())
871 return InternalError;
873 bool additionalInfo = false;
874 for (CVariant::const_iterator_array itr = parameterObject["properties"].begin_array(); itr != parameterObject["properties"].end_array(); itr++)
876 CStdString fieldValue = itr->asString();
877 if (fieldValue == "cast" || fieldValue == "showlink" || fieldValue == "tag" || fieldValue == "streamdetails")
878 additionalInfo = true;
883 for (int index = 0; index < items.Size(); index++)
886 videodatabase.GetMovieInfo("", *(items[index]->GetVideoInfoTag()), items[index]->GetVideoInfoTag()->m_iDbId);
890 int size = items.Size();
891 if (!limit && items.HasProperty("total") && items.GetProperty("total").asInteger() > size)
892 size = (int)items.GetProperty("total").asInteger();
893 HandleFileItemList("movieid", true, "movies", items, parameterObject, result, size, limit);
898 JSONRPC_STATUS CVideoLibrary::GetAdditionalEpisodeDetails(const CVariant ¶meterObject, CFileItemList &items, CVariant &result, CVideoDatabase &videodatabase, bool limit /* = true */)
900 if (!videodatabase.Open())
901 return InternalError;
903 bool additionalInfo = false;
904 for (CVariant::const_iterator_array itr = parameterObject["properties"].begin_array(); itr != parameterObject["properties"].end_array(); itr++)
906 CStdString fieldValue = itr->asString();
907 if (fieldValue == "cast" || fieldValue == "streamdetails")
908 additionalInfo = true;
913 for (int index = 0; index < items.Size(); index++)
916 videodatabase.GetEpisodeInfo("", *(items[index]->GetVideoInfoTag()), items[index]->GetVideoInfoTag()->m_iDbId);
920 int size = items.Size();
921 if (!limit && items.HasProperty("total") && items.GetProperty("total").asInteger() > size)
922 size = (int)items.GetProperty("total").asInteger();
923 HandleFileItemList("episodeid", true, "episodes", items, parameterObject, result, size, limit);
928 JSONRPC_STATUS CVideoLibrary::GetAdditionalMusicVideoDetails(const CVariant ¶meterObject, CFileItemList &items, CVariant &result, CVideoDatabase &videodatabase, bool limit /* = true */)
930 if (!videodatabase.Open())
931 return InternalError;
933 bool streamdetails = false;
934 for (CVariant::const_iterator_array itr = parameterObject["properties"].begin_array(); itr != parameterObject["properties"].end_array(); itr++)
936 if (itr->asString() == "tag" || itr->asString() == "streamdetails")
937 streamdetails = true;
942 for (int index = 0; index < items.Size(); index++)
943 videodatabase.GetMusicVideoInfo("", *(items[index]->GetVideoInfoTag()), items[index]->GetVideoInfoTag()->m_iDbId);
946 int size = items.Size();
947 if (!limit && items.HasProperty("total") && items.GetProperty("total").asInteger() > size)
948 size = (int)items.GetProperty("total").asInteger();
949 HandleFileItemList("musicvideoid", true, "musicvideos", items, parameterObject, result, size, limit);
954 JSONRPC_STATUS CVideoLibrary::RemoveVideo(const CVariant ¶meterObject)
956 CVideoDatabase videodatabase;
957 if (!videodatabase.Open())
958 return InternalError;
960 if (parameterObject.isMember("movieid"))
961 videodatabase.DeleteMovie((int)parameterObject["movieid"].asInteger());
962 else if (parameterObject.isMember("tvshowid"))
963 videodatabase.DeleteTvShow((int)parameterObject["tvshowid"].asInteger());
964 else if (parameterObject.isMember("episodeid"))
965 videodatabase.DeleteEpisode((int)parameterObject["episodeid"].asInteger());
966 else if (parameterObject.isMember("musicvideoid"))
967 videodatabase.DeleteMusicVideo((int)parameterObject["musicvideoid"].asInteger());
969 CJSONRPCUtils::NotifyItemUpdated();
973 void CVideoLibrary::UpdateResumePoint(const CVariant ¶meterObject, CVideoInfoTag &details, CVideoDatabase &videodatabase)
975 if (!parameterObject["resume"].isNull())
977 int position = (int)parameterObject["resume"]["position"].asInteger();
979 videodatabase.ClearBookMarksOfFile(details.m_strFileNameAndPath, CBookmark::RESUME);
983 if (videodatabase.GetResumeBookMark(details.m_strFileNameAndPath, bookmark))
985 bookmark.timeInSeconds = position;
987 int total = (int)parameterObject["resume"]["total"].asInteger();
989 bookmark.totalTimeInSeconds = total;
990 videodatabase.AddBookMarkToFile(details.m_strFileNameAndPath, bookmark, CBookmark::RESUME);
996 void CVideoLibrary::UpdateVideoTag(const CVariant ¶meterObject, CVideoInfoTag& details, std::map<std::string, std::string> &artwork, std::set<std::string> &removedArtwork)
998 if (ParameterNotNull(parameterObject, "title"))
999 details.m_strTitle = parameterObject["title"].asString();
1000 if (ParameterNotNull(parameterObject, "playcount"))
1001 details.m_playCount = (int)parameterObject["playcount"].asInteger();
1002 if (ParameterNotNull(parameterObject, "runtime"))
1003 details.m_duration = (int)parameterObject["runtime"].asInteger();
1004 if (ParameterNotNull(parameterObject, "director"))
1005 CopyStringArray(parameterObject["director"], details.m_director);
1006 if (ParameterNotNull(parameterObject, "studio"))
1007 CopyStringArray(parameterObject["studio"], details.m_studio);
1008 if (ParameterNotNull(parameterObject, "year"))
1009 details.m_iYear = (int)parameterObject["year"].asInteger();
1010 if (ParameterNotNull(parameterObject, "plot"))
1011 details.m_strPlot = parameterObject["plot"].asString();
1012 if (ParameterNotNull(parameterObject, "album"))
1013 details.m_strAlbum = parameterObject["album"].asString();
1014 if (ParameterNotNull(parameterObject, "artist"))
1015 CopyStringArray(parameterObject["artist"], details.m_artist);
1016 if (ParameterNotNull(parameterObject, "genre"))
1017 CopyStringArray(parameterObject["genre"], details.m_genre);
1018 if (ParameterNotNull(parameterObject, "track"))
1019 details.m_iTrack = (int)parameterObject["track"].asInteger();
1020 if (ParameterNotNull(parameterObject, "rating"))
1021 details.m_fRating = parameterObject["rating"].asFloat();
1022 if (ParameterNotNull(parameterObject, "mpaa"))
1023 details.m_strMPAARating = parameterObject["mpaa"].asString();
1024 if (ParameterNotNull(parameterObject, "imdbnumber"))
1025 details.m_strIMDBNumber = parameterObject["imdbnumber"].asString();
1026 if (ParameterNotNull(parameterObject, "premiered"))
1027 details.m_premiered.SetFromDBDate(parameterObject["premiered"].asString());
1028 if (ParameterNotNull(parameterObject, "votes"))
1029 details.m_strVotes = parameterObject["votes"].asString();
1030 if (ParameterNotNull(parameterObject, "lastplayed"))
1031 details.m_lastPlayed.SetFromDBDateTime(parameterObject["lastplayed"].asString());
1032 if (ParameterNotNull(parameterObject, "firstaired"))
1033 details.m_firstAired.SetFromDBDateTime(parameterObject["firstaired"].asString());
1034 if (ParameterNotNull(parameterObject, "productioncode"))
1035 details.m_strProductionCode = parameterObject["productioncode"].asString();
1036 if (ParameterNotNull(parameterObject, "season"))
1037 details.m_iSeason = (int)parameterObject["season"].asInteger();
1038 if (ParameterNotNull(parameterObject, "episode"))
1039 details.m_iEpisode = (int)parameterObject["episode"].asInteger();
1040 if (ParameterNotNull(parameterObject, "originaltitle"))
1041 details.m_strOriginalTitle = parameterObject["originaltitle"].asString();
1042 if (ParameterNotNull(parameterObject, "trailer"))
1043 details.m_strTrailer = parameterObject["trailer"].asString();
1044 if (ParameterNotNull(parameterObject, "tagline"))
1045 details.m_strTagLine = parameterObject["tagline"].asString();
1046 if (ParameterNotNull(parameterObject, "plotoutline"))
1047 details.m_strPlotOutline = parameterObject["plotoutline"].asString();
1048 if (ParameterNotNull(parameterObject, "writer"))
1049 CopyStringArray(parameterObject["writer"], details.m_writingCredits);
1050 if (ParameterNotNull(parameterObject, "country"))
1051 CopyStringArray(parameterObject["country"], details.m_country);
1052 if (ParameterNotNull(parameterObject, "top250"))
1053 details.m_iTop250 = (int)parameterObject["top250"].asInteger();
1054 if (ParameterNotNull(parameterObject, "sorttitle"))
1055 details.m_strSortTitle = parameterObject["sorttitle"].asString();
1056 if (ParameterNotNull(parameterObject, "episodeguide"))
1057 details.m_strEpisodeGuide = parameterObject["episodeguide"].asString();
1058 if (ParameterNotNull(parameterObject, "set"))
1059 details.m_strSet = parameterObject["set"].asString();
1060 if (ParameterNotNull(parameterObject, "showlink"))
1061 CopyStringArray(parameterObject["showlink"], details.m_showLink);
1062 if (ParameterNotNull(parameterObject, "thumbnail"))
1063 artwork["thumb"] = parameterObject["thumbnail"].asString();
1064 if (ParameterNotNull(parameterObject, "fanart"))
1065 artwork["fanart"] = parameterObject["fanart"].asString();
1066 if (ParameterNotNull(parameterObject, "tag"))
1067 CopyStringArray(parameterObject["tag"], details.m_tags);
1068 if (ParameterNotNull(parameterObject, "art"))
1070 CVariant art = parameterObject["art"];
1071 for (CVariant::const_iterator_map artIt = art.begin_map(); artIt != art.end_map(); artIt++)
1073 if (artIt->second.isString() && !artIt->second.asString().empty())
1074 artwork[artIt->first] = CTextureUtils::UnwrapImageURL(artIt->second.asString());
1075 else if (artIt->second.isNull())
1077 artwork.erase(artIt->first);
1078 removedArtwork.insert(artIt->first);