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 socket
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

@@ -64,120 +61,132 @@ class Options(usage.Options):
[ '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)
else:
port = int(port)
if listenPort < 1024 or listenPort > 65535:
port = int(args[1])
if port < 1024 or port > 65535:
raise ValueError(
'port must be between 1024 and 65535')
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