[textures] move image wrapping functions into a separate class
[vuplus_xbmc] / xbmc / interfaces / json-rpc / FileItemHandler.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include <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 "TextureDatabase.h"
39 #include "video/VideoThumbLoader.h"
40 #include "music/MusicThumbLoader.h"
41 #include "Util.h"
42 #include "pvr/channels/PVRChannel.h"
43 #include "epg/Epg.h"
44 #include "epg/EpgContainer.h"
45
46 using namespace MUSIC_INFO;
47 using namespace JSONRPC;
48 using namespace XFILE;
49
50 bool CFileItemHandler::GetField(const std::string &field, const CVariant &info, const CFileItemPtr &item, CVariant &result, bool &fetchedArt, CThumbLoader *thumbLoader /* = NULL */)
51 {
52   if (result.isMember(field) && !result[field].empty())
53     return true;
54
55   // overwrite serialized values
56   if (item)
57   {
58     if (field == "mimetype" && item->GetMimeType().empty())
59     {
60       item->FillInMimeType(false);
61       result[field] = item->GetMimeType();
62       return true;
63     }
64   }
65
66   // check for serialized values
67   if (info.isMember(field) && !info[field].isNull())
68   {
69     result[field] = info[field];
70     return true;
71   }
72
73   // check if the field requires special handling
74   if (item)
75   {
76     if (item->IsAlbum())
77     {
78       if (field == "albumlabel")
79       {
80         result[field] = item->GetProperty("album_label");
81         return true;
82       }
83       if (item->HasProperty("album_" + field + "_array"))
84       {
85         result[field] = item->GetProperty("album_" + field + "_array");
86         return true;
87       }
88       if (item->HasProperty("album_" + field))
89       {
90         result[field] = item->GetProperty("album_" + field);
91         return true;
92       }
93     }
94     
95     if (item->HasProperty("artist_" + field + "_array"))
96     {
97       result[field] = item->GetProperty("artist_" + field + "_array");
98       return true;
99     }
100     if (item->HasProperty("artist_" + field))
101     {
102       result[field] = item->GetProperty("artist_" + field);
103       return true;
104     }
105
106     if (field == "art")
107     {
108       if (thumbLoader != NULL && item->GetArt().size() <= 0 && !fetchedArt &&
109         ((item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_iDbId > -1) || (item->HasMusicInfoTag() && item->GetMusicInfoTag()->GetDatabaseId() > -1)))
110       {
111         thumbLoader->FillLibraryArt(*item);
112         fetchedArt = true;
113       }
114
115       CGUIListItem::ArtMap artMap = item->GetArt();
116       CVariant artObj(CVariant::VariantTypeObject);
117       for (CGUIListItem::ArtMap::const_iterator artIt = artMap.begin(); artIt != artMap.end(); ++artIt)
118       {
119         if (!artIt->second.empty())
120           artObj[artIt->first] = CTextureUtils::GetWrappedImageURL(artIt->second);
121       }
122
123       result["art"] = artObj;
124       return true;
125     }
126     
127     if (field == "thumbnail")
128     {
129       if (thumbLoader != NULL && !item->HasArt("thumb") && !fetchedArt &&
130         ((item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_iDbId > -1) || (item->HasMusicInfoTag() && item->GetMusicInfoTag()->GetDatabaseId() > -1)))
131       {
132         thumbLoader->FillLibraryArt(*item);
133         fetchedArt = true;
134       }
135       else if (item->HasPictureInfoTag() && !item->HasArt("thumb"))
136         item->SetArt("thumb", CTextureUtils::GetWrappedThumbURL(item->GetPath()));
137       
138       if (item->HasArt("thumb"))
139         result["thumbnail"] = CTextureUtils::GetWrappedImageURL(item->GetArt("thumb"));
140       else
141         result["thumbnail"] = "";
142       
143       return true;
144     }
145     
146     if (field == "fanart")
147     {
148       if (thumbLoader != NULL && !item->HasArt("fanart") && !fetchedArt &&
149         ((item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_iDbId > -1) || (item->HasMusicInfoTag() && item->GetMusicInfoTag()->GetDatabaseId() > -1)))
150       {
151         thumbLoader->FillLibraryArt(*item);
152         fetchedArt = true;
153       }
154       
155       if (item->HasArt("fanart"))
156         result["fanart"] = CTextureUtils::GetWrappedImageURL(item->GetArt("fanart"));
157       else
158         result["fanart"] = "";
159       
160       return true;
161     }
162     
163     if (item->HasVideoInfoTag() && item->GetVideoContentType() == VIDEODB_CONTENT_TVSHOWS)
164     {
165       if (item->GetVideoInfoTag()->m_iSeason < 0 && field == "season")
166       {
167         result[field] = (int)item->GetProperty("totalseasons").asInteger();
168         return true;
169       }
170       if (field == "watchedepisodes")
171       {
172         result[field] = (int)item->GetProperty("watchedepisodes").asInteger();
173         return true;
174       }
175     }
176     
177     if (field == "lastmodified" && item->m_dateTime.IsValid())
178     {
179       result[field] = item->m_dateTime.GetAsLocalizedDateTime();
180       return true;
181     }
182
183     if (item->HasProperty(field))
184     {
185       result[field] = item->GetProperty(field);
186       return true;
187     }
188   }
189
190   return false;
191 }
192
193 void CFileItemHandler::FillDetails(const ISerializable *info, const CFileItemPtr &item, std::set<std::string> &fields, CVariant &result, CThumbLoader *thumbLoader /* = NULL */)
194 {
195   if (info == NULL || fields.size() == 0)
196     return;
197
198   CVariant serialization;
199   info->Serialize(serialization);
200
201   bool fetchedArt = false;
202
203   std::set<std::string> originalFields = fields;
204
205   for (std::set<std::string>::const_iterator fieldIt = originalFields.begin(); fieldIt != originalFields.end(); ++fieldIt)
206   {
207     if (GetField(*fieldIt, serialization, item, result, fetchedArt, thumbLoader) && result.isMember(*fieldIt) && !result[*fieldIt].empty())
208       fields.erase(*fieldIt);
209   }
210 }
211
212 void CFileItemHandler::HandleFileItemList(const char *ID, bool allowFile, const char *resultname, CFileItemList &items, const CVariant &parameterObject, CVariant &result, bool sortLimit /* = true */)
213 {
214   HandleFileItemList(ID, allowFile, resultname, items, parameterObject, result, items.Size(), sortLimit);
215 }
216
217 void CFileItemHandler::HandleFileItemList(const char *ID, bool allowFile, const char *resultname, CFileItemList &items, const CVariant &parameterObject, CVariant &result, int size, bool sortLimit /* = true */)
218 {
219   int start, end;
220   HandleLimits(parameterObject, result, size, start, end);
221
222   if (sortLimit)
223     Sort(items, parameterObject);
224   else
225   {
226     start = 0;
227     end = items.Size();
228   }
229
230   CThumbLoader *thumbLoader = NULL;
231   if (end - start > 0)
232   {
233     if (items.Get(start)->HasVideoInfoTag())
234       thumbLoader = new CVideoThumbLoader();
235     else if (items.Get(start)->HasMusicInfoTag())
236       thumbLoader = new CMusicThumbLoader();
237
238     if (thumbLoader != NULL)
239       thumbLoader->OnLoaderStart();
240   }
241
242   std::set<std::string> fields;
243   if (parameterObject.isMember("properties") && parameterObject["properties"].isArray())
244   {
245     for (CVariant::const_iterator_array field = parameterObject["properties"].begin_array(); field != parameterObject["properties"].end_array(); field++)
246       fields.insert(field->asString());
247   }
248
249   for (int i = start; i < end; i++)
250   {
251     CFileItemPtr item = items.Get(i);
252     HandleFileItem(ID, allowFile, resultname, item, parameterObject, fields, result, true, thumbLoader);
253   }
254
255   delete thumbLoader;
256 }
257
258 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 */)
259 {
260   std::set<std::string> fields;
261   if (parameterObject.isMember("properties") && parameterObject["properties"].isArray())
262   {
263     for (CVariant::const_iterator_array field = parameterObject["properties"].begin_array(); field != parameterObject["properties"].end_array(); field++)
264       fields.insert(field->asString());
265   }
266
267   HandleFileItem(ID, allowFile, resultname, item, parameterObject, fields, result, append, thumbLoader);
268 }
269
270 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 */)
271 {
272   CVariant object;
273   std::set<std::string> fields(validFields.begin(), validFields.end());
274
275   if (item.get())
276   {
277     std::set<std::string>::const_iterator fileField = fields.find("file");
278     if (fileField != fields.end())
279     {
280       if (allowFile)
281       {
282         if (item->HasVideoInfoTag() && !item->GetVideoInfoTag()->GetPath().IsEmpty())
283           object["file"] = item->GetVideoInfoTag()->GetPath().c_str();
284         if (item->HasMusicInfoTag() && !item->GetMusicInfoTag()->GetURL().IsEmpty())
285           object["file"] = item->GetMusicInfoTag()->GetURL().c_str();
286
287         if (!object.isMember("file"))
288           object["file"] = item->GetPath().c_str();
289       }
290       fields.erase(fileField);
291     }
292
293     if (ID)
294     {
295       if (item->HasPVRChannelInfoTag() && item->GetPVRChannelInfoTag()->ChannelID() > 0)
296          object[ID] = item->GetPVRChannelInfoTag()->ChannelID();
297       else if (item->HasEPGInfoTag() && item->GetEPGInfoTag()->UniqueBroadcastID() > 0)
298          object[ID] = item->GetEPGInfoTag()->UniqueBroadcastID();
299       else if (item->HasMusicInfoTag() && item->GetMusicInfoTag()->GetDatabaseId() > 0)
300         object[ID] = (int)item->GetMusicInfoTag()->GetDatabaseId();
301       else if (item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_iDbId > 0)
302         object[ID] = item->GetVideoInfoTag()->m_iDbId;
303
304       if (stricmp(ID, "id") == 0)
305       {
306         if (item->HasPVRChannelInfoTag())
307           object["type"] = "channel";
308         else if (item->HasMusicInfoTag())
309         {
310           std::string type = item->GetMusicInfoTag()->GetType();
311           if (type == "album" || type == "song" || type == "artist")
312             object["type"] = type;
313           else
314             object["type"] = "song";
315         }
316         else if (item->HasVideoInfoTag() && !item->GetVideoInfoTag()->m_type.empty())
317         {
318           std::string type = item->GetVideoInfoTag()->m_type;
319           if (type == "movie" || type == "tvshow" || type == "episode" || type == "musicvideo")
320             object["type"] = type;
321         }
322         else if (item->HasPictureInfoTag())
323           object["type"] = "picture";
324
325         if (!object.isMember("type"))
326           object["type"] = "unknown";
327
328         if (fields.find("filetype") != fields.end())
329         {
330           if (item->m_bIsFolder)
331             object["filetype"] = "directory";
332           else 
333             object["filetype"] = "file";
334         }
335       }
336     }
337
338     bool deleteThumbloader = false;
339     if (thumbLoader == NULL)
340     {
341       if (item->HasVideoInfoTag())
342         thumbLoader = new CVideoThumbLoader();
343       else if (item->HasMusicInfoTag())
344         thumbLoader = new CMusicThumbLoader();
345
346       if (thumbLoader != NULL)
347       {
348         deleteThumbloader = true;
349         thumbLoader->OnLoaderStart();
350       }
351     }
352
353     if (item->HasPVRChannelInfoTag())
354       FillDetails(item->GetPVRChannelInfoTag(), item, fields, object, thumbLoader);
355     if (item->HasEPGInfoTag())
356       FillDetails(item->GetEPGInfoTag(), item, fields, object, thumbLoader);
357     if (item->HasVideoInfoTag())
358       FillDetails(item->GetVideoInfoTag(), item, fields, object, thumbLoader);
359     if (item->HasMusicInfoTag())
360       FillDetails(item->GetMusicInfoTag(), item, fields, object, thumbLoader);
361     if (item->HasPictureInfoTag())
362       FillDetails(item->GetPictureInfoTag(), item, fields, object, thumbLoader);
363     
364     FillDetails(item.get(), item, fields, object, thumbLoader);
365
366     if (deleteThumbloader)
367       delete thumbLoader;
368
369     object["label"] = item->GetLabel().c_str();
370   }
371   else
372     object = CVariant(CVariant::VariantTypeNull);
373
374   if (resultname)
375   {
376     if (append)
377       result[resultname].append(object);
378     else
379       result[resultname] = object;
380   }
381 }
382
383 bool CFileItemHandler::FillFileItemList(const CVariant &parameterObject, CFileItemList &list)
384 {
385   CAudioLibrary::FillFileItemList(parameterObject, list);
386   CVideoLibrary::FillFileItemList(parameterObject, list);
387   CFileOperations::FillFileItemList(parameterObject, list);
388
389   CStdString file = parameterObject["file"].asString();
390   if (!file.empty() && (URIUtils::IsURL(file) || (CFile::Exists(file) && !CDirectory::Exists(file))))
391   {
392     bool added = false;
393     for (int index = 0; index < list.Size(); index++)
394     {
395       if (list[index]->GetPath() == file)
396       {
397         added = true;
398         break;
399       }
400     }
401
402     if (!added)
403     {
404       CFileItemPtr item = CFileItemPtr(new CFileItem(file, false));
405       if (item->IsPicture())
406       {
407         CPictureInfoTag picture;
408         picture.Load(item->GetPath());
409         *item->GetPictureInfoTag() = picture;
410       }
411       if (item->GetLabel().empty())
412       {
413         item->SetLabel(CUtil::GetTitleFromPath(file, false));
414         if (item->GetLabel().empty())
415           item->SetLabel(URIUtils::GetFileName(file));
416       }
417       list.Add(item);
418     }
419   }
420
421   return (list.Size() > 0);
422 }
423
424 void CFileItemHandler::Sort(CFileItemList &items, const CVariant &parameterObject)
425 {
426   SortDescription sorting;
427   if (!ParseSorting(parameterObject, sorting.sortBy, sorting.sortOrder, sorting.sortAttributes))
428     return;
429
430   items.Sort(sorting);
431 }