mirror of
https://github.com/Team-Resurgent/XBMC4Xbox.git
synced 2026-08-15 11:18:13 -07:00
If ever adding the XBMC4Xbox source to GitHub use "git add -f -A" or it wont add all the files.
686 lines
22 KiB
C++
686 lines
22 KiB
C++
/*
|
|
* Copyright (C) 2005-2013 Team XBMC
|
|
* http://xbmc.org
|
|
*
|
|
* This Program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This Program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with XBMC; see the file COPYING. If not, see
|
|
* <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
|
|
#include "system.h"
|
|
#include "utils/log.h"
|
|
#include "PluginDirectory.h"
|
|
#include "utils/URIUtils.h"
|
|
#ifdef HAS_PYTHON
|
|
#include "lib/libPython/XBPython.h"
|
|
#endif
|
|
#include "../utils/SingleLock.h"
|
|
#include "PluginSettings.h"
|
|
#include "GUIWindowManager.h"
|
|
#include "dialogs/GUIDialogProgress.h"
|
|
#include "FileSystem/File.h"
|
|
#include "settings/GUISettings.h"
|
|
#include "FileItem.h"
|
|
#include "LocalizeStrings.h"
|
|
|
|
using namespace XFILE;
|
|
using namespace std;
|
|
|
|
vector<CPluginDirectory *> CPluginDirectory::globalHandles;
|
|
CCriticalSection CPluginDirectory::m_handleLock;
|
|
|
|
CPluginDirectory::CPluginDirectory(void)
|
|
{
|
|
m_fetchComplete = CreateEvent(NULL, false, false, NULL);
|
|
m_listItems = new CFileItemList;
|
|
m_fileResult = new CFileItem;
|
|
}
|
|
|
|
CPluginDirectory::~CPluginDirectory(void)
|
|
{
|
|
CloseHandle(m_fetchComplete);
|
|
delete m_listItems;
|
|
delete m_fileResult;
|
|
}
|
|
|
|
int CPluginDirectory::getNewHandle(CPluginDirectory *cp)
|
|
{
|
|
CSingleLock lock(m_handleLock);
|
|
int handle = (int)globalHandles.size();
|
|
globalHandles.push_back(cp);
|
|
return handle;
|
|
}
|
|
|
|
void CPluginDirectory::removeHandle(int handle)
|
|
{
|
|
CSingleLock lock(m_handleLock);
|
|
if (handle >= 0 && handle < (int)globalHandles.size())
|
|
globalHandles.erase(globalHandles.begin() + handle);
|
|
}
|
|
|
|
bool CPluginDirectory::StartScript(const CStdString& strPath)
|
|
{
|
|
CURL url(strPath);
|
|
|
|
CStdString fileName;
|
|
|
|
// path is special://home/plugins/<path from here>
|
|
CStdString pathToScript = "special://home/plugins/";
|
|
URIUtils::AddFileToFolder(pathToScript, url.GetHostName(), pathToScript);
|
|
URIUtils::AddFileToFolder(pathToScript, url.GetFileName(), pathToScript);
|
|
URIUtils::AddFileToFolder(pathToScript, "default.py", pathToScript);
|
|
|
|
// base path
|
|
CStdString basePath = "plugin://";
|
|
URIUtils::AddFileToFolder(basePath, url.GetHostName(), basePath);
|
|
URIUtils::AddFileToFolder(basePath, url.GetFileName(), basePath);
|
|
|
|
// options
|
|
CStdString options = url.GetOptions();
|
|
URIUtils::RemoveSlashAtEnd(options); // This MAY kill some scripts (eg though with a URL ending with a slash), but
|
|
// is needed for all others, as XBMC adds slashes to "folders"
|
|
|
|
// Load the plugin settings
|
|
CLog::Log(LOGDEBUG, "%s - URL for plugin settings: %s", __FUNCTION__, url.GetFileName().c_str() );
|
|
g_currentPluginSettings.Load(url);
|
|
|
|
// Load language strings
|
|
LoadPluginStrings(url);
|
|
|
|
// reset our wait event, and grab a new handle
|
|
ResetEvent(m_fetchComplete);
|
|
int handle = getNewHandle(this);
|
|
|
|
// clear out our status variables
|
|
m_fileResult->Reset();
|
|
m_listItems->Clear();
|
|
m_listItems->SetPath(strPath);
|
|
m_cancelled = false;
|
|
m_success = false;
|
|
m_totalItems = 0;
|
|
|
|
// setup our parameters to send the script
|
|
CStdString strHandle;
|
|
strHandle.Format("%i", handle);
|
|
const char *plugin_argv[] = {basePath.c_str(), strHandle.c_str(), options.c_str(), NULL };
|
|
|
|
// run the script
|
|
CLog::Log(LOGDEBUG, "%s - calling plugin %s('%s','%s','%s')", __FUNCTION__, pathToScript.c_str(), plugin_argv[0], plugin_argv[1], plugin_argv[2]);
|
|
bool success = false;
|
|
#ifdef HAS_PYTHON
|
|
if (g_pythonParser.evalFile(pathToScript.c_str(), 3, (const char**)plugin_argv) >= 0)
|
|
{ // wait for our script to finish
|
|
CStdString scriptName = url.GetFileName();
|
|
URIUtils::RemoveSlashAtEnd(scriptName);
|
|
success = WaitOnScriptResult(pathToScript, scriptName);
|
|
}
|
|
else
|
|
#endif
|
|
CLog::Log(LOGERROR, "Unable to run plugin %s", pathToScript.c_str());
|
|
|
|
// free our handle
|
|
removeHandle(handle);
|
|
|
|
return success;
|
|
}
|
|
|
|
bool CPluginDirectory::GetPluginResult(const CStdString& strPath, CFileItem &resultItem)
|
|
{
|
|
CPluginDirectory* newDir = new CPluginDirectory();
|
|
|
|
bool success = newDir->StartScript(strPath);
|
|
|
|
if (success)
|
|
{ // update the play path, saving the old one as needed
|
|
if (!resultItem.HasProperty("original_listitem_url"))
|
|
resultItem.SetProperty("original_listitem_url", resultItem.GetPath());
|
|
resultItem.SetPath(newDir->m_fileResult->GetPath());
|
|
resultItem.SetMimeType(newDir->m_fileResult->GetMimeType(false));
|
|
}
|
|
delete newDir;
|
|
|
|
return success;
|
|
}
|
|
|
|
bool CPluginDirectory::AddItem(int handle, const CFileItem *item, int totalItems)
|
|
{
|
|
CSingleLock lock(m_handleLock);
|
|
if (handle < 0 || handle >= (int)globalHandles.size())
|
|
{
|
|
CLog::Log(LOGERROR, " %s - called with an invalid handle.", __FUNCTION__);
|
|
return false;
|
|
}
|
|
|
|
CPluginDirectory *dir = globalHandles[handle];
|
|
CFileItemPtr pItem(new CFileItem(*item));
|
|
dir->m_listItems->Add(pItem);
|
|
dir->m_totalItems = totalItems;
|
|
|
|
return !dir->m_cancelled;
|
|
}
|
|
|
|
bool CPluginDirectory::AddItems(int handle, const CFileItemList *items, int totalItems)
|
|
{
|
|
CSingleLock lock(m_handleLock);
|
|
if (handle < 0 || handle >= (int)globalHandles.size())
|
|
{
|
|
CLog::Log(LOGERROR, " %s - called with an invalid handle.", __FUNCTION__);
|
|
return false;
|
|
}
|
|
|
|
CPluginDirectory *dir = globalHandles[handle];
|
|
CFileItemList pItemList = *items;
|
|
dir->m_listItems->Append(pItemList);
|
|
dir->m_totalItems = totalItems;
|
|
|
|
return !dir->m_cancelled;
|
|
}
|
|
|
|
void CPluginDirectory::EndOfDirectory(int handle, bool success, bool replaceListing, bool cacheToDisc)
|
|
{
|
|
CSingleLock lock(m_handleLock);
|
|
if (handle < 0 || handle >= (int)globalHandles.size())
|
|
{
|
|
CLog::Log(LOGERROR, " %s - called with an invalid handle.", __FUNCTION__);
|
|
return;
|
|
}
|
|
CPluginDirectory *dir = globalHandles[handle];
|
|
|
|
// set cache to disc
|
|
dir->m_listItems->SetCacheToDisc(cacheToDisc ? CFileItemList::CACHE_IF_SLOW : CFileItemList::CACHE_NEVER);
|
|
|
|
dir->m_success = success;
|
|
dir->m_listItems->SetReplaceListing(replaceListing);
|
|
|
|
if (!dir->m_listItems->HasSortDetails())
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_NONE, 552, LABEL_MASKS("%L", "%D"));
|
|
|
|
// Unload temporary language strings
|
|
ClearPluginStrings();
|
|
|
|
// set the event to mark that we're done
|
|
SetEvent(dir->m_fetchComplete);
|
|
}
|
|
|
|
void CPluginDirectory::AddSortMethod(int handle, SORT_METHOD sortMethod, const CStdString &label2Mask)
|
|
{
|
|
CSingleLock lock(m_handleLock);
|
|
if (handle < 0 || handle >= (int)globalHandles.size())
|
|
{
|
|
CLog::Log(LOGERROR, "%s - called with an invalid handle.", __FUNCTION__);
|
|
return;
|
|
}
|
|
|
|
CPluginDirectory *dir = globalHandles[handle];
|
|
|
|
// TODO: Add all sort methods and fix which labels go on the right or left
|
|
switch(sortMethod)
|
|
{
|
|
case SORT_METHOD_LABEL:
|
|
case SORT_METHOD_LABEL_IGNORE_THE:
|
|
{
|
|
if (g_guiSettings.GetBool("filelists.ignorethewhensorting"))
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_LABEL_IGNORE_THE, 551, LABEL_MASKS("%T", label2Mask));
|
|
else
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_LABEL, 551, LABEL_MASKS("%T", label2Mask));
|
|
break;
|
|
}
|
|
case SORT_METHOD_TITLE:
|
|
case SORT_METHOD_TITLE_IGNORE_THE:
|
|
{
|
|
if (g_guiSettings.GetBool("filelists.ignorethewhensorting"))
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_TITLE_IGNORE_THE, 556, LABEL_MASKS("%T", label2Mask));
|
|
else
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_TITLE, 556, LABEL_MASKS("%T", label2Mask));
|
|
break;
|
|
}
|
|
case SORT_METHOD_ARTIST:
|
|
case SORT_METHOD_ARTIST_IGNORE_THE:
|
|
{
|
|
if (g_guiSettings.GetBool("filelists.ignorethewhensorting"))
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_ARTIST_IGNORE_THE, 557, LABEL_MASKS("%T", "%A"));
|
|
else
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_ARTIST, 557, LABEL_MASKS("%T", "%A"));
|
|
break;
|
|
}
|
|
case SORT_METHOD_ALBUM:
|
|
case SORT_METHOD_ALBUM_IGNORE_THE:
|
|
{
|
|
if (g_guiSettings.GetBool("filelists.ignorethewhensorting"))
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_ALBUM_IGNORE_THE, 558, LABEL_MASKS("%T", "%B"));
|
|
else
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_ALBUM, 558, LABEL_MASKS("%T", "%B"));
|
|
break;
|
|
}
|
|
case SORT_METHOD_DATE:
|
|
{
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_DATE, 552, LABEL_MASKS("%T", "%J"));
|
|
break;
|
|
}
|
|
case SORT_METHOD_BITRATE:
|
|
{
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_BITRATE, 623, LABEL_MASKS("%T", "%X"));
|
|
break;
|
|
}
|
|
case SORT_METHOD_SIZE:
|
|
{
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_SIZE, 553, LABEL_MASKS("%T", "%I"));
|
|
break;
|
|
}
|
|
case SORT_METHOD_FILE:
|
|
{
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_FILE, 561, LABEL_MASKS("%T", label2Mask));
|
|
break;
|
|
}
|
|
case SORT_METHOD_TRACKNUM:
|
|
{
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_TRACKNUM, 554, LABEL_MASKS("[%N. ]%T", label2Mask));
|
|
break;
|
|
}
|
|
case SORT_METHOD_DURATION:
|
|
{
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_DURATION, 555, LABEL_MASKS("%T", "%D"));
|
|
break;
|
|
}
|
|
case SORT_METHOD_VIDEO_RATING:
|
|
{
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_VIDEO_RATING, 563, LABEL_MASKS("%T", "%R"));
|
|
break;
|
|
}
|
|
case SORT_METHOD_YEAR:
|
|
{
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_YEAR, 562, LABEL_MASKS("%T", "%Y"));
|
|
break;
|
|
}
|
|
case SORT_METHOD_SONG_RATING:
|
|
{
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_SONG_RATING, 563, LABEL_MASKS("%T", "%R"));
|
|
break;
|
|
}
|
|
case SORT_METHOD_GENRE:
|
|
{
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_GENRE, 515, LABEL_MASKS("%T", "%G"));
|
|
break;
|
|
}
|
|
case SORT_METHOD_COUNTRY:
|
|
{
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_COUNTRY, 574, LABEL_MASKS("%T", "%G"));
|
|
break;
|
|
}
|
|
case SORT_METHOD_VIDEO_TITLE:
|
|
{
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_VIDEO_TITLE, 369, LABEL_MASKS("%T", label2Mask));
|
|
break;
|
|
}
|
|
case SORT_METHOD_MPAA_RATING:
|
|
{
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_MPAA_RATING, 563, LABEL_MASKS("%T", "%O"));
|
|
break;
|
|
}
|
|
case SORT_METHOD_VIDEO_RUNTIME:
|
|
{
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_VIDEO_RUNTIME, 555, LABEL_MASKS("%T", "%D"));
|
|
break;
|
|
}
|
|
case SORT_METHOD_STUDIO:
|
|
case SORT_METHOD_STUDIO_IGNORE_THE:
|
|
{
|
|
if (g_guiSettings.GetBool("filelists.ignorethewhensorting"))
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_STUDIO_IGNORE_THE, 572, LABEL_MASKS("%T", "%U"));
|
|
else
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_STUDIO, 572, LABEL_MASKS("%T", "%U"));
|
|
break;
|
|
}
|
|
case SORT_METHOD_PROGRAM_COUNT:
|
|
{
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_PROGRAM_COUNT, 567, LABEL_MASKS("%T", "%C"));
|
|
break;
|
|
}
|
|
case SORT_METHOD_UNSORTED:
|
|
{
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_UNSORTED, 571, LABEL_MASKS("%T", label2Mask));
|
|
break;
|
|
}
|
|
case SORT_METHOD_NONE:
|
|
{
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_NONE, 552, LABEL_MASKS("%T", label2Mask));
|
|
break;
|
|
}
|
|
case SORT_METHOD_DRIVE_TYPE:
|
|
{
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_DRIVE_TYPE, 564, LABEL_MASKS()); // Preformatted
|
|
break;
|
|
}
|
|
case SORT_METHOD_PLAYLIST_ORDER:
|
|
{
|
|
CStdString strTrackLeft=g_guiSettings.GetString("musicfiles.trackformat");
|
|
CStdString strTrackRight=g_guiSettings.GetString("musicfiles.trackformatright");
|
|
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_PLAYLIST_ORDER, 559, LABEL_MASKS(strTrackLeft, strTrackRight));
|
|
break;
|
|
}
|
|
case SORT_METHOD_EPISODE:
|
|
{
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_EPISODE,20359,LABEL_MASKS("%E. %T","%R"));
|
|
break;
|
|
}
|
|
case SORT_METHOD_PRODUCTIONCODE:
|
|
{
|
|
//dir->m_listItems.AddSortMethod(SORT_METHOD_PRODUCTIONCODE,20368,LABEL_MASKS("%E. %T","%P", "%E. %T","%P"));
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_PRODUCTIONCODE,20368,LABEL_MASKS("%H. %T","%P", "%H. %T","%P"));
|
|
break;
|
|
}
|
|
case SORT_METHOD_LISTENERS:
|
|
{
|
|
dir->m_listItems->AddSortMethod(SORT_METHOD_LISTENERS,20455,LABEL_MASKS("%T","%W"));
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool CPluginDirectory::GetDirectory(const CStdString& strPath, CFileItemList& items)
|
|
{
|
|
CURL url(strPath);
|
|
if (url.GetFileName().IsEmpty())
|
|
{ // called with no script - should never happen
|
|
return GetPluginsDirectory(url.GetHostName(), items);
|
|
}
|
|
|
|
bool success = this->StartScript(strPath);
|
|
|
|
// append the items to the list
|
|
items.Assign(*m_listItems, true); // true to keep the current items
|
|
m_listItems->Clear();
|
|
return success;
|
|
}
|
|
|
|
bool CPluginDirectory::RunScriptWithParams(const CStdString& strPath)
|
|
{
|
|
CURL url(strPath);
|
|
if (url.GetFileName().IsEmpty()) // called with no script - should never happen
|
|
return false;
|
|
|
|
// Load the settings incase they changed while in the plugins directory
|
|
g_currentPluginSettings.Load(url);
|
|
|
|
// Load language strings
|
|
LoadPluginStrings(url);
|
|
|
|
// path is special://home/plugins/<path from here>
|
|
CStdString pathToScript = "special://home/plugins/";
|
|
URIUtils::AddFileToFolder(pathToScript, url.GetHostName(), pathToScript);
|
|
URIUtils::AddFileToFolder(pathToScript, url.GetFileName(), pathToScript);
|
|
URIUtils::AddFileToFolder(pathToScript, "default.py", pathToScript);
|
|
|
|
// options
|
|
CStdString options = url.GetOptions();
|
|
URIUtils::RemoveSlashAtEnd(options); // This MAY kill some scripts (eg though with a URL ending with a slash), but
|
|
// is needed for all others, as XBMC adds slashes to "folders"
|
|
// base path
|
|
CStdString basePath = "plugin://";
|
|
URIUtils::AddFileToFolder(basePath, url.GetHostName(), basePath);
|
|
URIUtils::AddFileToFolder(basePath, url.GetFileName(), basePath);
|
|
|
|
// setup our parameters to send the script
|
|
CStdString strHandle;
|
|
strHandle.Format("%i", -1);
|
|
const char *argv[3];
|
|
argv[0] = basePath.c_str();
|
|
argv[1] = strHandle.c_str();
|
|
argv[2] = options.c_str();
|
|
|
|
// run the script
|
|
#ifdef HAS_PYTHON
|
|
CLog::Log(LOGDEBUG, "%s - calling plugin %s('%s','%s','%s')", __FUNCTION__, pathToScript.c_str(), argv[0], argv[1], argv[2]);
|
|
if (g_pythonParser.evalFile(pathToScript.c_str(), 3, (const char**)argv) >= 0)
|
|
return true;
|
|
else
|
|
#endif
|
|
CLog::Log(LOGERROR, "Unable to run plugin %s", pathToScript.c_str());
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CPluginDirectory::HasPlugins(const CStdString &type)
|
|
{
|
|
CStdString path = "special://home/plugins/";
|
|
URIUtils::AddFileToFolder(path, type, path);
|
|
CFileItemList items;
|
|
if (CDirectory::GetDirectory(path, items, "/", false))
|
|
{
|
|
for (int i = 0; i < items.Size(); i++)
|
|
{
|
|
CFileItemPtr item = items[i];
|
|
if (item->m_bIsFolder && !item->IsParentFolder() && !item->m_bIsShareOrDrive)
|
|
{
|
|
CStdString defaultPY;
|
|
URIUtils::AddFileToFolder(item->GetPath(), "default.py", defaultPY);
|
|
if (XFILE::CFile::Exists(defaultPY))
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CPluginDirectory::GetPluginsDirectory(const CStdString &type, CFileItemList &items)
|
|
{
|
|
// retrieve our folder
|
|
CStdString pluginsFolder = "special://home/plugins";
|
|
URIUtils::AddFileToFolder(pluginsFolder, type, pluginsFolder);
|
|
URIUtils::AddSlashAtEnd(pluginsFolder);
|
|
|
|
if (!CDirectory::GetDirectory(pluginsFolder, items, "*.py", false))
|
|
return false;
|
|
|
|
CStdString path = items.GetPath();
|
|
path.Replace("special://home/plugins/", "plugin://");
|
|
items.SetPath(path);
|
|
|
|
// flatten any folders - TODO: Assigning of thumbs
|
|
for (int i = 0; i < items.Size(); i++)
|
|
{
|
|
CFileItemPtr item = items[i];
|
|
item->SetThumbnailImage("");
|
|
item->SetCachedProgramThumb();
|
|
if (!item->HasThumbnail())
|
|
item->SetUserProgramThumb();
|
|
if (!item->HasThumbnail())
|
|
{
|
|
CFileItem item2(item->GetPath());
|
|
item2.SetPath(URIUtils::AddFileToFolder(item->GetPath(),"default.py"));
|
|
item2.m_bIsFolder = false;
|
|
item2.SetCachedProgramThumb();
|
|
if (!item2.HasThumbnail())
|
|
item2.SetUserProgramThumb();
|
|
if (item2.HasThumbnail())
|
|
{
|
|
XFILE::CFile::Cache(item2.GetThumbnailImage(),item->GetCachedProgramThumb());
|
|
item->SetThumbnailImage(item->GetCachedProgramThumb());
|
|
}
|
|
}
|
|
path = item->GetPath();
|
|
path.Replace("special://home/plugins/", "plugin://");
|
|
path.Replace("\\", "/");
|
|
item->SetPath(path);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CPluginDirectory::WaitOnScriptResult(const CStdString &scriptPath, const CStdString &scriptName)
|
|
{
|
|
const unsigned int timeBeforeProgressBar = 1500;
|
|
const unsigned int timeToKillScript = 1000;
|
|
|
|
DWORD startTime = timeGetTime();
|
|
CGUIDialogProgress *progressBar = NULL;
|
|
|
|
CLog::Log(LOGDEBUG, "%s - waiting on the %s plugin...", __FUNCTION__, scriptName.c_str());
|
|
while (true)
|
|
{
|
|
CSingleExit ex(g_graphicsContext);
|
|
// check if the python script is finished
|
|
if (WaitForSingleObject(m_fetchComplete, 20) == WAIT_OBJECT_0)
|
|
{ // python has returned
|
|
CLog::Log(LOGDEBUG, "%s- plugin returned %s", __FUNCTION__, m_success ? "successfully" : "failure");
|
|
break;
|
|
}
|
|
ex.Restore();
|
|
|
|
// check our script is still running
|
|
#ifdef HAS_PYTHON
|
|
int id = g_pythonParser.getScriptId(scriptPath.c_str());
|
|
if (id == -1)
|
|
#endif
|
|
{ // check whether we exited normally
|
|
if (WaitForSingleObject(m_fetchComplete, 0) == WAIT_TIMEOUT)
|
|
{ // python didn't return correctly
|
|
CLog::Log(LOGDEBUG, " %s - plugin exited prematurely - terminating", __FUNCTION__);
|
|
m_success = false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// check whether we should pop up the progress dialog
|
|
if (!progressBar && timeGetTime() - startTime > timeBeforeProgressBar)
|
|
{ // loading takes more then 1.5 secs, show a progress dialog
|
|
progressBar = (CGUIDialogProgress *)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
|
|
|
|
// if script has shown progressbar don't override it
|
|
if (progressBar && progressBar->IsActive())
|
|
{
|
|
startTime = timeGetTime();
|
|
progressBar = NULL;
|
|
}
|
|
|
|
if (progressBar)
|
|
{
|
|
progressBar->SetHeading(scriptName);
|
|
progressBar->SetLine(0, 1040);
|
|
progressBar->SetLine(1, "");
|
|
progressBar->SetLine(2, "");
|
|
progressBar->StartModal();
|
|
}
|
|
}
|
|
|
|
if (progressBar)
|
|
{ // update the progress bar and check for user cancel
|
|
CStdString label;
|
|
if (m_totalItems > 0)
|
|
{
|
|
label.Format(g_localizeStrings.Get(1042).c_str(), m_listItems->Size(), m_totalItems);
|
|
progressBar->SetPercentage((int)((m_listItems->Size() * 100 ) / m_totalItems));
|
|
progressBar->ShowProgressBar(true);
|
|
}
|
|
else
|
|
label.Format(g_localizeStrings.Get(1041).c_str(), m_listItems->Size());
|
|
progressBar->SetLine(2, label);
|
|
progressBar->Progress();
|
|
if (progressBar->IsCanceled())
|
|
{ // user has cancelled our process - cancel our process
|
|
if (!m_cancelled)
|
|
{
|
|
m_cancelled = true;
|
|
startTime = timeGetTime();
|
|
}
|
|
if (m_cancelled && timeGetTime() - startTime > timeToKillScript)
|
|
{ // cancel our script
|
|
#ifdef HAS_PYTHON
|
|
int id = g_pythonParser.getScriptId(scriptPath.c_str());
|
|
if (id != -1 && g_pythonParser.isRunning(id))
|
|
{
|
|
CLog::Log(LOGDEBUG, "%s- cancelling plugin %s", __FUNCTION__, scriptName.c_str());
|
|
g_pythonParser.stopScript(id);
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (progressBar)
|
|
progressBar->Close();
|
|
|
|
return !m_cancelled && m_success;
|
|
}
|
|
|
|
void CPluginDirectory::SetResolvedUrl(int handle, bool success, const CFileItem *resultItem)
|
|
{
|
|
CSingleLock lock(m_handleLock);
|
|
if (handle < 0 || handle >= (int)globalHandles.size())
|
|
{
|
|
CLog::Log(LOGERROR, " %s - called with an invalid handle.", __FUNCTION__);
|
|
return;
|
|
}
|
|
CPluginDirectory* dir = globalHandles[handle];
|
|
|
|
dir->m_success = success;
|
|
*dir->m_fileResult = *resultItem;
|
|
|
|
// set the event to mark that we're done
|
|
SetEvent(dir->m_fetchComplete);
|
|
}
|
|
|
|
void CPluginDirectory::SetContent(int handle, const CStdString &strContent)
|
|
{
|
|
if (handle < 0 || handle >= (int)globalHandles.size())
|
|
{
|
|
CLog::Log(LOGERROR, "%s called with an invalid handle.", __FUNCTION__);
|
|
return;
|
|
}
|
|
|
|
CPluginDirectory *dir = globalHandles[handle];
|
|
dir->m_listItems->SetContent(strContent);
|
|
}
|
|
|
|
void CPluginDirectory::SetProperty(int handle, const CStdString &strProperty, const CStdString &strValue)
|
|
{
|
|
CSingleLock lock(m_handleLock);
|
|
if (handle < 0 || handle >= (int)globalHandles.size())
|
|
{
|
|
CLog::Log(LOGERROR, "%s called with an invalid handle.", __FUNCTION__);
|
|
return;
|
|
}
|
|
|
|
CPluginDirectory *dir = globalHandles[handle];
|
|
dir->m_listItems->SetProperty(strProperty, strValue);
|
|
}
|
|
|
|
void CPluginDirectory::LoadPluginStrings(const CURL &url)
|
|
{
|
|
// Path where the plugin resides
|
|
CStdString pathToPlugin = "special://home/plugins/";
|
|
URIUtils::AddFileToFolder(pathToPlugin, url.GetHostName(), pathToPlugin);
|
|
URIUtils::AddFileToFolder(pathToPlugin, url.GetFileName(), pathToPlugin);
|
|
|
|
// Path where the language strings reside
|
|
CStdString pathToLanguageFile = pathToPlugin;
|
|
URIUtils::AddFileToFolder(pathToLanguageFile, "resources", pathToLanguageFile);
|
|
URIUtils::AddFileToFolder(pathToLanguageFile, "language", pathToLanguageFile);
|
|
URIUtils::AddSlashAtEnd(pathToLanguageFile);
|
|
|
|
// Load language strings temporarily
|
|
g_localizeStringsTemp.Load(pathToLanguageFile, g_guiSettings.GetString("locale.language"));
|
|
}
|
|
|
|
void CPluginDirectory::ClearPluginStrings()
|
|
{
|
|
// Unload temporary language strings
|
|
g_localizeStringsTemp.Clear();
|
|
}
|