aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--project/VS2008Express/XBMC.vcproj8
-rw-r--r--xbmc/FileItem.cpp8
-rw-r--r--xbmc/FileItem.h1
-rw-r--r--xbmc/FileSystem/FactoryDirectory.cpp2
-rw-r--r--xbmc/FileSystem/FactoryFileDirectory.cpp5
-rw-r--r--xbmc/FileSystem/RSSDirectory.cpp444
-rw-r--r--xbmc/FileSystem/RSSDirectory.h9
-rw-r--r--xbmc/Settings.cpp6
-rw-r--r--xbmc/Util.cpp12
-rw-r--r--xbmc/utils/Makefile1
-rw-r--r--xbmc/utils/RssFeed.cpp463
-rw-r--r--xbmc/utils/RssFeed.h83
12 files changed, 461 insertions, 581 deletions
diff --git a/project/VS2008Express/XBMC.vcproj b/project/VS2008Express/XBMC.vcproj
index c92ea1d54f..471303d47e 100644
--- a/project/VS2008Express/XBMC.vcproj
+++ b/project/VS2008Express/XBMC.vcproj
@@ -3098,14 +3098,6 @@
>
</File>
<File
- RelativePath="..\..\xbmc\utils\RssFeed.cpp"
- >
- </File>
- <File
- RelativePath="..\..\xbmc\utils\RssFeed.h"
- >
- </File>
- <File
RelativePath="..\..\xbmc\utils\RssReader.cpp"
>
</File>
diff --git a/xbmc/FileItem.cpp b/xbmc/FileItem.cpp
index d5f1f599ef..7963bb7bc2 100644
--- a/xbmc/FileItem.cpp
+++ b/xbmc/FileItem.cpp
@@ -625,6 +625,7 @@ bool CFileItem::IsFileFolder() const
IsPlayList() && g_advancedSettings.m_playlistAsFolders ||
IsZIP() ||
IsRAR() ||
+ IsRSS() ||
IsType(".ogg") ||
IsType(".nsf") ||
IsType(".sid") ||
@@ -724,6 +725,13 @@ bool CFileItem::IsCBR() const
return CUtil::GetExtension(m_strPath).Equals(".cbr", false);
}
+bool CFileItem::IsRSS() const
+{
+ return m_strPath.Left(6).Equals("rss://", false)
+ || CUtil::GetExtension(m_strPath).Equals(".rss", false)
+ || GetContentType() == "application/rss+xml";
+}
+
bool CFileItem::IsStack() const
{
return CUtil::IsStack(m_strPath);
diff --git a/xbmc/FileItem.h b/xbmc/FileItem.h
index 1addd3863b..890aa7ddbf 100644
--- a/xbmc/FileItem.h
+++ b/xbmc/FileItem.h
@@ -132,6 +132,7 @@ public:
bool IsHDHomeRun() const;
bool IsVTP() const;
bool IsLiveTV() const;
+ bool IsRSS() const;
void RemoveExtension();
void CleanString();
diff --git a/xbmc/FileSystem/FactoryDirectory.cpp b/xbmc/FileSystem/FactoryDirectory.cpp
index eee479426a..74130152a5 100644
--- a/xbmc/FileSystem/FactoryDirectory.cpp
+++ b/xbmc/FileSystem/FactoryDirectory.cpp
@@ -98,7 +98,7 @@ IDirectory* CFactoryDirectory::Create(const CStdString& strPath)
{
CURL url(strPath);
- CFileItem item;
+ CFileItem item(strPath, false);
IFileDirectory* pDir=CFactoryFileDirectory::Create(strPath, &item);
if (pDir)
return pDir;
diff --git a/xbmc/FileSystem/FactoryFileDirectory.cpp b/xbmc/FileSystem/FactoryFileDirectory.cpp
index 6f805e2974..a7710a718a 100644
--- a/xbmc/FileSystem/FactoryFileDirectory.cpp
+++ b/xbmc/FileSystem/FactoryFileDirectory.cpp
@@ -28,6 +28,7 @@
#include "NSFFileDirectory.h"
#include "SIDFileDirectory.h"
#include "ASAPFileDirectory.h"
+#include "RSSDirectory.h"
#include "cores/paplayer/ASAPCodec.h"
#endif
#include "RarDirectory.h"
@@ -104,6 +105,10 @@ IFileDirectory* CFactoryFileDirectory::Create(const CStdString& strPath, CFileIt
delete pDir;
return NULL;
}
+
+ if (pItem->IsRSS())
+ return new CRSSDirectory();
+
#endif
if (strExtension.Equals(".zip"))
{
diff --git a/xbmc/FileSystem/RSSDirectory.cpp b/xbmc/FileSystem/RSSDirectory.cpp
index 211c568462..135f87d29a 100644
--- a/xbmc/FileSystem/RSSDirectory.cpp
+++ b/xbmc/FileSystem/RSSDirectory.cpp
@@ -20,13 +20,19 @@
*/
#include "RSSDirectory.h"
-#include "RssFeed.h"
-#include "Util.h"
#include "FileItem.h"
-#include "FileCurl.h"
+#include "Settings.h"
+#include "Util.h"
+#include "tinyXML/tinyxml.h"
+#include "HTMLUtil.h"
+#include "StringUtils.h"
+#include "VideoInfoTag.h"
+#include "utils/log.h"
+#include "URL.h"
using namespace XFILE;
using namespace DIRECTORY;
+using namespace std;
CRSSDirectory::CRSSDirectory()
{
@@ -37,21 +43,433 @@ CRSSDirectory::~CRSSDirectory()
{
}
-bool CRSSDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items)
+bool CRSSDirectory::ContainsFiles(const CStdString& strPath)
{
- CStdString path(strPath);
- CUtil::RemoveSlashAtEnd(path);
+ CFileItemList items;
+ if(!GetDirectory(strPath, items))
+ return false;
- CURL url(path);
- url.SetProtocol("http");
+ return items.Size() > 0;
+}
+
+static bool IsPathToMedia(const CStdString& strPath )
+{
+ CStdString extension;
+ CUtil::GetExtension(strPath, extension);
+
+ if (extension.IsEmpty())
+ return false;
+
+ extension.ToLower();
- CRssFeed feed;
- feed.Init(url.Get());
- feed.ReadFeed();
+ if (g_stSettings.m_videoExtensions.Find(extension) != -1)
+ return true;
- feed.GetItemList(items);
- if (items.Size() == 0)
+ if (g_stSettings.m_musicExtensions.Find(extension) != -1)
+ return true;
+
+ if (g_stSettings.m_pictureExtensions.Find(extension) != -1)
+ return true;
+
+ return false;
+}
+
+static bool IsPathToThumbnail(const CStdString& strPath )
+{
+ // Currently just check if this is an image, maybe we will add some
+ // other checks later
+ CStdString extension;
+ CUtil::GetExtension(strPath, extension);
+
+ if (extension.IsEmpty())
return false;
+ extension.ToLower();
+
+ if (g_stSettings.m_pictureExtensions.Find(extension) != -1)
+ return true;
+
+ return false;
+}
+
+static time_t ParseDate(const CStdString & strDate)
+{
+ struct tm pubDate = {0};
+ // TODO: Handle time zone
+ strptime(strDate.c_str(), "%a, %d %b %Y %H:%M:%S", &pubDate);
+ // Check the difference between the time of last check and time of the item
+ return mktime(&pubDate);
+}
+
+// helper to avoid null dereference
+static inline CStdString S(const char * s)
+{
+ if(s)
+ return s;
+ else
+ return "";
+}
+
+static void ParseItemMRSS(CFileItemPtr& item, TiXmlElement* item_child, const CStdString& name, const CStdString& xmlns)
+{
+ CVideoInfoTag* vtag = item->GetVideoInfoTag();
+ CStdString text = S(item_child->GetText());
+
+ if(name == "content")
+ {
+ const char* url = item_child->Attribute("url");
+ const char* type = item_child->Attribute("type");
+ const char* dur = item_child->Attribute("duration");
+
+ if (url && item->m_strPath == "" && IsPathToMedia(url))
+ item->m_strPath = url;
+
+ if (type)
+ {
+ CStdString strType(type);
+ item->SetContentType(strType);
+ if (url && item->m_strPath.IsEmpty() &&
+ (strType.Left(6).Equals("video/") ||
+ strType.Left(6).Equals("audio/")
+ ))
+ item->m_strPath = url;
+ }
+
+ if(dur)
+ StringUtils::SecondsToTimeString(atoi(dur), vtag->m_strRuntime);
+
+ // Go over all child nodes of the media content and get the thumbnail
+ TiXmlElement* media_content_child = item_child->FirstChildElement("media:thumbnail");
+ if (media_content_child && media_content_child->Value() && strcmp(media_content_child->Value(), "media:thumbnail") == 0)
+ {
+ const char * url = media_content_child->Attribute("url");
+ if (url && IsPathToThumbnail(url))
+ item->SetThumbnailImage(url);
+ }
+ }
+ else if(name == "thumbnail")
+ {
+ if(item_child->GetText() && IsPathToThumbnail(item_child->GetText()))
+ item->SetThumbnailImage(item_child->GetText());
+ else
+ {
+ const char * url = item_child->Attribute("url");
+ if(url && IsPathToThumbnail(url))
+ item->SetThumbnailImage(url);
+ }
+ }
+ else if (name == "title")
+ {
+ if(text.IsEmpty())
+ return;
+
+ item->SetLabel(text);
+ vtag->m_strTitle = text;
+ }
+ else if(name == "description")
+ {
+ if(text.IsEmpty())
+ return;
+
+ CStdString description = text;
+ if(S(item_child->Attribute("type")) == "html")
+ HTML::CHTMLUtil::RemoveTags(description);
+ item->SetProperty("description", description);
+ item->SetLabel2(description);
+
+ vtag->m_strPlotOutline = description;
+ vtag->m_strPlot = description;
+ }
+ else if(name == "category")
+ {
+ if(text.IsEmpty())
+ return;
+
+ vtag->m_strGenre = text;
+ }
+ else if(name == "rating")
+ {
+ if(text.IsEmpty())
+ return;
+ if(atof(text.c_str()) > 0.0f && atof(text.c_str()) <= 10.0f)
+ vtag->m_fRating = (float)atof(text.c_str());
+ else
+ vtag->m_strMPAARating = text;
+ }
+ else if(name == "credit")
+ {
+ CStdString role = S(item_child->Attribute("role"));
+ if(role == "director")
+ vtag->m_strDirector += ", " + text;
+ else if(role == "author")
+ vtag->m_strWritingCredits += ", " + text;
+ else if(role == "actor")
+ {
+ SActorInfo actor;
+ actor.strName = text;
+ vtag->m_cast.push_back(actor);
+ }
+ }
+
+}
+
+static void ParseItemItunes(CFileItemPtr& item, TiXmlElement* item_child, const CStdString& name, const CStdString& xmlns)
+{
+ if(name == "image")
+ {
+ if(item_child->GetText() && IsPathToThumbnail(item_child->GetText()))
+ item->SetThumbnailImage(item_child->GetText());
+ else
+ {
+ const char * url = item_child->Attribute("href");
+ if(url && IsPathToThumbnail(url))
+ item->SetThumbnailImage(url);
+ }
+ }
+ else if(name == "summary")
+ {
+ if(item_child->GetText())
+ {
+ CStdString description = item_child->GetText();
+ item->SetProperty("description", description);
+ item->SetLabel2(description);
+ }
+ }
+ else if(name == "subtitle")
+ {
+ if(item_child->GetText())
+ {
+ CStdString description = item_child->GetText();
+ item->SetProperty("description", description);
+ item->SetLabel2(description);
+ }
+ }
+ else if(name == "author")
+ {
+ if(item_child->GetText())
+ item->SetProperty("author", item_child->GetText());
+ }
+ else if(name == "duration")
+ {
+ if(item_child->GetText())
+ item->SetProperty("duration", item_child->GetText());
+ }
+ else if(name == "keywords")
+ {
+ if(item_child->GetText())
+ item->SetProperty("keywords", item_child->GetText());
+ }
+}
+
+static void ParseItemRSS(CFileItemPtr& item, TiXmlElement* item_child, const CStdString& name, const CStdString& xmlns)
+{
+ if (name == "title")
+ {
+ if (item_child->GetText())
+ item->SetLabel(item_child->GetText());
+ }
+ else if (name == "pubDate")
+ {
+ CDateTime pubDate(ParseDate(item_child->GetText()));
+ item->m_dateTime = pubDate;
+ }
+ else if (name == "link")
+ {
+ if (item_child->GetText())
+ {
+ string strLink = item_child->GetText();
+
+ string strPrefix = strLink.substr(0, strLink.find_first_of(":"));
+ if (strPrefix == "rss")
+ {
+ // If this is an rss item, we treat it as another level in the directory
+ item->m_bIsFolder = true;
+ item->m_strPath = strLink;
+ }
+ else if (item->m_strPath == "" && IsPathToMedia(strLink))
+ item->m_strPath = strLink;
+ }
+ }
+ else if(name == "enclosure")
+ {
+ const char * url = item_child->Attribute("url");
+ if (url && item->m_strPath.IsEmpty() && IsPathToMedia(url))
+ item->m_strPath = url;
+ const char * content_type = item_child->Attribute("type");
+ if (content_type)
+ {
+ item->SetContentType(content_type);
+ CStdString strContentType(content_type);
+ if (url && item->m_strPath.IsEmpty() &&
+ (strContentType.Left(6).Equals("video/") ||
+ strContentType.Left(6).Equals("audio/")
+ ))
+ item->m_strPath = url;
+ }
+ const char * len = item_child->Attribute("length");
+ if (len)
+ item->m_dwSize = _atoi64(len);
+ }
+ else if(name == "description")
+ {
+ CStdString description = item_child->GetText();
+ HTML::CHTMLUtil::RemoveTags(description);
+ item->SetProperty("description", description);
+ item->SetLabel2(description);
+ }
+ else if(name == "guid")
+ {
+ if (item->m_strPath.IsEmpty() && IsPathToMedia(item_child->Value()))
+ {
+ if(item_child->GetText())
+ item->m_strPath = item_child->GetText();
+ }
+ }
+}
+
+static void ParseItemVoddler(CFileItemPtr& item, TiXmlElement* element, const CStdString& name, const CStdString& xmlns)
+{
+ CVideoInfoTag* vtag = item->GetVideoInfoTag();
+ CStdString text = S(element->GetText());
+
+ if(name == "trailer")
+ {
+ vtag->m_strTrailer = text;
+
+ CStdString type = S(element->Attribute("type"));
+ if(item->m_strPath.IsEmpty())
+ {
+ item->m_strPath = text;
+ item->SetContentType(type);
+ }
+ }
+ else if(name == "year")
+ vtag->m_iYear = atoi(text);
+ else if(name == "tagline")
+ vtag->m_strTagLine = text;
+ else if(name == "posterwall")
+ {
+ const char* url = element->Attribute("url");
+ if(url)
+ item->SetProperty("fanart_image", url);
+ else if(IsPathToThumbnail(text))
+ item->SetProperty("fanart_image", text);
+ }
+}
+
+
+bool CRSSDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items)
+{
+ /* check cache */
+ if(m_path == strPath)
+ {
+ items = m_items;
+ return true;
+ }
+
+ /* clear cache */
+ m_items.Clear();
+ m_path == "";
+
+ TiXmlDocument xmlDoc;
+ if (!xmlDoc.LoadFile(strPath))
+ {
+ CLog::Log(LOGERROR,"failed to load xml from <%s>. error: <%d>", strPath.c_str(), xmlDoc.ErrorId());
+ return false;
+ }
+ if (xmlDoc.Error())
+ {
+ CLog::Log(LOGERROR,"error parsing xml doc from <%s>. error: <%d>", strPath.c_str(), xmlDoc.ErrorId());
+ return false;
+ }
+
+ TiXmlElement* rssXmlNode = xmlDoc.RootElement();
+
+ if (!rssXmlNode)
+ return false;
+
+ CStdString strMediaThumbnail ;
+
+ TiXmlHandle docHandle( &xmlDoc );
+ TiXmlElement* channelXmlNode = docHandle.FirstChild( "rss" ).FirstChild( "channel" ).Element();
+ if (channelXmlNode)
+ {
+ TiXmlElement* aNode = channelXmlNode->FirstChildElement("title");
+ if (aNode && !aNode->NoChildren())
+ items.SetProperty("rss:title", aNode->FirstChild()->Value());
+
+ aNode = channelXmlNode->FirstChildElement("itunes:summary");
+ if (aNode && !aNode->NoChildren())
+ items.SetProperty("rss:description", aNode->FirstChild()->Value());
+
+ if (!items.HasProperty("rss:description"))
+ {
+ aNode = channelXmlNode->FirstChildElement("description");
+ if (aNode && !aNode->NoChildren())
+ items.SetProperty("rss:description", aNode->FirstChild()->Value());
+ }
+
+ // Get channel thumbnail
+ TiXmlHandle chanHandle( channelXmlNode );
+ aNode = chanHandle.FirstChild("image").FirstChild("url").Element();
+ if (aNode && !aNode->NoChildren())
+ items.SetProperty("rss:image", aNode->FirstChild()->Value());
+
+ if (!items.HasProperty("rss:image"))
+ {
+ aNode = chanHandle.FirstChild("itunes:image").Element();
+ if (aNode && !aNode->NoChildren())
+ items.SetProperty("rss:image", aNode->FirstChild()->Value());
+ }
+ }
+ else
+ return false;
+
+ TiXmlElement* child = NULL;
+ TiXmlElement* item_child = NULL;
+ for (child = channelXmlNode->FirstChildElement("item"); child; child = child->NextSiblingElement())
+ {
+ // Create new item,
+ CFileItemPtr item(new CFileItem());
+
+ for (item_child = child->FirstChildElement(); item_child; item_child = item_child->NextSiblingElement())
+ {
+ CStdString name = item_child->Value();
+ CStdString xmlns;
+ int pos = name.Find(':');
+ if(pos >= 0)
+ {
+ xmlns = name.Left(pos);
+ name.Delete(0, pos+1);
+ }
+
+ if(xmlns == "media")
+ ParseItemMRSS(item, item_child, name, xmlns);
+ else if (xmlns == "itunes")
+ ParseItemItunes(item, item_child, name, xmlns);
+ else if (xmlns == "voddler")
+ ParseItemVoddler(item, item_child, name, xmlns);
+ else
+ ParseItemRSS(item, item_child, name, xmlns);
+
+ } // for item
+
+ // clean up ", " added during build
+ if(item->HasVideoInfoTag())
+ {
+ item->GetVideoInfoTag()->m_strDirector.Delete(0, 2);
+ item->GetVideoInfoTag()->m_strWritingCredits.Delete(0, 2);
+ }
+
+ item->SetProperty("isrss", "1");
+ item->SetProperty("chanthumb",strMediaThumbnail);
+
+ if (!item->m_strPath.IsEmpty())
+ items.Add(item);
+ }
+
+ m_items = items;
+ m_path = strPath;
+
return true;
}
diff --git a/xbmc/FileSystem/RSSDirectory.h b/xbmc/FileSystem/RSSDirectory.h
index c9aea0db61..03a83d0085 100644
--- a/xbmc/FileSystem/RSSDirectory.h
+++ b/xbmc/FileSystem/RSSDirectory.h
@@ -22,18 +22,23 @@
#ifndef CRSSDIRECTORY_H_
#define CRSSDIRECTORY_H_
-#include "IDirectory.h"
+#include "IFileDirectory.h"
+#include "FileItem.h"
namespace DIRECTORY
{
- class CRSSDirectory : public IDirectory
+ class CRSSDirectory : public IFileDirectory
{
public:
CRSSDirectory();
virtual ~CRSSDirectory();
virtual bool GetDirectory(const CStdString& strPath, CFileItemList &items);
virtual bool IsAllowed(const CStdString &strFile) const { return true; };
+ virtual bool ContainsFiles(const CStdString& strPath);
virtual DIR_CACHE_TYPE GetCacheType(const CStdString& strPath) const { return DIR_CACHE_ALWAYS; };
+
+ CFileItemList m_items;
+ CStdString m_path;
};
}
diff --git a/xbmc/Settings.cpp b/xbmc/Settings.cpp
index c3eaa780a5..a8058daf69 100644
--- a/xbmc/Settings.cpp
+++ b/xbmc/Settings.cpp
@@ -103,9 +103,9 @@ void CSettings::Initialize()
m_stSettings.m_fZoomAmount = 1.0f;
m_stSettings.m_fPixelRatio = 1.0f;
- m_stSettings.m_pictureExtensions = ".png|.jpg|.jpeg|.bmp|.gif|.ico|.tif|.tiff|.tga|.pcx|.cbz|.zip|.cbr|.rar|.m3u|.dng|.nef|.cr2|.crw|.orf|.arw|.erf|.3fr|.dcr|.x3f|.mef|.raf|.mrw|.pef|.sr2";
- m_stSettings.m_musicExtensions = ".nsv|.m4a|.flac|.aac|.strm|.pls|.rm|.rma|.mpa|.wav|.wma|.ogg|.mp3|.mp2|.m3u|.mod|.amf|.669|.dmf|.dsm|.far|.gdm|.imf|.it|.m15|.med|.okt|.s3m|.stm|.sfx|.ult|.uni|.xm|.sid|.ac3|.dts|.cue|.aif|.aiff|.wpl|.ape|.mac|.mpc|.mp+|.mpp|.shn|.zip|.rar|.wv|.nsf|.spc|.gym|.adplug|.adx|.dsp|.adp|.ymf|.ast|.afc|.hps|.xsp|.xwav|.waa|.wvs|.wam|.gcm|.idsp|.mpdsp|.mss|.spt|.rsd|.mid|.kar|.sap|.cmc|.cmr|.dmc|.mpt|.mpd|.rmt|.tmc|.tm8|.tm2|.oga|.url|.pxml|.tta";
- m_stSettings.m_videoExtensions = ".m4v|.3g2|.3gp|.nsv|.tp|.ts|.ty|.strm|.pls|.rm|.rmvb|.m3u|.ifo|.mov|.qt|.divx|.xvid|.bivx|.vob|.nrg|.img|.iso|.pva|.wmv|.asf|.asx|.ogm|.m2v|.avi|.bin|.dat|.mpg|.mpeg|.mp4|.mkv|.avc|.vp3|.svq3|.nuv|.viv|.dv|.fli|.flv|.rar|.001|.wpl|.zip|.vdr|.dvr-ms|.xsp|.mts|.m2t|.m2ts|.evo|.ogv|.sdp|.avs|.rec|.url|.pxml|.vc1|.h264|.rcv";
+ m_stSettings.m_pictureExtensions = ".png|.jpg|.jpeg|.bmp|.gif|.ico|.tif|.tiff|.tga|.pcx|.cbz|.zip|.cbr|.rar|.m3u|.dng|.nef|.cr2|.crw|.orf|.arw|.erf|.3fr|.dcr|.x3f|.mef|.raf|.mrw|.pef|.sr2|.rss";
+ m_stSettings.m_musicExtensions = ".nsv|.m4a|.flac|.aac|.strm|.pls|.rm|.rma|.mpa|.wav|.wma|.ogg|.mp3|.mp2|.m3u|.mod|.amf|.669|.dmf|.dsm|.far|.gdm|.imf|.it|.m15|.med|.okt|.s3m|.stm|.sfx|.ult|.uni|.xm|.sid|.ac3|.dts|.cue|.aif|.aiff|.wpl|.ape|.mac|.mpc|.mp+|.mpp|.shn|.zip|.rar|.wv|.nsf|.spc|.gym|.adplug|.adx|.dsp|.adp|.ymf|.ast|.afc|.hps|.xsp|.xwav|.waa|.wvs|.wam|.gcm|.idsp|.mpdsp|.mss|.spt|.rsd|.mid|.kar|.sap|.cmc|.cmr|.dmc|.mpt|.mpd|.rmt|.tmc|.tm8|.tm2|.oga|.url|.pxml|.tta|.rss";
+ m_stSettings.m_videoExtensions = ".m4v|.3g2|.3gp|.nsv|.tp|.ts|.ty|.strm|.pls|.rm|.rmvb|.m3u|.ifo|.mov|.qt|.divx|.xvid|.bivx|.vob|.nrg|.img|.iso|.pva|.wmv|.asf|.asx|.ogm|.m2v|.avi|.bin|.dat|.mpg|.mpeg|.mp4|.mkv|.avc|.vp3|.svq3|.nuv|.viv|.dv|.fli|.flv|.rar|.001|.wpl|.zip|.vdr|.dvr-ms|.xsp|.mts|.m2t|.m2ts|.evo|.ogv|.sdp|.avs|.rec|.url|.pxml|.vc1|.h264|.rcv|.rss";
// internal music extensions
m_stSettings.m_musicExtensions += "|.sidstream|.oggstream|.nsfstream|.asapstream|.cdda";
diff --git a/xbmc/Util.cpp b/xbmc/Util.cpp
index 24421e3207..1c52528c6a 100644
--- a/xbmc/Util.cpp
+++ b/xbmc/Util.cpp
@@ -41,6 +41,7 @@
#include "FileSystem/MultiPathDirectory.h"
#include "FileSystem/DirectoryCache.h"
#include "FileSystem/SpecialProtocol.h"
+#include "FileSystem/RSSDirectory.h"
#include "ThumbnailCache.h"
#include "FileSystem/RarManager.h"
#include "FileSystem/CMythDirectory.h"
@@ -54,7 +55,6 @@
#include "cores/VideoRenderers/RenderManager.h"
#endif
#include "utils/RegExp.h"
-#include "utils/RssFeed.h"
#include "GUISettings.h"
#include "TextureManager.h"
#include "utils/fstrcmp.h"
@@ -183,12 +183,10 @@ CStdString CUtil::GetTitleFromPath(const CStdString& strFileNameAndPath, bool bI
if (url.GetProtocol() == "rss")
{
- url.SetProtocol("http");
- path = url.Get();
- CRssFeed feed;
- feed.Init(path);
- feed.ReadFeed();
- strFilename = feed.GetFeedTitle();
+ CRSSDirectory dir;
+ CFileItemList items;
+ if(dir.GetDirectory(strFileNameAndPath, items) && items.HasProperty("rss:title"))
+ return items.GetProperty("rss:title");
}
// LastFM
diff --git a/xbmc/utils/Makefile b/xbmc/utils/Makefile
index fbb60a46e9..d208da2501 100644
--- a/xbmc/utils/Makefile
+++ b/xbmc/utils/Makefile
@@ -46,7 +46,6 @@ SRCS=AlarmClock.cpp \
Fanart.cpp \
ScraperUrl.cpp \
MusicArtistInfo.cpp \
- RssFeed.cpp \
Mutex.cpp \
md5.cpp \
ArabicShaping.cpp \
diff --git a/xbmc/utils/RssFeed.cpp b/xbmc/utils/RssFeed.cpp
deleted file mode 100644
index a25a66fdd1..0000000000
--- a/xbmc/utils/RssFeed.cpp
+++ /dev/null
@@ -1,463 +0,0 @@
-/*
- * Copyright (C) 2005-2008 Team XBMC
- * http://www.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, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- */
-
-#include "RssFeed.h"
-#include "Settings.h"
-#include "Util.h"
-#include "FileSystem/FileCurl.h"
-#include "tinyXML/tinyxml.h"
-#include "HTMLUtil.h"
-#include "StringUtils.h"
-#include "VideoInfoTag.h"
-
-using namespace std;
-
-CRssFeed::CRssFeed()
-{
-
-}
-
-CRssFeed::~CRssFeed()
-{
-
-}
-
-bool CRssFeed::Init(const CStdString& strURL)
-{
- m_strURL = strURL;
-
- CLog::Log(LOGINFO, "Initializing feed: %s", m_strURL.c_str());
- return true;
-}
-
-time_t CRssFeed::ParseDate(const CStdString & strDate)
-{
- struct tm pubDate = {0};
- // TODO: Handle time zone
- strptime(strDate.c_str(), "%a, %d %b %Y %H:%M:%S", &pubDate);
- // Check the difference between the time of last check and time of the item
- return mktime(&pubDate);
-}
-
-// helper to avoid null dereference
-static inline CStdString S(const char * s)
-{
- if(s)
- return s;
- else
- return "";
-}
-
-void CRssFeed::ParseItemMRSS(CFileItemPtr& item, TiXmlElement* item_child, const CStdString& name, const CStdString& xmlns)
-{
- CVideoInfoTag* vtag = item->GetVideoInfoTag();
- CStdString text = S(item_child->GetText());
-
- if(name == "content")
- {
- const char* url = item_child->Attribute("url");
- const char* type = item_child->Attribute("type");
- const char* dur = item_child->Attribute("duration");
-
- if (url && item->m_strPath == "" && IsPathToMedia(url))
- item->m_strPath = url;
-
- if (type)
- {
- CStdString strType(type);
- item->SetContentType(strType);
- if (url && item->m_strPath.IsEmpty() &&
- (strType.Left(6).Equals("video/") ||
- strType.Left(6).Equals("audio/")
- ))
- item->m_strPath = url;
- }
-
- if(dur)
- StringUtils::SecondsToTimeString(atoi(dur), vtag->m_strRuntime);
-
- // Go over all child nodes of the media content and get the thumbnail
- TiXmlElement* media_content_child = item_child->FirstChildElement("media:thumbnail");
- if (media_content_child && media_content_child->Value() && strcmp(media_content_child->Value(), "media:thumbnail") == 0)
- {
- const char * url = media_content_child->Attribute("url");
- if (url && IsPathToThumbnail(url))
- item->SetThumbnailImage(url);
- }
- }
- else if(name == "thumbnail")
- {
- if(item_child->GetText() && IsPathToThumbnail(item_child->GetText()))
- item->SetThumbnailImage(item_child->GetText());
- else
- {
- const char * url = item_child->Attribute("url");
- if(url && IsPathToThumbnail(url))
- item->SetThumbnailImage(url);
- }
- }
- else if (name == "title")
- {
- if(text.IsEmpty())
- return;
-
- item->SetLabel(text);
- vtag->m_strTitle = text;
- }
- else if(name == "description")
- {
- if(text.IsEmpty())
- return;
-
- CStdString description = text;
- if(S(item_child->Attribute("type")) == "html")
- HTML::CHTMLUtil::RemoveTags(description);
- item->SetProperty("description", description);
- item->SetLabel2(description);
-
- vtag->m_strPlotOutline = description;
- vtag->m_strPlot = description;
- }
- else if(name == "category")
- {
- if(text.IsEmpty())
- return;
-
- vtag->m_strGenre = text;
- }
- else if(name == "rating")
- {
- if(text.IsEmpty())
- return;
- if(atof(text.c_str()) > 0.0f && atof(text.c_str()) <= 10.0f)
- vtag->m_fRating = (float)atof(text.c_str());
- else
- vtag->m_strMPAARating = text;
- }
- else if(name == "credit")
- {
- CStdString role = S(item_child->Attribute("role"));
- if(role == "director")
- vtag->m_strDirector += ", " + text;
- else if(role == "author")
- vtag->m_strWritingCredits += ", " + text;
- else if(role == "actor")
- {
- SActorInfo actor;
- actor.strName = text;
- vtag->m_cast.push_back(actor);
- }
- }
-
-}
-
-void CRssFeed::ParseItemItunes(CFileItemPtr& item, TiXmlElement* item_child, const CStdString& name, const CStdString& xmlns)
-{
- if(name == "image")
- {
- if(item_child->GetText() && IsPathToThumbnail(item_child->GetText()))
- item->SetThumbnailImage(item_child->GetText());
- else
- {
- const char * url = item_child->Attribute("href");
- if(url && IsPathToThumbnail(url))
- item->SetThumbnailImage(url);
- }
- }
- else if(name == "summary")
- {
- if(item_child->GetText())
- {
- CStdString description = item_child->GetText();
- item->SetProperty("description", description);
- item->SetLabel2(description);
- }
- }
- else if(name == "subtitle")
- {
- if(item_child->GetText())
- {
- CStdString description = item_child->GetText();
- item->SetProperty("description", description);
- item->SetLabel2(description);
- }
- }
- else if(name == "author")
- {
- if(item_child->GetText())
- item->SetProperty("author", item_child->GetText());
- }
- else if(name == "duration")
- {
- if(item_child->GetText())
- item->SetProperty("duration", item_child->GetText());
- }
- else if(name == "keywords")
- {
- if(item_child->GetText())
- item->SetProperty("keywords", item_child->GetText());
- }
-}
-
-void CRssFeed::ParseItemRSS(CFileItemPtr& item, TiXmlElement* item_child, const CStdString& name, const CStdString& xmlns)
-{
- if (name == "title")
- {
- if (item_child->GetText())
- item->SetLabel(item_child->GetText());
- }
- else if (name == "pubDate")
- {
- CDateTime pubDate(ParseDate(item_child->GetText()));
- item->m_dateTime = pubDate;
- }
- else if (name == "link")
- {
- if (item_child->GetText())
- {
- string strLink = item_child->GetText();
-
- string strPrefix = strLink.substr(0, strLink.find_first_of(":"));
- if (strPrefix == "rss")
- {
- // If this is an rss item, we treat it as another level in the directory
- item->m_bIsFolder = true;
- item->m_strPath = strLink;
- }
- else if (item->m_strPath == "" && IsPathToMedia(strLink))
- item->m_strPath = strLink;
- }
- }
- else if(name == "enclosure")
- {
- const char * url = item_child->Attribute("url");
- if (url && item->m_strPath.IsEmpty() && IsPathToMedia(url))
- item->m_strPath = url;
- const char * content_type = item_child->Attribute("type");
- if (content_type)
- {
- item->SetContentType(content_type);
- CStdString strContentType(content_type);
- if (url && item->m_strPath.IsEmpty() &&
- (strContentType.Left(6).Equals("video/") ||
- strContentType.Left(6).Equals("audio/")
- ))
- item->m_strPath = url;
- }
- const char * len = item_child->Attribute("length");
- if (len)
- item->m_dwSize = _atoi64(len);
- }
- else if(name == "description")
- {
- CStdString description = item_child->GetText();
- HTML::CHTMLUtil::RemoveTags(description);
- item->SetProperty("description", description);
- item->SetLabel2(description);
- }
- else if(name == "guid")
- {
- if (item->m_strPath.IsEmpty() && IsPathToMedia(item_child->Value()))
- {
- if(item_child->GetText())
- item->m_strPath = item_child->GetText();
- }
- }
-}
-
-void CRssFeed::ParseItemVoddler(CFileItemPtr& item, TiXmlElement* element, const CStdString& name, const CStdString& xmlns)
-{
- CVideoInfoTag* vtag = item->GetVideoInfoTag();
- CStdString text = S(element->GetText());
-
- if(name == "trailer")
- {
- vtag->m_strTrailer = text;
-
- CStdString type = S(element->Attribute("type"));
- if(item->m_strPath.IsEmpty())
- {
- item->m_strPath = text;
- item->SetContentType(type);
- }
- }
- else if(name == "year")
- vtag->m_iYear = atoi(text);
- else if(name == "tagline")
- vtag->m_strTagLine = text;
- else if(name == "posterwall")
- {
- const char* url = element->Attribute("url");
- if(url)
- item->SetProperty("fanart_image", url);
- else if(IsPathToThumbnail(text))
- item->SetProperty("fanart_image", text);
- }
-}
-
-bool CRssFeed::ReadFeed()
-{
- // Remove all previous items
- EnterCriticalSection(m_ItemVectorLock);
- items.Clear();
- LeaveCriticalSection(m_ItemVectorLock);
-
- CStdString strXML;
- XFILE::CFileCurl http;
- if (!http.Get(m_strURL, strXML))
- return false;
-
- TiXmlDocument xmlDoc;
- xmlDoc.Parse(strXML.c_str());
- if (xmlDoc.Error())
- CLog::Log(LOGERROR,"error parsing xml doc from <%s>. error: <%d>", m_strURL.c_str(), xmlDoc.ErrorId());
-
- TiXmlElement* rssXmlNode = xmlDoc.RootElement();
-
- if (!rssXmlNode)
- return false;
-
- CStdString strMediaThumbnail ;
-
- TiXmlHandle docHandle( &xmlDoc );
- TiXmlElement* channelXmlNode = docHandle.FirstChild( "rss" ).FirstChild( "channel" ).Element();
- if (channelXmlNode)
- {
- TiXmlElement* aNode = channelXmlNode->FirstChildElement("title");
- if (aNode && !aNode->NoChildren())
- m_strTitle = aNode->FirstChild()->Value();
-
- aNode = channelXmlNode->FirstChildElement("itunes:summary");
- if (aNode && !aNode->NoChildren())
- m_strDescription = aNode->FirstChild()->Value();
-
- if (m_strDescription.IsEmpty())
- {
- aNode = channelXmlNode->FirstChildElement("description");
- if (aNode && !aNode->NoChildren())
- m_strDescription = aNode->FirstChild()->Value();
- }
-
- // Get channel thumbnail
- TiXmlHandle chanHandle( channelXmlNode );
- aNode = chanHandle.FirstChild("image").FirstChild("url").Element();
- if (aNode && !aNode->NoChildren())
- strMediaThumbnail = aNode->FirstChild()->Value();
-
- if (strMediaThumbnail.IsEmpty() || !IsPathToThumbnail(strMediaThumbnail))
- {
- aNode = chanHandle.FirstChild("itunes:image").Element();
- if (aNode && !aNode->NoChildren())
- strMediaThumbnail = aNode->FirstChild()->Value();
- }
- }
- else
- return false;
-
- TiXmlElement* child = NULL;
- TiXmlElement* item_child = NULL;
- for (child = channelXmlNode->FirstChildElement("item"); child; child = child->NextSiblingElement())
- {
- // Create new item,
- CFileItemPtr item(new CFileItem());
-
- for (item_child = child->FirstChildElement(); item_child; item_child = item_child->NextSiblingElement())
- {
- CStdString name = item_child->Value();
- CStdString xmlns;
- int pos = name.Find(':');
- if(pos >= 0)
- {
- xmlns = name.Left(pos);
- name.Delete(0, pos+1);
- }
-
- if(xmlns == "media")
- ParseItemMRSS(item, item_child, name, xmlns);
- else if (xmlns == "itunes")
- ParseItemItunes(item, item_child, name, xmlns);
- else if (xmlns == "voddler")
- ParseItemVoddler(item, item_child, name, xmlns);
- else
- ParseItemRSS(item, item_child, name, xmlns);
-
- } // for item
-
- if(item->HasVideoInfoTag())
- {
- item->GetVideoInfoTag()->m_strDirector.Delete(0, 2);
- item->GetVideoInfoTag()->m_strWritingCredits.Delete(0, 2);
- }
-
- item->SetProperty("isrss", "1");
- item->SetProperty("chanthumb",strMediaThumbnail);
-
- if (!item->m_strPath.IsEmpty())
- {
- EnterCriticalSection(m_ItemVectorLock);
- items.Add(item);
- LeaveCriticalSection(m_ItemVectorLock);
- }
- }
-
- return true;
-}
-
-bool CRssFeed::IsPathToMedia(const CStdString& strPath )
-{
- CStdString extension;
- CUtil::GetExtension(strPath, extension);
-
- if (extension.IsEmpty())
- return false;
-
- extension.ToLower();
-
- if (g_stSettings.m_videoExtensions.Find(extension) != -1)
- return true;
-
- if (g_stSettings.m_musicExtensions.Find(extension) != -1)
- return true;
-
- if (g_stSettings.m_pictureExtensions.Find(extension) != -1)
- return true;
-
- return false;
-}
-
-bool CRssFeed::IsPathToThumbnail(const CStdString& strPath )
-{
- // Currently just check if this is an image, maybe we will add some
- // other checks later
- CStdString extension;
- CUtil::GetExtension(strPath, extension);
-
- if (extension.IsEmpty())
- return false;
-
- extension.ToLower();
-
- if (g_stSettings.m_pictureExtensions.Find(extension) != -1)
- return true;
-
- return false;
-}
-
diff --git a/xbmc/utils/RssFeed.h b/xbmc/utils/RssFeed.h
deleted file mode 100644
index c18db27e37..0000000000
--- a/xbmc/utils/RssFeed.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2005-2008 Team XBMC
- * http://www.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, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- */
-
-#ifndef RSS_FEED_H_
-#define RSS_FEED_H_
-
-#include <string>
-#include <vector>
-
-#include <time.h>
-
-#include "FileItem.h"
-
-class TiXmlElement;
-
-/**
- * The purpose of this class is to describe an RSS feed
- */
-class CRssFeed
-{
-public:
- CRssFeed();
- virtual ~CRssFeed();
-
- bool Init(const CStdString& strURL);
- void GetItemList(CFileItemList &feedItems)
- {
- for (int i = 0; i < items.Size(); i++) {
- feedItems.Add(items[i]);
- }
- }
-
- const CStdString& GetUrl() { return m_strURL; }
- const CStdString& GetFeedTitle() { return m_strTitle; }
-
- bool ReadFeed();
-
-private:
- static time_t ParseDate(const CStdString & strDate);
-
- static void ParseItemRSS (CFileItemPtr& item, TiXmlElement* element, const CStdString& name, const CStdString& xmlns);
- static void ParseItemMRSS (CFileItemPtr& item, TiXmlElement* element, const CStdString& name, const CStdString& xmlns);
- static void ParseItemItunes(CFileItemPtr& item, TiXmlElement* element, const CStdString& name, const CStdString& xmlns);
- static void ParseItemVoddler(CFileItemPtr& item, TiXmlElement* element, const CStdString& name, const CStdString& xmlns);
- static bool IsPathToMedia(const CStdString& strPath );
- static bool IsPathToThumbnail(const CStdString& strPath );
-
- CFileItemList items;
-
- // Lock that protects the feed vector
- CCriticalSection m_ItemVectorLock;
-
- CStdString m_strURL;
-
- // Channel information
- CStdString m_strTitle;
- CStdString m_strAuthor;
- CStdString m_strLink;
- CStdString m_strGuid; // globally unique identifier of the item in the entire feed
- CStdString m_strDescription;
- CStdString m_strThumbnail;
-};
-
-
-#endif /*RSS_FEED_H_*/