@@ -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 p ort > 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