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