summaryrefslogtreecommitdiffstats
path: root/xbmc/interfaces/json-rpc/FileOperations.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/interfaces/json-rpc/FileOperations.cpp')
-rw-r--r--xbmc/interfaces/json-rpc/FileOperations.cpp418
1 files changed, 418 insertions, 0 deletions
diff --git a/xbmc/interfaces/json-rpc/FileOperations.cpp b/xbmc/interfaces/json-rpc/FileOperations.cpp
new file mode 100644
index 0000000..6329a78
--- /dev/null
+++ b/xbmc/interfaces/json-rpc/FileOperations.cpp
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2005-2020 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "FileOperations.h"
+
+#include "AudioLibrary.h"
+#include "FileItem.h"
+#include "MediaSource.h"
+#include "ServiceBroker.h"
+#include "URL.h"
+#include "Util.h"
+#include "VideoLibrary.h"
+#include "filesystem/Directory.h"
+#include "media/MediaLockState.h"
+#include "settings/AdvancedSettings.h"
+#include "settings/MediaSourceSettings.h"
+#include "settings/SettingsComponent.h"
+#include "utils/FileExtensionProvider.h"
+#include "utils/FileUtils.h"
+#include "utils/URIUtils.h"
+#include "utils/Variant.h"
+#include "video/VideoDatabase.h"
+
+using namespace XFILE;
+using namespace JSONRPC;
+
+JSONRPC_STATUS CFileOperations::GetRootDirectory(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
+{
+ std::string media = parameterObject["media"].asString();
+ StringUtils::ToLower(media);
+
+ VECSOURCES *sources = CMediaSourceSettings::GetInstance().GetSources(media);
+ if (sources)
+ {
+ CFileItemList items;
+ for (unsigned int i = 0; i < (unsigned int)sources->size(); i++)
+ {
+ // Do not show sources which are locked
+ if (sources->at(i).m_iHasLock == LOCK_STATE_LOCKED)
+ continue;
+
+ items.Add(CFileItemPtr(new CFileItem(sources->at(i))));
+ }
+
+ for (unsigned int i = 0; i < (unsigned int)items.Size(); i++)
+ {
+ if (items[i]->IsSmb())
+ {
+ CURL url(items[i]->GetPath());
+ items[i]->SetPath(url.GetWithoutUserDetails());
+ }
+ }
+
+ CVariant param = parameterObject;
+ param["properties"] = CVariant(CVariant::VariantTypeArray);
+ param["properties"].append("file");
+
+ HandleFileItemList(NULL, true, "sources", items, param, result);
+ }
+
+ return OK;
+}
+
+JSONRPC_STATUS CFileOperations::GetDirectory(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
+{
+ std::string media = parameterObject["media"].asString();
+ StringUtils::ToLower(media);
+
+ CFileItemList items;
+ std::string strPath = parameterObject["directory"].asString();
+
+ if (!CFileUtils::RemoteAccessAllowed(strPath))
+ return InvalidParams;
+
+ std::vector<std::string> regexps;
+ std::string extensions;
+ if (media == "video")
+ {
+ regexps = CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoExcludeFromListingRegExps;
+ extensions = CServiceBroker::GetFileExtensionProvider().GetVideoExtensions();
+ items.SetProperty("set_videodb_details",
+ CVideoLibrary::GetDetailsFromJsonParameters(parameterObject));
+ }
+ else if (media == "music")
+ {
+ regexps = CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_audioExcludeFromListingRegExps;
+ extensions = CServiceBroker::GetFileExtensionProvider().GetMusicExtensions();
+ }
+ else if (media == "pictures")
+ {
+ regexps = CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_pictureExcludeFromListingRegExps;
+ extensions = CServiceBroker::GetFileExtensionProvider().GetPictureExtensions();
+ }
+
+ if (CDirectory::GetDirectory(strPath, items, extensions, DIR_FLAG_DEFAULTS))
+ {
+ // we might need to get additional information for music items
+ if (media == "music")
+ {
+ JSONRPC_STATUS status = CAudioLibrary::GetAdditionalDetails(parameterObject, items);
+ if (status != OK)
+ return status;
+ }
+
+ CFileItemList filteredFiles;
+ for (unsigned int i = 0; i < (unsigned int)items.Size(); i++)
+ {
+ if (CUtil::ExcludeFileOrFolder(items[i]->GetPath(), regexps))
+ continue;
+
+ if (items[i]->IsSmb())
+ {
+ CURL url(items[i]->GetPath());
+ items[i]->SetPath(url.GetWithoutUserDetails());
+ }
+
+ if ((media == "video" && items[i]->HasVideoInfoTag()) ||
+ (media == "music" && items[i]->HasMusicInfoTag()) ||
+ (media == "picture" && items[i]->HasPictureInfoTag()) ||
+ media == "files" ||
+ URIUtils::IsUPnP(items.GetPath()))
+ filteredFiles.Add(items[i]);
+ else
+ {
+ CFileItemPtr fileItem(new CFileItem());
+ if (FillFileItem(items[i], fileItem, media, parameterObject))
+ filteredFiles.Add(fileItem);
+ else
+ filteredFiles.Add(items[i]);
+ }
+ }
+
+ // Check if the "properties" list exists
+ // and make sure it contains the "file" and "filetype"
+ // fields
+ CVariant param = parameterObject;
+ if (!param.isMember("properties"))
+ param["properties"] = CVariant(CVariant::VariantTypeArray);
+
+ bool hasFileField = false;
+ for (CVariant::const_iterator_array itr = param["properties"].begin_array();
+ itr != param["properties"].end_array(); ++itr)
+ {
+ if (itr->asString().compare("file") == 0)
+ {
+ hasFileField = true;
+ break;
+ }
+ }
+
+ if (!hasFileField)
+ param["properties"].append("file");
+ param["properties"].append("filetype");
+
+ HandleFileItemList("id", true, "files", filteredFiles, param, result);
+
+ return OK;
+ }
+
+ return InvalidParams;
+}
+
+JSONRPC_STATUS CFileOperations::GetFileDetails(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
+{
+ std::string file = parameterObject["file"].asString();
+ if (!CFileUtils::Exists(file))
+ return InvalidParams;
+
+ if (!CFileUtils::RemoteAccessAllowed(file))
+ return InvalidParams;
+
+ std::string path = URIUtils::GetDirectory(file);
+
+ CFileItemList items;
+ if (path.empty())
+ return InvalidParams;
+
+ CFileItemPtr item;
+ if (CDirectory::GetDirectory(path, items, "", DIR_FLAG_DEFAULTS) && items.Contains(file))
+ item = items.Get(file);
+ else
+ item = CFileItemPtr(new CFileItem(file, false));
+
+ if (!URIUtils::IsUPnP(file))
+ FillFileItem(item, item, parameterObject["media"].asString(), parameterObject);
+
+ // Check if the "properties" list exists
+ // and make sure it contains the "file"
+ // field
+ CVariant param = parameterObject;
+ if (!param.isMember("properties"))
+ param["properties"] = CVariant(CVariant::VariantTypeArray);
+
+ bool hasFileField = false;
+ for (CVariant::const_iterator_array itr = param["properties"].begin_array();
+ itr != param["properties"].end_array(); ++itr)
+ {
+ if (itr->asString().compare("file") == 0)
+ {
+ hasFileField = true;
+ break;
+ }
+ }
+
+ if (!hasFileField)
+ param["properties"].append("file");
+ param["properties"].append("filetype");
+
+ HandleFileItem("id", true, "filedetails", item, parameterObject, param["properties"], result, false);
+ return OK;
+}
+
+JSONRPC_STATUS CFileOperations::SetFileDetails(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
+{
+ std::string media = parameterObject["media"].asString();
+ StringUtils::ToLower(media);
+
+ if (media.compare("video") != 0)
+ return InvalidParams;
+
+ std::string file = parameterObject["file"].asString();
+ if (!CFileUtils::Exists(file))
+ return InvalidParams;
+
+ if (!CFileUtils::RemoteAccessAllowed(file))
+ return InvalidParams;
+
+ CVideoDatabase videodatabase;
+ if (!videodatabase.Open())
+ return InternalError;
+
+ int fileId = videodatabase.AddFile(file);
+
+ CVideoInfoTag infos;
+ if (!videodatabase.GetFileInfo("", infos, fileId))
+ return InvalidParams;
+
+ CDateTime lastPlayed = infos.m_lastPlayed;
+ int playcount = infos.GetPlayCount();
+ if (!parameterObject["lastplayed"].isNull())
+ {
+ lastPlayed.Reset();
+ SetFromDBDateTime(parameterObject["lastplayed"], lastPlayed);
+ playcount = lastPlayed.IsValid() ? std::max(1, playcount) : 0;
+ }
+ if (!parameterObject["playcount"].isNull())
+ playcount = parameterObject["playcount"].asInteger();
+ if (playcount != infos.GetPlayCount() || lastPlayed != infos.m_lastPlayed)
+ videodatabase.SetPlayCount(CFileItem(infos), playcount, lastPlayed);
+
+ CVideoLibrary::UpdateResumePoint(parameterObject, infos, videodatabase);
+
+ videodatabase.GetFileInfo("", infos, fileId);
+ CJSONRPCUtils::NotifyItemUpdated(infos, std::map<std::string, std::string>{});
+ return ACK;
+}
+
+JSONRPC_STATUS CFileOperations::PrepareDownload(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
+{
+ std::string protocol;
+ if (transport->PrepareDownload(parameterObject["path"].asString().c_str(), result["details"], protocol))
+ {
+ result["protocol"] = protocol;
+
+ if ((transport->GetCapabilities() & FileDownloadDirect) == FileDownloadDirect)
+ result["mode"] = "direct";
+ else
+ result["mode"] = "redirect";
+
+ return OK;
+ }
+
+ return InvalidParams;
+}
+
+JSONRPC_STATUS CFileOperations::Download(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
+{
+ return transport->Download(parameterObject["path"].asString().c_str(), result) ? OK : InvalidParams;
+}
+
+bool CFileOperations::FillFileItem(
+ const std::shared_ptr<CFileItem>& originalItem,
+ std::shared_ptr<CFileItem>& item,
+ const std::string& media /* = "" */,
+ const CVariant& parameterObject /* = CVariant(CVariant::VariantTypeArray) */)
+{
+ if (originalItem.get() == NULL)
+ return false;
+
+ // copy all the available details
+ *item = *originalItem;
+
+ bool status = false;
+ std::string strFilename = originalItem->GetPath();
+ if (!strFilename.empty() && (CDirectory::Exists(strFilename) || CFileUtils::Exists(strFilename)))
+ {
+ if (media == "video")
+ status = CVideoLibrary::FillFileItem(strFilename, item, parameterObject);
+ else if (media == "music")
+ status = CAudioLibrary::FillFileItem(strFilename, item, parameterObject);
+
+ if (status && item->GetLabel().empty())
+ {
+ std::string label = originalItem->GetLabel();
+ if (label.empty())
+ {
+ bool isDir = CDirectory::Exists(strFilename);
+ label = CUtil::GetTitleFromPath(strFilename, isDir);
+ if (label.empty())
+ label = URIUtils::GetFileName(strFilename);
+ }
+
+ item->SetLabel(label);
+ }
+ else if (!status)
+ {
+ if (originalItem->GetLabel().empty())
+ {
+ bool isDir = CDirectory::Exists(strFilename);
+ std::string label = CUtil::GetTitleFromPath(strFilename, isDir);
+ if (label.empty())
+ return false;
+
+ item->SetLabel(label);
+ item->SetPath(strFilename);
+ item->m_bIsFolder = isDir;
+ }
+ else
+ *item = *originalItem;
+
+ status = true;
+ }
+ }
+
+ return status;
+}
+
+bool CFileOperations::FillFileItemList(const CVariant &parameterObject, CFileItemList &list)
+{
+ if (parameterObject.isMember("directory"))
+ {
+ std::string media = parameterObject["media"].asString();
+ StringUtils::ToLower(media);
+
+ std::string strPath = parameterObject["directory"].asString();
+ if (!strPath.empty())
+ {
+ CFileItemList items;
+ std::string extensions;
+ std::vector<std::string> regexps;
+
+ if (media == "video")
+ {
+ regexps = CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoExcludeFromListingRegExps;
+ extensions = CServiceBroker::GetFileExtensionProvider().GetVideoExtensions();
+ }
+ else if (media == "music")
+ {
+ regexps = CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_audioExcludeFromListingRegExps;
+ extensions = CServiceBroker::GetFileExtensionProvider().GetMusicExtensions();
+ }
+ else if (media == "pictures")
+ {
+ regexps = CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_pictureExcludeFromListingRegExps;
+ extensions = CServiceBroker::GetFileExtensionProvider().GetPictureExtensions();
+ }
+
+ CDirectory directory;
+ if (directory.GetDirectory(strPath, items, extensions, DIR_FLAG_DEFAULTS))
+ {
+ // Sort folders and files by filename to avoid reverse item order bug on some platforms,
+ // but leave items from a playlist, smartplaylist or upnp container in order supplied
+ if (!items.IsPlayList() && !items.IsSmartPlayList() && !URIUtils::IsUPnP(items.GetPath()))
+ items.Sort(SortByFile, SortOrderAscending);
+
+ CFileItemList filteredDirectories;
+ for (unsigned int i = 0; i < (unsigned int)items.Size(); i++)
+ {
+ if (CUtil::ExcludeFileOrFolder(items[i]->GetPath(), regexps))
+ continue;
+
+ if (items[i]->m_bIsFolder)
+ filteredDirectories.Add(items[i]);
+ else if ((media == "video" && items[i]->HasVideoInfoTag()) ||
+ (media == "music" && items[i]->HasMusicInfoTag()))
+ list.Add(items[i]);
+ else
+ {
+ CFileItemPtr fileItem(new CFileItem());
+ if (FillFileItem(items[i], fileItem, media, parameterObject))
+ list.Add(fileItem);
+ else if (media == "files")
+ list.Add(items[i]);
+ }
+ }
+
+ if (parameterObject.isMember("recursive") && parameterObject["recursive"].isBoolean())
+ {
+ for (int i = 0; i < filteredDirectories.Size(); i++)
+ {
+ CVariant val = parameterObject;
+ val["directory"] = filteredDirectories[i]->GetPath();
+ FillFileItemList(val, list);
+ }
+ }
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+}