#!/usr/bin/env python # Licensed under the MIT license # http://opensource.org/licenses/mit-license.php # Copyright 2005, Tim Potter # Copyright 2006 John-Mark Gurney # # $Id$ # # Modules to import, maybe config file or something? def tryloadmodule(mod): try: return __import__(mod) except ImportError: import traceback traceback.print_exc() pass # ZipStorage w/ tar support should be last as it will gobble up empty files. modules = [ 'dvd', 'shoutcast', 'ZipStorage' ] modmap = {} for i in modules: modmap[i] = tryloadmodule(i) import debug # my debugging module debug.doDebugging(True) # open up debugging port for i in modules: debug.insertnamespace(i, modmap[i]) from DIDLLite import TextItem, AudioItem, VideoItem, ImageItem, Resource, StorageFolder from FSStorage import FSDirectory import os import os.path import random import socket import string import sys from twisted.python import log from twisted.internet import reactor def generateuuid(): if False: return 'uuid:asdflkjewoifjslkdfj' return ''.join([ 'uuid:'] + map(lambda x: random.choice(string.letters), xrange(20))) listenAddr = sys.argv[1] if len(sys.argv) > 2: listenPort = int(sys.argv[2]) if listenPort < 1024 or listenPort > 65535: raise ValueError, 'port out of range' else: listenPort = random.randint(10000, 65000) log.startLogging(sys.stdout) # Create SSDP server from SSDP import SSDPServer, SSDP_PORT, SSDP_ADDR s = SSDPServer() debug.insertnamespace('s', s) port = reactor.listenMulticast(SSDP_PORT, s) port.joinGroup(SSDP_ADDR) port.setLoopbackMode(0) # don't get our own sends uuid = generateuuid() urlbase = 'http://%s:%d/' % (listenAddr, listenPort) # Create SOAP server from twisted.web import server, resource, static from ContentDirectory import ContentDirectoryServer from ConnectionManager import ConnectionManagerServer class WebServer(resource.Resource): def __init__(self): resource.Resource.__init__(self) class RootDevice(static.Data): def __init__(self): r = { 'hostname': socket.gethostname(), 'uuid': uuid, 'urlbase': urlbase, } d = file('root-device.xml').read() % r static.Data.__init__(self, d, 'text/xml') root = WebServer() debug.insertnamespace('root', root) content = resource.Resource() cds = ContentDirectoryServer('My Media Server', klass = FSDirectory, path = 'media', urlbase = os.path.join(urlbase, 'content'), webbase = content) # This sets up the root to be the media dir so we don't have to enumerate the directory debug.insertnamespace('cds', cds) root.putChild('ContentDirectory', cds) cds = cds.control root.putChild('ConnectionManager', ConnectionManagerServer()) root.putChild('root-device.xml', RootDevice()) root.putChild('content', content) # Purely to ensure some sane mime-types. On MacOSX I need these. medianode = static.File('pymediaserv') medianode.contentTypes.update( { '.wmv': 'video/x-ms-wmv', #'.ts': 'video/mp2t', '.ts': 'video/mpeg', # we may want this instead of mp2t '.m2t': 'video/mpeg', '.mp4': 'video/mp4', #'.mp4': 'video/mpeg', '.dat': 'video/mpeg', # VCD tracks '.ogm': 'application/ogg', '.vob': 'video/mpeg', #'.m4a': 'audio/mp4', # D-Link can't seem to play AAC files. }) del medianode site = server.Site(root) reactor.listenTCP(listenPort, site) # we need to do this after the children are there, since we send notifies s.register('%s::upnp:rootdevice' % uuid, 'upnp:rootdevice', urlbase + 'root-device.xml') s.register(uuid, uuid, urlbase + 'root-device.xml') s.register('%s::urn:schemas-upnp-org:device:MediaServer:1' % uuid, 'urn:schemas-upnp-org:device:MediaServer:1', urlbase + 'root-device.xml') s.register('%s::urn:schemas-upnp-org:service:ConnectionManager:1' % uuid, 'urn:schemas-upnp-org:device:ConnectionManager:1', urlbase + 'root-device.xml') s.register('%s::urn:schemas-upnp-org:service:ContentDirectory:1' % uuid, 'urn:schemas-upnp-org:device:ContentDirectory:1', urlbase + 'root-device.xml') # Main loop reactor.run()