diff --git a/ContentDirectory.py b/ContentDirectory.py index 5826c91..b02ea50 100644 --- a/ContentDirectory.py +++ b/ContentDirectory.py @@ -29,9 +29,42 @@ from DIDLLite import DIDLElement, Container, Movie, Resource, MusicTrack import traceback from urllib import quote -class ContentDirectoryControl(UPnPPublisher): +class ContentDirectoryControl(UPnPPublisher, dict): """This class implements the CDS actions over SOAP.""" + def getnextID(self): + ret = str(self.nextID) + self.nextID += 1 + return ret + + def addContainer(self, parent, title, **kwargs): + ret = self.addItem(parent, Container, title, **kwargs) + self.children[ret] = [] + return ret + + def addItem(self, parent, klass, *args, **kwargs): + assert isinstance(self[parent], Container) + nid = self.getnextID() + i = klass(nid, parent, *args, **kwargs) + self.children[parent].append(i) + self[i.id] = i + return i.id + + def getchildren(self, item): + assert isinstance(self[item], Container) + return self.children[item][:] + + def __init__(self, title, *args): + super(ContentDirectoryControl, self).__init__(*args) + fakeparent = '-1' + self.nextID = 0 + self.children = { fakeparent: []} + self[fakeparent] = Container(None, '-1', 'fake') + root = self.addContainer(fakeparent, title) + assert root == '0' + del self[fakeparent] + del self.children[fakeparent] + # Required actions def soap_GetSearchCapabilities(self, *args, **kwargs): @@ -61,6 +94,8 @@ class ContentDirectoryControl(UPnPPublisher): (ObjectID, BrowseFlag, Filter, StartingIndex, RequestedCount, SortCriteria) = args + StartingIndex = int(StartingIndex) + RequestedCount = int(RequestedCount) log.msg('Browse(ObjectID=%s, BrowseFlags=%s, Filter=%s, ' 'StartingIndex=%s RequestedCount=%s SortCriteria=%s)' % @@ -68,40 +103,16 @@ class ContentDirectoryControl(UPnPPublisher): `RequestedCount`, `SortCriteria`)) didl = DIDLElement() + result = {} try: - - if ObjectID == '0': - c = Container('media', '0', 'All media') - c.childCount = 5 - c.searchable = 0 - didl.addItem(c) - - elif ObjectID == '0\\Music\\': - - c = Container('0\\Music\\Spotty\\', '0\\Music\\', 'Spotty') - c.childCount = 6 - c.searchable = 0 - didl.addItem(c) - - c = Container('0\\Music\\Foot\\', '0\\Music\\', 'Foot') - c.childCount = 1 - c.searchable = 0 - didl.addItem(c) - - - elif ObjectID == '0\\Music\\Spotty\\': - - m = MusicTrack('0\\Music\\media\\foo.mp3', '0\\Music\\', 'foo.mp3') - - m.res = Resource('http://192.168.1.105:8080/media/foo.mp3', 'http-get:*:audio/mpeg:*') - m.res.size = 1234 - m.res.bitrate = 256 - m.genre = 'Others' - m.artist = 'Others' - m.album = 'Others' - - didl.addItem(m) + if BrowseFlag == 'BrowseDirectChildren': + ch = self.getchildren(ObjectID)[StartingIndex: StartingIndex + RequestedCount] + log.msg(ch) + log.msg(dict.__repr__(self)) + filter(lambda x, s = self, d = didl: d.addItem(s[x.id]) and None, ch) + else: + didl.addItem(self[ObjectID]) result = {'BrowseResponse': {'Result': didl.toString() , 'NumberReturned': didl.numItems(), @@ -205,7 +216,8 @@ class ContentDirectoryControl(UPnPPublisher): (`ContainerID`, `ObjectID`)) class ContentDirectoryServer(resource.Resource): - def __init__(self): + def __init__(self, title): resource.Resource.__init__(self) self.putChild('scpd.xml', static.File('content-directory-scpd.xml')) - self.putChild('control', ContentDirectoryControl()) + self.control = ContentDirectoryControl(title) + self.putChild('control', self.control) diff --git a/pymediaserv b/pymediaserv index c34531d..7212625 100755 --- a/pymediaserv +++ b/pymediaserv @@ -5,10 +5,14 @@ # Copyright 2005, Tim Potter <tpot@samba.org> +from DIDLLite import TextItem, AudioItem, VideoItem, Resource +import os +import os.path import random import socket import string import sys +import traceback from twisted.python import log from twisted.internet import reactor @@ -61,10 +65,13 @@ class RootDevice(static.Data): static.Data.__init__(self, d, 'text/xml') root = WebServer() -root.putChild('ContentDirectory', ContentDirectoryServer()) +cds = ContentDirectoryServer('My Media Server') +root.putChild('ContentDirectory', cds) +cds = cds.control root.putChild('ConnectionManager', ConnectionManagerServer()) root.putChild('root-device.xml', RootDevice()) + # Area of server to serve media files from from MediaServer import MediaServer @@ -78,6 +85,33 @@ medianode.contentTypes.update( { }) root.putChild('media', medianode) +# Set up media files +allmedia = cds.addContainer('0', 'All Media') +log.msg('allmedia: %s' % repr(allmedia)) +for i in os.listdir('media'): + fpath = os.path.join('media', i) + try: + if not os.path.isfile(fpath): + log.msg('skipping: %s' % fpath) + continue + fn, ext = os.path.splitext(i) + mt = medianode.contentTypes[ext] + ty = mt.split('/')[0] + if ty == 'video': + klass = VideoItem + elif ty == 'audio': + klass = AudioItem + elif ty == 'text': + klass = TextItem + else: + raise KeyError, 'no item for mt: %s' % mt + + item = cds.addItem(allmedia, klass, fn) + cds[item].res = Resource('%smedia/%s' % (urlbase, i), 'http-get:*:%s:*' % mt) + cds[item].res.size = os.path.getsize(fpath) + except KeyError: + traceback.print_exc(file=log.logfile) + site = server.Site(root) reactor.listenTCP(listenPort, site)