1 /*
2 * Copyright (C) 2016-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
8
9 #include "VideoLibrary.h"
10
11 #include "TextureDatabase.h"
12 #include "Util.h"
13 #include "messaging/ApplicationMessenger.h"
14 #include "utils/SortUtils.h"
15 #include "utils/StringUtils.h"
16 #include "utils/URIUtils.h"
17 #include "utils/Variant.h"
18 #include "video/VideoDatabase.h"
19 #include "video/VideoLibraryQueue.h"
20
21 using namespace JSONRPC;
22 using namespace KODI::MESSAGING;
23
GetMovies(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)24 JSONRPC_STATUS CVideoLibrary::GetMovies(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
25 {
26 CVideoDatabase videodatabase;
27 if (!videodatabase.Open())
28 return InternalError;
29
30 SortDescription sorting;
31 ParseLimits(parameterObject, sorting.limitStart, sorting.limitEnd);
32 if (!ParseSorting(parameterObject, sorting.sortBy, sorting.sortOrder, sorting.sortAttributes))
33 return InvalidParams;
34
35 CVideoDbUrl videoUrl;
36 if (!videoUrl.FromString("videodb://movies/titles/"))
37 return InternalError;
38
39 int genreID = -1, year = -1, setID = 0;
40 const CVariant &filter = parameterObject["filter"];
41 if (filter.isMember("genreid"))
42 genreID = (int)filter["genreid"].asInteger();
43 else if (filter.isMember("genre"))
44 videoUrl.AddOption("genre", filter["genre"].asString());
45 else if (filter.isMember("year"))
46 year = (int)filter["year"].asInteger();
47 else if (filter.isMember("actor"))
48 videoUrl.AddOption("actor", filter["actor"].asString());
49 else if (filter.isMember("director"))
50 videoUrl.AddOption("director", filter["director"].asString());
51 else if (filter.isMember("studio"))
52 videoUrl.AddOption("studio", filter["studio"].asString());
53 else if (filter.isMember("country"))
54 videoUrl.AddOption("country", filter["country"].asString());
55 else if (filter.isMember("setid"))
56 setID = (int)filter["setid"].asInteger();
57 else if (filter.isMember("set"))
58 videoUrl.AddOption("set", filter["set"].asString());
59 else if (filter.isMember("tag"))
60 videoUrl.AddOption("tag", filter["tag"].asString());
61 else if (filter.isObject())
62 {
63 std::string xsp;
64 if (!GetXspFiltering("movies", filter, xsp))
65 return InvalidParams;
66
67 videoUrl.AddOption("xsp", xsp);
68 }
69
70 // setID must not be -1 otherwise GetMoviesNav() will return sets
71 if (setID < 0)
72 setID = 0;
73
74 CFileItemList items;
75 if (!videodatabase.GetMoviesNav(videoUrl.ToString(), items, genreID, year, -1, -1, -1, -1, setID, -1, sorting, RequiresAdditionalDetails(MediaTypeMovie, parameterObject)))
76 return InvalidParams;
77
78 return HandleItems("movieid", "movies", items, parameterObject, result, false);
79 }
80
GetMovieDetails(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)81 JSONRPC_STATUS CVideoLibrary::GetMovieDetails(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
82 {
83 int id = (int)parameterObject["movieid"].asInteger();
84
85 CVideoDatabase videodatabase;
86 if (!videodatabase.Open())
87 return InternalError;
88
89 CVideoInfoTag infos;
90 if (!videodatabase.GetMovieInfo("", infos, id, RequiresAdditionalDetails(MediaTypeMovie, parameterObject)) || infos.m_iDbId <= 0)
91 return InvalidParams;
92
93 HandleFileItem("movieid", true, "moviedetails", CFileItemPtr(new CFileItem(infos)), parameterObject, parameterObject["properties"], result, false);
94 return OK;
95 }
96
GetMovieSets(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)97 JSONRPC_STATUS CVideoLibrary::GetMovieSets(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
98 {
99 CVideoDatabase videodatabase;
100 if (!videodatabase.Open())
101 return InternalError;
102
103 CFileItemList items;
104 if (!videodatabase.GetSetsNav("videodb://movies/sets/", items, VIDEODB_CONTENT_MOVIES))
105 return InternalError;
106
107 HandleFileItemList("setid", false, "sets", items, parameterObject, result);
108 return OK;
109 }
110
GetMovieSetDetails(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)111 JSONRPC_STATUS CVideoLibrary::GetMovieSetDetails(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
112 {
113 int id = (int)parameterObject["setid"].asInteger();
114
115 CVideoDatabase videodatabase;
116 if (!videodatabase.Open())
117 return InternalError;
118
119 // Get movie set details
120 CVideoInfoTag infos;
121 if (!videodatabase.GetSetInfo(id, infos) || infos.m_iDbId <= 0)
122 return InvalidParams;
123
124 HandleFileItem("setid", false, "setdetails", CFileItemPtr(new CFileItem(infos)), parameterObject, parameterObject["properties"], result, false);
125
126 // Get movies from the set
127 CFileItemList items;
128 if (!videodatabase.GetMoviesNav("videodb://movies/titles/", items, -1, -1, -1, -1, -1, -1, id, -1, SortDescription(), RequiresAdditionalDetails(MediaTypeMovie, parameterObject["movies"])))
129 return InternalError;
130
131 return HandleItems("movieid", "movies", items, parameterObject["movies"], result["setdetails"], true);
132 }
133
GetTVShows(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)134 JSONRPC_STATUS CVideoLibrary::GetTVShows(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
135 {
136 CVideoDatabase videodatabase;
137 if (!videodatabase.Open())
138 return InternalError;
139
140 SortDescription sorting;
141 ParseLimits(parameterObject, sorting.limitStart, sorting.limitEnd);
142 if (!ParseSorting(parameterObject, sorting.sortBy, sorting.sortOrder, sorting.sortAttributes))
143 return InvalidParams;
144
145 CVideoDbUrl videoUrl;
146 if (!videoUrl.FromString("videodb://tvshows/titles/"))
147 return InternalError;
148
149 const CVariant &filter = parameterObject["filter"];
150 if (filter.isMember("genreid"))
151 videoUrl.AddOption("genreid", (int)filter["genreid"].asInteger());
152 else if (filter.isMember("genre"))
153 videoUrl.AddOption("genre", filter["genre"].asString());
154 else if (filter.isMember("year"))
155 videoUrl.AddOption("year", (int)filter["year"].asInteger());
156 else if (filter.isMember("actor"))
157 videoUrl.AddOption("actor", filter["actor"].asString());
158 else if (filter.isMember("studio"))
159 videoUrl.AddOption("studio", filter["studio"].asString());
160 else if (filter.isMember("tag"))
161 videoUrl.AddOption("tag", filter["tag"].asString());
162 else if (filter.isObject())
163 {
164 std::string xsp;
165 if (!GetXspFiltering("tvshows", filter, xsp))
166 return InvalidParams;
167
168 videoUrl.AddOption("xsp", xsp);
169 }
170
171 CFileItemList items;
172 CDatabase::Filter nofilter;
173 if (!videodatabase.GetTvShowsByWhere(videoUrl.ToString(), nofilter, items, sorting, RequiresAdditionalDetails(MediaTypeTvShow, parameterObject)))
174 return InvalidParams;
175
176 return HandleItems("tvshowid", "tvshows", items, parameterObject, result, false);
177 }
178
GetTVShowDetails(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)179 JSONRPC_STATUS CVideoLibrary::GetTVShowDetails(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
180 {
181 CVideoDatabase videodatabase;
182 if (!videodatabase.Open())
183 return InternalError;
184
185 int id = (int)parameterObject["tvshowid"].asInteger();
186
187 CFileItemPtr fileItem(new CFileItem());
188 CVideoInfoTag infos;
189 if (!videodatabase.GetTvShowInfo("", infos, id, fileItem.get(), RequiresAdditionalDetails(MediaTypeTvShow, parameterObject)) || infos.m_iDbId <= 0)
190 return InvalidParams;
191
192 fileItem->SetFromVideoInfoTag(infos);
193 HandleFileItem("tvshowid", true, "tvshowdetails", fileItem, parameterObject, parameterObject["properties"], result, false);
194 return OK;
195 }
196
GetSeasons(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)197 JSONRPC_STATUS CVideoLibrary::GetSeasons(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
198 {
199 CVideoDatabase videodatabase;
200 if (!videodatabase.Open())
201 return InternalError;
202
203 int tvshowID = (int)parameterObject["tvshowid"].asInteger();
204
205 std::string strPath = StringUtils::Format("videodb://tvshows/titles/%i/", tvshowID);
206 CFileItemList items;
207 if (!videodatabase.GetSeasonsNav(strPath, items, -1, -1, -1, -1, tvshowID, false))
208 return InternalError;
209
210 HandleFileItemList("seasonid", false, "seasons", items, parameterObject, result);
211 return OK;
212 }
213
GetSeasonDetails(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)214 JSONRPC_STATUS CVideoLibrary::GetSeasonDetails(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
215 {
216 CVideoDatabase videodatabase;
217 if (!videodatabase.Open())
218 return InternalError;
219
220 int id = (int)parameterObject["seasonid"].asInteger();
221
222 CVideoInfoTag infos;
223 if (!videodatabase.GetSeasonInfo(id, infos) ||
224 infos.m_iDbId <= 0 || infos.m_iIdShow <= 0)
225 return InvalidParams;
226
227 CFileItemPtr pItem = CFileItemPtr(new CFileItem(infos));
228 HandleFileItem("seasonid", false, "seasondetails", pItem, parameterObject, parameterObject["properties"], result, false);
229 return OK;
230 }
231
GetEpisodes(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)232 JSONRPC_STATUS CVideoLibrary::GetEpisodes(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
233 {
234 CVideoDatabase videodatabase;
235 if (!videodatabase.Open())
236 return InternalError;
237
238 SortDescription sorting;
239 ParseLimits(parameterObject, sorting.limitStart, sorting.limitEnd);
240 if (!ParseSorting(parameterObject, sorting.sortBy, sorting.sortOrder, sorting.sortAttributes))
241 return InvalidParams;
242
243 int tvshowID = (int)parameterObject["tvshowid"].asInteger();
244 int season = (int)parameterObject["season"].asInteger();
245
246 std::string strPath = StringUtils::Format("videodb://tvshows/titles/%i/%i/", tvshowID, season);
247
248 CVideoDbUrl videoUrl;
249 if (!videoUrl.FromString(strPath))
250 return InternalError;
251
252 const CVariant &filter = parameterObject["filter"];
253 if (filter.isMember("genreid"))
254 videoUrl.AddOption("genreid", (int)filter["genreid"].asInteger());
255 else if (filter.isMember("genre"))
256 videoUrl.AddOption("genre", filter["genre"].asString());
257 else if (filter.isMember("year"))
258 videoUrl.AddOption("year", (int)filter["year"].asInteger());
259 else if (filter.isMember("actor"))
260 videoUrl.AddOption("actor", filter["actor"].asString());
261 else if (filter.isMember("director"))
262 videoUrl.AddOption("director", filter["director"].asString());
263 else if (filter.isObject())
264 {
265 std::string xsp;
266 if (!GetXspFiltering("episodes", filter, xsp))
267 return InvalidParams;
268
269 videoUrl.AddOption("xsp", xsp);
270 }
271
272 if (tvshowID <= 0 && (season > 0 || videoUrl.HasOption("genreid") || videoUrl.HasOption("genre") || videoUrl.HasOption("actor")))
273 return InvalidParams;
274
275 if (tvshowID > 0)
276 {
277 videoUrl.AddOption("tvshowid", tvshowID);
278 if (season >= 0)
279 videoUrl.AddOption("season", season);
280 }
281
282 CFileItemList items;
283 if (!videodatabase.GetEpisodesByWhere(videoUrl.ToString(), CDatabase::Filter(), items, false, sorting, RequiresAdditionalDetails(MediaTypeEpisode, parameterObject)))
284 return InvalidParams;
285
286 return HandleItems("episodeid", "episodes", items, parameterObject, result, false);
287 }
288
GetEpisodeDetails(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)289 JSONRPC_STATUS CVideoLibrary::GetEpisodeDetails(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
290 {
291 CVideoDatabase videodatabase;
292 if (!videodatabase.Open())
293 return InternalError;
294
295 int id = (int)parameterObject["episodeid"].asInteger();
296
297 CVideoInfoTag infos;
298 if (!videodatabase.GetEpisodeInfo("", infos, id, RequiresAdditionalDetails(MediaTypeEpisode, parameterObject)) || infos.m_iDbId <= 0)
299 return InvalidParams;
300
301 CFileItemPtr pItem = CFileItemPtr(new CFileItem(infos));
302 // We need to set the correct base path to get the valid fanart
303 int tvshowid = infos.m_iIdShow;
304 if (tvshowid <= 0)
305 tvshowid = videodatabase.GetTvShowForEpisode(id);
306
307 std::string basePath = StringUtils::Format("videodb://tvshows/titles/%i/%i/%i", tvshowid, infos.m_iSeason, id);
308 pItem->SetPath(basePath);
309
310 HandleFileItem("episodeid", true, "episodedetails", pItem, parameterObject, parameterObject["properties"], result, false);
311 return OK;
312 }
313
GetMusicVideos(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)314 JSONRPC_STATUS CVideoLibrary::GetMusicVideos(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
315 {
316 CVideoDatabase videodatabase;
317 if (!videodatabase.Open())
318 return InternalError;
319
320 SortDescription sorting;
321 ParseLimits(parameterObject, sorting.limitStart, sorting.limitEnd);
322 if (!ParseSorting(parameterObject, sorting.sortBy, sorting.sortOrder, sorting.sortAttributes))
323 return InvalidParams;
324
325 CVideoDbUrl videoUrl;
326 if (!videoUrl.FromString("videodb://musicvideos/titles/"))
327 return InternalError;
328
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 std::string 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, RequiresAdditionalDetails(MediaTypeMusicVideo, parameterObject)))
356 return InternalError;
357
358 return HandleItems("musicvideoid", "musicvideos", items, parameterObject, result, false);
359 }
360
GetMusicVideoDetails(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)361 JSONRPC_STATUS CVideoLibrary::GetMusicVideoDetails(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, 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, RequiresAdditionalDetails(MediaTypeMusicVideo, parameterObject)) || 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
GetRecentlyAddedMovies(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)377 JSONRPC_STATUS CVideoLibrary::GetRecentlyAddedMovies(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
378 {
379 CVideoDatabase videodatabase;
380 if (!videodatabase.Open())
381 return InternalError;
382
383 CFileItemList items;
384 if (!videodatabase.GetRecentlyAddedMoviesNav("videodb://recentlyaddedmovies/", items, 0, RequiresAdditionalDetails(MediaTypeMovie, parameterObject)))
385 return InternalError;
386
387 return HandleItems("movieid", "movies", items, parameterObject, result, true);
388 }
389
GetRecentlyAddedEpisodes(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)390 JSONRPC_STATUS CVideoLibrary::GetRecentlyAddedEpisodes(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
391 {
392 CVideoDatabase videodatabase;
393 if (!videodatabase.Open())
394 return InternalError;
395
396 CFileItemList items;
397 if (!videodatabase.GetRecentlyAddedEpisodesNav("videodb://recentlyaddedepisodes/", items, 0, RequiresAdditionalDetails(MediaTypeEpisode, parameterObject)))
398 return InternalError;
399
400 return HandleItems("episodeid", "episodes", items, parameterObject, result, true);
401 }
402
GetRecentlyAddedMusicVideos(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)403 JSONRPC_STATUS CVideoLibrary::GetRecentlyAddedMusicVideos(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
404 {
405 CVideoDatabase videodatabase;
406 if (!videodatabase.Open())
407 return InternalError;
408
409 CFileItemList items;
410 if (!videodatabase.GetRecentlyAddedMusicVideosNav("videodb://recentlyaddedmusicvideos/", items, 0, RequiresAdditionalDetails(MediaTypeMusicVideo, parameterObject)))
411 return InternalError;
412
413 return HandleItems("musicvideoid", "musicvideos", items, parameterObject, result, true);
414 }
415
GetInProgressTVShows(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)416 JSONRPC_STATUS CVideoLibrary::GetInProgressTVShows(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
417 {
418 CVideoDatabase videodatabase;
419 if (!videodatabase.Open())
420 return InternalError;
421
422 CFileItemList items;
423 if (!videodatabase.GetInProgressTvShowsNav("videodb://inprogresstvshows/", items, 0, RequiresAdditionalDetails(MediaTypeTvShow, parameterObject)))
424 return InternalError;
425
426 return HandleItems("tvshowid", "tvshows", items, parameterObject, result, false);
427 }
428
GetGenres(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)429 JSONRPC_STATUS CVideoLibrary::GetGenres(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
430 {
431 std::string media = parameterObject["type"].asString();
432 StringUtils::ToLower(media);
433 int idContent = -1;
434
435 std::string strPath = "videodb://";
436 /* select which video content to get genres from*/
437 if (media == MediaTypeMovie)
438 {
439 idContent = VIDEODB_CONTENT_MOVIES;
440 strPath += "movies";
441 }
442 else if (media == MediaTypeTvShow)
443 {
444 idContent = VIDEODB_CONTENT_TVSHOWS;
445 strPath += "tvshows";
446 }
447 else if (media == MediaTypeMusicVideo)
448 {
449 idContent = VIDEODB_CONTENT_MUSICVIDEOS;
450 strPath += "musicvideos";
451 }
452 strPath += "/genres/";
453
454 CVideoDatabase videodatabase;
455 if (!videodatabase.Open())
456 return InternalError;
457
458 CFileItemList items;
459 if (!videodatabase.GetGenresNav(strPath, items, idContent))
460 return InternalError;
461
462 /* need to set strTitle in each item*/
463 for (unsigned int i = 0; i < (unsigned int)items.Size(); i++)
464 items[i]->GetVideoInfoTag()->m_strTitle = items[i]->GetLabel();
465
466 HandleFileItemList("genreid", false, "genres", items, parameterObject, result);
467 return OK;
468 }
469
GetTags(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)470 JSONRPC_STATUS CVideoLibrary::GetTags(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
471 {
472 std::string media = parameterObject["type"].asString();
473 StringUtils::ToLower(media);
474 int idContent = -1;
475
476 std::string strPath = "videodb://";
477 /* select which video content to get tags from*/
478 if (media == MediaTypeMovie)
479 {
480 idContent = VIDEODB_CONTENT_MOVIES;
481 strPath += "movies";
482 }
483 else if (media == MediaTypeTvShow)
484 {
485 idContent = VIDEODB_CONTENT_TVSHOWS;
486 strPath += "tvshows";
487 }
488 else if (media == MediaTypeMusicVideo)
489 {
490 idContent = VIDEODB_CONTENT_MUSICVIDEOS;
491 strPath += "musicvideos";
492 }
493 strPath += "/tags/";
494
495 CVideoDatabase videodatabase;
496 if (!videodatabase.Open())
497 return InternalError;
498
499 CFileItemList items;
500 if (!videodatabase.GetTagsNav(strPath, items, idContent))
501 return InternalError;
502
503 /* need to set strTitle in each item*/
504 for (int i = 0; i < items.Size(); i++)
505 items[i]->GetVideoInfoTag()->m_strTitle = items[i]->GetLabel();
506
507 HandleFileItemList("tagid", false, "tags", items, parameterObject, result);
508 return OK;
509 }
510
511 namespace
512 {
513 const std::map<std::string, std::string> mediaIDTypes = {
514 {"episodeid", MediaTypeEpisode},
515 {"tvshowid", MediaTypeTvShow},
516 {"seasonid", MediaTypeSeason},
517 {"movieid", MediaTypeMovie},
518 {"setid", MediaTypeVideoCollection},
519 {"musicvideoid", MediaTypeMusicVideo},
520 };
521 }
522
GetAvailableArtTypes(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)523 JSONRPC_STATUS CVideoLibrary::GetAvailableArtTypes(const std::string& method, ITransportLayer* transport, IClient* client, const CVariant& parameterObject, CVariant& result)
524 {
525 std::string mediaType;
526 int mediaID = -1;
527 for (const auto& mediaIDType : mediaIDTypes) {
528 if (parameterObject["item"].isMember(mediaIDType.first))
529 {
530 mediaType = mediaIDType.second;
531 mediaID = parameterObject["item"][mediaIDType.first].asInteger32();
532 break;
533 }
534 }
535 if (mediaID == -1)
536 return InternalError;
537
538 CVideoDatabase videodatabase;
539 if (!videodatabase.Open())
540 return InternalError;
541
542 CVariant availablearttypes = CVariant(CVariant::VariantTypeArray);
543 for (const auto& artType : videodatabase.GetAvailableArtTypesForItem(mediaID, mediaType))
544 {
545 availablearttypes.append(artType);
546 }
547 result = CVariant(CVariant::VariantTypeObject);
548 result["availablearttypes"] = availablearttypes;
549
550 return OK;
551 }
552
GetAvailableArt(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)553 JSONRPC_STATUS CVideoLibrary::GetAvailableArt(const std::string& method, ITransportLayer* transport, IClient* client, const CVariant& parameterObject, CVariant& result)
554 {
555 std::string mediaType;
556 int mediaID = -1;
557 for (const auto& mediaIDType : mediaIDTypes) {
558 if (parameterObject["item"].isMember(mediaIDType.first))
559 {
560 mediaType = mediaIDType.second;
561 mediaID = parameterObject["item"][mediaIDType.first].asInteger32();
562 break;
563 }
564 }
565 if (mediaID == -1)
566 return InternalError;
567
568 std::string artType = parameterObject["arttype"].asString();
569 StringUtils::ToLower(artType);
570
571 CVideoDatabase videodatabase;
572 if (!videodatabase.Open())
573 return InternalError;
574
575 CVariant availableart = CVariant(CVariant::VariantTypeArray);
576 for (const auto& artentry : videodatabase.GetAvailableArtForItem(mediaID, mediaType, artType))
577 {
578 CVariant item = CVariant(CVariant::VariantTypeObject);
579 item["url"] = CTextureUtils::GetWrappedImageURL(artentry.m_url);
580 item["arttype"] = artentry.m_aspect;
581 if (!artentry.m_preview.empty())
582 item["previewurl"] = CTextureUtils::GetWrappedImageURL(artentry.m_preview);
583 availableart.append(item);
584 }
585 result = CVariant(CVariant::VariantTypeObject);
586 result["availableart"] = availableart;
587
588 return OK;
589 }
590
SetMovieDetails(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)591 JSONRPC_STATUS CVideoLibrary::SetMovieDetails(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
592 {
593 int id = (int)parameterObject["movieid"].asInteger();
594
595 CVideoDatabase videodatabase;
596 if (!videodatabase.Open())
597 return InternalError;
598
599 CVideoInfoTag infos;
600 if (!videodatabase.GetMovieInfo("", infos, id) || infos.m_iDbId <= 0)
601 return InvalidParams;
602
603 // get artwork
604 std::map<std::string, std::string> artwork;
605 videodatabase.GetArtForItem(infos.m_iDbId, infos.m_type, artwork);
606
607 int playcount = infos.GetPlayCount();
608 CDateTime lastPlayed = infos.m_lastPlayed;
609
610 std::set<std::string> removedArtwork;
611 std::set<std::string> updatedDetails;
612 UpdateVideoTag(parameterObject, infos, artwork, removedArtwork, updatedDetails);
613
614 if (videodatabase.UpdateDetailsForMovie(id, infos, artwork, updatedDetails) <= 0)
615 return InternalError;
616
617 if (!videodatabase.RemoveArtForItem(infos.m_iDbId, MediaTypeMovie, removedArtwork))
618 return InternalError;
619
620 if (playcount != infos.GetPlayCount() || lastPlayed != infos.m_lastPlayed)
621 {
622 // restore original playcount or the new one won't be announced
623 int newPlaycount = infos.GetPlayCount();
624 infos.SetPlayCount(playcount);
625 videodatabase.SetPlayCount(CFileItem(infos), newPlaycount, infos.m_lastPlayed);
626 }
627
628 UpdateResumePoint(parameterObject, infos, videodatabase);
629
630 CJSONRPCUtils::NotifyItemUpdated(infos, artwork);
631 return ACK;
632 }
633
SetMovieSetDetails(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)634 JSONRPC_STATUS CVideoLibrary::SetMovieSetDetails(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
635 {
636 int id = (int)parameterObject["setid"].asInteger();
637
638 CVideoDatabase videodatabase;
639 if (!videodatabase.Open())
640 return InternalError;
641
642 CVideoInfoTag infos;
643 videodatabase.GetSetInfo(id, infos);
644 if (infos.m_iDbId <= 0)
645 {
646 videodatabase.Close();
647 return InvalidParams;
648 }
649
650 // get artwork
651 std::map<std::string, std::string> artwork;
652 videodatabase.GetArtForItem(infos.m_iDbId, infos.m_type, artwork);
653
654 std::set<std::string> removedArtwork;
655 std::set<std::string> updatedDetails;
656 UpdateVideoTag(parameterObject, infos, artwork, removedArtwork, updatedDetails);
657
658 if (videodatabase.SetDetailsForMovieSet(infos, artwork, id) <= 0)
659 return InternalError;
660
661 if (!videodatabase.RemoveArtForItem(infos.m_iDbId, "set", removedArtwork))
662 return InternalError;
663
664 CJSONRPCUtils::NotifyItemUpdated();
665 return ACK;
666 }
667
SetTVShowDetails(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)668 JSONRPC_STATUS CVideoLibrary::SetTVShowDetails(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
669 {
670 int id = (int)parameterObject["tvshowid"].asInteger();
671
672 CVideoDatabase videodatabase;
673 if (!videodatabase.Open())
674 return InternalError;
675
676 CVideoInfoTag infos;
677 if (!videodatabase.GetTvShowInfo("", infos, id) || infos.m_iDbId <= 0)
678 return InvalidParams;
679
680 // get artwork
681 std::map<std::string, std::string> artwork;
682 videodatabase.GetArtForItem(infos.m_iDbId, infos.m_type, artwork);
683
684 std::map<int, std::map<std::string, std::string> > seasonArt;
685 videodatabase.GetTvShowSeasonArt(infos.m_iDbId, seasonArt);
686
687 std::set<std::string> removedArtwork;
688 std::set<std::string> updatedDetails;
689 UpdateVideoTag(parameterObject, infos, artwork, removedArtwork, updatedDetails);
690
691 // we need to manually remove tags/taglinks for now because they aren't replaced
692 // due to scrapers not supporting them
693 videodatabase.RemoveTagsFromItem(id, MediaTypeTvShow);
694
695 if (!videodatabase.UpdateDetailsForTvShow(id, infos, artwork, seasonArt))
696 return InternalError;
697
698 if (!videodatabase.RemoveArtForItem(infos.m_iDbId, MediaTypeTvShow, removedArtwork))
699 return InternalError;
700
701 CJSONRPCUtils::NotifyItemUpdated();
702 return ACK;
703 }
704
SetSeasonDetails(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)705 JSONRPC_STATUS CVideoLibrary::SetSeasonDetails(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
706 {
707 int id = (int)parameterObject["seasonid"].asInteger();
708
709 CVideoDatabase videodatabase;
710 if (!videodatabase.Open())
711 return InternalError;
712
713 CVideoInfoTag infos;
714 videodatabase.GetSeasonInfo(id, infos);
715 if (infos.m_iDbId <= 0 || infos.m_iIdShow <= 0)
716 {
717 videodatabase.Close();
718 return InvalidParams;
719 }
720
721 // get artwork
722 std::map<std::string, std::string> artwork;
723 videodatabase.GetArtForItem(infos.m_iDbId, infos.m_type, artwork);
724
725 std::set<std::string> removedArtwork;
726 std::set<std::string> updatedDetails;
727 UpdateVideoTag(parameterObject, infos, artwork, removedArtwork, updatedDetails);
728 if (ParameterNotNull(parameterObject, "title"))
729 infos.SetSortTitle(parameterObject["title"].asString());
730
731 if (videodatabase.SetDetailsForSeason(infos, artwork, infos.m_iIdShow, id) <= 0)
732 return InternalError;
733
734 if (!videodatabase.RemoveArtForItem(infos.m_iDbId, MediaTypeSeason, removedArtwork))
735 return InternalError;
736
737 CJSONRPCUtils::NotifyItemUpdated();
738 return ACK;
739 }
740
SetEpisodeDetails(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)741 JSONRPC_STATUS CVideoLibrary::SetEpisodeDetails(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
742 {
743 int id = (int)parameterObject["episodeid"].asInteger();
744
745 CVideoDatabase videodatabase;
746 if (!videodatabase.Open())
747 return InternalError;
748
749 CVideoInfoTag infos;
750 videodatabase.GetEpisodeInfo("", infos, id);
751 if (infos.m_iDbId <= 0)
752 {
753 videodatabase.Close();
754 return InvalidParams;
755 }
756
757 int tvshowid = videodatabase.GetTvShowForEpisode(id);
758 if (tvshowid <= 0)
759 {
760 videodatabase.Close();
761 return InvalidParams;
762 }
763
764 // get artwork
765 std::map<std::string, std::string> artwork;
766 videodatabase.GetArtForItem(infos.m_iDbId, infos.m_type, artwork);
767
768 int playcount = infos.GetPlayCount();
769 CDateTime lastPlayed = infos.m_lastPlayed;
770
771 std::set<std::string> removedArtwork;
772 std::set<std::string> updatedDetails;
773 UpdateVideoTag(parameterObject, infos, artwork, removedArtwork, updatedDetails);
774
775 if (videodatabase.SetDetailsForEpisode(infos.m_strFileNameAndPath, infos, artwork, tvshowid, id) <= 0)
776 return InternalError;
777
778 if (!videodatabase.RemoveArtForItem(infos.m_iDbId, MediaTypeEpisode, removedArtwork))
779 return InternalError;
780
781 if (playcount != infos.GetPlayCount() || lastPlayed != infos.m_lastPlayed)
782 {
783 // restore original playcount or the new one won't be announced
784 int newPlaycount = infos.GetPlayCount();
785 infos.SetPlayCount(playcount);
786 videodatabase.SetPlayCount(CFileItem(infos), newPlaycount, infos.m_lastPlayed);
787 }
788
789 UpdateResumePoint(parameterObject, infos, videodatabase);
790
791 CJSONRPCUtils::NotifyItemUpdated();
792 return ACK;
793 }
794
SetMusicVideoDetails(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)795 JSONRPC_STATUS CVideoLibrary::SetMusicVideoDetails(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
796 {
797 int id = (int)parameterObject["musicvideoid"].asInteger();
798
799 CVideoDatabase videodatabase;
800 if (!videodatabase.Open())
801 return InternalError;
802
803 CVideoInfoTag infos;
804 videodatabase.GetMusicVideoInfo("", infos, id);
805 if (infos.m_iDbId <= 0)
806 {
807 videodatabase.Close();
808 return InvalidParams;
809 }
810
811 // get artwork
812 std::map<std::string, std::string> artwork;
813 videodatabase.GetArtForItem(infos.m_iDbId, infos.m_type, artwork);
814
815 int playcount = infos.GetPlayCount();
816 CDateTime lastPlayed = infos.m_lastPlayed;
817
818 std::set<std::string> removedArtwork;
819 std::set<std::string> updatedDetails;
820 UpdateVideoTag(parameterObject, infos, artwork, removedArtwork, updatedDetails);
821
822 // we need to manually remove tags/taglinks for now because they aren't replaced
823 // due to scrapers not supporting them
824 videodatabase.RemoveTagsFromItem(id, MediaTypeMusicVideo);
825
826 if (videodatabase.SetDetailsForMusicVideo(infos.m_strFileNameAndPath, infos, artwork, id) <= 0)
827 return InternalError;
828
829 if (!videodatabase.RemoveArtForItem(infos.m_iDbId, MediaTypeMusicVideo, removedArtwork))
830 return InternalError;
831
832 if (playcount != infos.GetPlayCount()|| lastPlayed != infos.m_lastPlayed)
833 {
834 // restore original playcount or the new one won't be announced
835 int newPlaycount = infos.GetPlayCount();
836 infos.SetPlayCount(playcount);
837 videodatabase.SetPlayCount(CFileItem(infos), newPlaycount, infos.m_lastPlayed);
838 }
839
840 UpdateResumePoint(parameterObject, infos, videodatabase);
841
842 CJSONRPCUtils::NotifyItemUpdated();
843 return ACK;
844 }
845
RefreshMovie(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)846 JSONRPC_STATUS CVideoLibrary::RefreshMovie(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
847 {
848 int id = static_cast<int>(parameterObject["movieid"].asInteger());
849
850 CVideoDatabase videodatabase;
851 if (!videodatabase.Open())
852 return InternalError;
853
854 CVideoInfoTag infos;
855 if (!videodatabase.GetMovieInfo("", infos, id) || infos.m_iDbId <= 0)
856 return InvalidParams;
857
858 bool ignoreNfo = parameterObject["ignorenfo"].asBoolean();
859 std::string searchTitle = parameterObject["title"].asString();
860 CVideoLibraryQueue::GetInstance().RefreshItem(CFileItemPtr(new CFileItem(infos)), ignoreNfo, true, false, searchTitle);
861
862 return ACK;
863 }
864
RefreshTVShow(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)865 JSONRPC_STATUS CVideoLibrary::RefreshTVShow(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
866 {
867 int id = static_cast<int>(parameterObject["tvshowid"].asInteger());
868
869 CVideoDatabase videodatabase;
870 if (!videodatabase.Open())
871 return InternalError;
872
873 CFileItemPtr item(new CFileItem());
874 CVideoInfoTag infos;
875 if (!videodatabase.GetTvShowInfo("", infos, id, item.get()) || infos.m_iDbId <= 0)
876 return InvalidParams;
877
878 item->SetFromVideoInfoTag(infos);
879
880 bool ignoreNfo = parameterObject["ignorenfo"].asBoolean();
881 bool refreshEpisodes = parameterObject["refreshepisodes"].asBoolean();
882 std::string searchTitle = parameterObject["title"].asString();
883 CVideoLibraryQueue::GetInstance().RefreshItem(item, ignoreNfo, true, refreshEpisodes, searchTitle);
884
885 return ACK;
886 }
887
RefreshEpisode(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)888 JSONRPC_STATUS CVideoLibrary::RefreshEpisode(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
889 {
890 int id = (int)parameterObject["episodeid"].asInteger();
891
892 CVideoDatabase videodatabase;
893 if (!videodatabase.Open())
894 return InternalError;
895
896 CVideoInfoTag infos;
897 if (!videodatabase.GetEpisodeInfo("", infos, id) || infos.m_iDbId <= 0)
898 return InvalidParams;
899
900 CFileItemPtr item = CFileItemPtr(new CFileItem(infos));
901 // We need to set the correct base path to get the valid fanart
902 int tvshowid = infos.m_iIdShow;
903 if (tvshowid <= 0)
904 tvshowid = videodatabase.GetTvShowForEpisode(id);
905
906 bool ignoreNfo = parameterObject["ignorenfo"].asBoolean();
907 std::string searchTitle = parameterObject["title"].asString();
908 CVideoLibraryQueue::GetInstance().RefreshItem(item, ignoreNfo, true, false, searchTitle);
909
910 return ACK;
911 }
912
RefreshMusicVideo(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)913 JSONRPC_STATUS CVideoLibrary::RefreshMusicVideo(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
914 {
915 int id = static_cast<int>(parameterObject["musicvideoid"].asInteger());
916
917 CVideoDatabase videodatabase;
918 if (!videodatabase.Open())
919 return InternalError;
920
921 CVideoInfoTag infos;
922 if (!videodatabase.GetMusicVideoInfo("", infos, id) || infos.m_iDbId <= 0)
923 return InvalidParams;
924
925 bool ignoreNfo = parameterObject["ignorenfo"].asBoolean();
926 std::string searchTitle = parameterObject["title"].asString();
927 CVideoLibraryQueue::GetInstance().RefreshItem(CFileItemPtr(new CFileItem(infos)), ignoreNfo, true, false, searchTitle);
928
929 return ACK;
930 }
931
RemoveMovie(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)932 JSONRPC_STATUS CVideoLibrary::RemoveMovie(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
933 {
934 return RemoveVideo(parameterObject);
935 }
936
RemoveTVShow(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)937 JSONRPC_STATUS CVideoLibrary::RemoveTVShow(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
938 {
939 return RemoveVideo(parameterObject);
940 }
941
RemoveEpisode(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)942 JSONRPC_STATUS CVideoLibrary::RemoveEpisode(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
943 {
944 return RemoveVideo(parameterObject);
945 }
946
RemoveMusicVideo(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)947 JSONRPC_STATUS CVideoLibrary::RemoveMusicVideo(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
948 {
949 return RemoveVideo(parameterObject);
950 }
951
Scan(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)952 JSONRPC_STATUS CVideoLibrary::Scan(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
953 {
954 std::string directory = parameterObject["directory"].asString();
955 std::string cmd = StringUtils::Format("updatelibrary(video, %s, %s)", StringUtils::Paramify(directory).c_str(), parameterObject["showdialogs"].asBoolean() ? "true" : "false");
956
957 CApplicationMessenger::GetInstance().SendMsg(TMSG_EXECUTE_BUILT_IN, -1, -1, nullptr, cmd);
958 return ACK;
959 }
960
Export(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)961 JSONRPC_STATUS CVideoLibrary::Export(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
962 {
963 std::string cmd;
964 if (parameterObject["options"].isMember("path"))
965 cmd = StringUtils::Format("exportlibrary2(video, singlefile, %s)", StringUtils::Paramify(parameterObject["options"]["path"].asString()).c_str());
966 else
967 {
968 cmd = "exportlibrary2(video, separate, dummy";
969 if (parameterObject["options"]["images"].isBoolean() &&
970 parameterObject["options"]["images"].asBoolean() == true)
971 cmd += ", artwork";
972 if (parameterObject["options"]["overwrite"].isBoolean() &&
973 parameterObject["options"]["overwrite"].asBoolean() == true)
974 cmd += ", overwrite";
975 if (parameterObject["options"]["actorthumbs"].isBoolean() &&
976 parameterObject["options"]["actorthumbs"].asBoolean() == true)
977 cmd += ", actorthumbs";
978 cmd += ")";
979 }
980
981 CApplicationMessenger::GetInstance().SendMsg(TMSG_EXECUTE_BUILT_IN, -1, -1, nullptr, cmd);
982 return ACK;
983 }
984
Clean(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)985 JSONRPC_STATUS CVideoLibrary::Clean(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
986 {
987 std::string directory = parameterObject["directory"].asString();
988 std::string cmd;
989 if (parameterObject["content"].empty())
990 cmd = StringUtils::Format("cleanlibrary(video, {0}, {1})",
991 parameterObject["showdialogs"].asBoolean() ? "true" : "false",
992 StringUtils::Paramify(directory).c_str());
993 else
994 cmd = StringUtils::Format("cleanlibrary({0}, {1}, {2})", parameterObject["content"].asString(),
995 parameterObject["showdialogs"].asBoolean() ? "true" : "false",
996 StringUtils::Paramify(directory).c_str());
997
998 CApplicationMessenger::GetInstance().SendMsg(TMSG_EXECUTE_BUILT_IN, -1, -1, nullptr, cmd);
999 return ACK;
1000 }
1001
FillFileItem(const std::string & strFilename,CFileItemPtr & item,const CVariant & parameterObject)1002 bool CVideoLibrary::FillFileItem(const std::string &strFilename, CFileItemPtr &item, const CVariant ¶meterObject /* = CVariant(CVariant::VariantTypeArray) */)
1003 {
1004 CVideoDatabase videodatabase;
1005 if (strFilename.empty())
1006 return false;
1007
1008 bool filled = false;
1009 if (videodatabase.Open())
1010 {
1011 CVideoInfoTag details;
1012 if (videodatabase.LoadVideoInfo(strFilename, details))
1013 {
1014 item->SetFromVideoInfoTag(details);
1015 item->SetDynPath(strFilename);
1016 filled = true;
1017 }
1018 }
1019
1020 if (item->GetLabel().empty())
1021 {
1022 item->SetLabel(CUtil::GetTitleFromPath(strFilename, false));
1023 if (item->GetLabel().empty())
1024 item->SetLabel(URIUtils::GetFileName(strFilename));
1025 }
1026
1027 return filled;
1028 }
1029
FillFileItemList(const CVariant & parameterObject,CFileItemList & list)1030 bool CVideoLibrary::FillFileItemList(const CVariant ¶meterObject, CFileItemList &list)
1031 {
1032 CVideoDatabase videodatabase;
1033 if (!videodatabase.Open())
1034 return false;
1035
1036 std::string file = parameterObject["file"].asString();
1037 int movieID = (int)parameterObject["movieid"].asInteger(-1);
1038 int episodeID = (int)parameterObject["episodeid"].asInteger(-1);
1039 int musicVideoID = (int)parameterObject["musicvideoid"].asInteger(-1);
1040
1041 bool success = false;
1042 CFileItemPtr fileItem(new CFileItem());
1043 if (FillFileItem(file, fileItem))
1044 {
1045 success = true;
1046 list.Add(fileItem);
1047 }
1048
1049 if (movieID > 0)
1050 {
1051 CVideoInfoTag details;
1052 videodatabase.GetMovieInfo("", details, movieID);
1053 if (!details.IsEmpty())
1054 {
1055 list.Add(CFileItemPtr(new CFileItem(details)));
1056 success = true;
1057 }
1058 }
1059 if (episodeID > 0)
1060 {
1061 CVideoInfoTag details;
1062 if (videodatabase.GetEpisodeInfo("", details, episodeID) && !details.IsEmpty())
1063 {
1064 list.Add(CFileItemPtr(new CFileItem(details)));
1065 success = true;
1066 }
1067 }
1068 if (musicVideoID > 0)
1069 {
1070 CVideoInfoTag details;
1071 videodatabase.GetMusicVideoInfo("", details, musicVideoID);
1072 if (!details.IsEmpty())
1073 {
1074 list.Add(CFileItemPtr(new CFileItem(details)));
1075 success = true;
1076 }
1077 }
1078
1079 return success;
1080 }
1081
RequiresAdditionalDetails(const MediaType & mediaType,const CVariant & parameterObject)1082 int CVideoLibrary::RequiresAdditionalDetails(const MediaType& mediaType, const CVariant ¶meterObject)
1083 {
1084 if (mediaType != MediaTypeMovie && mediaType != MediaTypeTvShow && mediaType != MediaTypeEpisode && mediaType != MediaTypeMusicVideo)
1085 return VideoDbDetailsNone;
1086
1087 const CVariant& properties = parameterObject["properties"];
1088 int details = VideoDbDetailsNone;
1089 for (CVariant::const_iterator_array itr = properties.begin_array(); itr != properties.end_array(); itr++)
1090 {
1091 std::string propertyValue = itr->asString();
1092 if (propertyValue == "cast")
1093 details = details | VideoDbDetailsCast;
1094 else if (propertyValue == "ratings")
1095 details = details | VideoDbDetailsRating;
1096 else if (propertyValue == "uniqueid")
1097 details = details | VideoDbDetailsUniqueID;
1098 else if (propertyValue == "showlink")
1099 details = details | VideoDbDetailsShowLink;
1100 else if (propertyValue == "streamdetails")
1101 details = details | VideoDbDetailsStream;
1102 else if (propertyValue == "tag")
1103 details = details | VideoDbDetailsTag;
1104 }
1105 return details;
1106 }
1107
HandleItems(const char * idProperty,const char * resultName,CFileItemList & items,const CVariant & parameterObject,CVariant & result,bool limit)1108 JSONRPC_STATUS CVideoLibrary::HandleItems(const char *idProperty, const char *resultName, CFileItemList &items, const CVariant ¶meterObject, CVariant &result, bool limit /* = true */)
1109 {
1110 int size = items.Size();
1111 if (!limit && items.HasProperty("total") && items.GetProperty("total").asInteger() > size)
1112 size = (int)items.GetProperty("total").asInteger();
1113 HandleFileItemList(idProperty, true, resultName, items, parameterObject, result, size, limit);
1114
1115 return OK;
1116 }
1117
RemoveVideo(const CVariant & parameterObject)1118 JSONRPC_STATUS CVideoLibrary::RemoveVideo(const CVariant ¶meterObject)
1119 {
1120 CVideoDatabase videodatabase;
1121 if (!videodatabase.Open())
1122 return InternalError;
1123
1124 if (parameterObject.isMember("movieid"))
1125 videodatabase.DeleteMovie((int)parameterObject["movieid"].asInteger());
1126 else if (parameterObject.isMember("tvshowid"))
1127 videodatabase.DeleteTvShow((int)parameterObject["tvshowid"].asInteger());
1128 else if (parameterObject.isMember("episodeid"))
1129 videodatabase.DeleteEpisode((int)parameterObject["episodeid"].asInteger());
1130 else if (parameterObject.isMember("musicvideoid"))
1131 videodatabase.DeleteMusicVideo((int)parameterObject["musicvideoid"].asInteger());
1132
1133 CJSONRPCUtils::NotifyItemUpdated();
1134 return ACK;
1135 }
1136
UpdateResumePoint(const CVariant & parameterObject,CVideoInfoTag & details,CVideoDatabase & videodatabase)1137 void CVideoLibrary::UpdateResumePoint(const CVariant ¶meterObject, CVideoInfoTag &details, CVideoDatabase &videodatabase)
1138 {
1139 if (!parameterObject["resume"].isNull())
1140 {
1141 double position = (double)parameterObject["resume"]["position"].asDouble();
1142 if (position == 0.0)
1143 videodatabase.ClearBookMarksOfFile(details.m_strFileNameAndPath, CBookmark::RESUME);
1144 else
1145 {
1146 CBookmark bookmark;
1147 double total = (double)parameterObject["resume"]["total"].asDouble();
1148 if (total <= 0.0 && !videodatabase.GetResumeBookMark(details.m_strFileNameAndPath, bookmark))
1149 bookmark.totalTimeInSeconds = details.m_streamDetails.GetVideoDuration();
1150 else
1151 bookmark.totalTimeInSeconds = total;
1152
1153 bookmark.timeInSeconds = position;
1154 videodatabase.AddBookMarkToFile(details.m_strFileNameAndPath, bookmark, CBookmark::RESUME);
1155 }
1156 }
1157 }
1158
UpdateVideoTagField(const CVariant & parameterObject,const std::string & fieldName,std::vector<std::string> & fieldValue,std::set<std::string> & updatedDetails)1159 void CVideoLibrary::UpdateVideoTagField(const CVariant& parameterObject, const std::string& fieldName, std::vector<std::string>& fieldValue, std::set<std::string>& updatedDetails)
1160 {
1161 if (ParameterNotNull(parameterObject, fieldName))
1162 {
1163 CopyStringArray(parameterObject[fieldName], fieldValue);
1164 updatedDetails.insert(fieldName);
1165 }
1166 }
1167
UpdateVideoTag(const CVariant & parameterObject,CVideoInfoTag & details,std::map<std::string,std::string> & artwork,std::set<std::string> & removedArtwork,std::set<std::string> & updatedDetails)1168 void CVideoLibrary::UpdateVideoTag(const CVariant ¶meterObject, CVideoInfoTag& details, std::map<std::string, std::string> &artwork, std::set<std::string> &removedArtwork, std::set<std::string> &updatedDetails)
1169 {
1170 if (ParameterNotNull(parameterObject, "title"))
1171 details.SetTitle(parameterObject["title"].asString());
1172 if (ParameterNotNull(parameterObject, "playcount"))
1173 details.SetPlayCount(static_cast<int>(parameterObject["playcount"].asInteger()));
1174 if (ParameterNotNull(parameterObject, "runtime"))
1175 details.SetDuration(static_cast<int>(parameterObject["runtime"].asInteger()));
1176
1177 std::vector<std::string> director(details.m_director);
1178 UpdateVideoTagField(parameterObject, "director", director, updatedDetails);
1179 details.SetDirector(director);
1180
1181 std::vector<std::string> studio(details.m_studio);
1182 UpdateVideoTagField(parameterObject, "studio", studio, updatedDetails);
1183 details.SetStudio(studio);
1184
1185 if (ParameterNotNull(parameterObject, "plot"))
1186 details.SetPlot(parameterObject["plot"].asString());
1187 if (ParameterNotNull(parameterObject, "album"))
1188 details.SetAlbum(parameterObject["album"].asString());
1189
1190 std::vector<std::string> artist(details.m_artist);
1191 UpdateVideoTagField(parameterObject, "artist", artist, updatedDetails);
1192 details.SetArtist(artist);
1193
1194 std::vector<std::string> genre(details.m_genre);
1195 UpdateVideoTagField(parameterObject, "genre", genre, updatedDetails);
1196 details.SetGenre(genre);
1197
1198 if (ParameterNotNull(parameterObject, "track"))
1199 details.m_iTrack = (int)parameterObject["track"].asInteger();
1200 if (ParameterNotNull(parameterObject, "rating"))
1201 {
1202 details.SetRating(parameterObject["rating"].asFloat());
1203 updatedDetails.insert("ratings");
1204 }
1205 if (ParameterNotNull(parameterObject, "votes"))
1206 {
1207 details.SetVotes(StringUtils::ReturnDigits(parameterObject["votes"].asString()));
1208 updatedDetails.insert("ratings"); //Votes and ratings both need updates now, this will trigger those
1209 }
1210 if (ParameterNotNull(parameterObject, "ratings"))
1211 {
1212 CVariant ratings = parameterObject["ratings"];
1213 for (CVariant::const_iterator_map rIt = ratings.begin_map(); rIt != ratings.end_map(); rIt++)
1214 {
1215 if (rIt->second.isObject() && ParameterNotNull(rIt->second, "rating"))
1216 {
1217 const auto& rating = rIt->second;
1218 if (ParameterNotNull(rating, "votes"))
1219 {
1220 details.SetRating(rating["rating"].asFloat(),
1221 static_cast<int>(rating["votes"].asInteger()),
1222 rIt->first,
1223 (ParameterNotNull(rating, "default") && rating["default"].asBoolean()));
1224 }
1225 else
1226 details.SetRating(rating["rating"].asFloat(), rIt->first, (ParameterNotNull(rating, "default") && rating["default"].asBoolean()));
1227
1228 updatedDetails.insert("ratings");
1229 }
1230 else if (rIt->second.isNull())
1231 {
1232 details.RemoveRating(rIt->first);
1233 updatedDetails.insert("ratings");
1234 }
1235 }
1236 }
1237 if (ParameterNotNull(parameterObject, "userrating"))
1238 details.m_iUserRating = static_cast<int>(parameterObject["userrating"].asInteger());
1239 if (ParameterNotNull(parameterObject, "mpaa"))
1240 details.SetMPAARating(parameterObject["mpaa"].asString());
1241 if (ParameterNotNull(parameterObject, "imdbnumber"))
1242 {
1243 details.SetUniqueID(parameterObject["imdbnumber"].asString());
1244 updatedDetails.insert("uniqueid");
1245 }
1246 if (ParameterNotNull(parameterObject, "uniqueid"))
1247 {
1248 CVariant uniqueids = parameterObject["uniqueid"];
1249 for (CVariant::const_iterator_map idIt = uniqueids.begin_map(); idIt != uniqueids.end_map(); idIt++)
1250 {
1251 if (idIt->second.isString() && !idIt->second.asString().empty())
1252 {
1253 details.SetUniqueID(idIt->second.asString(), idIt->first);
1254 updatedDetails.insert("uniqueid");
1255 }
1256 else if (idIt->second.isNull() && idIt->first != details.GetDefaultUniqueID())
1257 {
1258 details.RemoveUniqueID(idIt->first);
1259 updatedDetails.insert("uniqueid");
1260 }
1261 }
1262 }
1263 if (ParameterNotNull(parameterObject, "premiered"))
1264 {
1265 CDateTime premiered;
1266 SetFromDBDate(parameterObject["premiered"], premiered);
1267 details.SetPremiered(premiered);
1268 }
1269 else if (ParameterNotNull(parameterObject, "year"))
1270 details.SetYear((int)parameterObject["year"].asInteger());
1271 if (ParameterNotNull(parameterObject, "lastplayed"))
1272 SetFromDBDateTime(parameterObject["lastplayed"], details.m_lastPlayed);
1273 if (ParameterNotNull(parameterObject, "firstaired"))
1274 SetFromDBDate(parameterObject["firstaired"], details.m_firstAired);
1275 if (ParameterNotNull(parameterObject, "productioncode"))
1276 details.SetProductionCode(parameterObject["productioncode"].asString());
1277 if (ParameterNotNull(parameterObject, "season"))
1278 details.m_iSeason = (int)parameterObject["season"].asInteger();
1279 if (ParameterNotNull(parameterObject, "episode"))
1280 details.m_iEpisode = (int)parameterObject["episode"].asInteger();
1281 if (ParameterNotNull(parameterObject, "originaltitle"))
1282 details.SetOriginalTitle(parameterObject["originaltitle"].asString());
1283 if (ParameterNotNull(parameterObject, "trailer"))
1284 details.SetTrailer(parameterObject["trailer"].asString());
1285 if (ParameterNotNull(parameterObject, "tagline"))
1286 details.SetTagLine(parameterObject["tagline"].asString());
1287 if (ParameterNotNull(parameterObject, "status"))
1288 details.SetStatus(parameterObject["status"].asString());
1289 if (ParameterNotNull(parameterObject, "plotoutline"))
1290 details.SetPlotOutline(parameterObject["plotoutline"].asString());
1291
1292 std::vector<std::string> credits(details.m_writingCredits);
1293 UpdateVideoTagField(parameterObject, "writer", credits, updatedDetails);
1294 details.SetWritingCredits(credits);
1295
1296 std::vector<std::string> country(details.m_country);
1297 UpdateVideoTagField(parameterObject, "country", country, updatedDetails);
1298 details.SetCountry(country);
1299
1300 if (ParameterNotNull(parameterObject, "top250"))
1301 details.m_iTop250 = (int)parameterObject["top250"].asInteger();
1302 if (ParameterNotNull(parameterObject, "sorttitle"))
1303 details.SetSortTitle(parameterObject["sorttitle"].asString());
1304 if (ParameterNotNull(parameterObject, "episodeguide"))
1305 details.SetEpisodeGuide(parameterObject["episodeguide"].asString());
1306 if (ParameterNotNull(parameterObject, "set"))
1307 {
1308 details.SetSet(parameterObject["set"].asString());
1309 updatedDetails.insert("set");
1310 }
1311
1312 std::vector<std::string> showLink(details.m_showLink);
1313 UpdateVideoTagField(parameterObject, "showlink", showLink, updatedDetails);
1314 details.SetShowLink(showLink);
1315
1316 std::vector<std::string> tags(details.m_tags);
1317 UpdateVideoTagField(parameterObject, "tag", tags, updatedDetails);
1318 details.SetTags(tags);
1319
1320 if (ParameterNotNull(parameterObject, "thumbnail"))
1321 {
1322 std::string value = parameterObject["thumbnail"].asString();
1323 artwork["thumb"] = StringUtils::Trim(value);
1324 updatedDetails.insert("art.altered");
1325 }
1326 if (ParameterNotNull(parameterObject, "fanart"))
1327 {
1328 std::string value = parameterObject["fanart"].asString();
1329 artwork["fanart"] = StringUtils::Trim(value);
1330 updatedDetails.insert("art.altered");
1331 }
1332
1333 if (ParameterNotNull(parameterObject, "art"))
1334 {
1335 CVariant art = parameterObject["art"];
1336 for (CVariant::const_iterator_map artIt = art.begin_map(); artIt != art.end_map(); artIt++)
1337 {
1338 if (artIt->second.isString() && !artIt->second.asString().empty())
1339 {
1340 artwork[artIt->first] = CTextureUtils::UnwrapImageURL(artIt->second.asString());
1341 updatedDetails.insert("art.altered");
1342 }
1343 else if (artIt->second.isNull())
1344 {
1345 artwork.erase(artIt->first);
1346 removedArtwork.insert(artIt->first);
1347 }
1348 }
1349 }
1350
1351 if (ParameterNotNull(parameterObject, "dateadded"))
1352 {
1353 SetFromDBDateTime(parameterObject["dateadded"], details.m_dateAdded);
1354 updatedDetails.insert("dateadded");
1355 }
1356 }
1357