00001
00002
00003
00004
00005
00006
00007
00008
00010
00011
00012 #include <limits.h>
00013 #include <stdint.h>
00014
00015
00016 #include "upnpcdstv.h"
00017 #include "httprequest.h"
00018 #include "storagegroup.h"
00019 #include "mythmiscutil.h"
00020 #include "mythcorecontext.h"
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 UPnpCDSRootInfo UPnpCDSTv::g_RootNodes[] =
00041 {
00042 { "All Recordings",
00043 "*",
00044 "SELECT 0 as key, "
00045 "CONCAT( title, ': ', subtitle) as name, "
00046 "1 as children "
00047 "FROM recorded "
00048 "%1 "
00049 "ORDER BY starttime DESC",
00050 "", "starttime DESC" },
00051
00052 { "By Title",
00053 "title",
00054 "SELECT title as id, "
00055 "title as name, "
00056 "count( title ) as children "
00057 "FROM recorded "
00058 "%1 "
00059 "GROUP BY title "
00060 "ORDER BY title",
00061 "WHERE title=:KEY", "title" },
00062
00063 { "By Genre",
00064 "category",
00065 "SELECT category as id, "
00066 "category as name, "
00067 "count( category ) as children "
00068 "FROM recorded "
00069 "%1 "
00070 "GROUP BY category "
00071 "ORDER BY category",
00072 "WHERE category=:KEY", "category" },
00073
00074 { "By Date",
00075 "DATE_FORMAT(starttime, '%Y-%m-%d')",
00076 "SELECT DATE_FORMAT(starttime, '%Y-%m-%d') as id, "
00077 "DATE_FORMAT(starttime, '%Y-%m-%d %W') as name, "
00078 "count( DATE_FORMAT(starttime, '%Y-%m-%d %W') ) as children "
00079 "FROM recorded "
00080 "%1 "
00081 "GROUP BY name "
00082 "ORDER BY starttime DESC",
00083 "WHERE DATE_FORMAT(starttime, '%Y-%m-%d') =:KEY", "starttime DESC" },
00084
00085 { "By Channel",
00086 "chanid",
00087 "SELECT channel.chanid as id, "
00088 "CONCAT(channel.channum, ' ', channel.callsign) as name, "
00089 "count( channum ) as children "
00090 "FROM channel "
00091 "INNER JOIN recorded ON channel.chanid = recorded.chanid "
00092 "%1 "
00093 "GROUP BY name "
00094 "ORDER BY channel.chanid",
00095 "WHERE channel.chanid=:KEY", ""},
00096
00097 { "By Group",
00098 "recgroup",
00099 "SELECT recgroup as id, "
00100 "recgroup as name, count( recgroup ) as children "
00101 "FROM recorded "
00102 "%1 "
00103 "GROUP BY recgroup "
00104 "ORDER BY recgroup",
00105 "WHERE recgroup=:KEY", "recgroup" }
00106 };
00107
00108 int UPnpCDSTv::g_nRootCount = sizeof( g_RootNodes ) / sizeof( UPnpCDSRootInfo );
00109
00111
00113
00114 UPnpCDSRootInfo *UPnpCDSTv::GetRootInfo( int nIdx )
00115 {
00116 if ((nIdx >=0 ) && ( nIdx < g_nRootCount ))
00117 return &(g_RootNodes[ nIdx ]);
00118
00119 return NULL;
00120 }
00121
00123
00125
00126 int UPnpCDSTv::GetRootCount()
00127 {
00128 return g_nRootCount;
00129 }
00130
00132
00134
00135 QString UPnpCDSTv::GetTableName( QString )
00136 {
00137 return "recorded";
00138 }
00139
00141
00143
00144 QString UPnpCDSTv::GetItemListSQL( QString )
00145 {
00146 return "SELECT chanid, starttime, endtime, title, " \
00147 "subtitle, description, category, " \
00148 "hostname, recgroup, filesize, " \
00149 "basename, progstart, progend, " \
00150 "storagegroup " \
00151 "FROM recorded ";
00152 }
00153
00155
00157
00158 void UPnpCDSTv::BuildItemQuery( MSqlQuery &query, const QStringMap &mapParams )
00159 {
00160 int nChanId = mapParams[ "ChanId" ].toInt();
00161 QString sStartTime = mapParams[ "StartTime" ];
00162
00163 QString sSQL = QString("%1 WHERE chanid=:CHANID AND starttime=:STARTTIME ")
00164 .arg( GetItemListSQL() );
00165
00166 query.prepare( sSQL );
00167
00168 query.bindValue(":CHANID" , (int)nChanId );
00169 query.bindValue(":STARTTIME", sStartTime );
00170 }
00171
00173
00175
00176 bool UPnpCDSTv::IsBrowseRequestForUs( UPnpCDSRequest *pRequest )
00177 {
00178
00179
00180
00181
00182
00183
00184
00185
00186 if (pRequest->m_eClient == CDS_ClientXBox &&
00187 pRequest->m_sContainerID == "15" &&
00188 gCoreContext->GetSetting("UPnP/WMPSource") != "1")
00189 {
00190 pRequest->m_sObjectId = "Videos/0";
00191
00192 LOG(VB_UPNP, LOG_INFO,
00193 "UPnpCDSTv::IsBrowseRequestForUs - Yes ContainerID == 15");
00194 return true;
00195 }
00196
00197
00198
00199
00200 if (pRequest->m_eClient == CDS_ClientWMP &&
00201 pRequest->m_nClientVersion < 12.0 &&
00202 pRequest->m_sContainerID == "13" &&
00203 gCoreContext->GetSetting("UPnP/WMPSource") != "1")
00204 {
00205 pRequest->m_sObjectId = "RecTv/0";
00206
00207 LOG(VB_UPNP, LOG_INFO,
00208 "UPnpCDSTv::IsBrowseRequestForUs - Yes, ObjectId == 13");
00209 return true;
00210 }
00211
00212 LOG(VB_UPNP, LOG_INFO,
00213 "UPnpCDSTv::IsBrowseRequestForUs - Not sure... Calling base class.");
00214
00215 return UPnpCDSExtension::IsBrowseRequestForUs( pRequest );
00216 }
00217
00219
00221
00222 bool UPnpCDSTv::IsSearchRequestForUs( UPnpCDSRequest *pRequest )
00223 {
00224
00225
00226
00227
00228
00229
00230
00231
00232 if (pRequest->m_eClient == CDS_ClientXBox &&
00233 pRequest->m_sContainerID == "15" &&
00234 gCoreContext->GetSetting("UPnP/WMPSource") != "1")
00235 {
00236 pRequest->m_sObjectId = "Videos/0";
00237
00238 LOG(VB_UPNP, LOG_INFO, "UPnpCDSTv::IsSearchRequestForUs... Yes.");
00239
00240 return true;
00241 }
00242
00243
00244 if ((pRequest->m_sObjectId.isEmpty()) &&
00245 (!pRequest->m_sContainerID.isEmpty()))
00246 pRequest->m_sObjectId = pRequest->m_sContainerID;
00247
00248
00249
00250 bool bOurs = UPnpCDSExtension::IsSearchRequestForUs( pRequest );
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260 if ( bOurs && pRequest->m_eClient == CDS_ClientWMP &&
00261 pRequest->m_nClientVersion < 12.0)
00262 {
00263
00264 if ( gCoreContext->GetSetting("UPnP/WMPSource") != "1")
00265 {
00266 pRequest->m_sObjectId = "RecTv/0";
00267
00268 pRequest->m_sParentId = '8';
00269 }
00270 else
00271 bOurs = false;
00272 }
00273
00274 return bOurs;
00275 }
00276
00278
00280
00281 void UPnpCDSTv::AddItem( const UPnpCDSRequest *pRequest,
00282 const QString &sObjectId,
00283 UPnpCDSExtensionResults *pResults,
00284 bool bAddRef,
00285 MSqlQuery &query )
00286 {
00287 int nChanid = query.value( 0).toInt();
00288 QDateTime dtStartTime = query.value( 1).toDateTime();
00289 QDateTime dtEndTime = query.value( 2).toDateTime();
00290 QString sTitle = query.value( 3).toString();
00291 QString sSubtitle = query.value( 4).toString();
00292 QString sDescription = query.value( 5).toString();
00293 QString sCategory = query.value( 6).toString();
00294 QString sHostName = query.value( 7).toString();
00295 QString sRecGroup = query.value( 8).toString();
00296 uint64_t nFileSize = query.value( 9).toULongLong();
00297 QString sBaseName = query.value(10).toString();
00298
00299 QDateTime dtProgStart = query.value(11).toDateTime();
00300 QDateTime dtProgEnd = query.value(12).toDateTime();
00301 QString sStorageGrp = query.value(13).toString();
00302
00303
00304
00305
00306
00307 if (!m_mapBackendIp.contains( sHostName ))
00308 m_mapBackendIp[ sHostName ] = gCoreContext->GetSettingOnHost( "BackendServerIp", sHostName);
00309
00310 if (!m_mapBackendPort.contains( sHostName ))
00311 m_mapBackendPort[ sHostName ] = gCoreContext->GetSettingOnHost("BackendStatusPort", sHostName);
00312
00313
00314
00315
00316
00317 QString sName = sTitle + ": " + (sSubtitle.isEmpty() ? sDescription.left(128) : sSubtitle);
00318
00319 QString sURIBase = QString( "http://%1:%2/Content/" )
00320 .arg( m_mapBackendIp [ sHostName ] )
00321 .arg( m_mapBackendPort[ sHostName ] );
00322
00323 QString sURIParams = QString( "?ChanId=%1&StartTime=%2" )
00324 .arg( nChanid )
00325 .arg( dtStartTime.toUTC().toString(Qt::ISODate));
00326
00327 QString sId = QString( "RecTv/0/item%1")
00328 .arg( sURIParams );
00329
00330 CDSObject *pItem = CDSObject::CreateVideoItem( sId,
00331 sName,
00332 sObjectId );
00333 pItem->m_bRestricted = false;
00334 pItem->m_bSearchable = true;
00335 pItem->m_sWriteStatus = "WRITABLE";
00336
00337 if ( bAddRef )
00338 {
00339 QString sRefId = QString( "%1/0/item%2")
00340 .arg( m_sExtensionId )
00341 .arg( sURIParams );
00342
00343 pItem->SetPropValue( "refID", sRefId );
00344 }
00345
00346 pItem->SetPropValue( "genre" , sCategory );
00347 pItem->SetPropValue( "longDescription", sDescription );
00348 pItem->SetPropValue( "description" , sSubtitle );
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364 pItem->SetPropValue( "creator" , "[Unknown Author]" );
00365 pItem->SetPropValue( "artist" , "[Unknown Author]" );
00366 pItem->SetPropValue( "album" , "[Unknown Series]" );
00367 pItem->SetPropValue( "actor" , "[Unknown Author]" );
00368 pItem->SetPropValue( "date" , dtStartTime.toString(Qt::ISODate));
00369
00370 pResults->Add( pItem );
00371
00372
00373
00374
00375
00376 StorageGroup sg(sStorageGrp, sHostName);
00377 QString sFilePath = sg.FindFile(sBaseName);
00378 QString sMimeType;
00379
00380 if ( QFile::exists(sFilePath) )
00381 sMimeType = HTTPRequest::TestMimeType( sFilePath );
00382 else
00383 sMimeType = HTTPRequest::TestMimeType( sBaseName );
00384
00385
00386
00387
00388
00389 if (pRequest->m_eClient == CDS_ClientWMP &&
00390 pRequest->m_nClientVersion >= 12.0)
00391 {
00392 sMimeType = "video/x-ms-dvr";
00393 }
00394
00395
00396
00397 if ( pRequest->m_eClient == CDS_ClientSonyDB )
00398 {
00399 sMimeType = "video/avi";
00400 }
00401
00402
00403
00404 QString sProtocol = QString( "http-get:*:%1:DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01500000000000000000000000000000" ).arg( sMimeType );
00405 QString sURI = QString( "%1GetRecording%2").arg( sURIBase )
00406 .arg( sURIParams );
00407
00408
00409
00410 if (sMimeType == "video/mpeg")
00411 {
00412 sProtocol += ";DLNA.ORG_PN=MPEG_TS_SD_NA_ISO";
00413 }
00414
00415 Resource *pRes = pItem->AddResource( sProtocol, sURI );
00416
00417 uint uiStart = dtProgStart.toTime_t();
00418 uint uiEnd = dtProgEnd.toTime_t();
00419 uint uiDur = uiEnd - uiStart;
00420
00421 MSqlQuery query2(MSqlQuery::InitCon());
00422 query2.prepare( "SELECT data FROM recordedmarkup WHERE chanid=:CHANID AND "
00423 "starttime=:STARTTIME AND type = 33" );
00424 query2.bindValue(":CHANID", (int)nChanid);
00425 query2.bindValue(":STARTTIME", dtProgStart.toString("yyyy/MM/dd hh:mm:ss"));
00426 if (query2.exec() && query2.next())
00427 uiDur = query2.value(0).toUInt() / 1000;
00428
00429 QString sDur;
00430
00431 sDur.sprintf("%02d:%02d:%02d",
00432 (uiDur / 3600) % 24,
00433 (uiDur / 60) % 60,
00434 uiDur % 60);
00435
00436 LOG(VB_UPNP, LOG_DEBUG, "Duration: " + sDur );
00437
00438 pRes->AddAttribute( "duration" , sDur );
00439 pRes->AddAttribute( "size" , QString::number( nFileSize) );
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461 sURI = QString( "%1GetPreviewImage%2%3").arg( sURIBase )
00462 .arg( sURIParams )
00463 .arg( "&Width=160" );
00464
00465 pItem->SetPropValue( "albumArtURI", sURI );
00466 Property *pProp = pItem->GetProperty("albumArtURI");
00467 if (pProp)
00468 {
00469 pProp->AddAttribute("dlna:profileID", "PNG_TN");
00470 pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0");
00471
00472 }
00473
00474 }
00475
00476