|
MythTV
0.26-pre
|
00001 // Program Name: upnpcdsvideo.cpp 00002 // 00003 // Purpose - UPnP Content Directory Extension for MythVideo Videos 00004 // 00006 00007 // POSIX headers 00008 #include <limits.h> 00009 00010 // Qt headers 00011 #include <QFileInfo> 00012 00013 // MythTV headers 00014 #include "upnpcdsvideo.h" 00015 #include "httprequest.h" 00016 #include "mythmiscutil.h" 00017 #include "mythcorecontext.h" 00018 #include "storagegroup.h" 00019 00020 #define LOC QString("UPnpCDSVideo: ") 00021 #define LOC_WARN QString("UPnpCDSVideo, Warning: ") 00022 #define LOC_ERR QString("UPnpCDSVideo, Error: ") 00023 00024 UPnpCDSRootInfo UPnpCDSVideo::g_RootNodes[] = 00025 { 00026 { "All Videos", 00027 "*", 00028 "SELECT 0 as key, " 00029 "title as name, " 00030 "1 as children " 00031 "FROM videometadata " 00032 "%1 " 00033 "ORDER BY title", 00034 "", "title" } 00035 00036 }; 00037 00038 int UPnpCDSVideo::g_nRootCount = 1; 00039 00040 //int UPnpCDSVideo::g_nRootCount; 00041 //= sizeof( g_RootNodes ) / sizeof( UPnpCDSRootInfo ); 00042 00044 // 00046 00047 UPnpCDSRootInfo *UPnpCDSVideo::GetRootInfo( int nIdx ) 00048 { 00049 if ((nIdx >=0 ) && ( nIdx < g_nRootCount )) 00050 return &(g_RootNodes[ nIdx ]); 00051 00052 return NULL; 00053 } 00054 00056 // 00058 00059 int UPnpCDSVideo::GetRootCount() 00060 { 00061 return g_nRootCount; 00062 } 00063 00065 // 00067 00068 QString UPnpCDSVideo::GetTableName( QString sColumn ) 00069 { 00070 return "videometadata"; 00071 } 00072 00074 // 00076 00077 QString UPnpCDSVideo::GetItemListSQL( QString sColumn ) 00078 { 00079 return "SELECT intid, title, subtitle, filename, director, plot, " 00080 "rating, year, userrating, length, " 00081 "season, episode, coverfile, insertdate, host FROM videometadata"; 00082 00083 } 00084 00086 // 00088 00089 void UPnpCDSVideo::BuildItemQuery( MSqlQuery &query, const QStringMap &mapParams ) 00090 { 00091 int nVideoID = mapParams[ "Id" ].toInt(); 00092 00093 QString sSQL = QString( "%1 WHERE intid=:VIDEOID ORDER BY title DESC" ) 00094 .arg( GetItemListSQL( ) ); 00095 00096 query.prepare( sSQL ); 00097 00098 query.bindValue( ":VIDEOID", (int)nVideoID ); 00099 } 00100 00102 // 00104 00105 bool UPnpCDSVideo::IsBrowseRequestForUs( UPnpCDSRequest *pRequest ) 00106 { 00107 // ---------------------------------------------------------------------- 00108 // See if we need to modify the request for compatibility 00109 // ---------------------------------------------------------------------- 00110 00111 // ---------------------------------------------------------------------- 00112 // Xbox360 compatibility code. 00113 // ---------------------------------------------------------------------- 00114 00115 if (pRequest->m_eClient == CDS_ClientXBox && 00116 pRequest->m_sContainerID == "15" && 00117 gCoreContext->GetSetting("UPnP/WMPSource") == "1") 00118 { 00119 pRequest->m_sObjectId = "Videos/0"; 00120 00121 LOG(VB_UPNP, LOG_INFO, 00122 "UPnpCDSVideo::IsBrowseRequestForUs - Yes ContainerID == 15"); 00123 return true; 00124 } 00125 00126 if ((pRequest->m_sObjectId.isEmpty()) && 00127 (!pRequest->m_sContainerID.isEmpty())) 00128 pRequest->m_sObjectId = pRequest->m_sContainerID; 00129 00130 // ---------------------------------------------------------------------- 00131 // WMP11 compatibility code 00132 // 00133 // In this mode browsing for "Videos" is forced to either Videos (us) 00134 // or RecordedTV (handled by upnpcdstv) 00135 // 00136 // ---------------------------------------------------------------------- 00137 00138 if (pRequest->m_eClient == CDS_ClientWMP && 00139 pRequest->m_sContainerID == "13" && 00140 pRequest->m_nClientVersion < 12.0 && 00141 gCoreContext->GetSetting("UPnP/WMPSource") == "1") 00142 { 00143 pRequest->m_sObjectId = "Videos/0"; 00144 00145 LOG(VB_UPNP, LOG_INFO, 00146 "UPnpCDSVideo::IsBrowseRequestForUs - Yes ContainerID == 13"); 00147 return true; 00148 } 00149 00150 LOG(VB_UPNP, LOG_INFO, 00151 "UPnpCDSVideo::IsBrowseRequestForUs - Not sure... Calling base class."); 00152 00153 return UPnpCDSExtension::IsBrowseRequestForUs( pRequest ); 00154 } 00155 00157 // 00159 00160 bool UPnpCDSVideo::IsSearchRequestForUs( UPnpCDSRequest *pRequest ) 00161 { 00162 // ---------------------------------------------------------------------- 00163 // See if we need to modify the request for compatibility 00164 // ---------------------------------------------------------------------- 00165 00166 // ---------------------------------------------------------------------- 00167 // XBox 360 compatibility code 00168 // ---------------------------------------------------------------------- 00169 00170 00171 if (pRequest->m_eClient == CDS_ClientXBox && 00172 pRequest->m_sContainerID == "15" && 00173 gCoreContext->GetSetting("UPnP/WMPSource") == "1") 00174 { 00175 pRequest->m_sObjectId = "Videos/0"; 00176 00177 LOG(VB_UPNP, LOG_INFO, "UPnpCDSVideo::IsSearchRequestForUs... Yes."); 00178 00179 return true; 00180 } 00181 00182 if ((pRequest->m_sObjectId.isEmpty()) && 00183 (!pRequest->m_sContainerID.isEmpty())) 00184 pRequest->m_sObjectId = pRequest->m_sContainerID; 00185 00186 // ---------------------------------------------------------------------- 00187 00188 bool bOurs = UPnpCDSExtension::IsSearchRequestForUs( pRequest ); 00189 00190 // ---------------------------------------------------------------------- 00191 // WMP11 compatibility code 00192 // ---------------------------------------------------------------------- 00193 00194 if ( bOurs && pRequest->m_eClient == CDS_ClientWMP && 00195 pRequest->m_nClientVersion < 12.0 ) 00196 { 00197 if ( gCoreContext->GetSetting("UPnP/WMPSource") == "1") 00198 { 00199 pRequest->m_sObjectId = "Videos/0"; 00200 // -=>TODO: Not sure why this was added. 00201 pRequest->m_sParentId = "8"; 00202 } 00203 else 00204 bOurs = false; 00205 } 00206 00207 return bOurs; 00208 } 00209 00211 // 00213 00214 int UPnpCDSVideo::GetDistinctCount( UPnpCDSRootInfo *pInfo ) 00215 { 00216 int nCount = 0; 00217 00218 MSqlQuery query(MSqlQuery::InitCon()); 00219 00220 query.prepare("SELECT COUNT(*) FROM videometadata"); 00221 00222 if (query.exec() && query.next()) 00223 { 00224 nCount = query.value(0).toInt(); 00225 } 00226 00227 return nCount; 00228 } 00229 00230 00232 // 00234 00235 void UPnpCDSVideo::AddItem( const UPnpCDSRequest *pRequest, 00236 const QString &sObjectId, 00237 UPnpCDSExtensionResults *pResults, 00238 bool bAddRef, 00239 MSqlQuery &query ) 00240 { 00241 00242 int nVidID = query.value( 0).toInt(); 00243 QString sTitle = query.value( 1).toString(); 00244 QString sSubtitle = query.value( 2).toString(); 00245 QString sFilePath = query.value( 3).toString(); 00246 QString sDirector = query.value( 4).toString(); 00247 QString sPlot = query.value( 5).toString(); 00248 QString sRating = query.value( 6).toString(); 00249 // int nYear = query.value( 7).toInt(); 00250 // int nUserRating = query.value( 8).toInt(); 00251 int nLength = query.value( 9).toInt(); 00252 // int nSeason = query.value(10).toInt(); 00253 // int nEpisode = query.value(11).toInt(); 00254 QString sCoverArt = query.value(12).toString(); 00255 QDateTime dtInsertDate = query.value(13).toDateTime(); 00256 QString sHostName = query.value(14).toString(); 00257 00258 // ---------------------------------------------------------------------- 00259 // Cache Host ip Address & Port 00260 // ---------------------------------------------------------------------- 00261 00262 // If the host-name is empty then we assume it is our local host 00263 // otherwise, we look up the host's IP address and port. When the 00264 // client then trys to play the video it will be directed to the 00265 // host which actually has the content. 00266 if (!m_mapBackendIp.contains( sHostName )) 00267 { 00268 if (sHostName.isEmpty()) 00269 { 00270 m_mapBackendIp[sHostName] = 00271 gCoreContext->GetSetting( "BackendServerIP" ); 00272 } 00273 else 00274 { 00275 m_mapBackendIp[sHostName] = 00276 gCoreContext->GetSettingOnHost( "BackendServerIp", sHostName); 00277 } 00278 } 00279 00280 if (!m_mapBackendPort.contains( sHostName )) 00281 { 00282 if (sHostName.isEmpty()) 00283 { 00284 m_mapBackendPort[sHostName] = 00285 gCoreContext->GetSetting( "BackendStatusPort" ); 00286 } 00287 else 00288 { 00289 m_mapBackendPort[sHostName] = 00290 gCoreContext->GetSettingOnHost("BackendStatusPort", sHostName); 00291 } 00292 } 00293 00294 00295 // ---------------------------------------------------------------------- 00296 // Build Support Strings 00297 // ---------------------------------------------------------------------- 00298 00299 QString sName = sTitle; 00300 if( !sSubtitle.isEmpty() ) 00301 { 00302 sName += " - " + sSubtitle; 00303 } 00304 00305 QString sURIBase = QString( "http://%1:%2/Content/" ) 00306 .arg( m_mapBackendIp [sHostName] ) 00307 .arg( m_mapBackendPort[sHostName] ); 00308 00309 QString sURIParams = QString( "?Id=%1" ).arg( nVidID ); 00310 QString sId = QString( "Videos/0/item%1").arg( sURIParams ); 00311 00312 QString sParentID = "Videos/0"; 00313 00314 QString sAlbumArtURI= QString( "%1GetVideoArt%2") 00315 .arg( sURIBase ) 00316 .arg( sURIParams ); 00317 00318 CDSObject *pItem = CDSObject::CreateVideoItem( sId, sName, sParentID ); 00319 00320 pItem->m_bRestricted = false; 00321 pItem->m_bSearchable = true; 00322 pItem->m_sWriteStatus = "WRITABLE"; 00323 00324 pItem->SetPropValue( "longDescription", sPlot ); 00325 // ?? pItem->SetPropValue( "description" , sTitle ); 00326 pItem->SetPropValue( "director" , sDirector ); 00327 00328 pItem->SetPropValue( "genre" , "[Unknown Genre]" ); 00329 pItem->SetPropValue( "actor" , "[Unknown Author]" ); 00330 pItem->SetPropValue( "creator" , "[Unknown Creator]" ); 00331 pItem->SetPropValue( "album" , "[Unknown Album]" ); 00332 00333 //pItem->SetPropValue( "producer" , ); 00334 //pItem->SetPropValue( "rating" , ); 00335 //pItem->SetPropValue( "actor" , ); 00336 //pItem->SetPropValue( "publisher" , ); 00337 //pItem->SetPropValue( "language" , ); 00338 //pItem->SetPropValue( "relation" , ); 00339 //pItem->SetPropValue( "region" , ); 00340 00341 if ((sCoverArt != "") && (sCoverArt != "No Cover")) 00342 pItem->SetPropValue( "albumArtURI" , sAlbumArtURI); 00343 00344 if ( bAddRef ) 00345 { 00346 QString sRefId = QString( "%1/0/item%2").arg( m_sExtensionId ) 00347 .arg( sURIParams ); 00348 00349 pItem->SetPropValue( "refID", sRefId ); 00350 } 00351 00352 QString sFullFileName = sFilePath; 00353 if (!QFile::exists( sFullFileName )) 00354 { 00355 StorageGroup sgroup("Videos"); 00356 sFullFileName = sgroup.FindFile( sFullFileName ); 00357 } 00358 QFileInfo fInfo( sFullFileName ); 00359 00360 pItem->SetPropValue( "date", dtInsertDate.toString( "yyyy-MM-dd")); 00361 pResults->Add( pItem ); 00362 00363 // ---------------------------------------------------------------------- 00364 // Add Video Resource Element based on File extension (HTTP) 00365 // ---------------------------------------------------------------------- 00366 00367 QString sMimeType = HTTPRequest::GetMimeType( fInfo.suffix() ); 00368 00369 // If we are dealing with a Sony Blu-ray player then we fake the 00370 // MIME type to force the video to appear 00371 if ( pRequest->m_eClient == CDS_ClientSonyDB ) 00372 { 00373 sMimeType = "video/avi"; 00374 } 00375 00376 QString sProtocol = QString( "http-get:*:%1:DLNA.ORG_OP=01;DLNA.ORG_CI=0;" 00377 "DLNA.ORG_FLAGS=0150000000000000000000000000" 00378 "0000" ).arg( sMimeType ); 00379 QString sURI = QString( "%1GetVideo%2").arg( sURIBase ) 00380 .arg( sURIParams ); 00381 00382 Resource *pRes = pItem->AddResource( sProtocol, sURI ); 00383 00384 pRes->AddAttribute( "size" , QString("%1").arg(fInfo.size()) ); 00385 00386 QString sDur; 00387 sDur.sprintf("%02d:%02d:00", (nLength / 60), nLength % 60 ); 00388 00389 pRes->AddAttribute( "duration" , sDur ); 00390 }
1.7.6.1