@@ -0,0 +1,1546 @@
+%22%22%22%0ACode adapted from Dan Krause.%0Ahttps://gist.github.com/dankrause/6000248%0Ahttp://github.com/dankrause%0A%22%22%22%0Aimport socket%0Aimport httplib%0Aimport StringIO%0A%0A%0Aclass SSDPResponse(object):%0A%0A    class _FakeSocket(StringIO.StringIO):%0A        def makefile(self, *args, **kw):%0A            return self%0A%0A    def __init__(self, response):%0A        r = httplib.HTTPResponse(self._FakeSocket(response))%0A        r.begin()%0A        self.location = r.getheader('location')%0A        self.usn = r.getheader('usn')%0A        self.st = r.getheader('st')%0A        self.cache = r.getheader('cache-control').split('=')%5B1%5D%0A%0A    def __repr__(self):%0A        return '%3CSSDPResponse(%7Blocation%7D, %7Bst%7D, %7Busn%7D)'.format(**self.__dict__)%0A%0A%0Adef discover(timeout=2, retries=1):%0A%0A    group = ('239.255.255.250', 1900)%0A%0A    message = '%5Cr%5Cn'.join(%5B%0A        'M-SEARCH * HTTP/1.1',%0A        'HOST: %7B0%7D:%7B1%7D'.format(*group),%0A        'MAN: %22ssdp:discover%22',%0A        'ST: %7Bst%7D','MX: 3','',''%5D)%0A%0A    socket.setdefaulttimeout(timeout)%0A%0A    responses = %7B%7D%0A%0A    for _ in range(retries):%0A%0A        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)%0A        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)%0A        sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)%0A        sock.sendto(message.format(st='roku:ecp'), group)%0A%0A        while 1:%0A            try:%0A                response = SSDPResponse(sock.recv(1024))%0A                responses%5Bresponse.location%5D = response%0A            except socket.timeout:%0A                break%0A%0A    return responses.values()%0A

Add SSDP discovery code. Will remove if I don't get permission from author.