diff --git a/pymeds.py b/pymeds.py index c9a24d6..4e4dcb5 100755 --- a/pymeds.py +++ b/pymeds.py @@ -41,7 +41,6 @@ for i in modules: 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 @@ -51,38 +50,51 @@ import string import sys from twisted.python import log from twisted.internet import reactor +from twisted.application import internet, service +from twisted.python import usage 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) +class Options(usage.Options): + optParameters = [ + [ 'title', 't', 'My Media Server', 'Title of the server.', ], + [ 'path', 'p', 'media', 'Root path of the media to be served.', ], + ] -log.startLogging(sys.stdout) + def parseArgs(self, addr, port=None): + self['addr'] = addr + if port is None: + port = random.randint(10000, 65000) + else: + port = int(port) + if listenPort < 1024 or listenPort > 65535: + raise ValueError( + 'port must be between 1024 and 65535') + self['port'] = port -# Create SSDP server +listenAddr = config['addr'] +listenPort = config['port'] + +application = service.Application("PyMeds") +# Create SSDP server from SSDP import SSDPServer, SSDP_PORT, SSDP_ADDR s = SSDPServer() debug.insertnamespace('s', s) -port = reactor.listenMulticast(SSDP_PORT, s, listenMultiple=True) +port = internet.MulticastServer(SSDP_PORT, s, listenMultiple=True) +port.setServiceParent(application) port.joinGroup(SSDP_ADDR) port.setLoopbackMode(0) # don't get our own sends uuid = generateuuid() urlbase = 'http://%s:%d/' % (listenAddr, listenPort) -# Create SOAP server - +# Create SOAP server and content server from twisted.web import server, resource, static from ContentDirectory import ContentDirectoryServer from ConnectionManager import ConnectionManagerServer @@ -104,16 +116,11 @@ class RootDevice(static.Data): root = WebServer() debug.insertnamespace('root', root) content = resource.Resource() -mediapath = 'media' -if not os.path.isdir(mediapath): - print >>sys.stderr, \ - 'Sorry, %s is not a directory, no content to serve.' % `mediapath` - sys.exit(1) - -# This sets up the root to be the media dir so we don't have to -# enumerate the directory -cds = ContentDirectoryServer('My Media Server', klass=FSDirectory, - path=mediapath, 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 +cds = ContentDirectoryServer(config['title'], klass=FSDirectory, + path=config['path'], urlbase=os.path.join(urlbase, 'content'), + webbase=content) debug.insertnamespace('cds', cds) root.putChild('ContentDirectory', cds) cds = cds.control @@ -123,6 +130,7 @@ root.putChild('content', content) # Purely to ensure some sane mime-types. On MacOSX I need these. +# XXX - There isn't any easier way to get to the mime-type dict that I know of. medianode = static.File('pymediaserv') medianode.contentTypes.update( { # From: http://support.microsoft.com/kb/288102 @@ -135,6 +143,10 @@ medianode.contentTypes.update( { '.wm': 'video/x-ms-wm', '.wmx': 'video/x-ms-wmx', + # From: http://www.matroska.org/technical/specs/notes.html + '.mkv': 'video/x-matroska', + '.mka': 'audio/x-matroska', + #'.ts': 'video/mp2t', '.ts': 'video/mpeg', # we may want this instead of mp2t '.m2t': 'video/mpeg', @@ -149,29 +161,23 @@ medianode.contentTypes.update( { del medianode site = server.Site(root) -reactor.listenTCP(listenPort, site) +internet.TCPServer(listenPort, site).setServiceParent(application) # we need to do this after the children are there, since we send notifies +import urlparse +rdxml = urlparse.join(urlbase, 'root-device.xml') s.register('%s::upnp:rootdevice' % uuid, - 'upnp:rootdevice', - urlbase + 'root-device.xml') + 'upnp:rootdevice', rdxml) s.register(uuid, uuid, - urlbase + 'root-device.xml') + rdxml) s.register('%s::urn:schemas-upnp-org:device:MediaServer:1' % uuid, - 'urn:schemas-upnp-org:device:MediaServer:1', - urlbase + 'root-device.xml') + 'urn:schemas-upnp-org:device:MediaServer:1', rdxml) s.register('%s::urn:schemas-upnp-org:service:ConnectionManager:1' % uuid, - 'urn:schemas-upnp-org:device:ConnectionManager:1', - urlbase + 'root-device.xml') + 'urn:schemas-upnp-org:device:ConnectionManager:1', rdxml) 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() + 'urn:schemas-upnp-org:device:ContentDirectory:1', rdxml)