/*
* 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 "PlayListXML.h"
#include "FileItem.h"
#include "Util.h"
#include "filesystem/File.h"
#include "media/MediaLockState.h"
#include "utils/StringUtils.h"
#include "utils/URIUtils.h"
#include "utils/Variant.h"
#include "utils/XMLUtils.h"
#include "utils/log.h"
using namespace PLAYLIST;
using namespace XFILE;
/*
Playlist example (must be stored with .pxml extension):
mms://stream02.rambler.ru/eurosport
Евроспорт
LIVETV
RU
1
123
mms://video.rfn.ru/vesti_24
Вести 24
LIVETV
RU
2
*/
CPlayListXML::CPlayListXML(void) = default;
CPlayListXML::~CPlayListXML(void) = default;
static inline std::string GetString( const TiXmlElement* pRootElement, const char *tagName )
{
std::string strValue;
if ( XMLUtils::GetString(pRootElement, tagName, strValue) )
return strValue;
return "";
}
bool CPlayListXML::Load( const std::string& strFileName )
{
CXBMCTinyXML xmlDoc;
m_strPlayListName = URIUtils::GetFileName(strFileName);
URIUtils::GetParentPath(strFileName, m_strBasePath);
Clear();
// Try to load the file as XML. If it does not load, return an error.
if ( !xmlDoc.LoadFile( strFileName ) )
{
CLog::Log(LOGERROR, "Playlist {} has invalid format/malformed xml", strFileName);
return false;
}
TiXmlElement *pRootElement = xmlDoc.RootElement();
// If the stream does not contain "streams", still ok. Not an error.
if (!pRootElement || StringUtils::CompareNoCase(pRootElement->Value(), "streams"))
{
CLog::Log(LOGERROR, "Playlist {} has no root", strFileName);
return false;
}
TiXmlElement* pSet = pRootElement->FirstChildElement("stream");
while ( pSet )
{
// Get parameters
std::string url = GetString( pSet, "url" );
std::string name = GetString( pSet, "name" );
std::string category = GetString( pSet, "category" );
std::string lang = GetString( pSet, "lang" );
std::string channel = GetString( pSet, "channel" );
std::string lockpass = GetString( pSet, "lockpassword" );
// If url is empty, it doesn't make any sense
if ( !url.empty() )
{
// If the name is empty, use url
if ( name.empty() )
name = url;
// Append language to the name, and also set as metadata
if ( !lang.empty() )
name += " [" + lang + "]";
std::string info = name;
CFileItemPtr newItem( new CFileItem(info) );
newItem->SetPath(url);
// Set language as metadata
if ( !lang.empty() )
newItem->SetProperty("language", lang.c_str() );
// Set category as metadata
if ( !category.empty() )
newItem->SetProperty("category", category.c_str() );
// Set channel as extra info and as metadata
if ( !channel.empty() )
{
newItem->SetProperty("remotechannel", channel.c_str() );
newItem->SetExtraInfo( "Channel: " + channel );
}
if ( !lockpass.empty() )
{
newItem->m_strLockCode = lockpass;
newItem->m_iHasLock = LOCK_STATE_LOCKED;
newItem->m_iLockMode = LOCK_MODE_NUMERIC;
}
Add(newItem);
}
else
CLog::Log(LOGERROR, "Playlist entry {} in file {} has missing tag", name, strFileName);
pSet = pSet->NextSiblingElement("stream");
}
return true;
}
void CPlayListXML::Save(const std::string& strFileName) const
{
if (!m_vecItems.size()) return ;
std::string strPlaylist = CUtil::MakeLegalPath(strFileName);
CFile file;
if (!file.OpenForWrite(strPlaylist, true))
{
CLog::Log(LOGERROR, "Could not save WPL playlist: [{}]", strPlaylist);
return ;
}
std::string write;
write += StringUtils::Format("\n");
write += StringUtils::Format("\n");
for (int i = 0; i < (int)m_vecItems.size(); ++i)
{
CFileItemPtr item = m_vecItems[i];
write += StringUtils::Format(" \n" );
write += StringUtils::Format(" {}", item->GetPath().c_str());
write += StringUtils::Format(" {}", item->GetLabel());
if ( !item->GetProperty("language").empty() )
write += StringUtils::Format(" {}", item->GetProperty("language").asString());
if ( !item->GetProperty("category").empty() )
write += StringUtils::Format(" {}",
item->GetProperty("category").asString());
if ( !item->GetProperty("remotechannel").empty() )
write += StringUtils::Format(" {}",
item->GetProperty("remotechannel").asString());
if (item->m_iHasLock > LOCK_STATE_NO_LOCK)
write += StringUtils::Format(" {}", item->m_strLockCode);
write += StringUtils::Format(" \n\n" );
}
write += StringUtils::Format("\n");
file.Write(write.c_str(), write.size());
file.Close();
}