view iview.py @ 0:fa7ca67af8c9

Initial commit of a python program to fetch iview streams using flvstreamer.
author Daniel O'Connor <darius@dons.net.au>
date Thu, 20 Aug 2009 16:48:16 +0930
parents
children f914f08d69f5
line wrap: on
line source

#!/usr/bin/env python

import exceptions
import htmlentitydefs
import re
import sys
import time
import urllib2
import xml.dom.minidom as minidom
from xml.parsers.expat import ExpatError

confurl = 'http://www.abc.net.au/iview/iview_231_config.xml'

pattern = re.compile("&(\w+?);")

def descape_entity(m, defs=htmlentitydefs.entitydefs):
    try:
        return defs[m.group(1)]
    except KeyError:
        return m.group(0) # use as is
def descape(string):
    return pattern.sub(descape_entity, string)

def toBool(s):
    if type(s) is bool:
        return s
    s = str(s).strip().lower()
    return not s[0] in ['f','n','0']

class NoAsset(exceptions.Exception):
    pass

class Series(object):
    def __init__(self, seriesElem):
        self.id = seriesElem.getAttribute("id")
        self.url = seriesElem.getAttribute("href")
        
        # Fetch titles and so on
        #print "Fetching series URL " + self.url
        xmlp = minidom.parse(urllib2.urlopen(self.url))
        self.title = self.gatherChildren(xmlp.getElementsByTagName("title"))
        self.descr = self.gatherChildren(xmlp.getElementsByTagName("description"))

        # No asset means unpublished?
        assets = xmlp.getElementsByTagName("abc:videoAsset")
        if len(assets) == 0:
            raise NoAsset

        self.asset = assets[0].childNodes[0].data.rstrip('.flv')

        rating = xmlp.getElementsByTagName("abc:rating")[0].childNodes
        if len(rating) > 0:
            self.rating = descape(rating[0].data)
        else:
            self.rating = "unrated"

        self.imgurl = xmlp.getElementsByTagName("image")[0].getElementsByTagName("url")[0].childNodes[0].data
        self.expiry = time.strptime(xmlp.getElementsByTagName("abc:expireDate")[0].childNodes[0].data ,
                                    '%d/%m/%Y %H:%M:%S')

    def gatherChildren(self, elemList):
        rtn = []
        for e in elemList:
            if len(e.childNodes) > 0:
                rtn.append(descape(e.childNodes[0].data.strip()))
        return rtn

class Channel(object):
    def __init__(self, chanElem):
        self.id = chanElem.getAttribute("id")
        self.sort = chanElem.getAttribute("sort")
        self.path = chanElem.getAttribute("path")
        self.thumb = chanElem.getAttribute("thumb")
        self.name = descape(chanElem.getElementsByTagName("name")[0].childNodes[0].data)
        self.descr = descape(chanElem.getElementsByTagName("description")[0].childNodes[0].data)
        self.series = []

    def getSeries(self):
        # This can take ages
        print "Fetching series for channel " + self.name
        # Series is nested for some reason
        xmlp = minidom.parse(urllib2.urlopen(self.path))
        nl = xmlp.getElementsByTagName("series")[0]
        for s in nl.getElementsByTagName("series"):
            try:
                self.series.append(Series(s))
            except ExpatError:
                print "Unable to parse XML, skipping"
                continue
            except NoAsset:
                print "No asset tag, skipping"
                continue
            
class IView(object):
    def __init__(self):
        # Fetch and parse config URL
        #print "Fetching configuration URL"
        xmlp = minidom.parse(urllib2.urlopen(confurl))
        self.params = {}
        for param in xmlp.getElementsByTagName("param"):
            self.params[param.getAttribute("name")] = param.getAttribute("value")

        # Get token & metered status from auth_path URL
        #print "Fetching authorisation information"
        self.getAuth()

        # Build channel list
        #print "Fetching channel list"
        xmlp = minidom.parse(urllib2.urlopen(self.params['base_url'] + '/' + self.params['xml_channels']))
        self.channels = []
        for chan in xmlp.getElementsByTagName("channel"):
            self.channels.append(Channel(chan))

    def getAuth(self):
        xmlp = minidom.parse(urllib2.urlopen(self.params['auth_path']))
        self.token = xmlp.getElementsByTagName("token")[0].childNodes[0].data
        self.metered = not toBool(xmlp.getElementsByTagName("free")[0].childNodes[0].data)

        server = xmlp.getElementsByTagName("server")[0].childNodes
        if len(server) == 0:
            self.rtmp = self.params['server_streaming'].rstrip('/ondemand') + '////' + self.params['media_path']
            self.tcurl = self.params['server_streaming']
        else:
            self.rtmp = xmlp.getElementsByTagName("server")[0].childNodes[0].data
            self.tcurl = None

    def genFetchCmd(self, series, outfile):
        cmd = ['-m', '1200']
        if self.tcurl == None:
            cmd += ['-r', self.rtmp + '?auth=' + self.token]
            cmd += ['-y', series.asset]
        else:
            cmd += ['-r', self.rtmp + series.asset]
            cmd += ['-t', self.tcurl + '?auth=' + self.token]
        cmd += ['-o', outfile]
        return cmd

# Non-metered:    
#/home/darius/projects/flvstreamer/flvstreamer_x86
# -r rtmp://cp53909.edgefcs.net////flash/playback/_definst_/catch_up/compass_09_23_28
# -t rtmp://cp53909.edgefcs.net/ondemand?auth=daEbFbibab6d4c0cwdjcwcya4dTb9cucucw-bkJnTd-8-klt_rFzqL&aifp=v001
# -o ./compass_09_23_28.flv -m 1200