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