MythTV  0.26-pre
upnpcdsmusic.cpp
Go to the documentation of this file.
00001 
00002 // Program Name: upnpcdsmusic.cpp
00003 //
00004 // Purpose - uPnp Content Directory Extension for Music
00005 //
00006 // Created By  : David Blain                    Created On : Jan. 24, 2005
00007 // Modified By :                                Modified On:
00008 //
00010 
00011 #include <climits>
00012 
00013 #include <QFileInfo>
00014 
00015 #include "upnpcdsmusic.h"
00016 #include "httprequest.h"
00017 #include "mythcorecontext.h"
00018 
00019 /*
00020    Music                            Music
00021     - All Music                     Music/All
00022       + <Track 1>                   Music/All/item?Id=1
00023       + <Track 2>
00024       + <Track 3>
00025     - PlayLists
00026     - By Artist                     Music/artist
00027       - <Artist 1>                  Music/artist/artistKey=Pink Floyd
00028         - <Album 1>                 Music/artist/artistKey=Pink Floyd/album/albumKey=The Wall
00029           + <Track 1>               Music/artist/artistKey=Pink Floyd/album/albumKey=The Wall/item?Id=1
00030           + <Track 2>
00031     - By Album
00032       - <Album 1>
00033         + <Track 1>
00034         + <Track 2>
00035     - By Recently Added
00036       + <Track 1>
00037       + <Track 2>
00038     - By Genre
00039       - By Artist                   Music/artist
00040         - <Artist 1>                Music/artist/artistKey=Pink Floyd
00041           - <Album 1>               Music/artist/artistKey=Pink Floyd/album/albumKey=The Wall
00042             + <Track 1>             Music/artist/artistKey=Pink Floyd/album/albumKey=The Wall/item?Id=1
00043             + <Track 2>
00044 */
00045 
00046 UPnpCDSRootInfo UPnpCDSMusic::g_RootNodes[] =
00047 {
00048     {   "All Music",
00049         "*",
00050         "SELECT song_id as id, "
00051           "name, "
00052           "1 as children "
00053             "FROM music_songs song "
00054             "%1 "
00055             "ORDER BY name",
00056         "", "name" },
00057 
00058 #if 0
00059 // This is currently broken... need to handle list of items with single parent
00060 // (like 'All Music')
00061 
00062     {   "Recently Added",
00063         "*",
00064         "SELECT song_id id, "
00065           "name, "
00066           "1 as children "
00067             "FROM music_songs song "
00068             "%1 "
00069             "ORDER BY name",
00070         "WHERE (DATEDIFF( CURDATE(), date_modified ) <= 30 ) ", "" },
00071 #endif
00072 
00073     {   "By Album",
00074         "song.album_id",
00075         "SELECT a.album_id as id, "
00076           "a.album_name as name, "
00077           "count( song.album_id ) as children "
00078             "FROM music_songs song join music_albums a on a.album_id = song.album_id "
00079             "%1 "
00080             "GROUP BY a.album_id "
00081             "ORDER BY a.album_name",
00082         "WHERE song.album_id=:KEY", "album.album_name" },
00083 
00084 #if 0
00085     {   "By Artist",
00086         "artist_id",
00087         "SELECT a.artist_id as id, "
00088           "a.artist_name as name, "
00089           "count( distinct song.artist_id ) as children "
00090             "FROM music_songs song join music_artists a on a.artist_id = song.artist_id "
00091             "%1 "
00092             "GROUP BY a.artist_id "
00093             "ORDER BY a.artist_name",
00094         "WHERE song.artist_id=:KEY", "" },
00095 
00096 {   "By Genre",
00097         "genre_id",
00098         "SELECT g.genre_id as id, "
00099           "genre as name, "
00100           "count( distinct song.genre_id ) as children "
00101             "FROM music_songs song join music_genres g on g.genre_id = song.genre_id "
00102             "%1 "
00103             "GROUP BY g.genre_id "
00104             "ORDER BY g.genre",
00105         "WHERE song.genre_id=:KEY", "" },
00106 #endif
00107 
00108 };
00109 
00110 int UPnpCDSMusic::g_nRootCount = sizeof( g_RootNodes ) / sizeof( UPnpCDSRootInfo );
00111 
00113 //
00115 
00116 UPnpCDSRootInfo *UPnpCDSMusic::GetRootInfo( int nIdx )
00117 {
00118     if ((nIdx >=0 ) && ( nIdx < g_nRootCount ))
00119         return &(g_RootNodes[ nIdx ]);
00120 
00121     return NULL;
00122 }
00123 
00125 //
00127 
00128 int UPnpCDSMusic::GetRootCount()
00129 {
00130     return g_nRootCount;
00131 }
00132 
00134 //
00136 
00137 QString UPnpCDSMusic::GetTableName( QString sColumn )
00138 {
00139     return "music_songs song";
00140 }
00141 
00143 //
00145 
00146 QString UPnpCDSMusic::GetItemListSQL( QString /* sColumn */ )
00147 {
00148     return "SELECT song.song_id as intid, artist.artist_name as artist, "     \
00149            "album.album_name as album, song.name as title, "                  \
00150            "genre.genre, song.year, song.track as tracknum, "                 \
00151            "song.description, song.filename, song.length "                    \
00152            "FROM music_songs song "                                           \
00153            " join music_artists artist on artist.artist_id = song.artist_id " \
00154            " join music_albums album on album.album_id = song.album_id "      \
00155            " join music_genres genre on  genre.genre_id = song.genre_id ";
00156 }
00157 
00159 //
00161 
00162 void UPnpCDSMusic::BuildItemQuery( MSqlQuery &query, const QStringMap &mapParams )
00163 {
00164     int     nId    = mapParams[ "Id" ].toInt();
00165 
00166     QString sSQL = QString( "%1 WHERE song.song_id=:ID " )
00167                       .arg( GetItemListSQL() );
00168 
00169     query.prepare( sSQL );
00170 
00171     query.bindValue( ":ID", (int)nId );
00172 }
00173 
00175 //
00177 
00178 bool UPnpCDSMusic::IsBrowseRequestForUs( UPnpCDSRequest *pRequest )
00179 {
00180     // ----------------------------------------------------------------------
00181     // See if we need to modify the request for compatibility
00182     // ----------------------------------------------------------------------
00183 
00184     // Xbox360 compatibility code.
00185 
00186     if (pRequest->m_eClient == CDS_ClientXBox && 
00187         pRequest->m_sContainerID == "7")
00188     {
00189         pRequest->m_sObjectId = "Music";
00190 
00191         LOG(VB_UPNP, LOG_INFO,
00192             "UPnpCDSMusic::IsBrowseRequestForUs - Yes, ContainerId == 7");
00193 
00194         return true;
00195     }
00196 
00197     if ((pRequest->m_sObjectId.isEmpty()) && 
00198         (!pRequest->m_sContainerID.isEmpty()))
00199         pRequest->m_sObjectId = pRequest->m_sContainerID;
00200 
00201     LOG(VB_UPNP, LOG_INFO,
00202         "UPnpCDSMusic::IsBrowseRequestForUs - Not sure... Calling base class.");
00203 
00204     return UPnpCDSExtension::IsBrowseRequestForUs( pRequest );
00205 }
00206 
00208 //
00210 
00211 bool UPnpCDSMusic::IsSearchRequestForUs( UPnpCDSRequest *pRequest )
00212 {
00213     // ----------------------------------------------------------------------
00214     // See if we need to modify the request for compatibility
00215     // ----------------------------------------------------------------------
00216 
00217     // XBox 360 compatibility code
00218 
00219     if (pRequest->m_eClient == CDS_ClientXBox && 
00220         pRequest->m_sContainerID == "7")
00221     {
00222         pRequest->m_sObjectId       = "Music/1";
00223         pRequest->m_sSearchCriteria = "object.container.album.musicAlbum";
00224         pRequest->m_sSearchList.append( pRequest->m_sSearchCriteria );
00225 
00226         LOG(VB_UPNP, LOG_INFO, "UPnpCDSMusic::IsSearchRequestForUs... Yes.");
00227 
00228         return true;
00229     }
00230 
00231     if (pRequest->m_sContainerID == "4")
00232     {
00233         pRequest->m_sObjectId       = "Music";
00234         pRequest->m_sSearchCriteria = "object.item.audioItem.musicTrack";
00235         pRequest->m_sSearchList.append( pRequest->m_sSearchCriteria );
00236 
00237         LOG(VB_UPNP, LOG_INFO, "UPnpCDSMusic::IsSearchRequestForUs... Yes.");
00238 
00239         return true;
00240     }
00241 
00242     if ((pRequest->m_sObjectId.isEmpty()) && 
00243         (!pRequest->m_sContainerID.isEmpty()))
00244         pRequest->m_sObjectId = pRequest->m_sContainerID;
00245 
00246     LOG(VB_UPNP, LOG_INFO,
00247         "UPnpCDSMusic::IsSearchRequestForUs.. Don't know, calling base class.");
00248 
00249     return UPnpCDSExtension::IsSearchRequestForUs( pRequest );
00250 }
00251 
00253 //
00255 
00256 void UPnpCDSMusic::AddItem( const UPnpCDSRequest    *pRequest, 
00257                             const QString           &sObjectId,
00258                             UPnpCDSExtensionResults *pResults,
00259                             bool                     bAddRef,
00260                             MSqlQuery               &query )
00261 {
00262     QString        sName;
00263 
00264     int            nId          = query.value( 0).toInt();
00265     QString        sArtist      = query.value( 1).toString();
00266     QString        sAlbum       = query.value( 2).toString();
00267     QString        sTitle       = query.value( 3).toString();
00268     QString        sGenre       = query.value( 4).toString();
00269 //    int            nYear        = query.value( 5).toInt();
00270     int            nTrackNum    = query.value( 6).toInt();
00271     QString        sDescription = query.value( 7).toString();
00272     QString        sFileName    = query.value( 8).toString();
00273     uint           nLength      = query.value( 9).toInt();
00274 
00275 #if 0
00276     if ((nNodeIdx == 0) || (nNodeIdx == 1))
00277     {
00278         sName = QString( "%1-%2:%3" )
00279                    .arg( sArtist)
00280                    .arg( sAlbum )
00281                    .arg( sTitle );
00282     }
00283     else
00284 #endif
00285         sName = sTitle;
00286 
00287 
00288     // ----------------------------------------------------------------------
00289     // Cache Host ip Address & Port
00290     // ----------------------------------------------------------------------
00291 
00292 #if 0
00293     if (!m_mapBackendIp.contains( sHostName ))
00294         m_mapBackendIp[ sHostName ] = gCoreContext->GetSettingOnHost( "BackendServerIp", sHostName);
00295 
00296     if (!m_mapBackendPort.contains( sHostName ))
00297         m_mapBackendPort[ sHostName ] = gCoreContext->GetSettingOnHost("BackendStatusPort", sHostName);
00298 #endif
00299 
00300     QString sServerIp = gCoreContext->GetSetting( "BackendServerIp"   );
00301     QString sPort     = gCoreContext->GetSetting( "BackendStatusPort" );
00302 
00303     // ----------------------------------------------------------------------
00304     // Build Support Strings
00305     // ----------------------------------------------------------------------
00306 
00307     QString sURIBase   = QString( "http://%1:%2/Content/" )
00308                             .arg( sServerIp )
00309                             .arg( sPort     );
00310 
00311     QString sURIParams = QString( "?Id=%1" )
00312                             .arg( nId );
00313 
00314 
00315     QString sId        = QString( "Music/1/item%1")
00316                             .arg( sURIParams );
00317 
00318     CDSObject *pItem   = CDSObject::CreateMusicTrack( sId,
00319                                                       sName,
00320                                                       sObjectId );
00321     pItem->m_bRestricted  = true;
00322     pItem->m_bSearchable  = true;
00323     pItem->m_sWriteStatus = "NOT_WRITABLE";
00324 
00325     if ( bAddRef )
00326     {
00327         QString sRefId = QString( "%1/0/item%2")
00328                             .arg( m_sExtensionId )
00329                             .arg( sURIParams     );
00330 
00331         pItem->SetPropValue( "refID", sRefId );
00332     }
00333 
00334     pItem->SetPropValue( "genre"                , sGenre      );
00335     pItem->SetPropValue( "description"          , sTitle      );
00336     pItem->SetPropValue( "longDescription"      , sDescription);
00337 
00338     pItem->SetPropValue( "artist"               ,  sArtist    );
00339     pItem->SetPropValue( "album"                ,  sAlbum     );
00340     pItem->SetPropValue( "originalTrackNumber"  ,  QString::number(nTrackNum));
00341 
00342 #if 0
00343     pObject->AddProperty( new Property( "publisher"       , "dc"   ));
00344     pObject->AddProperty( new Property( "language"        , "dc"   ));
00345     pObject->AddProperty( new Property( "relation"        , "dc"   ));
00346     pObject->AddProperty( new Property( "rights"          , "dc"   ));
00347 
00348 
00349     pObject->AddProperty( new Property( "playlist"            , "upnp" ));
00350     pObject->AddProperty( new Property( "storageMedium"       , "upnp" ));
00351     pObject->AddProperty( new Property( "contributor"         , "dc"   ));
00352     pObject->AddProperty( new Property( "date"                , "dc"   ));
00353 #endif
00354 
00355     pResults->Add( pItem );
00356 
00357     // ----------------------------------------------------------------------
00358     // Add Music Resource Element based on File extension (HTTP)
00359     // ----------------------------------------------------------------------
00360 
00361     QFileInfo fInfo( sFileName );
00362 
00363     QString sMimeType = HTTPRequest::GetMimeType( fInfo.suffix() );
00364     QString sProtocol = QString( "http-get:*:%1:DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01500000000000000000000000000000" ).arg( sMimeType  );
00365     QString sURI      = QString( "%1GetMusic%2").arg( sURIBase   )
00366                                                 .arg( sURIParams );
00367 
00368     Resource *pRes = pItem->AddResource( sProtocol, sURI );
00369 
00370     nLength /= 1000;
00371 
00372     QString sDur;
00373 
00374     sDur.sprintf("%02d:%02d:%02d",
00375                   (nLength / 3600) % 24,
00376                   (nLength / 60) % 60,
00377                   nLength % 60);
00378 
00379     pRes->AddAttribute( "duration"  , sDur      );
00380 }
00381 
00382 // vim:ts=4:sw=4:ai:et:si:sts=4
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends