Browse Source

Make this closer to a real twisted program... we do proper command

line parsing now...  but keep the old interface..

This allows us to parametize the service better, but I still need
to make it a plugin if I want twistd to be happy... but now someone
can write a .tac file w/ a config and things will work...

[git-p4: depot-paths = "//depot/": change = 1271]
main
John-Mark Gurney 16 years ago
parent
commit
d13e86b9ed
2 changed files with 146 additions and 114 deletions
  1. +23
    -0
      pymediaserv
  2. +123
    -114
      pymeds.py

+ 23
- 0
pymediaserv View File

@@ -0,0 +1,23 @@
#!/usr/bin/env python

from twisted.internet import reactor
from twisted.application import service
from twisted.python import log, usage
import pymeds
import sys

if __name__ == '__main__':
config = pymeds.Options()
try:
config.parseOptions()
except usage.UsageError, errortext:
print '%s: %s' % (sys.argv[0], errortext)
print '%s: Try --help for usage details.' % sys.argv[0]
sys.exit(1)

log.startLogging(sys.stdout)
ser = pymeds.makeService(config)
ser.startService()
reactor.addSystemEventTrigger('before', 'shutdown',
service.IService(ser).stopService)
reactor.run()

+ 123
- 114
pymeds.py View File

@@ -47,9 +47,6 @@ import os.path
import random import random
import socket import socket
import string import string
import sys
from twisted.python import log
from twisted.internet import reactor
from twisted.application import internet, service from twisted.application import internet, service
from twisted.python import usage from twisted.python import usage


@@ -64,120 +61,132 @@ class Options(usage.Options):
[ 'path', 'p', 'media', 'Root path of the media to be served.', ], [ 'path', 'p', 'media', 'Root path of the media to be served.', ],
] ]


def parseArgs(self, addr, port=None):
self['addr'] = addr
if port is None:
def postOptions(self):
p = self['path']
if not os.path.isdir(p):
raise usage.UsageError, 'path %s does not exist' % `p`

def parseArgs(self, *args):
# XXX - twisted doesn't let you provide a message on what
# arguments are required, so we will do our own work in here.

if len(args) not in (1, 2):
raise usage.UsageError, 'Arguments: addr [ port ]'

self['addr'] = args[0]
if len(args) == 1:
port = random.randint(10000, 65000) port = random.randint(10000, 65000)
else: else:
port = int(port)
if listenPort < 1024 or listenPort > 65535:
port = int(args[1])
if port < 1024 or port > 65535:
raise ValueError( raise ValueError(
'port must be between 1024 and 65535') 'port must be between 1024 and 65535')
self['port'] = port self['port'] = port


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 = 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 and content 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()
# 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
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.
# 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
'.asf': 'video/x-ms-asf',
'.asx': 'video/x-ms-asf',
'.wma': 'audio/x-ms-wma',
'.wax': 'audio/x-ms-wax',
'.wmv': 'video/x-ms-wmv',
'.wvx': 'video/x-ms-wvx',
'.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',
'.m2ts': '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)
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', rdxml)

s.register(uuid,
uuid,
rdxml)

s.register('%s::urn:schemas-upnp-org:device:MediaServer:1' % uuid,
'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', rdxml)

s.register('%s::urn:schemas-upnp-org:service:ContentDirectory:1' % uuid,
'urn:schemas-upnp-org:device:ContentDirectory:1', rdxml)
def makeService(config):
listenAddr = config['addr']
listenPort = config['port']

serv = service.MultiService()

# Create SSDP server
from SSDP import SSDPServer, SSDP_PORT

s = SSDPServer()
debug.insertnamespace('s', s)

internet.MulticastServer(SSDP_PORT, s,
listenMultiple=True).setServiceParent(serv)

uuid = generateuuid()
urlbase = 'http://%s:%d/' % (listenAddr, listenPort)

# Create SOAP server and content 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()
# 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
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.
# 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
'.asf': 'video/x-ms-asf',
'.asx': 'video/x-ms-asf',
'.wma': 'audio/x-ms-wma',
'.wax': 'audio/x-ms-wax',
'.wmv': 'video/x-ms-wmv',
'.wvx': 'video/x-ms-wvx',
'.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',
'.m2ts': '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)
internet.TCPServer(listenPort, site).setServiceParent(serv)

# we need to do this after the children are there, since we send notifies
import urlparse
rdxml = urlparse.urljoin(urlbase, 'root-device.xml')
s.register('%s::upnp:rootdevice' % uuid,
'upnp:rootdevice', rdxml)

s.register(uuid,
uuid,
rdxml)

s.register('%s::urn:schemas-upnp-org:device:MediaServer:1' % uuid,
'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', rdxml)

s.register('%s::urn:schemas-upnp-org:service:ContentDirectory:1' % uuid,
'urn:schemas-upnp-org:device:ContentDirectory:1', rdxml)

return serv

Loading…
Cancel
Save