Thursday, October 15, 2015

CSS to Display UPnP Media Info

I was playing with UPnP and my goal interest was to display on webpage what is currently playing on XBOX360. (But would work on most of UPnP devices.)
So first we need python script which will ask for information. For this we need service AVTransport and action GetMediaInfo, if you are not familiar with UPnP you can find more here
I have few others monitoring scripts which are storing info about devices in my network to sqlite3 DB. Following script use this DB to find current uri for of my XBOX 360 UPnP service and send the request to get the data.
#! /usr/bin/python

import sqlite3
import sys
import cgi
import httplib, urllib
import re
import suds

#As UPnP ports are dynamic I'm getting info from my DB, info is stored by monitoring script.
select_query = "SELECT ip,upnp_port FROM devices WHERE name like 'XBOX 360';"
judodb = sqlite3.connect('/var/www/judo.db')
cur = judodb.cursor()
rows = cur.execute(select_query)
for row in rows:
  ip = row[0]
  upnp_port = row[1]

judodb.commit()
judodb.close()


url = ip + ":" + str(upnp_port)
controlUrl = "/Control/AVTransport"
service = "urn:schemas-upnp-org:service:AVTransport:1"
soap_args = "0"

actions = ["GetTransportInfo", "GetMediaInfo"]

for action in actions:
  conn = httplib.HTTPConnection(url)
  soap_data = ''+soap_args+''

  #FOR DEBUG
  #print soap_data

  params = urllib.urlencode({'q': 'set'})
  headers = { "Content-Type": "text/xml", "Content-Length": "%d" % len(soap_data), "SOAPACTION": '"'+service+'#'+action+'"' }

  conn.request("POST", controlUrl , "", headers)
  conn.send(soap_data)

  response = conn.getresponse()

  #FOR DEBUG
  #print response.status, response.reason

  #In UPnP there is sometime nested xml inside xml as string with < and > instead of < and >
  #lines below fix this to male it all one xml
  responsestr = response.read()
  responsestr = responsestr.replace(">",">")
  responsestr = responsestr.replace("<","<")

  print responsestr

I use javascript XMLHttpRequest to call the script and write the data I get to webpage. Below is eaxmple of such data.
<div id="UPnPPlayInfo" class="list"><!--?xml version="1.0"?-->
<s:envelope s:encodingstyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
 <s:body>
  <u:gettransportinforesponse xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
    <currenttransportstate>STOPPED</currenttransportstate>
    <currenttransportstatus>OK</currenttransportstatus>
    <currentspeed>1</currentspeed>
  </u:gettransportinforesponse>
 </s:body>
</s:envelope>


<!--?xml version="1.0"?-->
<s:envelope s:encodingstyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
 <s:body>
  <u:getmediainforesponse xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
           <nrtracks>1</nrtracks>
           <mediaduration>0:01:51.856</mediaduration>
           <currenturi>http://10.0.0.33:9001/disk/DLNA-PNMP3-OP01-FLAGS01700000/O0$1$8I566796.mp3</currenturi>
           <currenturimetadata>
             <item id="0$1$12$4477R566796" parentid="0$1$12$4477" refid="0$1$8I566796" restricted="1">
               <dc:title>Ja zadam</dc:title><dc:date>2009-01-01</dc:date>
               <upnp:genre>Folk</upnp:genre
               ><upnp:album>Virtualky</upnp:album>
               <upnp:originaltracknumber>4</upnp:originaltracknumber>
               <dc:creator>Jaromir Nohavica</dc:creator>
               <upnp:albumarturi dlna:profileid="JPEG_TN">http://10.0.0.33:9001/disk/DLNA-PNJPEG_TN-OP01-CI1-FLAGS00d00000/defaultalbumart/a_u_d_i_o.jpg/O0$1$8I566796.jpg?scale=160x160</upnp:albumarturi>
               <upnp:artist>Jaromir Nohavica</upnp:artist>
               <pv:extension>mp3</pv:extension>
               <upnp:albumartist>Jaromir Nohavica</upnp:albumartist>
               <pv:modificationtime>1255889570</pv:modificationtime>
               <pv:addedtime>1401613856</pv:addedtime>
               <pv:lastupdated>1255889570</pv:lastupdated>
               <pv:album_crosslink>0$1$12$4153</pv:album_crosslink>
               <pv:artist_crosslink>0$1$11$3960</pv:artist_crosslink>
               <pv:genre_crosslink>0$1$10$2756</pv:genre_crosslink>
               <pv:numberofthisdisc>1</pv:numberofthisdisc>
               <upnp:author role="Composer">Jaromir Nohavica</upnp:author>
               <upnp:artist role="Composer">Jaromir Nohavica</upnp:artist>
               <pv:bookmark>uuid:55076f6e-6b79-4d65-64a7-5067f0a1791f,-L21udC9tZWRpYVNoYXJlcy9tdXNpYy9tdXNpYy9KYXJvbWlyX05vaGF2aWNhL1ZpcnR1YWxreS9qYV96YWRhbS5tcDM=</pv:bookmark>
            </item>
          </currenturimetadata>
    </u:getmediainforesponse>
  </s:body>
</s:envelope>

Last thing I need to do is to use CSS to display only what I want and add some formatting and additional text.
/* LIST OF TAGS TO BE NOT DISPLAYED  */
currenttransportstatus, currentspeed, currenturi, playmedium, recordmedium, writestatus, res, mediaduration, nrtracks, desc {display: none}
upnp\:class, upnp\:albumarturi, dc\:creator, upnp\:albumartist, upnp\:author  {display: none}
pv\:extension, pv\:modificationtime, pv\:addedtime, pv\:lastupdated, pv\:album_crosslink, pv\:artist_crosslink, pv\:genre_crosslink, pv\:bookmark, pv\:numberofdiscs, pv\:numberofthisdisc {display: none}

DIDL-Lite {display: block}

Meta_Info:before {content: "Currently Playing:"; font-weight: bold}
Play_Mode:before {content: "Play mode:"; font-weight: bold}

/* LIST OF TAGS TO BE DISPLAYED ONE PER LINE */
upnp\:genre, upnp\:originaltracknumber, upnp\:album, upnp\:artist, dc\:title, dc\:date, dc\:publisher {display: list-item; list-style-type: none}


upnp\:artist:before {content: "Artist: "; margin-left: 10px; font-weight: bold}
upnp\:album:before {content: "Album: "; margin-left: 10px; font-weight: bold}
upnp\:genre:before {content: "Genre: "; margin-left: 10px; font-weight: bold}
upnp\:originaltracknumber:before {content: "Track No.: "; margin-left: 10px; font-weight: bold}
dc\:title:before {content: "Song: "; margin-left: 10px; font-weight: bold}
dc\:date:before {content: "Date: "; margin-left: 10px; font-weight: bold}
dc\:publisher:before {content: "Publisher: "; margin-left: 10px; font-weight: bold}