diff options
-rw-r--r-- | project/VS2008Express/XBMC.vcproj | 8 | ||||
-rw-r--r-- | xbmc/FileItem.cpp | 8 | ||||
-rw-r--r-- | xbmc/FileItem.h | 1 | ||||
-rw-r--r-- | xbmc/FileSystem/FactoryDirectory.cpp | 2 | ||||
-rw-r--r-- | xbmc/FileSystem/FactoryFileDirectory.cpp | 5 | ||||
-rw-r--r-- | xbmc/FileSystem/RSSDirectory.cpp | 444 | ||||
-rw-r--r-- | xbmc/FileSystem/RSSDirectory.h | 9 | ||||
-rw-r--r-- | xbmc/Settings.cpp | 6 | ||||
-rw-r--r-- | xbmc/Util.cpp | 12 | ||||
-rw-r--r-- | xbmc/utils/Makefile | 1 | ||||
-rw-r--r-- | xbmc/utils/RssFeed.cpp | 463 | ||||
-rw-r--r-- | xbmc/utils/RssFeed.h | 83 |
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_*/ |