Example #1
0
void UPnpCDSTv::AddItem( const UPnpCDSRequest    *pRequest, 
                         const QString           &sObjectId,
                         UPnpCDSExtensionResults *pResults,
                         bool                     bAddRef,
                         MSqlQuery               &query )
{
    int            nChanid      = query.value( 0).toInt();
    QDateTime      dtStartTime  = query.value( 1).toDateTime();
    QDateTime      dtEndTime    = query.value( 2).toDateTime();
    QString        sTitle       = query.value( 3).toString();
    QString        sSubtitle    = query.value( 4).toString();
    QString        sDescription = query.value( 5).toString();
    QString        sCategory    = query.value( 6).toString();
    QString        sHostName    = query.value( 7).toString();
    QString        sRecGroup    = query.value( 8).toString();
    uint64_t       nFileSize    = query.value( 9).toULongLong();
    QString        sBaseName    = query.value(10).toString();

    QDateTime      dtProgStart  = query.value(11).toDateTime();
    QDateTime      dtProgEnd    = query.value(12).toDateTime();
    QString        sStorageGrp  = query.value(13).toString();

    // ----------------------------------------------------------------------
    // Cache Host ip Address & Port
    // ----------------------------------------------------------------------

    if (!m_mapBackendIp.contains( sHostName ))
        m_mapBackendIp[ sHostName ] = gCoreContext->GetSettingOnHost( "BackendServerIp", sHostName);

    if (!m_mapBackendPort.contains( sHostName ))
        m_mapBackendPort[ sHostName ] = gCoreContext->GetSettingOnHost("BackendStatusPort", sHostName);

    // ----------------------------------------------------------------------
    // Build Support Strings
    // ----------------------------------------------------------------------

    QString sName      = sTitle + ": " + (sSubtitle.isEmpty() ? sDescription : sSubtitle);

    QString sURIBase   = QString( "http://%1:%2/Myth/" )
                            .arg( m_mapBackendIp  [ sHostName ] )
                            .arg( m_mapBackendPort[ sHostName ] );

    QString sURIParams = QString( "?ChanId=%1&StartTime=%2" )
                            .arg( nChanid )
                            .arg( dtStartTime.toString(Qt::ISODate));

    QString sId        = QString( "RecTv/0/item%1")
                            .arg( sURIParams );

    CDSObject *pItem   = CDSObject::CreateVideoItem( sId,
                                                     sName,
                                                     sObjectId );
    pItem->m_bRestricted  = false;
    pItem->m_bSearchable  = true;
    pItem->m_sWriteStatus = "WRITABLE";

    if ( bAddRef )
    {
        QString sRefId = QString( "%1/0/item%2")
                            .arg( m_sExtensionId )
                            .arg( sURIParams     );

        pItem->SetPropValue( "refID", sRefId );
    }

    pItem->SetPropValue( "genre"          , sCategory    );
    pItem->SetPropValue( "longDescription", sDescription );
    pItem->SetPropValue( "description"    , sSubtitle    );

    //pItem->SetPropValue( "producer"       , );
    //pItem->SetPropValue( "rating"         , );
    //pItem->SetPropValue( "actor"          , );
    //pItem->SetPropValue( "director"       , );
    //pItem->SetPropValue( "publisher"      , );
    //pItem->SetPropValue( "language"       , );
    //pItem->SetPropValue( "relation"       , );
    //pItem->SetPropValue( "region"         , );

    // ----------------------------------------------------------------------
    // Needed for Microsoft Media Player Compatibility
    // (Won't display correct Title without them)
    // ----------------------------------------------------------------------

    pItem->SetPropValue( "creator"       , "[Unknown Author]" );
    pItem->SetPropValue( "artist"        , "[Unknown Author]" );
    pItem->SetPropValue( "album"         , "[Unknown Series]" );
    pItem->SetPropValue( "actor"         , "[Unknown Author]" );
    pItem->SetPropValue( "date"          , dtStartTime.toString(Qt::ISODate));

    pResults->Add( pItem );

    // ----------------------------------------------------------------------
    // Add Video Resource Element based on File contents/extension (HTTP)
    // ----------------------------------------------------------------------

    StorageGroup sg(sStorageGrp, sHostName);
    QString sFilePath = sg.FindRecordingFile(sBaseName);
    QString sMimeType;

    if ( QFile::exists(sFilePath) )
        sMimeType = HTTPRequest::TestMimeType( sFilePath );
    else
        sMimeType = HTTPRequest::TestMimeType( sBaseName );


    // If we are dealing with Window Media Player 12 (i.e. Windows 7)
    // then fake the Mime type to place the recorded TV in the
    // recorded TV section.
    if (pRequest->m_eClient == CDS_ClientWMP && pRequest->m_nClientVersion >= 12.0)
    {
        sMimeType = "video/x-ms-dvr";
    }

    // DLNA string below is temp fix for ps3 seeking.
    QString sProtocol = QString( "http-get:*:%1:DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01500000000000000000000000000000" ).arg( sMimeType  );
    QString sURI      = QString( "%1GetRecording%2").arg( sURIBase   )
                                                    .arg( sURIParams );

    Resource *pRes = pItem->AddResource( sProtocol, sURI );

    uint uiStart = dtProgStart.toTime_t();
    uint uiEnd   = dtProgEnd.toTime_t();
    uint uiDur   = uiEnd - uiStart;

    QString sDur;

    sDur.sprintf("%02d:%02d:%02d",
                  (uiDur / 3600) % 24,
                  (uiDur / 60) % 60,
                   uiDur % 60);


    pRes->AddAttribute( "duration"  , sDur      );
    pRes->AddAttribute( "size"      , QString::number( nFileSize) );

/*
    // ----------------------------------------------------------------------
    // Add Video Resource Element based on File extension (mythtv)
    // ----------------------------------------------------------------------

    sProtocol = QString( "myth:*:%1:*"     ).arg( sMimeType  );
    sURI      = QString( "myth://%1/%2" )
                   .arg( m_mapBackendIp  [ sHostName ] )
                   .arg( sBaseName );

    pRes = pItem->AddResource( sProtocol, sURI );

    pRes->AddAttribute( "duration"  , sDur      );
    pRes->AddAttribute( "size"      , QString::number( nFileSize) );
*/

    // ----------------------------------------------------------------------
    // Add Preview URI as albumArt
    // ----------------------------------------------------------------------

    sURI = QString( "%1GetPreviewImage%2%3").arg( sURIBase   )
                                            .arg( sURIParams )
                                            .arg( "&Width=160" ); 

    pItem->SetPropValue( "albumArtURI", sURI );
    Property *pProp = pItem->GetProperty("albumArtURI");
    if (pProp)
    {
        pProp->AddAttribute("dlna:profileID", "PNG_TN");
        pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0");
    
    }

}
Example #2
0
bool UPnpCDSVideo::LoadVideos(const UPnpCDSRequest* pRequest,
                              UPnpCDSExtensionResults* pResults,
                              IDTokenMap tokens)
{
    QString sRequestId = pRequest->m_sObjectId;

    uint16_t nCount = pRequest->m_nRequestedCount;
    uint16_t nOffset = pRequest->m_nStartingIndex;

    // We must use a dedicated connection to get an acccurate value from
    // FOUND_ROWS()
    MSqlQuery query(MSqlQuery::InitCon(MSqlQuery::kDedicatedConnection));

    QString sql = "SELECT SQL_CALC_FOUND_ROWS "
                  "v.intid, title, subtitle, filename, director, plot, "
                  "rating, year, userrating, length, "
                  "season, episode, coverfile, insertdate, host, "
                  "g.genre, studio, collectionref, contenttype "
                  "FROM videometadata v "
                  "LEFT JOIN videogenre g ON g.intid=v.category "
                  "%1 " //
                  "ORDER BY title, season, episode "
                  "LIMIT :OFFSET,:COUNT ";

    QStringList clauses;
    QString whereString = BuildWhereClause(clauses, tokens);

    query.prepare(sql.arg(whereString));

    BindValues(query, tokens);

    query.bindValue(":OFFSET", nOffset);
    query.bindValue(":COUNT", nCount);

    if (!query.exec())
        return false;

    while (query.next())
    {

        int            nVidID       = query.value( 0).toInt();
        QString        sTitle       = query.value( 1).toString();
        QString        sSubtitle    = query.value( 2).toString();
        QString        sFilePath    = query.value( 3).toString();
        QString        sDirector    = query.value( 4).toString();
        QString        sPlot        = query.value( 5).toString();
        // QString        sRating      = query.value( 6).toString();
        int            nYear        = query.value( 7).toInt();
        // int             nUserRating  = query.value( 8).toInt();

        uint32_t       nLength      = query.value( 9).toUInt();
        // Convert from minutes to milliseconds
        nLength = (nLength * 60 *1000);

        int            nSeason      = query.value(10).toInt();
        int            nEpisode     = query.value(11).toInt();
        QString        sCoverArt    = query.value(12).toString();
        QDateTime      dtInsertDate =
            MythDate::as_utc(query.value(13).toDateTime());
        QString        sHostName    = query.value(14).toString();
        QString        sGenre       = query.value(15).toString();
    //    QString        sStudio      = query.value(16).toString();
    //    QString        sCollectionRef    = query.value(17).toString();
        QString        sContentType = query.value(18).toString();

        // ----------------------------------------------------------------------
        // Cache Host ip Address & Port
        // ----------------------------------------------------------------------

        // If the host-name is empty then we assume it is our local host
        // otherwise, we look up the host's IP address and port.  When the
        // client then trys to play the video it will be directed to the
        // host which actually has the content.
        if (!m_mapBackendIp.contains( sHostName ))
        {
            if (sHostName.isEmpty())
            {
                m_mapBackendIp[sHostName] =
                    gCoreContext->GetBackendServerIP4();
            }
            else
            {
                m_mapBackendIp[sHostName] =
                    gCoreContext->GetBackendServerIP4(sHostName);
            }
        }

        if (!m_mapBackendPort.contains( sHostName ))
        {
            if (sHostName.isEmpty())
            {
                m_mapBackendPort[sHostName] =
                    gCoreContext->GetBackendStatusPort();
            }
            else
            {
                m_mapBackendPort[sHostName] =
                    gCoreContext->GetBackendStatusPort(sHostName);
            }
        }


        // ----------------------------------------------------------------------
        // Build Support Strings
        // ----------------------------------------------------------------------

        QString sName      = sTitle;
        if( !sSubtitle.isEmpty() )
        {
            sName += " - " + sSubtitle;
        }

        QUrl URIBase;
        URIBase.setScheme("http");
        URIBase.setHost(m_mapBackendIp[sHostName]);
        URIBase.setPort(m_mapBackendPort[sHostName]);

        CDSObject *pItem;
        if (sContentType == "MOVIE")
        {
            pItem = CDSObject::CreateMovie( CreateIDString(sRequestId, "Video", nVidID),
                                            sTitle,
                                            pRequest->m_sParentId );
        }
        else
        {
            pItem = CDSObject::CreateVideoItem( CreateIDString(sRequestId, "Video", nVidID),
                                                sName,
                                                pRequest->m_sParentId );
        }

        if (!sSubtitle.isEmpty())
            pItem->SetPropValue( "description", sSubtitle );
        else
            pItem->SetPropValue( "description", sPlot.left(128).append(" ..."));
        pItem->SetPropValue( "longDescription", sPlot );
        pItem->SetPropValue( "director"       , sDirector );

        if (nEpisode > 0 || nSeason > 0) // There has got to be a better way
        {
            pItem->SetPropValue( "seriesTitle"  , sTitle );
            pItem->SetPropValue( "programTitle"  , sSubtitle );
            pItem->SetPropValue( "episodeNumber"  , QString::number(nEpisode));
            //pItem->SetPropValue( "episodeCount"  , nEpisodeCount);
        }

        pItem->SetPropValue( "genre"       , sGenre );
        if (nYear > 1830 && nYear < 9999)
            pItem->SetPropValue( "date",  QDate(nYear,1,1).toString(Qt::ISODate));
        else
            pItem->SetPropValue( "date", UPnPDateTime::DateTimeFormat(dtInsertDate) );

        // HACK: Windows Media Centre Compat (Not a UPnP or DLNA requirement, should only be done for WMC)
//         pItem->SetPropValue( "genre"          , "[Unknown Genre]"     );
//         pItem->SetPropValue( "actor"          , "[Unknown Author]"    );
//         pItem->SetPropValue( "creator"        , "[Unknown Creator]"   );
//         pItem->SetPropValue( "album"          , "[Unknown Album]"     );
        ////

        //pItem->SetPropValue( "producer"       , );
        //pItem->SetPropValue( "rating"         , );
        //pItem->SetPropValue( "actor"          , );
        //pItem->SetPropValue( "publisher"      , );
        //pItem->SetPropValue( "language"       , );
        //pItem->SetPropValue( "relation"       , );
        //pItem->SetPropValue( "region"         , );

        // Only add the reference ID for items which are not in the
        // 'All Videos' container
        QString sRefIDBase = QString("%1/Video").arg(m_sExtensionId);
        if ( pRequest->m_sParentId != sRefIDBase )
        {
            QString sRefId = QString( "%1=%2")
                                .arg( sRefIDBase )
                                .arg( nVidID );

            pItem->SetPropValue( "refID", sRefId );
        }

        // FIXME - If the slave or storage hosting this video is offline we
        //         won't find it. We probably shouldn't list it, but better
        //         still would be storing the filesize in the database so we
        //         don't waste time re-checking it constantly
        QString sFullFileName = sFilePath;
        if (!QFile::exists( sFullFileName ))
        {
            StorageGroup sgroup("Videos");
            sFullFileName = sgroup.FindFile( sFullFileName );
        }
        QFileInfo fInfo( sFullFileName );

        // ----------------------------------------------------------------------
        // Add Video Resource Element based on File extension (HTTP)
        // ----------------------------------------------------------------------

        QString sMimeType = HTTPRequest::GetMimeType( QFileInfo(sFilePath).suffix() );

        // HACK: If we are dealing with a Sony Blu-ray player then we fake the
        // MIME type to force the video to appear
//         if ( pRequest->m_eClient == CDS_ClientSonyDB )
//         {
//             sMimeType = "video/avi";
//         }

        QUrl    resURI    = URIBase;
        QUrlQuery resQuery;
        resURI.setPath("/Content/GetVideo");
        resQuery.addQueryItem("Id", QString::number(nVidID));
        resURI.setQuery(resQuery);

        // DLNA requires a mimetype of video/mp2p for TS files, it's not the
        // correct mimetype, but then DLNA doesn't seem to care about such
        // things
        if (sMimeType == "video/mp2t" || sMimeType == "video/mp2p")
            sMimeType = "video/mpeg";

        QString sProtocol = DLNA::ProtocolInfoString(UPNPProtocol::kHTTP,
                                                     sMimeType);

        Resource *pRes = pItem->AddResource( sProtocol, resURI.toEncoded() );
        pRes->AddAttribute( "size"    , QString("%1").arg(fInfo.size()) );
        pRes->AddAttribute( "duration", UPnPDateTime::resDurationFormat(nLength) );

        // ----------------------------------------------------------------------
        // Add Artwork
        // ----------------------------------------------------------------------
        if (!sCoverArt.isEmpty() && (sCoverArt != "No Cover"))
        {
            PopulateArtworkURIS(pItem, nVidID, URIBase);
        }

        pResults->Add( pItem );
        pItem->DecrRef();
    }

    // Just in case FOUND_ROWS() should fail, ensure m_nTotalMatches contains
    // at least the size of this result set
    if (query.size() >= 0)
        pResults->m_nTotalMatches = query.size();

    // Fetch the total number of matches ignoring any LIMITs
    query.prepare("SELECT FOUND_ROWS()");
    if (query.exec() && query.next())
            pResults->m_nTotalMatches = query.value(0).toUInt();

    return true;
}
Example #3
0
void UPnpCDSTv::AddItem( const UPnpCDSRequest    *pRequest, 
                         const QString           &sObjectId,
                         UPnpCDSExtensionResults *pResults,
                         bool                     bAddRef,
                         MSqlQuery               &query )
{
    int            nChanid      = query.value( 0).toInt();
    QDateTime      dtStartTime  = MythDate::as_utc(query.value(1).toDateTime());
    QDateTime      dtEndTime    = MythDate::as_utc(query.value(2).toDateTime());
    QString        sTitle       = query.value( 3).toString();
    QString        sSubtitle    = query.value( 4).toString();
    QString        sDescription = query.value( 5).toString();
    QString        sCategory    = query.value( 6).toString();
    QString        sHostName    = query.value( 7).toString();
    QString        sRecGroup    = query.value( 8).toString();
    uint64_t       nFileSize    = query.value( 9).toULongLong();
    QString        sBaseName    = query.value(10).toString();

    QDateTime      dtProgStart  =
        MythDate::as_utc(query.value(11).toDateTime());
    QDateTime      dtProgEnd    =
        MythDate::as_utc(query.value(12).toDateTime());
    QString        sStorageGrp  = query.value(13).toString();

    QString        sInetRef     = query.value(14).toString();

    // ----------------------------------------------------------------------
    // Cache Host ip Address & Port
    // ----------------------------------------------------------------------

    if (!m_mapBackendIp.contains( sHostName ))
        m_mapBackendIp[ sHostName ] = gCoreContext->GetBackendServerIP4(sHostName);

    if (!m_mapBackendPort.contains( sHostName ))
        m_mapBackendPort[ sHostName ] = gCoreContext->GetBackendStatusPort(sHostName);

    // ----------------------------------------------------------------------
    // Build Support Strings
    // ----------------------------------------------------------------------

    QString sName      = sTitle + ": " + (sSubtitle.isEmpty() ? sDescription.left(128) : sSubtitle);

    QString sURIBase   = QString( "http://%1:%2/Content/" )
                            .arg( m_mapBackendIp  [ sHostName ] )
                            .arg( m_mapBackendPort[ sHostName ] );

    QString sURIParams = QString( "?ChanId=%1&amp;StartTime=%2" )
                            .arg( nChanid )
                            .arg( dtStartTime.toString(Qt::ISODate));

    QString sId        = QString( "RecTv/0/item%1")
                            .arg( sURIParams );

    CDSObject *pItem   = CDSObject::CreateVideoItem( sId,
                                                     sName,
                                                     sObjectId );
    pItem->m_bRestricted  = false;
    pItem->m_bSearchable  = true;
    pItem->m_sWriteStatus = "WRITABLE";

    if ( bAddRef )
    {
        QString sRefId = QString( "%1/0/item%2")
                            .arg( m_sExtensionId )
                            .arg( sURIParams     );

        pItem->SetPropValue( "refID", sRefId );
    }

    pItem->SetPropValue( "genre"          , sCategory    );
    pItem->SetPropValue( "longDescription", sDescription );
    pItem->SetPropValue( "description"    , sSubtitle    );

    //pItem->SetPropValue( "producer"       , );
    //pItem->SetPropValue( "rating"         , );
    //pItem->SetPropValue( "actor"          , );
    //pItem->SetPropValue( "director"       , );
    //pItem->SetPropValue( "publisher"      , );
    //pItem->SetPropValue( "language"       , );
    //pItem->SetPropValue( "relation"       , );
    //pItem->SetPropValue( "region"         , );

    // ----------------------------------------------------------------------
    // Needed for Microsoft Media Player Compatibility
    // (Won't display correct Title without them)
    // ----------------------------------------------------------------------

    pItem->SetPropValue( "creator"       , "[Unknown Author]" );
    pItem->SetPropValue( "artist"        , "[Unknown Author]" );
    pItem->SetPropValue( "album"         , "[Unknown Series]" );
    pItem->SetPropValue( "actor"         , "[Unknown Author]" );
    pItem->SetPropValue( "date"          , dtStartTime.toString(Qt::ISODate));

    pResults->Add( pItem );

    // ----------------------------------------------------------------------
    // Add Video Resource Element based on File contents/extension (HTTP)
    // ----------------------------------------------------------------------

    StorageGroup sg(sStorageGrp, sHostName);
    QString sFilePath = sg.FindFile(sBaseName);
    QString sMimeType;

    if ( QFile::exists(sFilePath) )
        sMimeType = HTTPRequest::TestMimeType( sFilePath );
    else
        sMimeType = HTTPRequest::TestMimeType( sBaseName );


    // If we are dealing with Window Media Player 12 (i.e. Windows 7)
    // then fake the Mime type to place the recorded TV in the
    // recorded TV section.
    if (pRequest->m_eClient == CDS_ClientWMP &&
        pRequest->m_nClientVersion >= 12.0)
    {
        sMimeType = "video/x-ms-dvr";
    }

    // If we are dealing with a Sony Blu-ray player then we fake the
    // MIME type to force the video to appear
    if ( pRequest->m_eClient == CDS_ClientSonyDB )
    {
        sMimeType = "video/avi";
    }


    // DLNA string below is temp fix for ps3 seeking.
    QString sProtocol = QString( "http-get:*:%1:DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01500000000000000000000000000000" ).arg( sMimeType  );
    QString sURI      = QString( "%1GetRecording%2").arg( sURIBase   )
                                                    .arg( sURIParams );

    // Sony BDPS370 requires a DLNA Profile Name
    // FIXME: detection to determine the correct DLNA Profile Name
    if (sMimeType == "video/mpeg")
    {
        sProtocol += ";DLNA.ORG_PN=MPEG_TS_SD_NA_ISO";
    }

    Resource *pRes = pItem->AddResource( sProtocol, sURI );

    uint uiStart = dtProgStart.toTime_t();
    uint uiEnd   = dtProgEnd.toTime_t();
    uint uiDur   = uiEnd - uiStart;
    
    MSqlQuery query2(MSqlQuery::InitCon());
    query2.prepare( "SELECT data FROM recordedmarkup WHERE chanid=:CHANID AND "
                    "starttime=:STARTTIME AND type = 33" );
    query2.bindValue(":CHANID", (int)nChanid);
    query2.bindValue(":STARTTIME", dtStartTime);
    if (query2.exec() && query2.next())
        uiDur = query2.value(0).toUInt() / 1000;

    QString sDur;

    sDur.sprintf("%02d:%02d:%02d",
                  (uiDur / 3600) % 24,
                  (uiDur / 60) % 60,
                   uiDur % 60);

    LOG(VB_UPNP, LOG_DEBUG, "Duration: " + sDur );

    pRes->AddAttribute( "duration"  , sDur      );
    pRes->AddAttribute( "size"      , QString::number( nFileSize) );

/*
    // ----------------------------------------------------------------------
    // Add Video Resource Element based on File extension (mythtv)
    // ----------------------------------------------------------------------

    sProtocol = QString( "myth:*:%1:*"     ).arg( sMimeType  );
    sURI      = QString( "myth://%1/%2" )
                   .arg( m_mapBackendIp  [ sHostName ] )
                   .arg( sBaseName );

    pRes = pItem->AddResource( sProtocol, sURI );

    pRes->AddAttribute( "duration"  , sDur      );
    pRes->AddAttribute( "size"      , QString::number( nFileSize) );
*/

    // ----------------------------------------------------------------------
    // Add Preview URI as <res>
    // MUST be _TN and 160px
    // ----------------------------------------------------------------------

    sURI = QString( "%1GetPreviewImage%2%3").arg( sURIBase   )
                                            .arg( sURIParams )
                                            .arg( "&amp;Width=160" );

    // TODO: Must be JPG for minimal compliance
    sProtocol = QString( "http-get:*:image/png:DLNA.ORG_PN=PNG_TN");
    pItem->AddResource( sProtocol, sURI );

    // ----------------------------------------------------------------------
    // Add Artwork URI as albumArt
    // ----------------------------------------------------------------------

    sURI = QString( "%1GetRecordingArtwork?Type=coverart&amp;Inetref=%3")
                                              .arg( sURIBase   )
                                              .arg( sInetRef   );

    QList<Property*> propList = pItem->GetProperties("albumArtURI");
    if (propList.size() >= 4)
    {
        // Prefer JPEG over PNG here, although PNG is allowed JPEG probably
        // has wider device support and crucially the filesizes are smaller
        // which speeds up loading times over the network

        // We MUST include the thumbnail size, but since some clients may use the
        // first image they see and the thumbnail is tiny, instead return the
        // medium first. The large could be very large, which is no good if the
        // client is pulling images for an entire list at once!

        // Medium
        Property *pProp = propList.at(0);
        if (pProp)
        {
            // Must be no more than 1024x768
            pProp->m_sValue = sURI;
            pProp->m_sValue.append("&amp;Width=1024&amp;Height=768");
            pProp->AddAttribute("dlna:profileID", "JPG_MED");
            pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0");
        }

        // Thumbnail
        pProp = propList.at(1);
        if (pProp)
        {
            // At least one albumArtURI must be a ThumbNail (TN) no larger
            // than 160x160, and it must also be a jpeg
            pProp->m_sValue = sURI;
            pProp->m_sValue.append("&amp;Width=160&amp;Height=160");
            pProp->AddAttribute("dlna:profileID", "JPG_TN");
            pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0");
        }

        // Medium
        pProp = propList.at(2);
        if (pProp)
        {
            // Must be no more than 1024x768
            pProp->m_sValue = sURI;
            pProp->m_sValue.append("&amp;Width=1024&amp;Height=768");
            pProp->AddAttribute("dlna:profileID", "JPG_MED");
            pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0");
        }

        // Large
        pProp = propList.at(3);
        if (pProp)
        {
            // Must be no more than 4096x4096 - for our purposes, just return
            // a fullsize image
            pProp->m_sValue = sURI;
            pProp->AddAttribute("dlna:profileID", "JPG_LRG");
            pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0");
        }
    }


}
Example #4
0
void UPnpCDSMusic::AddItem( const UPnpCDSRequest    *pRequest, 
                            const QString           &sObjectId,
                            UPnpCDSExtensionResults *pResults,
                            bool                     bAddRef,
                            MSqlQuery               &query )
{
    QString        sName;

    int            nId          = query.value( 0).toInt();
    QString        sArtist      = query.value( 1).toString();
    QString        sAlbum       = query.value( 2).toString();
    QString        sTitle       = query.value( 3).toString();
    QString        sGenre       = query.value( 4).toString();
    int            nYear        = query.value( 5).toInt();
    int            nTrackNum    = query.value( 6).toInt();
    QString        sDescription = query.value( 7).toString();
    QString        sFileName    = query.value( 8).toString();
    uint           nLength      = query.value( 9).toInt();
    uint64_t       nFileSize    = (quint64)query.value(10).toULongLong();

#if 0
    if ((nNodeIdx == 0) || (nNodeIdx == 1))
    {
        sName = QString( "%1-%2:%3" )
                   .arg( sArtist)
                   .arg( sAlbum )
                   .arg( sTitle );
    }
    else
#endif
        sName = sTitle;


    // ----------------------------------------------------------------------
    // Cache Host ip Address & Port
    // ----------------------------------------------------------------------

#if 0
    if (!m_mapBackendIp.contains( sHostName ))
        m_mapBackendIp[ sHostName ] = gCoreContext->GetSettingOnHost( "BackendServerIp", sHostName);

    if (!m_mapBackendPort.contains( sHostName ))
        m_mapBackendPort[ sHostName ] = gCoreContext->GetSettingOnHost("BackendStatusPort", sHostName);
#endif

    QString sServerIp = gCoreContext->GetSetting( "BackendServerIp"   );
    QString sPort     = gCoreContext->GetSetting( "BackendStatusPort" );

    // ----------------------------------------------------------------------
    // Build Support Strings
    // ----------------------------------------------------------------------

    QString sURIBase   = QString( "http://%1:%2/Content/" )
                            .arg( sServerIp )
                            .arg( sPort     );

    QString sURIParams = QString( "?Id=%1" )
                            .arg( nId );


    QString sId        = QString( "Music/1/item%1")
                            .arg( sURIParams );

    CDSObject *pItem   = CDSObject::CreateMusicTrack( sId,
                                                      sName,
                                                      sObjectId );
    pItem->m_bRestricted  = true;
    pItem->m_bSearchable  = true;
    pItem->m_sWriteStatus = "NOT_WRITABLE";

    if ( bAddRef )
    {
        QString sRefId = QString( "%1/0/item%2")
                            .arg( m_sExtensionId )
                            .arg( sURIParams     );

        pItem->SetPropValue( "refID", sRefId );
    }

    pItem->SetPropValue( "genre"                , sGenre      );
    pItem->SetPropValue( "description"          , sTitle      );
    pItem->SetPropValue( "longDescription"      , sDescription);

    pItem->SetPropValue( "artist"               ,  sArtist    );
    pItem->SetPropValue( "album"                ,  sAlbum     );
    pItem->SetPropValue( "originalTrackNumber"  ,  QString::number(nTrackNum));
    if (nYear > 0 && nYear < 9999)
        pItem->SetPropValue( "date",  QDate(nYear,1,1).toString(Qt::ISODate));

#if 0
    pObject->AddProperty( new Property( "publisher"       , "dc"   ));
    pObject->AddProperty( new Property( "language"        , "dc"   ));
    pObject->AddProperty( new Property( "relation"        , "dc"   ));
    pObject->AddProperty( new Property( "rights"          , "dc"   ));


    pObject->AddProperty( new Property( "playlist"            , "upnp" ));
    pObject->AddProperty( new Property( "storageMedium"       , "upnp" ));
    pObject->AddProperty( new Property( "contributor"         , "dc"   ));
    pObject->AddProperty( new Property( "date"                , "dc"   ));
#endif

    QString sArtURI = QString( "%1GetAlbumArt?Id=%2").arg( sURIBase   )
                                                     .arg( nId );

    QList<Property*> propList = pItem->GetProperties("albumArtURI");
    if (propList.size() >= 4)
    {
        // Prefer JPEG over PNG here, although PNG is allowed JPEG probably
        // has wider device support and crucially the filesizes are smaller
        // which speeds up loading times over the network

        // We MUST include the thumbnail size, but since some clients may use the
        // first image they see and the thumbnail is tiny, instead return the
        // medium first. The large could be very large, which is no good if the
        // client is pulling images for an entire list at once!

        // Medium
        Property *pProp = propList.at(0);
        if (pProp)
        {
            // Must be no more than 1024x768
            pProp->m_sValue = sArtURI;
            pProp->m_sValue.append("&amp;Width=1024&amp;Height=768");
            pProp->AddAttribute("dlna:profileID", "JPG_MED");
            pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0");
        }

        // Thumbnail
        pProp = propList.at(1);
        if (pProp)
        {
            // At least one albumArtURI must be a ThumbNail (TN) no larger
            // than 160x160, and it must also be a jpeg
            pProp->m_sValue = sArtURI;
            pProp->m_sValue.append("&amp;Width=160&amp;Height=160");
            pProp->AddAttribute("dlna:profileID", "JPG_TN");
            pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0");
        }

        // Small
        pProp = propList.at(2);
        if (pProp)
        {
            // Must be no more than 640x480
            pProp->m_sValue = sArtURI;
            pProp->m_sValue.append("&amp;Width=640&amp;Height=480");
            pProp->AddAttribute("dlna:profileID", "JPG_SM");
            pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0");
        }

        // Large
        pProp = propList.at(3);
        if (pProp)
        {
            // Must be no more than 4096x4096 - for our purposes, just return
            // a fullsize image
            pProp->m_sValue = sArtURI;
            pProp->AddAttribute("dlna:profileID", "JPG_LRG");
            pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0");
        }
    }

    pResults->Add( pItem );

    // ----------------------------------------------------------------------
    // Add Music Resource Element based on File extension (HTTP)
    // ----------------------------------------------------------------------

    QFileInfo fInfo( sFileName );

    QString sMimeType = HTTPRequest::GetMimeType( fInfo.suffix() );
    QString sProtocol = QString( "http-get:*:%1:DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01500000000000000000000000000000" ).arg( sMimeType  );
    QString sURI      = QString( "%1GetMusic%2").arg( sURIBase   )
                                                .arg( sURIParams );

    Resource *pRes = pItem->AddResource( sProtocol, sURI );

    nLength /= 1000;

    QString sDur;

    sDur.sprintf("%02d:%02d:%02d",
                  (nLength / 3600) % 24,
                  (nLength / 60) % 60,
                  nLength % 60);

    pRes->AddAttribute( "duration"  , sDur      );
    if (nFileSize > 0)
        pRes->AddAttribute( "size"      , QString::number( nFileSize) );
}
Example #5
0
void UPnpCDSMusic::AddItem( const UPnpCDSRequest    *pRequest, 
                            const QString           &sObjectId,
                            UPnpCDSExtensionResults *pResults,
                            bool                     bAddRef,
                            MSqlQuery               &query )
{
    QString        sName;

    int            nId          = query.value( 0).toInt();
    QString        sArtist      = query.value( 1).toString();
    QString        sAlbum       = query.value( 2).toString();
    QString        sTitle       = query.value( 3).toString();
    QString        sGenre       = query.value( 4).toString();
//    int            nYear        = query.value( 5).toInt();
    int            nTrackNum    = query.value( 6).toInt();
    QString        sDescription = query.value( 7).toString();
    QString        sFileName    = query.value( 8).toString();
    uint           nLength      = query.value( 9).toInt();

/*
    if ((nNodeIdx == 0) || (nNodeIdx == 1))
    {
        sName = QString( "%1-%2:%3" )
                   .arg( sArtist)
                   .arg( sAlbum )
                   .arg( sTitle );
    }
    else
*/
        sName = sTitle;

//cout << nId << " " << sName << endl;


    // ----------------------------------------------------------------------
    // Cache Host ip Address & Port
    // ----------------------------------------------------------------------

//    if (!m_mapBackendIp.contains( sHostName ))
//        m_mapBackendIp[ sHostName ] = gCoreContext->GetSettingOnHost( "BackendServerIp", sHostName);
//
//    if (!m_mapBackendPort.contains( sHostName ))
//        m_mapBackendPort[ sHostName ] = gCoreContext->GetSettingOnHost("BackendStatusPort", sHostName);

    QString sServerIp = gCoreContext->GetSetting( "BackendServerIp"   );
    QString sPort     = gCoreContext->GetSetting( "BackendStatusPort" );

    // ----------------------------------------------------------------------
    // Build Support Strings
    // ----------------------------------------------------------------------

    QString sURIBase   = QString( "http://%1:%2/Myth/" )
                            .arg( sServerIp )
                            .arg( sPort     );

    QString sURIParams = QString( "?Id=%1" )
                            .arg( nId );


    QString sId        = QString( "Music/1/item%1")
                            .arg( sURIParams );

    CDSObject *pItem   = CDSObject::CreateMusicTrack( sId,
                                                      sName,
                                                      sObjectId );
    pItem->m_bRestricted  = true;
    pItem->m_bSearchable  = true;
    pItem->m_sWriteStatus = "NOT_WRITABLE";

    if ( bAddRef )
    {
        QString sRefId = QString( "%1/0/item%2")
                            .arg( m_sExtensionId )
                            .arg( sURIParams     );

        pItem->SetPropValue( "refID", sRefId );
    }

    pItem->SetPropValue( "genre"                , sGenre      );
    pItem->SetPropValue( "description"          , sTitle      );
    pItem->SetPropValue( "longDescription"      , sDescription);

    pItem->SetPropValue( "artist"               ,  sArtist    );
    pItem->SetPropValue( "album"                ,  sAlbum     );
    pItem->SetPropValue( "originalTrackNumber"  ,  QString::number( nTrackNum  ));

/*

    pObject->AddProperty( new Property( "publisher"       , "dc"   ));
    pObject->AddProperty( new Property( "language"        , "dc"   ));
    pObject->AddProperty( new Property( "relation"        , "dc"   ));
    pObject->AddProperty( new Property( "rights"          , "dc"   ));


    pObject->AddProperty( new Property( "playlist"            , "upnp" ));
    pObject->AddProperty( new Property( "storageMedium"       , "upnp" ));
    pObject->AddProperty( new Property( "contributor"         , "dc"   ));
    pObject->AddProperty( new Property( "date"                , "dc"   ));

*/


    pResults->Add( pItem );

    // ----------------------------------------------------------------------
    // Add Music Resource Element based on File extension (HTTP)
    // ----------------------------------------------------------------------

    QFileInfo fInfo( sFileName );

    QString sMimeType = HTTPRequest::GetMimeType( fInfo.suffix() );
    QString sProtocol = QString( "http-get:*:%1:DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01500000000000000000000000000000" ).arg( sMimeType  );
    QString sURI      = QString( "%1GetMusic%2").arg( sURIBase   )
                                                .arg( sURIParams );

    Resource *pRes = pItem->AddResource( sProtocol, sURI );

    nLength /= 1000;

    QString sDur;

    sDur.sprintf("%02d:%02d:%02d",
                  (nLength / 3600) % 24,
                  (nLength / 60) % 60,
                  nLength % 60);

    pRes->AddAttribute( "duration"  , sDur      );
}