2 * Copyright (C) 2005-2008 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
22 // RTVDirectory.cpp: implementation of the CRTVDirectory class.
24 //////////////////////////////////////////////////////////////////////
26 #include "RTVDirectory.h"
27 #include "utils/URIUtils.h"
28 #include "SectionLoader.h"
30 #include "tinyXML/tinyxml.h"
33 using namespace XFILE;
37 #include "lib/libRTV/interface.h"
40 //////////////////////////////////////////////////////////////////////
41 // Construction/Destruction
42 //////////////////////////////////////////////////////////////////////
44 CRTVDirectory::CRTVDirectory(void)
46 CSectionLoader::Load("LIBRTV");
49 CRTVDirectory::~CRTVDirectory(void)
51 CSectionLoader::Unload("LIBRTV");
54 //*********************************************************************************************
55 bool CRTVDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items)
59 CStdString strRoot = strPath;
60 URIUtils::AddSlashAtEnd(strRoot);
62 // Host name is "*" so we try to discover all ReplayTVs. This requires some trickery but works.
63 if (url.GetHostName() == "*")
65 // Check to see whether the URL's path is blank or "Video"
66 if (url.GetFileName() == "" || url.GetFileName() == "Video")
68 int iOldSize=items.Size();
69 struct RTV * rtv = NULL;
72 // Request that all ReplayTVs on the LAN identify themselves. Each ReplayTV
73 // is given 3000ms to respond to the request. rtv_discovery returns an array
74 // of structs containing the IP and friendly name of all ReplayTVs found on the LAN.
75 // For some reason, DVArchive doesn't respond to this request (probably only responds
76 // to requests from an IP address of a real ReplayTV).
77 numRTV = rtv_discovery(&rtv, 3000);
79 // Run through the array and add the ReplayTVs found as folders in XBMC.
80 // We must add the IP of each ReplayTV as if it is a file name at the end of a the
81 // auto-discover URL--e.g. rtv://*/192.168.1.100--because XBMC does not permit
82 // dyamically added shares and will not play from them. This little trickery is
83 // the best workaround I could come up with.
84 for (int i = 0; i < numRTV; i++)
86 CFileItemPtr pItem(new CFileItem(rtv[i].friendlyName));
87 // This will keep the /Video or / and allow one to set up an auto ReplayTV
88 // share of either type--simple file listing or ReplayGuide listing.
89 pItem->SetPath(strRoot + rtv[i].hostname);
90 pItem->m_bIsFolder = true;
91 pItem->SetLabelPreformated(true);
95 return (items.Size()>iOldSize);
96 // Else the URL's path should be an IP address of the ReplayTV
100 CStdString strURL, strRTV;
103 // Isolate the IP from the URL and replace the "*" with the real IP
104 // of the ReplayTV. E.g., rtv://*/Video/192.168.1.100/ becomes
105 // rtv://192.168.1.100/Video/ . This trickery makes things work.
106 strURL = strRoot.TrimRight('/');
107 pos = strURL.ReverseFind('/');
108 strRTV = strURL.Left(pos + 1);
109 strRTV.Replace("*", strURL.Mid(pos + 1));
112 // Force the newly constructed share into the right variables to
113 // be further processed by the remainder of GetDirectory.
119 // Allow for ReplayTVs on ports other than 80
120 CStdString strHostAndPort;
121 strHostAndPort = url.GetHostName();
125 sprintf(buffer,"%i",url.GetPort());
126 strHostAndPort += ':';
127 strHostAndPort += buffer;
130 // No path given, list shows from ReplayGuide
131 if (url.GetFileName() == "")
133 unsigned char * data = NULL;
135 // Get the RTV guide data in XML format
136 rtv_get_guide_xml(&data, strHostAndPort.c_str());
138 // Begin parsing the XML data
139 TiXmlDocument xmlDoc;
140 xmlDoc.Parse( (const char *) data );
141 if ( xmlDoc.Error() )
146 TiXmlElement* pRootElement = xmlDoc.RootElement();
153 const TiXmlNode *pChild = pRootElement->FirstChild();
156 CStdString strTagName = pChild->Value();
158 if ( !strcmpi(strTagName.c_str(), "ITEM") )
160 const TiXmlNode *nameNode = pChild->FirstChild("DISPLAYNAME");
161 // const TiXmlNode *qualityNode = pChild->FirstChild("QUALITY");
162 const TiXmlNode *recordedNode = pChild->FirstChild("RECORDED");
163 const TiXmlNode *pathNode = pChild->FirstChild("PATH");
164 // const TiXmlNode *durationNode = pChild->FirstChild("DURATION");
165 const TiXmlNode *sizeNode = pChild->FirstChild("SIZE");
166 const TiXmlNode *atrbNode = pChild->FirstChild("ATTRIB");
168 SYSTEMTIME dtDateTime;
169 DWORD dwFileSize = 0;
170 memset(&dtDateTime, 0, sizeof(dtDateTime));
173 const char* szName = NULL;
176 szName = nameNode->FirstChild()->Value() ;
180 // Something went wrong, the recording has no name
186 // const char* szQuality = NULL;
189 // szQuality = qualityNode->FirstChild()->Value() ;
195 CStdString strRecorded = recordedNode->FirstChild()->Value();
196 int iYear, iMonth, iDay;
198 iYear = atoi(strRecorded.Left(4).c_str());
199 iMonth = atoi(strRecorded.Mid(5, 2).c_str());
200 iDay = atoi(strRecorded.Mid(8, 2).c_str());
201 dtDateTime.wYear = iYear;
202 dtDateTime.wMonth = iMonth;
203 dtDateTime.wDay = iDay;
205 int iHour, iMin, iSec;
206 iHour = atoi(strRecorded.Mid(11, 2).c_str());
207 iMin = atoi(strRecorded.Mid(14, 2).c_str());
208 iSec = atoi(strRecorded.Mid(17, 2).c_str());
209 dtDateTime.wHour = iHour;
210 dtDateTime.wMinute = iMin;
211 dtDateTime.wSecond = iSec;
215 const char* szPath = NULL;
218 szPath = pathNode->FirstChild()->Value() ;
222 // Something went wrong, the recording has no filename
228 // const char* szDuration = NULL;
231 // szDuration = durationNode->FirstChild()->Value() ;
235 // NOTE: Size here is actually just duration in minutes because
236 // filesize is not reported by the stripped down GuideParser I use
239 dwFileSize = atol( sizeNode->FirstChild()->Value() );
243 // NOTE: Not currently reported in the XML guide data, nor is it particularly
244 // needed unless someone wants to add the ability to sub-divide the recordings
245 // into categories, as on a real RTV.
249 attrib = atoi( atrbNode->FirstChild()->Value() );
252 bool bIsFolder(false);
253 if (attrib & FILE_ATTRIBUTE_DIRECTORY)
256 CFileItemPtr pItem(new CFileItem(szName));
257 pItem->m_dateTime=dtDateTime;
258 pItem->SetPath(strRoot + szPath);
259 // Hack to show duration of show in minutes as KB in XMBC because
260 // it doesn't currently permit showing duration in minutes.
261 // E.g., a 30 minute show will show as 29.3 KB in XBMC.
262 pItem->m_dwSize = dwFileSize * 1000;
263 pItem->m_bIsFolder = bIsFolder;
264 pItem->SetLabelPreformated(true);
268 pChild = pChild->NextSibling();
273 // Path given (usually Video), list filenames only
278 unsigned char * data;
280 unsigned long status;
282 // Return a listing of all files in the given path
283 status = rtv_list_files(&data, strHostAndPort.c_str(), url.GetFileName().c_str());
289 // Loop through the file list using pointers p and q, where p will point to the current
290 // filename and q will point to the next filename
294 // Look for the end of the current line of the file listing
296 // If found, replace the newline character with the NULL terminator
300 // Increment q so that it points to the next filename
302 // *p should be the current null-terminated filename in the list
305 // Only display MPEG files in XBMC (but not circular.mpg, as that is the RTV
306 // video buffer and XBMC may cause problems if it tries to play it)
307 if (strstr(p, ".mpg") && !strstr(p, "circular"))
309 CFileItemPtr pItem(new CFileItem(p));
310 pItem->SetPath(strRoot + p);
311 pItem->m_bIsFolder = false;
312 // The list returned by the RTV doesn't include file sizes, unfortunately
313 //pItem->m_dwSize = atol(szSize);
314 pItem->SetLabelPreformated(true);
319 // Point p to the next filename in the list and loop