A Python UPnP Media Server
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

131 lines
3.5 KiB

  1. #!/usr/bin/env python
  2. # Licensed under the MIT license
  3. # http://opensource.org/licenses/mit-license.php
  4. # Copyright 2005, Tim Potter <tpot@samba.org>
  5. # Copyright 2006 John-Mark Gurney <gurney_j@resnet.uroegon.edu>
  6. #
  7. # $Id$
  8. #
  9. # Modules to import, maybe config file or something?
  10. import dvd
  11. import shoutcast
  12. import ZipStorage # w/ tarfile support, it will gobble up empty files!
  13. from DIDLLite import TextItem, AudioItem, VideoItem, ImageItem, Resource, StorageFolder
  14. from FSStorage import FSDirectory
  15. import os
  16. import os.path
  17. import random
  18. import socket
  19. import string
  20. import sys
  21. from twisted.python import log
  22. from twisted.internet import reactor
  23. def generateuuid():
  24. if False:
  25. return 'uuid:asdflkjewoifjslkdfj'
  26. return ''.join([ 'uuid:'] + map(lambda x: random.choice(string.letters), xrange(20)))
  27. listenAddr = sys.argv[1]
  28. if len(sys.argv) > 2:
  29. listenPort = int(sys.argv[2])
  30. if listenPort < 1024 or listenPort > 65535:
  31. raise ValueError, 'port out of range'
  32. else:
  33. listenPort = random.randint(10000, 65000)
  34. log.startLogging(sys.stdout)
  35. # Create SSDP server
  36. from SSDP import SSDPServer, SSDP_PORT, SSDP_ADDR
  37. s = SSDPServer()
  38. port = reactor.listenMulticast(SSDP_PORT, s)
  39. port.joinGroup(SSDP_ADDR)
  40. port.setLoopbackMode(0) # don't get our own sends
  41. uuid = generateuuid()
  42. urlbase = 'http://%s:%d/' % (listenAddr, listenPort)
  43. # Create SOAP server
  44. from twisted.web import server, resource, static
  45. from ContentDirectory import ContentDirectoryServer
  46. from ConnectionManager import ConnectionManagerServer
  47. class WebServer(resource.Resource):
  48. def __init__(self):
  49. resource.Resource.__init__(self)
  50. class RootDevice(static.Data):
  51. def __init__(self):
  52. r = {
  53. 'hostname': socket.gethostname(),
  54. 'uuid': uuid,
  55. 'urlbase': urlbase,
  56. }
  57. d = file('root-device.xml').read() % r
  58. static.Data.__init__(self, d, 'text/xml')
  59. root = WebServer()
  60. content = resource.Resource()
  61. cds = ContentDirectoryServer('My Media Server', klass = FSDirectory, path = 'media', 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
  62. root.putChild('ContentDirectory', cds)
  63. cds = cds.control
  64. root.putChild('ConnectionManager', ConnectionManagerServer())
  65. root.putChild('root-device.xml', RootDevice())
  66. root.putChild('content', content)
  67. # Area of server to serve media files from
  68. from MediaServer import MediaServer
  69. medianode = static.File('media')
  70. medianode.contentTypes.update( {
  71. '.wmv': 'video/x-ms-wmv',
  72. #'.ts': 'video/mp2t',
  73. '.ts': 'video/mpeg', # we may want this instead of mp2t
  74. '.m2t': 'video/mpeg',
  75. #'.mp4': 'video/mp4',
  76. '.mp4': 'video/mpeg',
  77. '.dat': 'video/mpeg', # VCD tracks
  78. '.ogm': 'application/ogg',
  79. '.vob': 'video/mpeg',
  80. #'.m4a': 'audio/mp4', # D-Link can't seem to play AAC files.
  81. })
  82. root.putChild('media', medianode)
  83. site = server.Site(root)
  84. reactor.listenTCP(listenPort, site)
  85. # we need to do this after the children are there, since we send notifies
  86. s.register('%s::upnp:rootdevice' % uuid,
  87. 'upnp:rootdevice',
  88. urlbase + 'root-device.xml')
  89. s.register(uuid,
  90. uuid,
  91. urlbase + 'root-device.xml')
  92. s.register('%s::urn:schemas-upnp-org:device:MediaServer:1' % uuid,
  93. 'urn:schemas-upnp-org:device:MediaServer:1',
  94. urlbase + 'root-device.xml')
  95. s.register('%s::urn:schemas-upnp-org:service:ConnectionManager:1' % uuid,
  96. 'urn:schemas-upnp-org:device:ConnectionManager:1',
  97. urlbase + 'root-device.xml')
  98. s.register('%s::urn:schemas-upnp-org:service:ContentDirectory:1' % uuid,
  99. 'urn:schemas-upnp-org:device:ContentDirectory:1',
  100. urlbase + 'root-device.xml')
  101. # Main loop
  102. reactor.run()