jsonrpc: fix "filetype" property being (unexpectedly) returned for Player.GetItem...
[vuplus_xbmc] / xbmc / interfaces / json-rpc / FileOperations.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 "FileOperations.h"
22 #include "VideoLibrary.h"
23 #include "AudioLibrary.h"
24 #include "MediaSource.h"
25 #include "filesystem/Directory.h"
26 #include "filesystem/File.h"
27 #include "FileItem.h"
28 #include "settings/AdvancedSettings.h"
29 #include "settings/MediaSourceSettings.h"
30 #include "Util.h"
31 #include "URL.h"
32 #include "utils/URIUtils.h"
33 #include "utils/FileUtils.h"
34
35 using namespace XFILE;
36 using namespace JSONRPC;
37
38 JSONRPC_STATUS CFileOperations::GetRootDirectory(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
39 {
40   CStdString media = parameterObject["media"].asString();
41   media = media.ToLower();
42
43   VECSOURCES *sources = CMediaSourceSettings::Get().GetSources(media);
44   if (sources)
45   {
46     CFileItemList items;
47     for (unsigned int i = 0; i < (unsigned int)sources->size(); i++)
48     {
49       // Do not show sources which are locked
50       if (sources->at(i).m_iHasLock == 2)
51         continue;
52
53       items.Add(CFileItemPtr(new CFileItem(sources->at(i))));
54     }
55
56     for (unsigned int i = 0; i < (unsigned int)items.Size(); i++)
57     {
58       if (items[i]->IsSmb())
59       {
60         CURL url(items[i]->GetPath());
61         items[i]->SetPath(url.GetWithoutUserDetails());
62       }
63     }
64
65     CVariant param = parameterObject;
66     param["properties"] = CVariant(CVariant::VariantTypeArray);
67     param["properties"].append("file");
68
69     HandleFileItemList(NULL, true, "sources", items, param, result);
70   }
71
72   return OK;
73 }
74
75 JSONRPC_STATUS CFileOperations::GetDirectory(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
76 {
77   CStdString media = parameterObject["media"].asString();
78   media = media.ToLower();
79
80   CFileItemList items;
81   CStdString strPath = parameterObject["directory"].asString();
82
83   if (!CFileUtils::RemoteAccessAllowed(strPath))
84     return InvalidParams;
85
86   CStdStringArray regexps;
87   CStdString extensions = "";
88   if (media.Equals("video"))
89   {
90     regexps = g_advancedSettings.m_videoExcludeFromListingRegExps;
91     extensions = g_advancedSettings.m_videoExtensions;
92   }
93   else if (media.Equals("music"))
94   {
95     regexps = g_advancedSettings.m_audioExcludeFromListingRegExps;
96     extensions = g_advancedSettings.m_musicExtensions;
97   }
98   else if (media.Equals("pictures"))
99   {
100     regexps = g_advancedSettings.m_pictureExcludeFromListingRegExps;
101     extensions = g_advancedSettings.m_pictureExtensions;
102   }
103
104   if (CDirectory::GetDirectory(strPath, items, extensions))
105   {
106     CFileItemList filteredFiles;
107     for (unsigned int i = 0; i < (unsigned int)items.Size(); i++)
108     {
109       if (CUtil::ExcludeFileOrFolder(items[i]->GetPath(), regexps))
110         continue;
111
112       if (items[i]->IsSmb())
113       {
114         CURL url(items[i]->GetPath());
115         items[i]->SetPath(url.GetWithoutUserDetails());
116       }
117
118       if ((media == "video" && items[i]->HasVideoInfoTag()) ||
119           (media == "music" && items[i]->HasMusicInfoTag()) ||
120           (media == "picture" && items[i]->HasPictureInfoTag()) ||
121            media == "files" ||
122            URIUtils::IsUPnP(items.GetPath()))
123           filteredFiles.Add(items[i]);
124       else
125       {
126         CFileItemPtr fileItem(new CFileItem());
127         if (FillFileItem(items[i], fileItem, media, parameterObject))
128             filteredFiles.Add(fileItem);
129         else
130             filteredFiles.Add(items[i]);
131       }
132     }
133
134     // Check if the "properties" list exists
135     // and make sure it contains the "file"
136     // field
137     CVariant param = parameterObject;
138     if (!param.isMember("properties"))
139       param["properties"] = CVariant(CVariant::VariantTypeArray);
140
141     bool hasFileField = false;
142     for (CVariant::const_iterator_array itr = param["properties"].begin_array(); itr != param["properties"].end_array(); itr++)
143     {
144       if (itr->asString().compare("file") == 0)
145       {
146         hasFileField = true;
147         break;
148       }
149     }
150
151     if (!hasFileField)
152       param["properties"].append("file");
153
154     HandleFileItemList("id", true, "files", filteredFiles, param, result);
155     for (CVariant::iterator_array item = result["files"].begin_array(); item != result["files"].end_array(); ++item)
156     {
157       if (!item->isMember("file"))
158         continue;
159
160       CFileItemPtr pItem = filteredFiles.Get((*item)["file"].asString());
161       if (pItem == NULL)
162         continue;
163
164       if (pItem->m_bIsFolder)
165         (*item)["filetype"] = "directory";
166       else
167         (*item)["filetype"] = "file";
168     }
169
170     return OK;
171   }
172
173   return InvalidParams;
174 }
175
176 JSONRPC_STATUS CFileOperations::GetFileDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
177 {
178   CStdString file = parameterObject["file"].asString();
179   if (!CFile::Exists(file))
180     return InvalidParams;
181
182   if (!CFileUtils::RemoteAccessAllowed(file))
183     return InvalidParams;
184
185   CStdString path;
186   URIUtils::GetDirectory(file, path);
187
188   CFileItemList items;
189   if (path.empty() || !CDirectory::GetDirectory(path, items) || !items.Contains(file))
190     return InvalidParams;
191
192   CFileItemPtr item = items.Get(file);
193   if (!URIUtils::IsUPnP(file))
194     FillFileItem(item, item, parameterObject["media"].asString(), parameterObject);
195
196   // Check if the "properties" list exists
197   // and make sure it contains the "file"
198   // field
199   CVariant param = parameterObject;
200   if (!param.isMember("properties"))
201     param["properties"] = CVariant(CVariant::VariantTypeArray);
202
203   bool hasFileField = false;
204   for (CVariant::const_iterator_array itr = param["properties"].begin_array(); itr != param["properties"].end_array(); itr++)
205   {
206     if (itr->asString().compare("file") == 0)
207     {
208       hasFileField = true;
209       break;
210     }
211   }
212
213   if (!hasFileField)
214     param["properties"].append("file");
215
216   HandleFileItem("id", true, "filedetails", item, parameterObject, param["properties"], result, false);
217   return OK;
218 }
219
220 JSONRPC_STATUS CFileOperations::PrepareDownload(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
221 {
222   std::string protocol;
223   if (transport->PrepareDownload(parameterObject["path"].asString().c_str(), result["details"], protocol))
224   {
225     result["protocol"] = protocol;
226
227     if ((transport->GetCapabilities() & FileDownloadDirect) == FileDownloadDirect)
228       result["mode"] = "direct";
229     else
230       result["mode"] = "redirect";
231
232     return OK;
233   }
234   
235   return InvalidParams;
236 }
237
238 JSONRPC_STATUS CFileOperations::Download(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
239 {
240   return transport->Download(parameterObject["path"].asString().c_str(), result) ? OK : InvalidParams;
241 }
242
243 bool CFileOperations::FillFileItem(const CFileItemPtr &originalItem, CFileItemPtr &item, CStdString media /* = "" */, const CVariant &parameterObject /* = CVariant(CVariant::VariantTypeArray) */)
244 {
245   if (originalItem.get() == NULL)
246     return false;
247
248   // copy all the available details
249   *item = *originalItem;
250
251   bool status = false;
252   CStdString strFilename = originalItem->GetPath();
253   if (!strFilename.empty() && (CDirectory::Exists(strFilename) || CFile::Exists(strFilename)))
254   {
255     if (media.Equals("video"))
256       status = CVideoLibrary::FillFileItem(strFilename, item, parameterObject);
257     else if (media.Equals("music"))
258       status = CAudioLibrary::FillFileItem(strFilename, item, parameterObject);
259
260     if (status && item->GetLabel().empty())
261     {
262       CStdString label = originalItem->GetLabel();
263       if (label.empty())
264       {
265         bool isDir = CDirectory::Exists(strFilename);
266         label = CUtil::GetTitleFromPath(strFilename, isDir);
267         if (label.empty())
268           label = URIUtils::GetFileName(strFilename);
269       }
270
271       item->SetLabel(label);
272     }
273     else if (!status)
274     {
275       if (originalItem->GetLabel().empty())
276       {
277         bool isDir = CDirectory::Exists(strFilename);
278         CStdString label = CUtil::GetTitleFromPath(strFilename, isDir);
279         if (label.empty())
280           return false;
281
282         item->SetLabel(label);
283         item->SetPath(strFilename);
284         item->m_bIsFolder = isDir;
285       }
286       else
287         *item = *originalItem;
288
289       status = true;
290     }
291   }
292
293   return status;
294 }
295
296 bool CFileOperations::FillFileItemList(const CVariant &parameterObject, CFileItemList &list)
297 {
298   if (parameterObject.isMember("directory"))
299   {
300     CStdString media =  parameterObject["media"].asString();
301     media = media.ToLower();
302
303     CStdString strPath = parameterObject["directory"].asString();
304     if (!strPath.empty())
305     {
306       CFileItemList items;
307       CStdString extensions = "";
308       CStdStringArray regexps;
309
310       if (media.Equals("video"))
311       {
312         regexps = g_advancedSettings.m_videoExcludeFromListingRegExps;
313         extensions = g_advancedSettings.m_videoExtensions;
314       }
315       else if (media.Equals("music"))
316       {
317         regexps = g_advancedSettings.m_audioExcludeFromListingRegExps;
318         extensions = g_advancedSettings.m_musicExtensions;
319       }
320       else if (media.Equals("pictures"))
321       {
322         regexps = g_advancedSettings.m_pictureExcludeFromListingRegExps;
323         extensions = g_advancedSettings.m_pictureExtensions;
324       }
325
326       CDirectory directory;
327       if (directory.GetDirectory(strPath, items, extensions))
328       {
329         items.Sort(SORT_METHOD_FILE, SortOrderAscending);
330         CFileItemList filteredDirectories;
331         for (unsigned int i = 0; i < (unsigned int)items.Size(); i++)
332         {
333           if (CUtil::ExcludeFileOrFolder(items[i]->GetPath(), regexps))
334             continue;
335
336           if (items[i]->m_bIsFolder)
337             filteredDirectories.Add(items[i]);
338           else if ((media == "video" && items[i]->HasVideoInfoTag()) ||
339                    (media == "music" && items[i]->HasMusicInfoTag()))
340             list.Add(items[i]);
341           else
342           {
343             CFileItemPtr fileItem(new CFileItem());
344             if (FillFileItem(items[i], fileItem, media, parameterObject))
345               list.Add(fileItem);
346             else if (media == "files")
347               list.Add(items[i]);
348           }
349         }
350
351         if (parameterObject.isMember("recursive") && parameterObject["recursive"].isBoolean())
352         {
353           for (int i = 0; i < filteredDirectories.Size(); i++)
354           {
355             CVariant val = parameterObject;
356             val["directory"] = filteredDirectories[i]->GetPath();
357             FillFileItemList(val, list);
358           }
359         }
360
361         return true;
362       }
363     }
364   }
365
366   return false;
367 }