Ticket #8801: upnp_video.patch

File upnp_video.patch, 35.6 KB (added by mattpyne@…, 14 years ago)

Patch for UPnP mythvideo support

  • programs/mythbackend/mythxml.cpp

     
    862862
    863863    MSqlQuery query(MSqlQuery::InitCon());
    864864
    865     query.prepare("SELECT coverart FROM upnpmedia WHERE intid = :ITEMID");
     865    query.prepare("SELECT coverfile FROM videometadata WHERE intid = :ITEMID");
    866866    query.bindValue(":ITEMID", sId);
    867867
    868868    if (!query.exec())
     
    885885        return;
    886886    }
    887887
     888    // ----------------------------------------------------------------------
     889    // Not there? Perhaps we need to look in a storage group?
     890    // ----------------------------------------------------------------------
     891    StorageGroup sgroup("Coverart");
     892        sFileName = sgroup.FindRecordingFile( sFileName );
     893
     894        if (sFileName != "")
     895        {
     896        VERBOSE(VB_IMPORTANT,
     897                QString("Found coverart '%1'").arg(sFileName));
     898
     899                pRequest->m_eResponseType   = ResponseTypeFile;
     900        pRequest->m_nResponseStatus = 200;
     901        pRequest->m_sFileName = sFileName;
     902        return;
     903        }
     904
     905        VERBOSE(VB_IMPORTANT,
     906                QString("Not found '%1'").arg(sFileName));
     907
    888908}
    889909
    890910void MythXML::GetAlbumArt( HTTPRequest *pRequest )
     
    17181738
    17191739    if (pData == NULL)
    17201740    {
    1721         QString sBasePath = "";
    1722 
    17231741        // ------------------------------------------------------------------
    17241742        // Load Track's FileName
    17251743        // ------------------------------------------------------------------
     
    17281746
    17291747        if (query.isConnected())
    17301748        {
    1731             query.prepare("SELECT filepath FROM upnpmedia WHERE intid = :KEY" );
     1749            query.prepare("SELECT filename FROM videometadata WHERE intid = :KEY" );
    17321750            query.bindValue(":KEY", sId );
    17331751
    17341752            if (!query.exec())
     
    17391757
    17401758            if (query.next())
    17411759            {
    1742                 pRequest->m_sFileName = QString( "%1/%2" ).arg( sBasePath )
    1743                                         .arg( query.value(0).toString() );
     1760                                QString sFileName = query.value(0).toString();
     1761
     1762                                if (!QFile::exists( sFileName ))
     1763                                {
     1764                                        StorageGroup sgroup("Videos");
     1765                                        sFileName = sgroup.FindRecordingFile( sFileName );
     1766                                }
     1767
     1768                pRequest->m_sFileName = sFileName;
    17441769            }
    17451770        }
    17461771
  • programs/mythbackend/mediaserver.cpp

     
    1515#include "upnpcdstv.h"
    1616#include "upnpcdsmusic.h"
    1717#include "upnpcdsvideo.h"
    18 #include "upnpmedia.h"
    1918
    2019//////////////////////////////////////////////////////////////////////////////
    2120//////////////////////////////////////////////////////////////////////////////
     
    177176            VERBOSE(VB_UPNP, "MediaServer::Registering UPnpCDSVideo Extension");
    178177
    179178            RegisterExtension(new UPnpCDSVideo());
    180 
    181             upnpMedia = new UPnpMedia(true,true);
    182             //upnpMedia->BuildMediaMap();
    183179        }
    184180
    185181        // VERBOSE(VB_UPNP, QString( "MediaServer::Adding Context Listener" ));
  • programs/mythbackend/upnpcdsvideo.h

     
    11//////////////////////////////////////////////////////////////////////////////
    22// Program Name: upnpcdstv.h
    3 //
    4 // Purpose - uPnp Content Directory Extension for Video
    5 //
     3//                                                                           
     4// Purpose - uPnp Content Directory Extention for Recorded TV
     5//                                                                           
    66// Created By  : David Blain                    Created On : Jan. 24, 2005
    7 // Modified By :                                Modified On:
    8 //
     7// Modified By :                                Modified On:                 
     8//                                                                           
    99//////////////////////////////////////////////////////////////////////////////
    1010
    1111#ifndef UPnpCDSVIDEO_H_
    1212#define UPnpCDSVIDEO_H_
    1313
     14#include "mainserver.h"
    1415#include "upnpcds.h"
    15 
     16             
    1617typedef QMap<int, QString> IntMap;
    1718
    1819//////////////////////////////////////////////////////////////////////////////
     
    3132
    3233    protected:
    3334
    34         virtual UPnpCDSExtensionResults *ProcessItem( UPnpCDSRequest          *pRequest,
    35                                                       UPnpCDSExtensionResults *pResults,
    36                                                       QStringList             &idPath );
    37 
    38         virtual void             CreateItems   ( UPnpCDSRequest          *pRequest,
    39                                                  UPnpCDSExtensionResults *pResults,
    40                                                  int                      nNodeIdx,
    41                                                  const QString           &sKey,
    42                                                  bool                     bAddRef );
    43 
    4435        virtual bool             IsBrowseRequestForUs( UPnpCDSRequest *pRequest );
    4536        virtual bool             IsSearchRequestForUs( UPnpCDSRequest *pRequest );
    4637
     
    5142        virtual QString          GetTableName  ( QString sColumn );
    5243        virtual QString          GetItemListSQL( QString sColumn = "");
    5344
    54         virtual void             BuildItemQuery( MSqlQuery        &query,
     45        virtual void             BuildItemQuery( MSqlQuery        &query, 
    5546                                                 const QStringMap &mapParams );
    5647
    57                                                  
    5848        virtual void             AddItem( const UPnpCDSRequest    *pRequest,
    59                                           const QString           &sObjectId,
     49                                                                                  const QString           &sObjectId,
    6050                                          UPnpCDSExtensionResults *pResults,
    61                                           bool                     bAddRef,
     51                                          bool                     bAddRef, 
    6252                                          MSqlQuery               &query );
    6353
    6454    public:
  • programs/mythbackend/upnpmedia.h

     
    1 #ifndef UPnpMEDIA_H_
    2 #define UPnpMEDIA_H_
    3 
    4 #include <QString>
    5 
    6 #include "upnputil.h" // for QStringMap
    7 
    8 #define STARTING_VIDEO_OBJECTID 100000
    9 
    10 //////////////////////////////////////////////////////////////////////////////
    11 //
    12 //////////////////////////////////////////////////////////////////////////////
    13 
    14 class MSqlQuery;
    15 class UPnpMedia
    16 {
    17   private:
    18     QStringMap           m_mapTitleNames;
    19     QStringMap           m_mapCoverArt;
    20     //QString              sMediaType;
    21 
    22     void FillMetaMaps(void);
    23     int GetBaseCount(void);
    24     QString GetTitleName(QString fPath, QString fName);
    25     QString GetCoverArt(QString fPath);
    26 
    27     int buildFileList(QString directory, int rootID, int itemID,
    28                       MSqlQuery &query);
    29 
    30     void RunRebuildLoop(void);
    31     static void *doUPnpMediaThread(void *param);
    32 
    33   public:
    34     UPnpMedia(bool runthread, bool master);
    35     ~UPnpMedia() {};
    36 
    37     void SetMediaType(QString mediatype) { sMediaType = mediatype; }
    38 
    39     void BuildMediaMap(void);
    40     QString sMediaType;
    41 };
    42 
    43 #endif
  • programs/mythbackend/upnpcdsvideo.cpp

     
    11// Program Name: upnpcdsvideo.cpp
    2 //
     2//                                                                           
    33// Purpose - uPnp Content Directory Extension for MythVideo Videos
    4 //
     4//                                                                           
    55//////////////////////////////////////////////////////////////////////////////
    66
    77// POSIX headers
     
    1313// MythTV headers
    1414#include "upnpcdsvideo.h"
    1515#include "httprequest.h"
    16 #include "upnpmedia.h"
    1716#include "util.h"
    1817#include "mythcorecontext.h"
     18#include "storagegroup.h"
    1919
    2020#define LOC QString("UPnpCDSVideo: ")
    2121#define LOC_WARN QString("UPnpCDSVideo, Warning: ")
    2222#define LOC_ERR QString("UPnpCDSVideo, Error: ")
    2323
    24 UPnpCDSRootInfo UPnpCDSVideo::g_RootNodes[] =
     24UPnpCDSRootInfo UPnpCDSVideo::g_RootNodes[] = 
    2525{
    26     {   "VideoRoot",
     26    {   "All Videos",
    2727        "*",
    2828        "SELECT 0 as key, "
    2929          "title as name, "
    3030          "1 as children "
    31             "FROM upnpmedia "
     31            "FROM videometadata "
    3232            "%1 "
    3333            "ORDER BY title",
    3434        "" }
     
    4747UPnpCDSRootInfo *UPnpCDSVideo::GetRootInfo( int nIdx )
    4848{
    4949    if ((nIdx >=0 ) && ( nIdx < g_nRootCount ))
    50         return &(g_RootNodes[ nIdx ]);
     50        return &(g_RootNodes[ nIdx ]); 
    5151
    5252    return NULL;
    5353}
     
    6767
    6868QString UPnpCDSVideo::GetTableName( QString sColumn )
    6969{
    70     return "upnpmedia";
     70    return "videometadata";
    7171}
    7272
    7373/////////////////////////////////////////////////////////////////////////////
     
    7676
    7777QString UPnpCDSVideo::GetItemListSQL( QString sColumn )
    7878{
    79     return "SELECT intid, title, filepath, " \
    80            "itemtype, itemproperties, parentid, "\
    81            "coverart FROM upnpmedia WHERE class = 'VIDEO'";
     79        return "SELECT intid, title, filename, director, plot, "
     80                        "rating, year, userrating, length, "
     81                        "season, episode, coverfile, insertdate, host FROM videometadata";
     82
    8283}
    8384
    8485/////////////////////////////////////////////////////////////////////////////
     
    8990{
    9091    int nVideoID = mapParams[ "Id" ].toInt();
    9192
    92     QString sSQL = QString( "%1 AND intid=:VIDEOID ORDER BY title DESC" )
     93    QString sSQL = QString( "WHERE %1 AND intid=:VIDEOID ORDER BY title DESC" )
    9394                                                    .arg( GetItemListSQL( ) );
    9495
    9596    query.prepare( sSQL );
     
    213214
    214215    MSqlQuery query(MSqlQuery::InitCon());
    215216
    216     query.prepare("SELECT COUNT(*) FROM upnpmedia WHERE class = 'VIDEO' "
    217                     "AND parentid = :ROOTID");
     217    query.prepare("SELECT COUNT(*) FROM videometadata");
    218218
    219     query.bindValue(":ROOTID", STARTING_VIDEO_OBJECTID);
    220 
    221219    if (query.exec() && query.next())
    222220    {
    223221        nCount = query.value(0).toInt();
     
    226224    return nCount;
    227225}
    228226
     227
    229228/////////////////////////////////////////////////////////////////////////////
    230229//
    231230/////////////////////////////////////////////////////////////////////////////
    232231
    233 UPnpCDSExtensionResults *UPnpCDSVideo::ProcessItem( UPnpCDSRequest          *pRequest,
    234                                                     UPnpCDSExtensionResults *pResults,
    235                                                     QStringList             &idPath )
     232void UPnpCDSVideo::AddItem( const UPnpCDSRequest    *pRequest,
     233                                                    const QString           &sObjectId,
     234                            UPnpCDSExtensionResults *pResults,
     235                            bool                     bAddRef,
     236                            MSqlQuery               &query )
    236237{
    237     pResults->m_nTotalMatches   = 0;
    238     pResults->m_nUpdateID       = 1;
    239238
    240     if (pRequest->m_sObjectId.length() == 0)
    241         return pResults;
     239    int            nVidID       = query.value( 0).toInt();
     240    QString        sTitle       = query.value( 1).toString();
     241    QString        sFilePath    = query.value( 2).toString();
     242    QString        sDirector    = query.value( 3).toString();
     243    QString        sPlot        = query.value( 4).toString();
     244    QString        sRating      = query.value( 5).toString();
     245    // int                     nYear        = query.value( 6).toInt();
     246    // int                         nUserRating  = query.value( 7).toInt();
     247    int                    nLength      = query.value( 8).toInt();
     248    // int                         nSeason      = query.value( 9).toInt();
     249    // int                         nEpisode     = query.value(10).toInt();
     250    QString        sCoverArt   = query.value(11).toString();
     251    QDateTime      dtInsertDate = query.value(12).toDateTime();
     252        QString                 sHostName       = query.value(13).toString();
    242253
    243     QStringList tokens = pRequest->m_sObjectId
    244         .split('/', QString::SkipEmptyParts);
    245     QString     sId    = tokens.last();
     254    // VERBOSE(VB_UPNP,QString("ID = %1, Title = %2, fname = %3 sObjectId = %4").arg(nVidID).arg(sTitle).arg(sFilePath).arg(sObjectId));
    246255
    247     if (sId.startsWith("Id"))
    248         sId = sId.right( sId.length() - 2);
     256    // ----------------------------------------------------------------------
     257    // Cache Host ip Address & Port
     258    // ----------------------------------------------------------------------
    249259
    250     switch( pRequest->m_eBrowseFlag )
     260    // If the host-name is empty then we assume it is our local host
     261    // otherwise, we look up the host's IP address and port.  When the
     262    // client then trys to play the video it will be directed to the
     263    // host which actually has the content.
     264    if (!m_mapBackendIp.contains( sHostName ))
    251265    {
    252         case CDS_BrowseMetadata:
     266        if (sHostName.isEmpty())
    253267        {
    254             // --------------------------------------------------------------
    255             // Return 1 Item
    256             // --------------------------------------------------------------
    257 
    258             QStringMap  mapParams;
    259 
    260             mapParams.insert( "Id", sId );
    261 
    262             MSqlQuery query(MSqlQuery::InitCon());
    263 
    264             if (query.isConnected())
    265             {
    266                 BuildItemQuery( query, mapParams );
    267 
    268                 if (query.exec() && query.next())
    269                 {
    270                         AddItem( pRequest, pRequest->m_sParentId, pResults, false, query );
    271                         pResults->m_nTotalMatches = 1;
    272                 }
    273             }
    274 
    275             break;
     268                m_mapBackendIp[ sHostName ] = gCoreContext->GetSetting( "BackendServerIP" );
    276269        }
    277 
    278         case CDS_BrowseDirectChildren:
    279         {
    280             pRequest->m_sParentId = sId;
    281 
    282             CreateItems( pRequest, pResults, 0, "", false );
    283 
    284             break;
    285         }
     270            else
     271            {
     272            m_mapBackendIp[ sHostName ] = gCoreContext->GetSettingOnHost( "BackendServerIp", sHostName);
     273            }
    286274    }
    287275
    288     return pResults;
    289 }
    290 
    291 /////////////////////////////////////////////////////////////////////////////
    292 //
    293 /////////////////////////////////////////////////////////////////////////////
    294 
    295 void UPnpCDSVideo::CreateItems( UPnpCDSRequest          *pRequest,
    296                                 UPnpCDSExtensionResults *pResults,
    297                                 int                      nNodeIdx,
    298                                 const QString           &sKey,
    299                                 bool                     bAddRef )
    300 {
    301     pResults->m_nTotalMatches = 0;
    302     pResults->m_nUpdateID     = 1;
    303 
    304     UPnpCDSRootInfo *pInfo = GetRootInfo( nNodeIdx );
    305 
    306     if (pInfo == NULL)
    307         return;
    308 
    309     if (pRequest->m_nRequestedCount == 0)
    310         pRequest->m_nRequestedCount = SHRT_MAX;
    311 
    312     MSqlQuery query(MSqlQuery::InitCon());
    313 
    314     if (query.isConnected())
     276    if (!m_mapBackendPort.contains( sHostName ))
    315277    {
    316         QString ParentClause;
    317         QString sWhere;
    318 
    319         if ( sKey.length() > 0)
     278        if (sHostName.isEmpty())
    320279        {
    321            sWhere = QString( "WHERE %1=:KEY " )
    322                        .arg( pInfo->column );
     280            m_mapBackendPort[ sHostName ] = gCoreContext->GetSetting( "BackendStatusPort" );
    323281        }
    324 
    325         if (pRequest->m_sObjectId.startsWith("Videos"))
    326         {
    327             if (!pRequest->m_sParentId.isEmpty())
    328             {
    329                 if (pRequest->m_sParentId == "Videos/0")
    330                 {
    331                     pRequest->m_sParentId = QString("%1")
    332                                 .arg(STARTING_VIDEO_OBJECTID);
    333                 }
    334             }
    335             else
    336             {
    337                 QStringList tokens =
    338                     pRequest->m_sObjectId.split('=', QString::SkipEmptyParts);
    339                 pRequest->m_sParentId = tokens.last();
    340             }
    341 
    342             if (pRequest->m_sSearchClass.isEmpty())
    343                 ParentClause = " AND parentid = \"" + pRequest->m_sParentId + "\"";
    344             else
    345                 pRequest->m_sParentId = '8';
    346 
    347             if (pRequest->m_sObjectId.startsWith("Videos/0"))
    348             {
    349                 pRequest->m_sObjectId = "Videos/0";
    350             }
    351 
    352             /*
    353             VERBOSE(VB_UPNP, QString("pRequest->m_sParentId=:%1: , "
    354                                      "pRequest->m_sObjectId=:%2:, sKey=:%3:")
    355                                                  .arg(pRequest->m_sParentId)
    356                                                  .arg(pRequest->m_sObjectId)
    357                                                  .arg(sKey));
    358              */
    359 
    360             if ((!pRequest->m_sParentId.isEmpty()) && (pRequest->m_sParentId != "8"))
    361                 pResults->m_nTotalMatches = GetCount( "parentid", pRequest->m_sParentId );
    362         }
    363282        else
    364             VERBOSE( VB_UPNP, QString( "UPnpCDSVideo::CreateItems: ******* ParentID Does NOT Start with 'Videos' ParentId = {0}" )
    365                                   .arg( pRequest->m_sParentId ));
    366 
    367         QString sSQL = QString( "%1 %2 LIMIT %3, %4" )
    368                           .arg( GetItemListSQL( pInfo->column )  )
    369                           .arg( sWhere + ParentClause )
    370                           .arg( pRequest->m_nStartingIndex  )
    371                           .arg( pRequest->m_nRequestedCount );
    372 
    373         query.prepare  ( sSQL );
    374         //VERBOSE(VB_UPNP, QString("sSQL = %1").arg(sSQL));
    375         if ( sKey.length() )
    376             query.bindValue(":KEY", sKey );
    377 
    378         if (query.exec())
    379283        {
    380             while(query.next())
    381                 AddItem( pRequest, pRequest->m_sObjectId, pResults, bAddRef, query );
    382 
     284            m_mapBackendPort[ sHostName ] = gCoreContext->GetSettingOnHost("BackendStatusPort", sHostName);
    383285        }
    384286    }
    385 }
    386 
    387 /////////////////////////////////////////////////////////////////////////////
    388 //
    389 /////////////////////////////////////////////////////////////////////////////
    390 
    391 void UPnpCDSVideo::AddItem( const UPnpCDSRequest    *pRequest,
    392                             const QString           &sObjectId,
    393                             UPnpCDSExtensionResults *pResults,
    394                             bool                     bAddRef,
    395                             MSqlQuery               &query )
    396 {
    397     int            nVidID       = query.value( 0).toInt();
    398     QString        sTitle       = query.value( 1).toString();
    399     QString        sFileName    = query.value( 2).toString();
    400     QString        sItemType    = query.value( 3).toString();
    401     QString        sParentID    = query.value( 5).toString();
    402     QString        sCoverArt    = query.value( 6).toString();
    403 
    404     // VERBOSE(VB_UPNP,QString("ID = %1, Title = %2, fname = %3 sObjectId = %4").arg(nVidID).arg(sTitle).arg(sFileName).arg(sObjectId));
    405 
     287   
     288   
    406289    // ----------------------------------------------------------------------
    407     // Cache Host ip Address & Port
    408     // ----------------------------------------------------------------------
    409     QString sServerIp = gCoreContext->GetSetting("BackendServerIp"   );
    410     QString sPort     = gCoreContext->GetSetting("BackendStatusPort" );
    411 
    412     // ----------------------------------------------------------------------
    413290    // Build Support Strings
    414291    // ----------------------------------------------------------------------
    415292
    416293    QString sName      = sTitle;
    417294
    418     QString sURIBase   = QString( "http://%1:%2/Myth/" )
    419                             .arg( sServerIp )
    420                             .arg( sPort    );
     295        QString sURIBase   = QString( "http://%1:%2/Myth/" )
     296                            .arg( m_mapBackendIp  [ sHostName ] )
     297                            .arg( m_mapBackendPort[ sHostName ] );
    421298
    422299    QString sURIParams = QString( "/Id%1" ).arg( nVidID );
    423300    QString sId        = QString( "Videos/0/item%1").arg( sURIParams );
    424301
    425     if (sParentID == QString("%1").arg(STARTING_VIDEO_OBJECTID))
    426     {
    427         sParentID = "Videos/0";
    428     }
    429     else
    430     {
    431         sParentID = QString( "Videos/0/item/Id%1")
    432                        .arg( sParentID );
    433     }
     302    QString sParentID = "Videos/0";
    434303
    435304    QString sAlbumArtURI= QString( "%1GetVideoArt%2")
    436305                        .arg( sURIBase   )
    437306                        .arg( sURIParams );
    438307
    439     CDSObject *pItem = NULL;
     308    CDSObject *pItem = CDSObject::CreateVideoItem( sId, sName, sParentID );
    440309
    441     if (sItemType == "FOLDER")
    442     {
    443         pItem   = CDSObject::CreateStorageFolder( sId, sName, sParentID);
    444         pItem->SetChildCount( GetCount( "parentid",QString( "%1" ).arg( nVidID )) );
    445 
    446         pItem->SetPropValue( "storageUsed", "0" );  //-=>TODO: need proper value
    447     }
    448     else if (sItemType == "FILE" )
    449         pItem   = CDSObject::CreateVideoItem( sId, sName, sParentID );
    450 
    451     if (!pItem)
    452     {
    453         VERBOSE(VB_IMPORTANT, LOC_ERR + "AddItem(): " +
    454         QString("sItemType has unknown type '%1'").arg(sItemType));
    455 
    456         return;
    457     }
    458 
    459310    pItem->m_bRestricted  = false;
    460311    pItem->m_bSearchable  = true;
    461312    pItem->m_sWriteStatus = "WRITABLE";
    462313
    463     pItem->SetPropValue( "genre"          , "[Unknown Genre]"     );
     314    pItem->SetPropValue( "longDescription", sPlot );
     315    // ?? pItem->SetPropValue( "description"    , sTitle );
     316    pItem->SetPropValue( "director"       , sDirector );
     317
     318        pItem->SetPropValue( "genre"          , "[Unknown Genre]"     );
    464319    pItem->SetPropValue( "actor"          , "[Unknown Author]"    );
    465320    pItem->SetPropValue( "creator"        , "[Unknown Author]"    );
    466321    pItem->SetPropValue( "album"          , "[Unknown Series]"    );
    467322
    468     if ((!sCoverArt.isEmpty()) && (sCoverArt != "No Cover"))
     323        //pItem->SetPropValue( "producer"       , );
     324    //pItem->SetPropValue( "rating"         , );
     325    //pItem->SetPropValue( "actor"          , );
     326    //pItem->SetPropValue( "publisher"      , );
     327    //pItem->SetPropValue( "language"       , );
     328    //pItem->SetPropValue( "relation"       , );
     329    //pItem->SetPropValue( "region"         , );
     330
     331    if ((sCoverArt != "") && (sCoverArt != "No Cover"))
    469332        pItem->SetPropValue( "albumArtURI"    , sAlbumArtURI);
    470333
    471334    if ( bAddRef )
     
    476339        pItem->SetPropValue( "refID", sRefId );
    477340    }
    478341
    479     QFileInfo fInfo( sFileName );
    480     QDateTime fDate = fInfo.lastModified();
     342        QString sFullFileName = sFilePath;
     343        if (!QFile::exists( sFullFileName ))
     344        {
     345                StorageGroup sgroup("Videos");
     346                sFullFileName = sgroup.FindRecordingFile( sFullFileName );
     347        }
     348    QFileInfo fInfo( sFullFileName );
    481349
    482     pItem->SetPropValue( "date", fDate.toString( "yyyy-MM-dd"));
     350    pItem->SetPropValue( "date", dtInsertDate.toString( "yyyy-MM-dd"));
    483351    pResults->Add( pItem );
    484352
    485353    // ----------------------------------------------------------------------
     
    496364    Resource *pRes = pItem->AddResource( sProtocol, sURI );
    497365
    498366    pRes->AddAttribute( "size"      , QString("%1").arg(fInfo.size()) );
    499     pRes->AddAttribute( "duration"  , "0:01:00.000"      );
    500367
    501 }
     368        QString sDur;
     369    sDur.sprintf("%02d:%02d:00",
     370                  (nLength / 60), nLength % 60 );
    502371
    503 // vim:ts=4:sw=4:ai:et:si:sts=4
     372    pRes->AddAttribute( "duration"  , sDur      );
     373}
  • programs/mythbackend/main_helpers.cpp

     
    306306    log_rotate(0);
    307307}
    308308
    309 void upnp_rebuild(int)
    310 {
    311     if (gCoreContext->IsMasterHost())
    312     {
    313         g_pUPnp->RebuildMediaMap();
    314     }
    315 
    316 }
    317 
    318309void showUsage(const MythCommandLineParser &cmdlineparser, const QString &version)
    319310{
    320311    QString    help  = cmdlineparser.GetHelpString(false);
     
    433424
    434425    if (cmdline.WantUPnPRebuild())
    435426    {
    436         VERBOSE(VB_GENERAL, "Rebuilding UPNP Media Map");
     427        VERBOSE(VB_GENERAL, "Rebuilding UPNP Media Map is no longer supported");
    437428
    438         UPnpMedia *rebuildit = new UPnpMedia(false,false);
    439         rebuildit->BuildMediaMap();
    440 
    441429        return BACKEND_EXIT_OK;
    442430    }
    443431
     
    768756            pHS->RegisterExtension(httpStatus);
    769757    }
    770758
    771     if (ismaster)
    772     {
    773         // kill -USR1 mythbackendpid will force a upnpmedia rebuild
    774         signal(SIGUSR1, &upnp_rebuild);
    775     }
    776 
    777759    VERBOSE(VB_IMPORTANT, QString("Enabled verbose msgs: %1")
    778760            .arg(verboseString));
    779761
  • programs/mythbackend/mythbackend.pro

     
    2121HEADERS += autoexpire.h encoderlink.h filetransfer.h httpstatus.h mainserver.h
    2222HEADERS += playbacksock.h scheduler.h server.h housekeeper.h backendutil.h
    2323HEADERS += upnpcdstv.h upnpcdsmusic.h upnpcdsvideo.h mediaserver.h
    24 HEADERS += mythxml.h upnpmedia.h main_helpers.h backendcontext.h
     24HEADERS += mythxml.h main_helpers.h backendcontext.h
    2525
    2626SOURCES += autoexpire.cpp encoderlink.cpp filetransfer.cpp httpstatus.cpp
    2727SOURCES += main.cpp mainserver.cpp playbacksock.cpp scheduler.cpp server.cpp
    2828SOURCES += housekeeper.cpp backendutil.cpp
    2929SOURCES += upnpcdstv.cpp upnpcdsmusic.cpp upnpcdsvideo.cpp mediaserver.cpp
    30 SOURCES += mythxml.cpp upnpmedia.cpp main_helpers.cpp backendcontext.cpp
     30SOURCES += mythxml.cpp main_helpers.cpp backendcontext.cpp
    3131
    3232using_oss:DEFINES += USING_OSS
    3333
  • programs/mythbackend/mediaserver.h

     
    1717#include "upnpcds.h"
    1818#include "upnpcmgr.h"
    1919#include "upnpmsrr.h"
    20 #include "upnpmedia.h"
    2120
    2221//////////////////////////////////////////////////////////////////////////////
    2322//////////////////////////////////////////////////////////////////////////////
     
    3433
    3534        UPnpCDS         *m_pUPnpCDS;     // Do not delete (auto deleted)
    3635        UPnpCMGR        *m_pUPnpCMGR;    // Do not delete (auto deleted)
    37         UPnpMedia       *upnpMedia;
    3836
    3937        QString          m_sSharePath;
    4038
     
    4341
    4442        virtual ~MediaServer();
    4543
    46         void RebuildMediaMap(void) { upnpMedia->BuildMediaMap(); };
    47 
    4844        void     RegisterExtension  ( UPnpCDSExtension    *pExtension );
    4945        void     UnregisterExtension( UPnpCDSExtension    *pExtension );
    5046
  • programs/mythbackend/upnpmedia.cpp

     
    1 #include <limits.h>
    2 #include <unistd.h>
    3 
    4 #include <cstdlib>
    5 
    6 #include <QFileInfo>
    7 #include <QDir>
    8 
    9 #include "mythcorecontext.h"
    10 #include "httprequest.h"
    11 #include "upnpmedia.h"
    12 #include "mythdb.h"
    13 #include "util.h"
    14 #include "pthread.h"
    15 
    16 #define LOC QString("UPnpMedia: ")
    17 
    18 /////////////////////////////////////////////////////////////////////////////
    19 //
    20 /////////////////////////////////////////////////////////////////////////////
    21 
    22 UPnpMedia::UPnpMedia(bool runthread, bool ismaster)
    23 {
    24 
    25     if (gCoreContext->GetNumSetting("UPnP/RebuildDelay",30) > 0)
    26     {
    27         VERBOSE(VB_GENERAL,"Enabling Upnpmedia rebuild thread.");
    28         if ((runthread) && (ismaster))
    29         {
    30             pthread_t upnpmediathread;
    31             pthread_create(&upnpmediathread, NULL, doUPnpMediaThread, this);
    32         }
    33     }
    34     else
    35     {
    36         VERBOSE(VB_GENERAL,"Upnpmedia rebuild disabled.");
    37     }
    38 
    39 }
    40 
    41 void UPnpMedia::RunRebuildLoop(void)
    42 {
    43 
    44     // Sleep a few seconds to wait for other stuff to settle down.
    45     sleep(10);
    46 
    47     int irebuildDelay = 1800;
    48 
    49     irebuildDelay = gCoreContext->GetNumSetting("UPnP/RebuildDelay",30) * 60;
    50 
    51     if (irebuildDelay < 60)
    52         irebuildDelay = 60;
    53 
    54     while (1)
    55     {
    56         //VERBOSE(VB_UPNP, "UPnpMedia::RunRebuildLoop Calling BuildMediaMap");
    57         BuildMediaMap();
    58 
    59         sleep(irebuildDelay + (random()%8));
    60     }
    61 }
    62 
    63 void *UPnpMedia::doUPnpMediaThread(void *param)
    64 {
    65     UPnpMedia *upnpmedia = static_cast<UPnpMedia*>(param);
    66     upnpmedia->RunRebuildLoop();
    67 
    68     return NULL;
    69 }
    70 
    71 QString UPnpMedia::GetTitleName(QString fPath, QString fName)
    72 {
    73     if (!m_mapTitleNames[fPath].isNull())
    74     {
    75         return m_mapTitleNames[fPath];
    76     }
    77     else
    78         return fName;
    79 }
    80 
    81 QString UPnpMedia::GetCoverArt(QString fPath)
    82 {
    83     if (!m_mapCoverArt[fPath].isNull())
    84     {
    85         return m_mapCoverArt[fPath];
    86     }
    87     else
    88         return "";
    89 }
    90 
    91 /////////////////////////////////////////////////////////////////////////////
    92 //
    93 /////////////////////////////////////////////////////////////////////////////
    94 
    95 // this should dynamically generate the SQL query and such
    96 void UPnpMedia::FillMetaMaps(void)
    97 {
    98     MSqlQuery query(MSqlQuery::InitCon());
    99 
    100     QString sSQL = "SELECT filename, title, coverfile FROM videometadata";
    101 
    102     query.prepare  ( sSQL );
    103 
    104     if (query.exec() && query.size() > 0)
    105     {
    106         while(query.next())
    107         {
    108             m_mapTitleNames[query.value(0).toString()] = query.value(1)
    109                                                                 .toString();
    110             m_mapCoverArt[query.value(0).toString()] = query.value(2)
    111                                                                 .toString();
    112         }
    113     }
    114 
    115 }
    116 
    117 
    118 int UPnpMedia::buildFileList(QString directory, int rootID, int itemID, MSqlQuery &query)
    119 {
    120 
    121     int parentid;
    122     QDir vidDir(directory);
    123     //VERBOSE(VB_UPNP, QString("buildFileList = %1, rootID = %2, itemID =
    124     //%3").arg(directory).arg(rootID).arg(itemID));
    125 
    126     if (rootID > 0)
    127         parentid = rootID;
    128     else
    129         parentid = itemID;
    130 
    131     vidDir.setSorting( QDir::DirsFirst | QDir::Name );
    132     QFileInfoList List = vidDir.entryInfoList();
    133     // If we can't read it's contents move on
    134     if (List.isEmpty())
    135         return itemID;
    136 
    137     for (QFileInfoList::iterator it = List.begin(); it != List.end(); ++it)
    138     {
    139         QFileInfo Info(*it);
    140         QString fName = Info.fileName();
    141         QString fPath = Info.filePath();
    142 
    143         if (fName == "." ||
    144             fName == "..")
    145         {
    146             continue;
    147         }
    148 
    149         if (Info.isDir())
    150         {
    151             itemID++;
    152 
    153             query.prepare("INSERT INTO upnpmedia "
    154                         "(intid, class, itemtype, parentid, itemproperties, "
    155             "filepath, filename, title, coverart) "
    156             "VALUES (:ITEMID, :ITEMCLASS, 'FOLDER', :PARENTID, '', "
    157             ":FILEPATH, :FILENAME, :TITLE, :COVERART)");
    158 
    159             query.bindValue(":ITEMCLASS", sMediaType);
    160             query.bindValue(":ITEMID", itemID);
    161             query.bindValue(":PARENTID", parentid);
    162             query.bindValue(":FILEPATH", fPath);
    163             query.bindValue(":FILENAME", fName);
    164 
    165             query.bindValue(":TITLE", GetTitleName(fPath,fName));
    166             query.bindValue(":COVERART", GetCoverArt(fPath));
    167 
    168             if (!query.exec())
    169                 MythDB::DBError("UPnpMedia::buildFileList", query);
    170 
    171             itemID = buildFileList(Info.filePath(), 0, itemID, query);
    172             continue;
    173 
    174         }
    175         else
    176         {
    177 /*
    178             if (handler->validextensions.count() > 0)
    179             {
    180                 QRegExp r;
    181 
    182                 r.setPattern("^" + Info.suffix() + "$");
    183                 r.setCaseSensitive(false);
    184                 QStringList result = handler->validextensions.grep(r);
    185                 if (result.isEmpty()) {
    186                     continue;
    187                 }
    188             }
    189 */
    190 
    191             itemID++;
    192 
    193 //            VERBOSE(VB_UPNP, QString("UPnpMedia Video File : (%1) (%2)")
    194 //                      .arg(itemID)
    195 //                                .arg(fName));
    196 
    197             query.prepare("INSERT INTO upnpmedia "
    198                         "(intid, class, itemtype, parentid, itemproperties, "
    199                         "filepath, filename, title, coverart) "
    200                         "VALUES (:ITEMID, :ITEMCLASS, 'FILE', :PARENTID, '', "
    201                         ":FILEPATH, :FILENAME, :TITLE, :COVERART)");
    202 
    203             query.bindValue(":ITEMCLASS", sMediaType);
    204             query.bindValue(":ITEMID", itemID);
    205             query.bindValue(":PARENTID", parentid);
    206             query.bindValue(":FILEPATH", fPath);
    207             query.bindValue(":FILENAME", fName);
    208 
    209             query.bindValue(":TITLE", GetTitleName(fPath,fName));
    210             query.bindValue(":COVERART", GetCoverArt(fPath));
    211 
    212             if (!query.exec())
    213                 MythDB::DBError("UPnpMedia::buildFileList", query);
    214 
    215         }
    216     }
    217 
    218     return itemID;
    219 }
    220 
    221 void UPnpMedia::BuildMediaMap(void)
    222 {
    223     MSqlQuery query(MSqlQuery::InitCon());
    224 
    225     // For now this class only does the video stuff, but eventually other media too
    226     sMediaType = "VIDEO";
    227 
    228     if (sMediaType == "VIDEO")
    229     {
    230         QString RootVidDir = gCoreContext->GetSetting("VideoStartupDir");
    231 
    232         if (!RootVidDir.isEmpty())
    233         {
    234 
    235             FillMetaMaps();
    236 
    237             query.prepare("DELETE FROM upnpmedia WHERE class = :ITEMCLASS");
    238             query.bindValue(":ITEMCLASS", sMediaType);
    239             if (!query.exec())
    240             {
    241                 MythDB::DBError("BuildMediaMap -- clearing table upnpmedia", query);
    242                 VERBOSE(VB_IMPORTANT, LOC + "BuildMediaMap - aborting");
    243                 return;
    244             }
    245 
    246             if (!query.exec("LOCK TABLES upnpmedia WRITE"))
    247                 MythDB::DBError("BuildMediaMap -- lock tables", query);
    248 
    249             VERBOSE(VB_UPNP, LOC + QString("VideoStartupDir = %1")
    250                                             .arg(RootVidDir));
    251 
    252             QStringList parts = RootVidDir.split(':', QString::SkipEmptyParts);
    253 
    254             int nextID = STARTING_VIDEO_OBJECTID;
    255 
    256             for ( QStringList::Iterator it = parts.begin(); it != parts.end();
    257                                                                         ++it )
    258             {
    259                 int filecount = nextID;
    260 
    261                 VERBOSE(VB_GENERAL, LOC + QString("BuildMediaMap %1 scan "
    262                                                 "starting in :%2:")
    263                                                     .arg(sMediaType)
    264                                                     .arg(*it));
    265 
    266                 nextID = buildFileList(*it,STARTING_VIDEO_OBJECTID, nextID,
    267                                                                         query);
    268 
    269                 if (!gCoreContext->GetSetting("UPnP/RecordingsUnderVideos").isEmpty())
    270                 {
    271                     VERBOSE(VB_ALL, "uPnP Unspecified error line 275, "
    272                                     "upnpmedia.cpp");
    273                     //   nextID = buildRecordingList(*it,STARTING_VIDEO_OBJECTID,
    274                     //                                        nextID,query);
    275                 }
    276 
    277                 filecount = (filecount - nextID) * -1;
    278 
    279                 VERBOSE(VB_GENERAL, LOC + QString("BuildMediaMap Done. Found "
    280                                                 "%1 objects").arg(filecount));
    281 
    282             }
    283 
    284             if (!query.exec("UNLOCK TABLES"))
    285                 MythDB::DBError("BuildMediaMap -- unlock tables", query);
    286 
    287         }
    288         else
    289         {
    290             VERBOSE(VB_GENERAL, LOC + "BuildMediaMap - no VideoStartupDir set, "
    291                                 " skipping scan.");
    292         }
    293 
    294     }
    295     else
    296     {
    297         VERBOSE(VB_GENERAL, LOC + QString("BuildMediaMap UNKNOWN MediaType %1 "
    298                             ", skipping scan.").arg(sMediaType));
    299     }
    300 
    301 }
    302 
    303