Viewing file: iradio_storage.py (11.41 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
# Licensed under the MIT license # http://opensource.org/licenses/mit-license.php
# Copyright 2007, Frank Scholz <coherence@beebits.net>
from twisted.internet import defer
from coherence.upnp.core import utils
from coherence.upnp.core.DIDLLite import classChooser, Container, Resource, DIDLElement
from coherence import log from coherence.backend import BackendItem, BackendStore
from urlparse import urlsplit
class ProxyStream(utils.ReverseProxyResource, log.Loggable): logCategory = 'iradio' def __init__(self, uri): self.uri = uri _,host_port,path,_,_ = urlsplit(uri) if host_port.find(':') != -1: host,port = tuple(host_port.split(':')) port = int(port) else: host = host_port port = 80
if path == '': path = '/'
#print "ProxyStream init", host, port, path utils.ReverseProxyResource.__init__(self, host, port, path)
def requestFinished(self, result): """ self.connection is set in utils.ReverseProxyResource.render """ self.info("ProxyStream requestFinished") self.connection.transport.loseConnection()
def render(self, request): self.info("this is our render method",request.method, request.uri, request.client, request.clientproto) self.info("render", request.getAllHeaders()) if request.clientproto == 'HTTP/1.1': self.connection = request.getHeader('connection') if self.connection: tokens = map(str.lower, self.connection.split(' ')) if 'close' in tokens: d = request.notifyFinish() d.addBoth(self.requestFinished) else: d = request.notifyFinish() d.addBoth(self.requestFinished) return utils.ReverseProxyResource.render(self, request)
class IRadioItem(log.Loggable): logCategory = 'iradio'
def __init__(self, id, obj, parent, mimetype, urlbase, UPnPClass,update=False): self.id = id
self.name = obj.get('name') self.mimetype = mimetype
self.parent = parent if parent: parent.add_child(self,update=update)
if parent == None: parent_id = -1 else: parent_id = parent.get_id()
self.item = UPnPClass(id, parent_id, self.name) if isinstance(self.item, Container): self.item.childCount = 0 self.child_count = 0 self.children = None
if( len(urlbase) and urlbase[-1] != '/'): urlbase += '/'
if self.mimetype == 'directory': self.url = urlbase + str(self.id) else: self.url = urlbase + str(self.id) self.location = ProxyStream(obj.get('url')) #self.url = obj.get('url')
if self.mimetype == 'directory': self.update_id = 0 else: res = Resource(self.url, 'http-get:*:%s:%s' % (obj.get('mimetype'), ';'.join(('DLNA.ORG_PN=MP3', 'DLNA.ORG_CI=0', 'DLNA.ORG_OP=01', 'DLNA.ORG_FLAGS=01700000000000000000000000000000')))) res.size = 0 #None self.item.res.append(res)
def remove(self): if self.parent: self.parent.remove_child(self) del self.item
def add_child(self, child, update=False): if self.children == None: self.children = [] self.children.append(child) self.child_count += 1 if isinstance(self.item, Container): self.item.childCount += 1 if update == True: self.update_id += 1
def remove_child(self, child): self.info("remove_from %d (%s) child %d (%s)" % (self.id, self.get_name(), child.id, child.get_name())) if child in self.children: self.child_count -= 1 if isinstance(self.item, Container): self.item.childCount -= 1 self.children.remove(child) self.update_id += 1
def get_children(self,start=0,request_count=0): if self.children == None: def got_page(result): result = utils.parse_xml(result, encoding='utf-8') tunein = result.find('tunein') if tunein != None: tunein = tunein.get('base','/sbin/tunein-station.pls') prot,host_port,path,_,_ = urlsplit(self.store.config.get('genrelist','http://www.shoutcast.com/sbin/newxml.phtml')) tunein = prot + '://' + host_port + tunein
def append_new(result, s): result = result[0].split('\n') for line in result: if line.startswith('File1='): s['url'] = line[6:] self.store.append(s,self) break
l = [] for station in result.findall('station'): if station.get('mt') == 'audio/mpeg': d2 = utils.getPage('%s?id=%s' % (tunein, station.get('id')), timeout=20) d2.addCallback(append_new, {'name':station.get('name').encode('utf-8'), 'mimetype':station.get('mt'), 'id':station.get('id'), 'url':None}) d2.addErrback(got_error) l.append(d2) dl = defer.DeferredList(l)
def process_items(result): self.info("process_item", result, self.children) if self.children == None: return [] if request_count == 0: return self.children[start:] else: return self.children[start:request_count]
dl.addCallback(process_items) return dl
def got_error(error): self.warning("connection to ShoutCast service failed! %r", error) self.debug("%r", error.getTraceback())
d = utils.getPage('%s?genre=%s' % (self.store.config.get('genrelist','http://www.shoutcast.com/sbin/newxml.phtml'),self.name)) d.addCallbacks(got_page, got_error, None, None, None, None) return d else: if request_count == 0: return self.children[start:] else: return self.children[start:request_count]
def get_child_count(self): return self.child_count
def get_id(self): return self.id
def get_update_id(self): if hasattr(self, 'update_id'): return self.update_id else: return None
def get_path(self): return self.url
def get_name(self): return self.name
def get_parent(self): return self.parent
def get_item(self): return self.item
def get_xml(self): return self.item.toString()
def __repr__(self): return 'id: ' + str(self.id) + ' @ ' + self.url + ' ' + self.name
class IRadioStore(BackendStore):
logCategory = 'iradio'
implements = ['MediaServer']
def __init__(self, server, **kwargs): BackendStore.__init__(self,server,**kwargs) self.next_id = 1000 self.config = kwargs self.name = kwargs.get('name','iRadioStore')
self.update_id = 0
self.wmc_mapping = {'4': 1000}
self.store = {}
self.init_completed()
def __repr__(self): return self.__class__.__name__
def append( self, obj, parent): if isinstance(obj, basestring): mimetype = 'directory' else: mimetype = obj['mimetype']
UPnPClass = classChooser(mimetype) id = self.getnextID() update = False if hasattr(self, 'update_id'): update = True
self.store[id] = IRadioItem( id, obj, parent, mimetype, self.urlbase, UPnPClass, update=update) self.store[id].store = self if hasattr(self, 'update_id'): self.update_id += 1 if self.server: self.server.content_directory_server.set_variable(0, 'SystemUpdateID', self.update_id) if parent: #value = '%d,%d' % (parent.get_id(),parent_get_update_id()) value = (parent.get_id(),parent.get_update_id()) if self.server: self.server.content_directory_server.set_variable(0, 'ContainerUpdateIDs', value)
if mimetype == 'directory': return self.store[id]
return None
def len(self): return len(self.store)
def get_by_id(self,id): if isinstance(id, basestring): id = id.split('@',1) id = id[0] try: id = int(id) except ValueError: id = 1000
if id == 0: id = 1000 try: return self.store[id] except: return None
def getnextID(self): ret = self.next_id self.next_id += 1 return ret
def upnp_init(self): self.current_connection_id = None #parent = self.append('iRadio', None)
#self.append({'name':'GrooveFM','mimetype':'audio/mpeg','url':'http://80.252.111.34:10028/'}, parent) #self.append({'name':'Dancing Queen','mimetype':'audio/mpeg','url':'http://netzflocken.de/files/dq.mp3'}, parent)
parent = self.append({'name':'iRadio','mimetype':'directory'}, None)
def got_page(result): result = utils.parse_xml(result, encoding='utf-8') for genre in result.findall('genre'): self.append({'name':genre.get('name').encode('utf-8'), 'mimetype':'directory', 'url':'%s?genre=%s' % (self.config.get('genrelist','http://www.shoutcast.com/sbin/newxml.phtml'),genre.get('name'))},parent)
def got_error(error): self.warning("connection to ShoutCast service failed! %r", error) self.debug("%r", error.getTraceback())
utils.getPage(self.config.get('genrelist','http://www.shoutcast.com/sbin/newxml.phtml')).addCallbacks(got_page, got_error, None, None, None, None)
if self.server: self.server.connection_manager_server.set_variable(0, 'SourceProtocolInfo', ['http-get:*:audio/mpeg:*', 'http-get:*:audio/x-scpls:*'], default=True)
def main():
f = IRadioStore(None)
def got_upnp_result(result): print "upnp", result
f.upnp_init() #print f.store #r = f.upnp_Browse(BrowseFlag='BrowseDirectChildren', # RequestedCount=0, # StartingIndex=0, # ObjectID=0, # SortCriteria='*', # Filter='') #got_upnp_result(r)
if __name__ == '__main__':
from twisted.internet import reactor
reactor.callWhenRunning(main) reactor.run()
|