6ab2548b98efdd4c92c7e2f57366c35f303e45bd
[vuplus_xbmc] / xbmc / interfaces / json-rpc / VideoLibrary.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "VideoLibrary.h"
22 #include "ApplicationMessenger.h"
23 #include "TextureCache.h"
24 #include "Util.h"
25 #include "utils/StringUtils.h"
26 #include "utils/URIUtils.h"
27 #include "video/VideoDatabase.h"
28
29 using namespace JSONRPC;
30
31 JSONRPC_STATUS CVideoLibrary::GetMovies(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
32 {
33   CVideoDatabase videodatabase;
34   if (!videodatabase.Open())
35     return InternalError;
36
37   SortDescription sorting;
38   ParseLimits(parameterObject, sorting.limitStart, sorting.limitEnd);
39   if (!ParseSorting(parameterObject, sorting.sortBy, sorting.sortOrder, sorting.sortAttributes))
40     return InvalidParams;
41
42   CVideoDbUrl videoUrl;
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())
67   {
68     CStdString xsp;
69     if (!GetXspFiltering("movies", filter, xsp))
70       return InvalidParams;
71
72     videoUrl.AddOption("xsp", xsp);
73   }
74
75   // setID must not be -1 otherwise GetMoviesNav() will return sets
76   if (setID < 0)
77     setID = 0;
78
79   CFileItemList items;
80   if (!videodatabase.GetMoviesNav(videoUrl.ToString(), items, genreID, year, -1, -1, -1, -1, setID, -1, sorting))
81     return InvalidParams;
82
83   return GetAdditionalMovieDetails(parameterObject, items, result, videodatabase, false);
84 }
85
86 JSONRPC_STATUS CVideoLibrary::GetMovieDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
87 {
88   int id = (int)parameterObject["movieid"].asInteger();
89
90   CVideoDatabase videodatabase;
91   if (!videodatabase.Open())
92     return InternalError;
93
94   CVideoInfoTag infos;
95   if (!videodatabase.GetMovieInfo("", infos, id) || infos.m_iDbId <= 0)
96     return InvalidParams;
97
98   HandleFileItem("movieid", true, "moviedetails", CFileItemPtr(new CFileItem(infos)), parameterObject, parameterObject["properties"], result, false);
99   return OK;
100 }
101
102 JSONRPC_STATUS CVideoLibrary::GetMovieSets(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
103 {
104   CVideoDatabase videodatabase;
105   if (!videodatabase.Open())
106     return InternalError;
107
108   CFileItemList items;
109   if (!videodatabase.GetSetsNav("videodb://movies/sets/", items, VIDEODB_CONTENT_MOVIES))
110     return InternalError;
111
112   HandleFileItemList("setid", false, "sets", items, parameterObject, result);
113   return OK;
114 }
115
116 JSONRPC_STATUS CVideoLibrary::GetMovieSetDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
117 {
118   int id = (int)parameterObject["setid"].asInteger();
119
120   CVideoDatabase videodatabase;
121   if (!videodatabase.Open())
122     return InternalError;
123
124   // Get movie set details
125   CVideoInfoTag infos;
126   if (!videodatabase.GetSetInfo(id, infos) || infos.m_iDbId <= 0)
127     return InvalidParams;
128
129   HandleFileItem("setid", false, "setdetails", CFileItemPtr(new CFileItem(infos)), parameterObject, parameterObject["properties"], result, false);
130
131   // Get movies from the set
132   CFileItemList items;
133   if (!videodatabase.GetMoviesNav("videodb://movies/titles/", items, -1, -1, -1, -1, -1, -1, id))
134     return InternalError;
135
136   return GetAdditionalMovieDetails(parameterObject["movies"], items, result["setdetails"], videodatabase, true);
137 }
138
139 JSONRPC_STATUS CVideoLibrary::GetTVShows(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
140 {
141   CVideoDatabase videodatabase;
142   if (!videodatabase.Open())
143     return InternalError;
144
145   SortDescription sorting;
146   ParseLimits(parameterObject, sorting.limitStart, sorting.limitEnd);
147   if (!ParseSorting(parameterObject, sorting.sortBy, sorting.sortOrder, sorting.sortAttributes))
148     return InvalidParams;
149
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())
167   {
168     CStdString xsp;
169     if (!GetXspFiltering("tvshows", filter, xsp))
170       return InvalidParams;
171
172     videoUrl.AddOption("xsp", xsp);
173   }
174
175   CFileItemList items;
176   if (!videodatabase.GetTvShowsNav(videoUrl.ToString(), items, genreID, year, -1, -1, -1, -1, sorting))
177     return InvalidParams;
178
179   bool additionalInfo = false;
180   for (CVariant::const_iterator_array itr = parameterObject["properties"].begin_array(); itr != parameterObject["properties"].end_array(); itr++)
181   {
182     CStdString fieldValue = itr->asString();
183     if (fieldValue == "cast" || fieldValue == "tag")
184       additionalInfo = true;
185   }
186
187   if (additionalInfo)
188   {
189     for (int index = 0; index < items.Size(); index++)
190       videodatabase.GetTvShowInfo("", *(items[index]->GetVideoInfoTag()), items[index]->GetVideoInfoTag()->m_iDbId);
191   }
192
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);
197
198   return OK;
199 }
200
201 JSONRPC_STATUS CVideoLibrary::GetTVShowDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
202 {
203   CVideoDatabase videodatabase;
204   if (!videodatabase.Open())
205     return InternalError;
206
207   int id = (int)parameterObject["tvshowid"].asInteger();
208
209   CVideoInfoTag infos;
210   if (!videodatabase.GetTvShowInfo("", infos, id) || infos.m_iDbId <= 0)
211     return InvalidParams;
212
213   HandleFileItem("tvshowid", true, "tvshowdetails", CFileItemPtr(new CFileItem(infos)), parameterObject, parameterObject["properties"], result, false);
214   return OK;
215 }
216
217 JSONRPC_STATUS CVideoLibrary::GetSeasons(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
218 {
219   CVideoDatabase videodatabase;
220   if (!videodatabase.Open())
221     return InternalError;
222
223   int tvshowID = (int)parameterObject["tvshowid"].asInteger();
224
225   CStdString strPath;
226   strPath.Format("videodb://tvshows/titles/%i/", tvshowID);
227   CFileItemList items;
228   if (!videodatabase.GetSeasonsNav(strPath, items, -1, -1, -1, -1, tvshowID, false))
229     return InternalError;
230
231   HandleFileItemList(NULL, false, "seasons", items, parameterObject, result);
232   return OK;
233 }
234
235 JSONRPC_STATUS CVideoLibrary::GetEpisodes(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
236 {
237   CVideoDatabase videodatabase;
238   if (!videodatabase.Open())
239     return InternalError;
240
241   SortDescription sorting;
242   ParseLimits(parameterObject, sorting.limitStart, sorting.limitEnd);
243   if (!ParseSorting(parameterObject, sorting.sortBy, sorting.sortOrder, sorting.sortAttributes))
244     return InvalidParams;
245
246   int tvshowID = (int)parameterObject["tvshowid"].asInteger();
247   int season   = (int)parameterObject["season"].asInteger();
248   
249   CStdString strPath;
250   strPath.Format("videodb://tvshows/titles/%i/%i/", tvshowID, season);
251
252   CVideoDbUrl videoUrl;
253   videoUrl.FromString(strPath);
254   const CVariant &filter = parameterObject["filter"];
255   if (filter.isMember("genreid"))
256     videoUrl.AddOption("genreid", (int)filter["genreid"].asInteger());
257   else if (filter.isMember("genre"))
258     videoUrl.AddOption("genre", filter["genre"].asString());
259   else if (filter.isMember("year"))
260     videoUrl.AddOption("year", (int)filter["year"].asInteger());
261   else if (filter.isMember("actor"))
262     videoUrl.AddOption("actor", filter["actor"].asString());
263   else if (filter.isMember("director"))
264     videoUrl.AddOption("director", filter["director"].asString());
265   else if (filter.isObject())
266   {
267     CStdString xsp;
268     if (!GetXspFiltering("episodes", filter, xsp))
269       return InvalidParams;
270
271     videoUrl.AddOption("xsp", xsp);
272   }
273
274   if (tvshowID <= 0 && (season > 0 || videoUrl.HasOption("genreid") || videoUrl.HasOption("genre") || videoUrl.HasOption("actor")))
275     return InvalidParams;
276
277   if (tvshowID > 0)
278   {
279     videoUrl.AddOption("tvshowid", tvshowID);
280     if (season >= 0)
281       videoUrl.AddOption("season", season);
282   }
283
284   CFileItemList items;
285   if (!videodatabase.GetEpisodesByWhere(videoUrl.ToString(), CDatabase::Filter(), items, false, sorting))
286     return InvalidParams;
287
288   return GetAdditionalEpisodeDetails(parameterObject, items, result, videodatabase, false);
289 }
290
291 JSONRPC_STATUS CVideoLibrary::GetEpisodeDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
292 {
293   CVideoDatabase videodatabase;
294   if (!videodatabase.Open())
295     return InternalError;
296
297   int id = (int)parameterObject["episodeid"].asInteger();
298
299   CVideoInfoTag infos;
300   if (!videodatabase.GetEpisodeInfo("", infos, id) || infos.m_iDbId <= 0)
301     return InvalidParams;
302
303   CFileItemPtr pItem = CFileItemPtr(new CFileItem(infos));
304   // We need to set the correct base path to get the valid fanart
305   int tvshowid = infos.m_iIdShow;
306   if (tvshowid <= 0)
307     tvshowid = videodatabase.GetTvShowForEpisode(id);
308
309   CStdString basePath; basePath.Format("videodb://tvshows/titles/%ld/%ld/%ld", tvshowid, infos.m_iSeason, id);
310   pItem->SetPath(basePath);
311
312   HandleFileItem("episodeid", true, "episodedetails", pItem, parameterObject, parameterObject["properties"], result, false);
313   return OK;
314 }
315
316 JSONRPC_STATUS CVideoLibrary::GetMusicVideos(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
317 {
318   CVideoDatabase videodatabase;
319   if (!videodatabase.Open())
320     return InternalError;
321
322   SortDescription sorting;
323   ParseLimits(parameterObject, sorting.limitStart, sorting.limitEnd);
324   if (!ParseSorting(parameterObject, sorting.sortBy, sorting.sortOrder, sorting.sortAttributes))
325     return InvalidParams;
326
327   CVideoDbUrl videoUrl;
328   videoUrl.FromString("videodb://musicvideos/titles/");
329   int genreID = -1, year = -1;
330   const CVariant &filter = parameterObject["filter"];
331   if (filter.isMember("artist"))
332     videoUrl.AddOption("artist", filter["artist"].asString());
333   else if (filter.isMember("genreid"))
334     genreID = (int)filter["genreid"].asInteger();
335   else if (filter.isMember("genre"))
336     videoUrl.AddOption("genre", filter["genre"].asString());
337   else if (filter.isMember("year"))
338     year = (int)filter["year"].asInteger();
339   else if (filter.isMember("director"))
340     videoUrl.AddOption("director", filter["director"].asString());
341   else if (filter.isMember("studio"))
342     videoUrl.AddOption("studio", filter["studio"].asString());
343   else if (filter.isMember("tag"))
344     videoUrl.AddOption("tag", filter["tag"].asString());
345   else if (filter.isObject())
346   {
347     CStdString xsp;
348     if (!GetXspFiltering("musicvideos", filter, xsp))
349       return InvalidParams;
350
351     videoUrl.AddOption("xsp", xsp);
352   }
353
354   CFileItemList items;
355   if (!videodatabase.GetMusicVideosNav(videoUrl.ToString(), items, genreID, year, -1, -1, -1, -1, -1, sorting))
356     return InternalError;
357
358   return GetAdditionalMusicVideoDetails(parameterObject, items, result, videodatabase, false);
359 }
360
361 JSONRPC_STATUS CVideoLibrary::GetMusicVideoDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
362 {
363   CVideoDatabase videodatabase;
364   if (!videodatabase.Open())
365     return InternalError;
366
367   int id = (int)parameterObject["musicvideoid"].asInteger();
368
369   CVideoInfoTag infos;
370   if (!videodatabase.GetMusicVideoInfo("", infos, id) || infos.m_iDbId <= 0)
371     return InvalidParams;
372
373   HandleFileItem("musicvideoid", true, "musicvideodetails", CFileItemPtr(new CFileItem(infos)), parameterObject, parameterObject["properties"], result, false);
374   return OK;
375 }
376
377 JSONRPC_STATUS CVideoLibrary::GetRecentlyAddedMovies(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
378 {
379   CVideoDatabase videodatabase;
380   if (!videodatabase.Open())
381     return InternalError;
382
383   CFileItemList items;
384   if (!videodatabase.GetRecentlyAddedMoviesNav("videodb://recentlyaddedmovies/", items))
385     return InternalError;
386
387   return GetAdditionalMovieDetails(parameterObject, items, result, videodatabase, true);
388 }
389
390 JSONRPC_STATUS CVideoLibrary::GetRecentlyAddedEpisodes(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
391 {
392   CVideoDatabase videodatabase;
393   if (!videodatabase.Open())
394     return InternalError;
395
396   CFileItemList items;
397   if (!videodatabase.GetRecentlyAddedEpisodesNav("videodb://recentlyaddedepisodes/", items))
398     return InternalError;
399
400   return GetAdditionalEpisodeDetails(parameterObject, items, result, videodatabase, true);
401 }
402
403 JSONRPC_STATUS CVideoLibrary::GetRecentlyAddedMusicVideos(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
404 {
405   CVideoDatabase videodatabase;
406   if (!videodatabase.Open())
407     return InternalError;
408
409   CFileItemList items;
410   if (!videodatabase.GetRecentlyAddedMusicVideosNav("videodb://recentlyaddedmusicvideos/", items))
411     return InternalError;
412
413   return GetAdditionalMusicVideoDetails(parameterObject, items, result, videodatabase, true);
414 }
415
416 JSONRPC_STATUS CVideoLibrary::GetGenres(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
417 {
418   CStdString media = parameterObject["type"].asString();
419   media = media.ToLower();
420   int idContent = -1;
421
422   CStdString strPath = "videodb://";
423   /* select which video content to get genres from*/
424   if (media.Equals("movie"))
425   {
426     idContent = VIDEODB_CONTENT_MOVIES;
427     strPath += "movies";
428   }
429   else if (media.Equals("tvshow"))
430   {
431     idContent = VIDEODB_CONTENT_TVSHOWS;
432     strPath += "tvshows";
433   }
434   else if (media.Equals("musicvideo"))
435   {
436     idContent = VIDEODB_CONTENT_MUSICVIDEOS;
437     strPath += "musicvideos";
438   }
439   strPath += "/genres/";
440  
441   CVideoDatabase videodatabase;
442   if (!videodatabase.Open())
443     return InternalError;
444
445   CFileItemList items;
446   if (!videodatabase.GetGenresNav(strPath, items, idContent))
447     return InternalError;
448
449   /* need to set strTitle in each item*/
450   for (unsigned int i = 0; i < (unsigned int)items.Size(); i++)
451     items[i]->GetVideoInfoTag()->m_strTitle = items[i]->GetLabel();
452
453   HandleFileItemList("genreid", false, "genres", items, parameterObject, result);
454   return OK;
455 }
456
457 JSONRPC_STATUS CVideoLibrary::SetMovieDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
458 {
459   int id = (int)parameterObject["movieid"].asInteger();
460
461   CVideoDatabase videodatabase;
462   if (!videodatabase.Open())
463     return InternalError;
464
465   CVideoInfoTag infos;
466   if (!videodatabase.GetMovieInfo("", infos, id) || infos.m_iDbId <= 0)
467     return InvalidParams;
468
469   // get artwork
470   std::map<std::string, std::string> artwork;
471   videodatabase.GetArtForItem(infos.m_iDbId, infos.m_type, artwork);
472
473   int playcount = infos.m_playCount;
474   CDateTime lastPlayed = infos.m_lastPlayed;
475
476   UpdateVideoTag(parameterObject, infos, artwork);
477
478   // we need to manually remove tags/taglinks for now because they aren't replaced
479   // due to scrapers not supporting them
480   videodatabase.RemoveTagsFromItem(id, "movie");
481
482   if (videodatabase.SetDetailsForMovie(infos.m_strFileNameAndPath, infos, artwork, id) <= 0)
483     return InternalError;
484
485   if (playcount != infos.m_playCount || lastPlayed != infos.m_lastPlayed)
486   {
487     // restore original playcount or the new one won't be announced
488     int newPlaycount = infos.m_playCount;
489     infos.m_playCount = playcount;
490     videodatabase.SetPlayCount(CFileItem(infos), newPlaycount, infos.m_lastPlayed.IsValid() ? infos.m_lastPlayed : CDateTime::GetCurrentDateTime());
491   }
492
493   UpdateResumePoint(parameterObject, infos, videodatabase);
494
495   CJSONRPCUtils::NotifyItemUpdated();
496   return ACK;
497 }
498
499 JSONRPC_STATUS CVideoLibrary::SetTVShowDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
500 {
501   int id = (int)parameterObject["tvshowid"].asInteger();
502
503   CVideoDatabase videodatabase;
504   if (!videodatabase.Open())
505     return InternalError;
506
507   CVideoInfoTag infos;
508   if (!videodatabase.GetTvShowInfo("", infos, id) || infos.m_iDbId <= 0)
509     return InvalidParams;
510
511   // get artwork
512   std::map<std::string, std::string> artwork;
513   videodatabase.GetArtForItem(infos.m_iDbId, infos.m_type, artwork);
514
515   std::map<int, std::map<std::string, std::string> > seasonArt;
516   videodatabase.GetTvShowSeasonArt(infos.m_iDbId, seasonArt);
517
518   int playcount = infos.m_playCount;
519   CDateTime lastPlayed = infos.m_lastPlayed;
520
521   UpdateVideoTag(parameterObject, infos, artwork);
522
523   // we need to manually remove tags/taglinks for now because they aren't replaced
524   // due to scrapers not supporting them
525   videodatabase.RemoveTagsFromItem(id, "tvshow");
526
527   if (videodatabase.SetDetailsForTvShow(infos.m_strFileNameAndPath, infos, artwork, seasonArt, id) <= 0)
528     return InternalError;
529
530   if (playcount != infos.m_playCount || lastPlayed != infos.m_lastPlayed)
531   {
532     // restore original playcount or the new one won't be announced
533     int newPlaycount = infos.m_playCount;
534     infos.m_playCount = playcount;
535     videodatabase.SetPlayCount(CFileItem(infos), newPlaycount, infos.m_lastPlayed.IsValid() ? infos.m_lastPlayed : CDateTime::GetCurrentDateTime());
536   }
537
538   CJSONRPCUtils::NotifyItemUpdated();
539   return ACK;
540 }
541
542 JSONRPC_STATUS CVideoLibrary::SetEpisodeDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
543 {
544   int id = (int)parameterObject["episodeid"].asInteger();
545
546   CVideoDatabase videodatabase;
547   if (!videodatabase.Open())
548     return InternalError;
549
550   CVideoInfoTag infos;
551   videodatabase.GetEpisodeInfo("", infos, id);
552   if (infos.m_iDbId <= 0)
553   {
554     videodatabase.Close();
555     return InvalidParams;
556   }
557
558   int tvshowid = videodatabase.GetTvShowForEpisode(id);
559   if (tvshowid <= 0)
560   {
561     videodatabase.Close();
562     return InvalidParams;
563   }
564
565   // get artwork
566   std::map<std::string, std::string> artwork;
567   videodatabase.GetArtForItem(infos.m_iDbId, infos.m_type, artwork);
568
569   int playcount = infos.m_playCount;
570   CDateTime lastPlayed = infos.m_lastPlayed;
571
572   UpdateVideoTag(parameterObject, infos, artwork);
573
574   if (videodatabase.SetDetailsForEpisode(infos.m_strFileNameAndPath, infos, artwork, tvshowid, id) <= 0)
575     return InternalError;
576
577   if (playcount != infos.m_playCount || lastPlayed != infos.m_lastPlayed)
578   {
579     // restore original playcount or the new one won't be announced
580     int newPlaycount = infos.m_playCount;
581     infos.m_playCount = playcount;
582     videodatabase.SetPlayCount(CFileItem(infos), newPlaycount, infos.m_lastPlayed.IsValid() ? infos.m_lastPlayed : CDateTime::GetCurrentDateTime());
583   }
584
585   UpdateResumePoint(parameterObject, infos, videodatabase);
586
587   CJSONRPCUtils::NotifyItemUpdated();
588   return ACK;
589 }
590
591 JSONRPC_STATUS CVideoLibrary::SetMusicVideoDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
592 {
593   int id = (int)parameterObject["musicvideoid"].asInteger();
594
595   CVideoDatabase videodatabase;
596   if (!videodatabase.Open())
597     return InternalError;
598
599   CVideoInfoTag infos;
600   videodatabase.GetMusicVideoInfo("", infos, id);
601   if (infos.m_iDbId <= 0)
602   {
603     videodatabase.Close();
604     return InvalidParams;
605   }
606
607   // get artwork
608   std::map<std::string, std::string> artwork;
609   videodatabase.GetArtForItem(infos.m_iDbId, infos.m_type, artwork);
610
611   int playcount = infos.m_playCount;
612   CDateTime lastPlayed = infos.m_lastPlayed;
613
614   UpdateVideoTag(parameterObject, infos, artwork);
615
616   // we need to manually remove tags/taglinks for now because they aren't replaced
617   // due to scrapers not supporting them
618   videodatabase.RemoveTagsFromItem(id, "musicvideo");
619
620   if (videodatabase.SetDetailsForMusicVideo(infos.m_strFileNameAndPath, infos, artwork, id) <= 0)
621     return InternalError;
622
623   if (playcount != infos.m_playCount || lastPlayed != infos.m_lastPlayed)
624   {
625     // restore original playcount or the new one won't be announced
626     int newPlaycount = infos.m_playCount;
627     infos.m_playCount = playcount;
628     videodatabase.SetPlayCount(CFileItem(infos), newPlaycount, infos.m_lastPlayed.IsValid() ? infos.m_lastPlayed : CDateTime::GetCurrentDateTime());
629   }
630
631   UpdateResumePoint(parameterObject, infos, videodatabase);
632
633   CJSONRPCUtils::NotifyItemUpdated();
634   return ACK;
635 }
636
637 JSONRPC_STATUS CVideoLibrary::RemoveMovie(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
638 {
639   return RemoveVideo(parameterObject);
640 }
641
642 JSONRPC_STATUS CVideoLibrary::RemoveTVShow(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
643 {
644   return RemoveVideo(parameterObject);
645 }
646
647 JSONRPC_STATUS CVideoLibrary::RemoveEpisode(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
648 {
649   return RemoveVideo(parameterObject);
650 }
651
652 JSONRPC_STATUS CVideoLibrary::RemoveMusicVideo(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
653 {
654   return RemoveVideo(parameterObject);
655 }
656
657 JSONRPC_STATUS CVideoLibrary::Scan(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
658 {
659   std::string directory = parameterObject["directory"].asString();
660   CStdString cmd;
661   if (directory.empty())
662     cmd = "updatelibrary(video)";
663   else
664     cmd.Format("updatelibrary(video, %s)", StringUtils::Paramify(directory).c_str());
665
666   CApplicationMessenger::Get().ExecBuiltIn(cmd);
667   return ACK;
668 }
669
670 JSONRPC_STATUS CVideoLibrary::Export(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
671 {
672   CStdString cmd;
673   if (parameterObject["options"].isMember("path"))
674     cmd.Format("exportlibrary(video, false, %s)", StringUtils::Paramify(parameterObject["options"]["path"].asString()));
675   else
676     cmd.Format("exportlibrary(video, true, %s, %s, %s)",
677       parameterObject["options"]["images"].asBoolean() ? "true" : "false",
678       parameterObject["options"]["overwrite"].asBoolean() ? "true" : "false",
679       parameterObject["options"]["actorthumbs"].asBoolean() ? "true" : "false");
680
681   CApplicationMessenger::Get().ExecBuiltIn(cmd);
682   return ACK;
683 }
684
685 JSONRPC_STATUS CVideoLibrary::Clean(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
686 {
687   CApplicationMessenger::Get().ExecBuiltIn("cleanlibrary(video)");
688   return ACK;
689 }
690
691 bool CVideoLibrary::FillFileItem(const CStdString &strFilename, CFileItemPtr &item, const CVariant &parameterObject /* = CVariant(CVariant::VariantTypeArray) */)
692 {
693   CVideoDatabase videodatabase;
694   if (strFilename.empty())
695     return false;
696   
697   bool filled = false;
698   if (videodatabase.Open())
699   {
700     CVideoInfoTag details;
701     if (videodatabase.LoadVideoInfo(strFilename, details))
702     {
703       item->SetFromVideoInfoTag(details);
704       filled = true;
705     }
706   }
707
708   if (item->GetLabel().empty())
709   {
710     item->SetLabel(CUtil::GetTitleFromPath(strFilename, false));
711     if (item->GetLabel().empty())
712       item->SetLabel(URIUtils::GetFileName(strFilename));
713   }
714
715   return filled;
716 }
717
718 bool CVideoLibrary::FillFileItemList(const CVariant &parameterObject, CFileItemList &list)
719 {
720   CVideoDatabase videodatabase;
721   if (!videodatabase.Open())
722     return false;
723
724   CStdString file = parameterObject["file"].asString();
725   int movieID = (int)parameterObject["movieid"].asInteger(-1);
726   int episodeID = (int)parameterObject["episodeid"].asInteger(-1);
727   int musicVideoID = (int)parameterObject["musicvideoid"].asInteger(-1);
728
729   bool success = false;
730   CFileItemPtr fileItem(new CFileItem());
731   if (FillFileItem(file, fileItem))
732   {
733     success = true;
734     list.Add(fileItem);
735   }
736
737   if (movieID > 0)
738   {
739     CVideoInfoTag details;
740     videodatabase.GetMovieInfo("", details, movieID);
741     if (!details.IsEmpty())
742     {
743       list.Add(CFileItemPtr(new CFileItem(details)));
744       success = true;
745     }
746   }
747   if (episodeID > 0)
748   {
749     CVideoInfoTag details;
750     if (videodatabase.GetEpisodeInfo("", details, episodeID) && !details.IsEmpty())
751     {
752       list.Add(CFileItemPtr(new CFileItem(details)));
753       success = true;
754     }
755   }
756   if (musicVideoID > 0)
757   {
758     CVideoInfoTag details;
759     videodatabase.GetMusicVideoInfo("", details, musicVideoID);
760     if (!details.IsEmpty())
761     {
762       list.Add(CFileItemPtr(new CFileItem(details)));
763       success = true;
764     }
765   }
766
767   return success;
768 }
769
770 JSONRPC_STATUS CVideoLibrary::GetAdditionalMovieDetails(const CVariant &parameterObject, CFileItemList &items, CVariant &result, CVideoDatabase &videodatabase, bool limit /* = true */)
771 {
772   if (!videodatabase.Open())
773     return InternalError;
774
775   bool additionalInfo = false;
776   for (CVariant::const_iterator_array itr = parameterObject["properties"].begin_array(); itr != parameterObject["properties"].end_array(); itr++)
777   {
778     CStdString fieldValue = itr->asString();
779     if (fieldValue == "cast" || fieldValue == "showlink" || fieldValue == "tag" || fieldValue == "streamdetails")
780       additionalInfo = true;
781   }
782
783   if (additionalInfo)
784   {
785     for (int index = 0; index < items.Size(); index++)
786     {
787       if (additionalInfo)
788         videodatabase.GetMovieInfo("", *(items[index]->GetVideoInfoTag()), items[index]->GetVideoInfoTag()->m_iDbId);
789     }
790   }
791
792   int size = items.Size();
793   if (!limit && items.HasProperty("total") && items.GetProperty("total").asInteger() > size)
794     size = (int)items.GetProperty("total").asInteger();
795   HandleFileItemList("movieid", true, "movies", items, parameterObject, result, size, limit);
796
797   return OK;
798 }
799
800 JSONRPC_STATUS CVideoLibrary::GetAdditionalEpisodeDetails(const CVariant &parameterObject, CFileItemList &items, CVariant &result, CVideoDatabase &videodatabase, bool limit /* = true */)
801 {
802   if (!videodatabase.Open())
803     return InternalError;
804
805   bool additionalInfo = false;
806   for (CVariant::const_iterator_array itr = parameterObject["properties"].begin_array(); itr != parameterObject["properties"].end_array(); itr++)
807   {
808     CStdString fieldValue = itr->asString();
809     if (fieldValue == "cast" || fieldValue == "streamdetails")
810       additionalInfo = true;
811   }
812
813   if (additionalInfo)
814   {
815     for (int index = 0; index < items.Size(); index++)
816     {
817       if (additionalInfo)
818         videodatabase.GetEpisodeInfo("", *(items[index]->GetVideoInfoTag()), items[index]->GetVideoInfoTag()->m_iDbId);
819     }
820   }
821   
822   int size = items.Size();
823   if (!limit && items.HasProperty("total") && items.GetProperty("total").asInteger() > size)
824     size = (int)items.GetProperty("total").asInteger();
825   HandleFileItemList("episodeid", true, "episodes", items, parameterObject, result, size, limit);
826
827   return OK;
828 }
829
830 JSONRPC_STATUS CVideoLibrary::GetAdditionalMusicVideoDetails(const CVariant &parameterObject, CFileItemList &items, CVariant &result, CVideoDatabase &videodatabase, bool limit /* = true */)
831 {
832   if (!videodatabase.Open())
833     return InternalError;
834
835   bool streamdetails = false;
836   for (CVariant::const_iterator_array itr = parameterObject["properties"].begin_array(); itr != parameterObject["properties"].end_array(); itr++)
837   {
838     if (itr->asString() == "tag" || itr->asString() == "streamdetails")
839       streamdetails = true;
840   }
841
842   if (streamdetails)
843   {
844     for (int index = 0; index < items.Size(); index++)
845       videodatabase.GetMusicVideoInfo("", *(items[index]->GetVideoInfoTag()), items[index]->GetVideoInfoTag()->m_iDbId);
846   }
847
848   int size = items.Size();
849   if (!limit && items.HasProperty("total") && items.GetProperty("total").asInteger() > size)
850     size = (int)items.GetProperty("total").asInteger();
851   HandleFileItemList("musicvideoid", true, "musicvideos", items, parameterObject, result, size, limit);
852
853   return OK;
854 }
855
856 JSONRPC_STATUS CVideoLibrary::RemoveVideo(const CVariant &parameterObject)
857 {
858   CVideoDatabase videodatabase;
859   if (!videodatabase.Open())
860     return InternalError;
861
862   if (parameterObject.isMember("movieid"))
863     videodatabase.DeleteMovie((int)parameterObject["movieid"].asInteger());
864   else if (parameterObject.isMember("tvshowid"))
865     videodatabase.DeleteTvShow((int)parameterObject["tvshowid"].asInteger());
866   else if (parameterObject.isMember("episodeid"))
867     videodatabase.DeleteEpisode((int)parameterObject["episodeid"].asInteger());
868   else if (parameterObject.isMember("musicvideoid"))
869     videodatabase.DeleteMusicVideo((int)parameterObject["musicvideoid"].asInteger());
870
871   CJSONRPCUtils::NotifyItemUpdated();
872   return ACK;
873 }
874
875 void CVideoLibrary::UpdateResumePoint(const CVariant &parameterObject, CVideoInfoTag &details, CVideoDatabase &videodatabase)
876 {
877   if (!parameterObject["resume"].isNull())
878   {
879     int position = (int)parameterObject["resume"]["position"].asInteger();
880     if (position == 0)
881       videodatabase.ClearBookMarksOfFile(details.m_strFileNameAndPath, CBookmark::RESUME);
882     else
883     {
884       CBookmark bookmark;
885       if (videodatabase.GetResumeBookMark(details.m_strFileNameAndPath, bookmark))
886       {
887         bookmark.timeInSeconds = position;
888       
889         int total = (int)parameterObject["resume"]["total"].asInteger();
890         if (total > 0)
891           bookmark.totalTimeInSeconds = total;
892         videodatabase.AddBookMarkToFile(details.m_strFileNameAndPath, bookmark, CBookmark::RESUME);
893       }
894     }
895   }
896 }
897
898 void CVideoLibrary::UpdateVideoTag(const CVariant &parameterObject, CVideoInfoTag& details, std::map<std::string, std::string> &artwork)
899 {
900   if (ParameterNotNull(parameterObject, "title"))
901     details.m_strTitle = parameterObject["title"].asString();
902   if (ParameterNotNull(parameterObject, "playcount"))
903     details.m_playCount = (int)parameterObject["playcount"].asInteger();
904   if (ParameterNotNull(parameterObject, "runtime"))
905     details.m_duration = (int)parameterObject["runtime"].asInteger();
906   if (ParameterNotNull(parameterObject, "director"))
907     CopyStringArray(parameterObject["director"], details.m_director);
908   if (ParameterNotNull(parameterObject, "studio"))
909     CopyStringArray(parameterObject["studio"], details.m_studio);
910   if (ParameterNotNull(parameterObject, "year"))
911     details.m_iYear = (int)parameterObject["year"].asInteger();
912   if (ParameterNotNull(parameterObject, "plot"))
913     details.m_strPlot = parameterObject["plot"].asString();
914   if (ParameterNotNull(parameterObject, "album"))
915     details.m_strAlbum = parameterObject["album"].asString();
916   if (ParameterNotNull(parameterObject, "artist"))
917     CopyStringArray(parameterObject["artist"], details.m_artist);
918   if (ParameterNotNull(parameterObject, "genre"))
919     CopyStringArray(parameterObject["genre"], details.m_genre);
920   if (ParameterNotNull(parameterObject, "track"))
921     details.m_iTrack = (int)parameterObject["track"].asInteger();
922   if (ParameterNotNull(parameterObject, "rating"))
923     details.m_fRating = parameterObject["rating"].asFloat();
924   if (ParameterNotNull(parameterObject, "mpaa"))
925     details.m_strMPAARating = parameterObject["mpaa"].asString();
926   if (ParameterNotNull(parameterObject, "imdbnumber"))
927     details.m_strIMDBNumber = parameterObject["imdbnumber"].asString();
928   if (ParameterNotNull(parameterObject, "premiered"))
929     details.m_premiered.SetFromDBDate(parameterObject["premiered"].asString());
930   if (ParameterNotNull(parameterObject, "votes"))
931     details.m_strVotes = parameterObject["votes"].asString();
932   if (ParameterNotNull(parameterObject, "lastplayed"))
933     details.m_lastPlayed.SetFromDBDateTime(parameterObject["lastplayed"].asString());
934   if (ParameterNotNull(parameterObject, "firstaired"))
935     details.m_firstAired.SetFromDBDateTime(parameterObject["firstaired"].asString());
936   if (ParameterNotNull(parameterObject, "productioncode"))
937     details.m_strProductionCode = parameterObject["productioncode"].asString();
938   if (ParameterNotNull(parameterObject, "season"))
939     details.m_iSeason = (int)parameterObject["season"].asInteger();
940   if (ParameterNotNull(parameterObject, "episode"))
941     details.m_iEpisode = (int)parameterObject["episode"].asInteger();
942   if (ParameterNotNull(parameterObject, "originaltitle"))
943     details.m_strOriginalTitle = parameterObject["originaltitle"].asString();
944   if (ParameterNotNull(parameterObject, "trailer"))
945     details.m_strTrailer = parameterObject["trailer"].asString();
946   if (ParameterNotNull(parameterObject, "tagline"))
947     details.m_strTagLine = parameterObject["tagline"].asString();
948   if (ParameterNotNull(parameterObject, "plotoutline"))
949     details.m_strPlotOutline = parameterObject["plotoutline"].asString();
950   if (ParameterNotNull(parameterObject, "writer"))
951     CopyStringArray(parameterObject["writer"], details.m_writingCredits);
952   if (ParameterNotNull(parameterObject, "country"))
953     CopyStringArray(parameterObject["country"], details.m_country);
954   if (ParameterNotNull(parameterObject, "top250"))
955     details.m_iTop250 = (int)parameterObject["top250"].asInteger();
956   if (ParameterNotNull(parameterObject, "sorttitle"))
957     details.m_strSortTitle = parameterObject["sorttitle"].asString();
958   if (ParameterNotNull(parameterObject, "episodeguide"))
959     details.m_strEpisodeGuide = parameterObject["episodeguide"].asString();
960   if (ParameterNotNull(parameterObject, "set"))
961     details.m_strSet = parameterObject["set"].asString();
962   if (ParameterNotNull(parameterObject, "showlink"))
963     CopyStringArray(parameterObject["showlink"], details.m_showLink);
964   if (ParameterNotNull(parameterObject, "thumbnail"))
965     artwork["thumb"] = parameterObject["thumbnail"].asString();
966   if (ParameterNotNull(parameterObject, "fanart"))
967     artwork["fanart"] = parameterObject["fanart"].asString();
968   if (ParameterNotNull(parameterObject, "tag"))
969     CopyStringArray(parameterObject["tag"], details.m_tags);
970   if (ParameterNotNull(parameterObject, "art"))
971   {
972     CVariant art = parameterObject["art"];
973     for (CVariant::const_iterator_map artIt = art.begin_map(); artIt != art.end_map(); artIt++)
974     {
975       if (!artIt->second.asString().empty())
976         artwork[artIt->first] = CTextureCache::UnwrapImageURL(artIt->second.asString());
977     }
978   }
979 }