00001
00002
00003
00004
00006
00007 #include "upnpcdsvideo.h"
00008 #include "httprequest.h"
00009 #include "upnpmedia.h"
00010
00011 #include <qfileinfo.h>
00012 #include <qregexp.h>
00013 #include <qurl.h>
00014 #include <qdir.h>
00015 #include <limits.h>
00016 #include "util.h"
00017
00018 #define LOC QString("UPnpCDSVideo: ")
00019 #define LOC_WARN QString("UPnpCDSVideo, Warning: ")
00020 #define LOC_ERR QString("UPnpCDSVideo, Error: ")
00021
00022 UPnpCDSRootInfo UPnpCDSVideo::g_RootNodes[] =
00023 {
00024 { "VideoRoot",
00025 "*",
00026 "SELECT 0 as key, "
00027 "title as name, "
00028 "1 as children "
00029 "FROM upnpmedia "
00030 "%1 "
00031 "ORDER BY title",
00032 "" }
00033
00034 };
00035
00036 int UPnpCDSVideo::g_nRootCount = 1;
00037
00038
00039
00040
00042
00044
00045 UPnpCDSRootInfo *UPnpCDSVideo::GetRootInfo( int nIdx )
00046 {
00047 if ((nIdx >=0 ) && ( nIdx < g_nRootCount ))
00048 return &(g_RootNodes[ nIdx ]);
00049
00050 return NULL;
00051 }
00052
00054
00056
00057 int UPnpCDSVideo::GetRootCount()
00058 {
00059 return g_nRootCount;
00060 }
00061
00063
00065
00066 QString UPnpCDSVideo::GetTableName( QString sColumn )
00067 {
00068 return "upnpmedia";
00069 }
00070
00072
00074
00075 QString UPnpCDSVideo::GetItemListSQL( QString sColumn )
00076 {
00077 return "SELECT intid, title, filepath, " \
00078 "itemtype, itemproperties, parentid, "\
00079 "coverart FROM upnpmedia WHERE class = 'VIDEO'";
00080 }
00081
00083
00085
00086 void UPnpCDSVideo::BuildItemQuery( MSqlQuery &query, const QStringMap &mapParams )
00087 {
00088 int nVideoID = mapParams[ "Id" ].toInt();
00089
00090 QString sSQL = QString( "%1 AND intid=:VIDEOID ORDER BY title DESC" )
00091 .arg( GetItemListSQL( ) );
00092
00093 query.prepare( sSQL );
00094
00095 query.bindValue( ":VIDEOID", (int)nVideoID );
00096 }
00097
00099
00101
00102 bool UPnpCDSVideo::IsBrowseRequestForUs( UPnpCDSRequest *pRequest )
00103 {
00104
00105
00106
00107
00108
00109
00110
00111
00112 if (pRequest->m_sContainerID == "15")
00113 {
00114 pRequest->m_sObjectId = "Videos/0";
00115
00116 VERBOSE( VB_UPNP, "UPnpCDSVideo::IsBrowseRequestForUs - Yes ContainerID == 15" );
00117 return true;
00118 }
00119
00120 if ((pRequest->m_sObjectId == "") && (pRequest->m_sContainerID != ""))
00121 pRequest->m_sObjectId = pRequest->m_sContainerID;
00122
00123
00124
00125
00126
00127 if (( pRequest->m_sObjectId == "13") &&
00128 ( gContext->GetSetting("UPnP/WMPSource") == "1"))
00129 {
00130 pRequest->m_sObjectId = "Videos/0";
00131
00132 VERBOSE( VB_UPNP, "UPnpCDSVideo::IsBrowseRequestForUs - Yes ContainerID == 13" );
00133 return true;
00134 }
00135
00136 VERBOSE( VB_UPNP, "UPnpCDSVideo::IsBrowseRequestForUs - Not sure... Calling base class." );
00137
00138 return UPnpCDSExtension::IsBrowseRequestForUs( pRequest );
00139 }
00140
00142
00144
00145 bool UPnpCDSVideo::IsSearchRequestForUs( UPnpCDSRequest *pRequest )
00146 {
00147
00148
00149
00150
00151
00152
00153
00154
00155 if (pRequest->m_sContainerID == "15")
00156 {
00157 pRequest->m_sObjectId = "Videos/0";
00158
00159 VERBOSE( VB_UPNP, "UPnpCDSVideo::IsSearchRequestForUs... Yes." );
00160
00161 return true;
00162 }
00163
00164 if ((pRequest->m_sObjectId == "") && (pRequest->m_sContainerID != ""))
00165 pRequest->m_sObjectId = pRequest->m_sContainerID;
00166
00167
00168
00169 bool bOurs = UPnpCDSExtension::IsSearchRequestForUs( pRequest );
00170
00171
00172
00173
00174
00175 if ( bOurs && ( pRequest->m_sObjectId == "0"))
00176 {
00177
00178 if ( gContext->GetSetting("UPnP/WMPSource") == "1")
00179 {
00180 pRequest->m_sObjectId = "Videos/0";
00181 pRequest->m_sParentId = "8";
00182 }
00183 else
00184 bOurs = false;
00185 }
00186
00187 return bOurs;
00188 }
00189
00191
00193
00194 int UPnpCDSVideo::GetDistinctCount( UPnpCDSRootInfo *pInfo )
00195 {
00196 int nCount = 0;
00197
00198 MSqlQuery query(MSqlQuery::InitCon());
00199
00200 query.prepare("SELECT COUNT(*) FROM upnpmedia WHERE class = 'VIDEO' "
00201 "AND parentid = :ROOTID");
00202
00203 query.bindValue(":ROOTID", STARTING_VIDEO_OBJECTID);
00204 query.exec();
00205
00206 if (query.size() > 0)
00207 {
00208 query.next();
00209 nCount = query.value(0).toInt();
00210 }
00211
00212 return nCount;
00213 }
00214
00216
00218
00219 UPnpCDSExtensionResults *UPnpCDSVideo::ProcessItem( UPnpCDSRequest *pRequest,
00220 UPnpCDSExtensionResults *pResults,
00221 QStringList &idPath )
00222 {
00223 pResults->m_nTotalMatches = 0;
00224 pResults->m_nUpdateID = 1;
00225
00226 if (pRequest->m_sObjectId.length() == 0)
00227 return pResults;
00228
00229 QStringList tokens = QStringList::split( "/", pRequest->m_sObjectId );
00230 QString sId = tokens.last();
00231
00232 if (sId.startsWith("Id"))
00233 sId = sId.right( sId.length() - 2);
00234
00235 switch( pRequest->m_eBrowseFlag )
00236 {
00237 case CDS_BrowseMetadata:
00238 {
00239
00240
00241
00242
00243 QStringMap mapParams;
00244
00245 mapParams.insert( "Id", sId );
00246
00247 MSqlQuery query(MSqlQuery::InitCon());
00248
00249 if (query.isConnected())
00250 {
00251 BuildItemQuery( query, mapParams );
00252 query.exec();
00253
00254 if (query.isActive() && query.size() > 0)
00255 {
00256 if ( query.next() )
00257 {
00258 AddItem( pRequest->m_sParentId, pResults, false, query );
00259 pResults->m_nTotalMatches = 1;
00260 }
00261 }
00262 }
00263
00264 break;
00265 }
00266
00267 case CDS_BrowseDirectChildren:
00268 {
00269 pRequest->m_sParentId = sId;
00270
00271 CreateItems( pRequest, pResults, 0, "", false );
00272
00273 break;
00274 }
00275 }
00276
00277 return pResults;
00278 }
00279
00281
00283
00284 void UPnpCDSVideo::CreateItems( UPnpCDSRequest *pRequest,
00285 UPnpCDSExtensionResults *pResults,
00286 int nNodeIdx,
00287 const QString &sKey,
00288 bool bAddRef )
00289 {
00290 pResults->m_nTotalMatches = 0;
00291 pResults->m_nUpdateID = 1;
00292 QString ParentClause;
00293
00294 UPnpCDSRootInfo *pInfo = GetRootInfo( nNodeIdx );
00295
00296 if (pInfo == NULL)
00297 return;
00298
00299 if (pRequest->m_nRequestedCount == 0)
00300 pRequest->m_nRequestedCount = SHRT_MAX;
00301
00302 MSqlQuery query(MSqlQuery::InitCon());
00303
00304 if (query.isConnected())
00305 {
00306 QString sWhere( "" );
00307
00308 if ( sKey.length() > 0)
00309 {
00310 sWhere = QString( "WHERE %1=:KEY " )
00311 .arg( pInfo->column );
00312 }
00313
00314 if (pRequest->m_sObjectId.startsWith("Videos", true))
00315 {
00316 if (pRequest->m_sParentId != "")
00317 {
00318 if (pRequest->m_sParentId == "Videos/0")
00319 {
00320 pRequest->m_sParentId = QString("%1")
00321 .arg(STARTING_VIDEO_OBJECTID);
00322 }
00323 }
00324 else
00325 {
00326 QStringList tokens = QStringList::split( "=", pRequest->m_sObjectId );
00327 pRequest->m_sParentId = tokens.last();
00328 }
00329
00330 if (pRequest->m_sSearchClass == "")
00331 ParentClause = " AND parentid = \"" + pRequest->m_sParentId + "\"";
00332 else
00333 pRequest->m_sParentId = "8";
00334
00335 if (pRequest->m_sObjectId.startsWith( "Videos/0", true))
00336 {
00337 pRequest->m_sObjectId = "Videos/0";
00338 }
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348 if ((pRequest->m_sParentId != "") && (pRequest->m_sParentId != "8"))
00349 pResults->m_nTotalMatches = GetCount( "parentid", pRequest->m_sParentId );
00350 }
00351 else
00352 VERBOSE( VB_UPNP, QString( "UPnpCDSVideo::CreateItems: ******* ParentID Does NOT Start with 'Videos' ParentId = {0}" )
00353 .arg( pRequest->m_sParentId ));
00354
00355 QString sSQL = QString( "%1 %2 LIMIT %3, %4" )
00356 .arg( GetItemListSQL( pInfo->column ) )
00357 .arg( sWhere + ParentClause )
00358 .arg( pRequest->m_nStartingIndex )
00359 .arg( pRequest->m_nRequestedCount );
00360
00361 query.prepare ( sSQL );
00362
00363 query.bindValue(":KEY", sKey );
00364 query.exec();
00365
00366 if (query.isActive() && query.size() > 0)
00367 {
00368 while(query.next())
00369 AddItem( pRequest->m_sObjectId, pResults, bAddRef, query );
00370
00371 }
00372 }
00373 }
00374
00376
00378
00379 void UPnpCDSVideo::AddItem( const QString &sObjectId,
00380 UPnpCDSExtensionResults *pResults,
00381 bool bAddRef,
00382 MSqlQuery &query )
00383 {
00384 int nVidID = query.value( 0).toInt();
00385 QString sTitle = QString::fromUtf8(query.value( 1).toString());
00386 QString sFileName = QString::fromUtf8(query.value( 2).toString());
00387 QString sItemType = query.value( 3).toString();
00388 QString sParentID = query.value( 5).toString();
00389 QString sCoverArt = query.value( 6).toString();
00390
00391
00392
00393
00394
00395
00396 QString sServerIp = gContext->GetSetting("BackendServerIp" );
00397 QString sPort = gContext->GetSetting("BackendStatusPort" );
00398
00399
00400
00401
00402
00403 QString sName = sTitle;
00404
00405 QString sURIBase = QString( "http://%1:%2/Myth/" )
00406 .arg( sServerIp )
00407 .arg( sPort );
00408
00409 QString sURIParams = QString( "/Id%1" ).arg( nVidID );
00410 QString sId = QString( "Videos/0/item%1").arg( sURIParams );
00411
00412 if (sParentID == QString("%1").arg(STARTING_VIDEO_OBJECTID))
00413 {
00414 sParentID = "Videos/0";
00415 }
00416 else
00417 {
00418 sParentID = QString( "Videos/0/item/Id%1")
00419 .arg( sParentID );
00420 }
00421
00422 QString sAlbumArtURI= QString( "%1GetVideoArt%2")
00423 .arg( sURIBase )
00424 .arg( sURIParams );
00425
00426 CDSObject *pItem = NULL;
00427
00428 if (sItemType == "FOLDER")
00429 {
00430 pItem = CDSObject::CreateStorageFolder( sId, sName, sParentID);
00431 pItem->SetChildCount( GetCount( "parentid",QString( "%1" ).arg( nVidID )) );
00432
00433 pItem->SetPropValue( "storageUsed", "0" );
00434 }
00435 else if (sItemType == "FILE" )
00436 pItem = CDSObject::CreateVideoItem( sId, sName, sParentID );
00437
00438 if (!pItem)
00439 {
00440 VERBOSE(VB_IMPORTANT, LOC_ERR + "AddItem(): " +
00441 QString("sItemType has unknown type '%1'").arg(sItemType));
00442
00443 return;
00444 }
00445
00446 pItem->m_bRestricted = false;
00447 pItem->m_bSearchable = true;
00448 pItem->m_sWriteStatus = "WRITABLE";
00449
00450 pItem->SetPropValue( "genre" , "[Unknown Genre]" );
00451 pItem->SetPropValue( "actor" , "[Unknown Author]" );
00452 pItem->SetPropValue( "creator" , "[Unknown Author]" );
00453 pItem->SetPropValue( "album" , "[Unknown Series]" );
00454
00455 if ((sCoverArt != "") && (sCoverArt != "No Cover"))
00456 pItem->SetPropValue( "albumArtURI" , sAlbumArtURI);
00457
00458 if ( bAddRef )
00459 {
00460 QString sRefId = QString( "%1/0/item%2").arg( m_sExtensionId )
00461 .arg( sURIParams );
00462
00463 pItem->SetPropValue( "refID", sRefId );
00464 }
00465
00466 QFileInfo fInfo( sFileName );
00467 QDateTime fDate = fInfo.lastModified();
00468
00469 pItem->SetPropValue( "date", fDate.toString( "yyyy-MM-dd"));
00470 pResults->Add( pItem );
00471
00472
00473
00474
00475
00476 QString sMimeType = HTTPRequest::GetMimeType( fInfo.extension( FALSE ));
00477 QString sProtocol = QString( "http-get:*:%1:DLNA.ORG_OP=01;DLNA.ORG_CI=0;"
00478 "DLNA.ORG_FLAGS=0150000000000000000000000000"
00479 "0000" ).arg( sMimeType );
00480 QString sURI = QString( "%1GetVideo%2").arg( sURIBase )
00481 .arg( sURIParams );
00482
00483 Resource *pRes = pItem->AddResource( sProtocol, sURI );
00484
00485 pRes->AddAttribute( "size" , QString("%1").arg(fInfo.size()) );
00486 pRes->AddAttribute( "duration" , "0:00:00.000" );
00487
00488 }