Merge pull request #2248 from Tolriq/compilationartist
[vuplus_xbmc] / xbmc / interfaces / json-rpc / FileItemHandler.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 <map>
22 #include <string.h>
23
24 #include "FileItemHandler.h"
25 #include "PlaylistOperations.h"
26 #include "AudioLibrary.h"
27 #include "VideoLibrary.h"
28 #include "FileOperations.h"
29 #include "utils/URIUtils.h"
30 #include "utils/ISerializable.h"
31 #include "utils/Variant.h"
32 #include "video/VideoInfoTag.h"
33 #include "music/tags/MusicInfoTag.h"
34 #include "pictures/PictureInfoTag.h"
35 #include "video/VideoDatabase.h"
36 #include "filesystem/Directory.h"
37 #include "filesystem/File.h"
38 #include "TextureCache.h"
39 #include "video/VideoThumbLoader.h"
40 #include "music/MusicThumbLoader.h"
41 #include "Util.h"
42 #include "pvr/channels/PVRChannel.h"
43
44 using namespace MUSIC_INFO;
45 using namespace JSONRPC;
46 using namespace XFILE;
47
48 bool CFileItemHandler::GetField(const std::string &field, const CVariant &info, const CFileItemPtr &item, CVariant &result, bool &fetchedArt, CThumbLoader *thumbLoader /* = NULL */)
49 {
50   if (result.isMember(field) && !result[field].empty())
51     return true;
52
53   if (info.isMember(field) && !info[field].isNull())
54   {
55     result[field] = info[field];
56     return true;
57   }
58
59   if (item)
60   {
61     if (item->IsAlbum())
62     {
63       if (field == "albumlabel")
64       {
65         result[field] = item->GetProperty("album_label");
66         return true;
67       }
68       if (item->HasProperty("album_" + field + "_array"))
69       {
70         result[field] = item->GetProperty("album_" + field + "_array");
71         return true;
72       }
73       if (item->HasProperty("album_" + field))
74       {
75         result[field] = item->GetProperty("album_" + field);
76         return true;
77       }
78     }
79     
80     if (item->HasProperty("artist_" + field + "_array"))
81     {
82       result[field] = item->GetProperty("artist_" + field + "_array");
83       return true;
84     }
85     if (item->HasProperty("artist_" + field))
86     {
87       result[field] = item->GetProperty("artist_" + field);
88       return true;
89     }
90
91     if (field == "art")
92     {
93       if (thumbLoader != NULL && item->GetArt().size() <= 0 && !fetchedArt &&
94         ((item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_iDbId > -1) || (item->HasMusicInfoTag() && item->GetMusicInfoTag()->GetDatabaseId() > -1)))
95       {
96         thumbLoader->FillLibraryArt(*item);
97         fetchedArt = true;
98       }
99
100       CGUIListItem::ArtMap artMap = item->GetArt();
101       CVariant artObj(CVariant::VariantTypeObject);
102       for (CGUIListItem::ArtMap::const_iterator artIt = artMap.begin(); artIt != artMap.end(); artIt++)
103       {
104         if (!artIt->second.empty())
105           artObj[artIt->first] = CTextureCache::GetWrappedImageURL(artIt->second);
106       }
107
108       result["art"] = artObj;
109       return true;
110     }
111     
112     if (field == "thumbnail")
113     {
114       if (thumbLoader != NULL && !item->HasArt("thumb") && !fetchedArt &&
115         ((item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_iDbId > -1) || (item->HasMusicInfoTag() && item->GetMusicInfoTag()->GetDatabaseId() > -1)))
116       {
117         thumbLoader->FillLibraryArt(*item);
118         fetchedArt = true;
119       }
120       else if (item->HasPictureInfoTag() && !item->HasArt("thumb"))
121         item->SetArt("thumb", CTextureCache::GetWrappedThumbURL(item->GetPath()));
122       
123       if (item->HasArt("thumb"))
124         result["thumbnail"] = CTextureCache::GetWrappedImageURL(item->GetArt("thumb"));
125       else
126         result["thumbnail"] = "";
127       
128       return true;
129     }
130     
131     if (field == "fanart")
132     {
133       if (thumbLoader != NULL && !item->HasArt("fanart") && !fetchedArt &&
134         ((item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_iDbId > -1) || (item->HasMusicInfoTag() && item->GetMusicInfoTag()->GetDatabaseId() > -1)))
135       {
136         thumbLoader->FillLibraryArt(*item);
137         fetchedArt = true;
138       }
139       
140       if (item->HasArt("fanart"))
141         result["fanart"] = CTextureCache::GetWrappedImageURL(item->GetArt("fanart"));
142       else
143         result["fanart"] = "";
144       
145       return true;
146     }
147     
148     if (item->HasVideoInfoTag() && item->GetVideoContentType() == VIDEODB_CONTENT_TVSHOWS)
149     {
150       if (item->GetVideoInfoTag()->m_iSeason < 0 && field == "season")
151       {
152         result[field] = (int)item->GetProperty("totalseasons").asInteger();
153         return true;
154       }
155       if (field == "watchedepisodes")
156       {
157         result[field] = (int)item->GetProperty("watchedepisodes").asInteger();
158         return true;
159       }
160     }
161     
162     if (field == "lastmodified" && item->m_dateTime.IsValid())
163     {
164       result[field] = item->m_dateTime.GetAsLocalizedDateTime();
165       return true;
166     }
167
168     if (item->HasProperty(field))
169     {
170       result[field] = item->GetProperty(field);
171       return true;
172     }
173   }
174
175   return false;
176 }
177
178 void CFileItemHandler::FillDetails(const ISerializable *info, const CFileItemPtr &item, std::set<std::string> &fields, CVariant &result, CThumbLoader *thumbLoader /* = NULL */)
179 {
180   if (info == NULL || fields.size() == 0)
181     return;
182
183   CVariant serialization;
184   info->Serialize(serialization);
185
186   bool fetchedArt = false;
187
188   std::set<std::string> originalFields = fields;
189
190   for (std::set<std::string>::const_iterator fieldIt = originalFields.begin(); fieldIt != originalFields.end(); fieldIt++)
191   {
192     if (GetField(*fieldIt, serialization, item, result, fetchedArt, thumbLoader) && result.isMember(*fieldIt) && !result[*fieldIt].empty())
193       fields.erase(*fieldIt);
194   }
195 }
196
197 void CFileItemHandler::HandleFileItemList(const char *ID, bool allowFile, const char *resultname, CFileItemList &items, const CVariant &parameterObject, CVariant &result, bool sortLimit /* = true */)
198 {
199   HandleFileItemList(ID, allowFile, resultname, items, parameterObject, result, items.Size(), sortLimit);
200 }
201
202 void CFileItemHandler::HandleFileItemList(const char *ID, bool allowFile, const char *resultname, CFileItemList &items, const CVariant &parameterObject, CVariant &result, int size, bool sortLimit /* = true */)
203 {
204   int start, end;
205   HandleLimits(parameterObject, result, size, start, end);
206
207   if (sortLimit)
208     Sort(items, parameterObject);
209   else
210   {
211     start = 0;
212     end = items.Size();
213   }
214
215   CThumbLoader *thumbLoader = NULL;
216   if (end - start > 0)
217   {
218     if (items.Get(start)->HasVideoInfoTag())
219       thumbLoader = new CVideoThumbLoader();
220     else if (items.Get(start)->HasMusicInfoTag())
221       thumbLoader = new CMusicThumbLoader();
222
223     if (thumbLoader != NULL)
224       thumbLoader->Initialize();
225   }
226
227   std::set<std::string> fields;
228   if (parameterObject.isMember("properties") && parameterObject["properties"].isArray())
229   {
230     for (CVariant::const_iterator_array field = parameterObject["properties"].begin_array(); field != parameterObject["properties"].end_array(); field++)
231       fields.insert(field->asString());
232   }
233
234   for (int i = start; i < end; i++)
235   {
236     CFileItemPtr item = items.Get(i);
237     HandleFileItem(ID, allowFile, resultname, item, parameterObject, fields, result, true, thumbLoader);
238   }
239
240   delete thumbLoader;
241 }
242
243 void CFileItemHandler::HandleFileItem(const char *ID, bool allowFile, const char *resultname, CFileItemPtr item, const CVariant &parameterObject, const CVariant &validFields, CVariant &result, bool append /* = true */, CThumbLoader *thumbLoader /* = NULL */)
244 {
245   std::set<std::string> fields;
246   if (parameterObject.isMember("properties") && parameterObject["properties"].isArray())
247   {
248     for (CVariant::const_iterator_array field = parameterObject["properties"].begin_array(); field != parameterObject["properties"].end_array(); field++)
249       fields.insert(field->asString());
250   }
251
252   HandleFileItem(ID, allowFile, resultname, item, parameterObject, fields, result, append, thumbLoader);
253 }
254
255 void CFileItemHandler::HandleFileItem(const char *ID, bool allowFile, const char *resultname, CFileItemPtr item, const CVariant &parameterObject, const std::set<std::string> &validFields, CVariant &result, bool append /* = true */, CThumbLoader *thumbLoader /* = NULL */)
256 {
257   CVariant object;
258   std::set<std::string> fields(validFields.begin(), validFields.end());
259
260   if (item.get())
261   {
262     std::set<std::string>::const_iterator fileField = fields.find("file");
263     if (fileField != fields.end())
264     {
265       if (allowFile)
266       {
267         if (item->HasVideoInfoTag() && !item->GetVideoInfoTag()->GetPath().IsEmpty())
268             object["file"] = item->GetVideoInfoTag()->GetPath().c_str();
269         if (item->HasMusicInfoTag() && !item->GetMusicInfoTag()->GetURL().IsEmpty())
270           object["file"] = item->GetMusicInfoTag()->GetURL().c_str();
271
272         if (!object.isMember("file"))
273           object["file"] = item->GetPath().c_str();
274       }
275       fields.erase(fileField);
276     }
277
278     if (ID)
279     {
280       if (item->HasPVRChannelInfoTag() && item->GetPVRChannelInfoTag()->ChannelID() > 0)
281          object[ID] = item->GetPVRChannelInfoTag()->ChannelID();
282       else if (item->HasMusicInfoTag() && item->GetMusicInfoTag()->GetDatabaseId() > 0)
283         object[ID] = (int)item->GetMusicInfoTag()->GetDatabaseId();
284       else if (item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_iDbId > 0)
285         object[ID] = item->GetVideoInfoTag()->m_iDbId;
286
287       if (stricmp(ID, "id") == 0)
288       {
289         if (item->HasPVRChannelInfoTag())
290           object["type"] = "channel";
291         else if (item->HasMusicInfoTag() && !item->GetMusicInfoTag()->GetType().empty())
292         {
293           std::string type = item->GetMusicInfoTag()->GetType();
294           if (type == "album" || type == "song")
295             object["type"] = type;
296         }
297         else if (item->HasVideoInfoTag() && !item->GetVideoInfoTag()->m_type.empty())
298         {
299           std::string type = item->GetVideoInfoTag()->m_type;
300           if (type == "movie" || type == "tvshow" || type == "episode" || type == "musicvideo")
301             object["type"] = type;
302         }
303         else if (item->HasPictureInfoTag())
304           object["type"] = "picture";
305
306         if (!object.isMember("type"))
307           object["type"] = "unknown";
308
309         if (item->m_bIsFolder)
310           object["filetype"] = "directory";
311         else 
312           object["filetype"] = "file";
313       }
314     }
315
316     bool deleteThumbloader = false;
317     if (thumbLoader == NULL)
318     {
319       if (item->HasVideoInfoTag())
320         thumbLoader = new CVideoThumbLoader();
321       else if (item->HasMusicInfoTag())
322         thumbLoader = new CMusicThumbLoader();
323
324       if (thumbLoader != NULL)
325       {
326         deleteThumbloader = true;
327         thumbLoader->Initialize();
328       }
329     }
330
331     if (item->HasPVRChannelInfoTag())
332       FillDetails(item->GetPVRChannelInfoTag(), item, fields, object, thumbLoader);
333     if (item->HasVideoInfoTag())
334       FillDetails(item->GetVideoInfoTag(), item, fields, object, thumbLoader);
335     if (item->HasMusicInfoTag())
336       FillDetails(item->GetMusicInfoTag(), item, fields, object, thumbLoader);
337     if (item->HasPictureInfoTag())
338       FillDetails(item->GetPictureInfoTag(), item, fields, object, thumbLoader);
339     
340     FillDetails(item.get(), item, fields, object, thumbLoader);
341
342     if (deleteThumbloader)
343       delete thumbLoader;
344
345     object["label"] = item->GetLabel().c_str();
346   }
347   else
348     object = CVariant(CVariant::VariantTypeNull);
349
350   if (resultname)
351   {
352     if (append)
353       result[resultname].append(object);
354     else
355       result[resultname] = object;
356   }
357 }
358
359 bool CFileItemHandler::FillFileItemList(const CVariant &parameterObject, CFileItemList &list)
360 {
361   CAudioLibrary::FillFileItemList(parameterObject, list);
362   CVideoLibrary::FillFileItemList(parameterObject, list);
363   CFileOperations::FillFileItemList(parameterObject, list);
364
365   CStdString file = parameterObject["file"].asString();
366   if (!file.empty() && (URIUtils::IsURL(file) || (CFile::Exists(file) && !CDirectory::Exists(file))))
367   {
368     bool added = false;
369     for (int index = 0; index < list.Size(); index++)
370     {
371       if (list[index]->GetPath() == file)
372       {
373         added = true;
374         break;
375       }
376     }
377
378     if (!added)
379     {
380       CFileItemPtr item = CFileItemPtr(new CFileItem(file, false));
381       if (item->IsPicture())
382       {
383         CPictureInfoTag picture;
384         picture.Load(item->GetPath());
385         *item->GetPictureInfoTag() = picture;
386       }
387       if (item->GetLabel().IsEmpty())
388         item->SetLabel(CUtil::GetTitleFromPath(file, false));
389       list.Add(item);
390     }
391   }
392
393   return (list.Size() > 0);
394 }
395
396 void CFileItemHandler::Sort(CFileItemList &items, const CVariant &parameterObject)
397 {
398   SortDescription sorting;
399   if (!ParseSorting(parameterObject, sorting.sortBy, sorting.sortOrder, sorting.sortAttributes))
400     return;
401
402   items.Sort(sorting);
403 }