python dlna 投屏
python-dlna,python投屏,python模拟投屏设备,python获取投屏视源,python伪装投屏设备
投屏分2种,投屏端如手机,被投屏端如电视。
本代码模拟的是投屏中的电视设备,被手机app搜索投屏视频的过程
dlna协议是投屏协议,可分成投屏端,和被投屏端
被投屏端主要就做2件件事,1服务被发现,2被交互处理
upnp是DLNA的基础协议,用于发现新加入局域网的设备
我分成2个脚本了,1upnp.py,2rsp.py
pycharm运行,python3,占用本机8889端口
http://localhost:8889/dlna/info.xml运行后能看到返回




 

 1upnp.py向多播地址宣告本服务

import socket
import http.server
import socketserver
import time
import struct
import xml.etree.ElementTree as ET


port = 8889
# uuid = "27d6877e-{}-ea12-abdf-cf8d50e36d54".format(randint(1000, 9999))
NLS = "27d6877e-6677-ea12-abdf-cf8d50e36d54"  # 我不知道什么东西,格式和uuid一样,但是不是一个东西
uuid = "27d6877e-6677-ea12-abdf-cf8d50e36d54"


def getLocalIp():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.connect(("119.29.29.29", 80))
    ip = s.getsockname()[0]
    s.close()
    return ip


class SSDPServer(socketserver.UDPServer):   # 用于创建一个能够监听指定端口的 UDP 服务器。
    allow_reuse_address = True


class SSDPHandler(socketserver.BaseRequestHandler):
    def handle(self):  # 用于处理接收到的 SSDP 消息,并打印出来。
        data = self.request[0].strip()
        print(f"Received SSDP message:\n{data.decode('utf-8')}")

def send_ssdp_broadcast():   # 生成并发送六条 SSDP 消息。这些消息遵循 UPnP 规范,用于设备的发现和声明。http://{}:{}/dlna/info.xml'
    # "LOCATION: http://"+ip+":"+str(port)+"/description.xml\r\n"
    print("----六条 SSDP 消息")
    ssdp_message1 = (
        "NOTIFY * HTTP/1.1\r\n"
        "HOST: 239.255.255.250:1900\r\n"
        "CACHE-CONTROL: max-age=66\r\n"
        "LOCATION: http://"+ip+":"+str(port)+"/dlna/info.xml\r\n"
        "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n"
        "01-NLS: "+NLS+"\r\n"
        "NT: upnp:rootdevice\r\n"
        "NTS: ssdp:alive\r\n"
        "SERVER: Linux/4.19.157-perf-download HTTP/1.0\r\n"
        "X-User-Agent: redsonic\r\n"
        "USN: uuid:"+uuid+"::upnp:rootdevice\r\n"
    )
    ssdp_message2 = (
        "NOTIFY * HTTP/1.1\r\n"
        "HOST: 239.255.255.250:1900\r\n"
        "CACHE-CONTROL: max-age=66\r\n"
        "LOCATION: http://"+ip+":"+str(port)+"/description.xml\r\n"
        "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n"
        "01-NLS: "+NLS+"\r\n"
        "NT: uuid:"+uuid+"\r\n"
        "NTS: ssdp:alive\r\n"
        "SERVER: Linux/4.19.157-perf-download HTTP/1.0\r\n"
        "X-User-Agent: redsonic\r\n"
        "USN: uuid:"+uuid+"\r\n"
    )
    ssdp_message3 = (
        "NOTIFY * HTTP/1.1\r\n"
        "HOST: 239.255.255.250:1900\r\n"
        "CACHE-CONTROL: max-age=66\r\n"
        "LOCATION: http://"+ip+":"+str(port)+"/description.xml\r\n"
        "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n"
        "01-NLS: "+NLS+"\r\n"
        "NT: urn:schemas-upnp-org:device:MediaRenderer:1\r\n"
        "NTS: ssdp:alive\r\n"
        "SERVER: Linux/4.19.157-perf-download HTTP/1.0\r\n"
        "X-User-Agent: redsonic\r\n"
        "USN: uuid:"+uuid+"::urn:schemas-upnp-org:device:MediaRenderer:1\r\n"
    )
    ssdp_message4 = (
        "NOTIFY * HTTP/1.1\r\n"
        "HOST: 239.255.255.250:1900\r\n"
        "CACHE-CONTROL: max-age=66\r\n"
        "LOCATION: http://"+ip+":"+str(port)+"/description.xml\r\n"
        "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n"
        "01-NLS: "+NLS+"\r\n"
        "NT: urn:schemas-upnp-org:service:AVTransport:1\r\n"
        "NTS: ssdp:alive\r\n"
        "SERVER: Linux/4.19.157-perf-download HTTP/1.0\r\n"
        "X-User-Agent: redsonic\r\n"
        "USN: uuid:"+uuid+"::urn:schemas-upnp-org:service:AVTransport:1\r\n"
    )
    ssdp_message5 = (
        "NOTIFY * HTTP/1.1\r\n"
        "HOST: 239.255.255.250:1900\r\n"
        "CACHE-CONTROL: max-age=66\r\n"
        "LOCATION: http://"+ip+":"+str(port)+"/description.xml\r\n"
        "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n"
        "01-NLS: "+NLS+"\r\n"
        "NT: urn:schemas-upnp-org:service:RenderingControl:1\r\n"
        "NTS: ssdp:alive\r\n"
        "SERVER: Linux/4.19.157-perf-download HTTP/1.0\r\n"
        "X-User-Agent: redsonic\r\n"
        "USN: uuid:"+uuid+"::urn:schemas-upnp-org:service:RenderingControl:1\r\n"
    )
    ssdp_message6 = (
        "NOTIFY * HTTP/1.1\r\n"
        "HOST: 239.255.255.250:1900\r\n"
        "CACHE-CONTROL: max-age=66\r\n"
        "LOCATION: http://"+ip+":"+str(port)+"/description.xml\r\n"
        "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n"
        "01-NLS: "+NLS+"\r\n"
        "NT: urn:schemas-upnp-org:service:ConnectionManager:1\r\n"
        "NTS: ssdp:alive\r\n"
        "SERVER: Linux/4.19.157-perf-download HTTP/1.0\r\n"
        "X-User-Agent: redsonic\r\n"
        "USN: uuid:"+uuid+"::urn:schemas-upnp-org:service:ConnectionManager:1\r\n"
    )

    multicast_group = ("239.255.255.250", 1900)
        # Create a UDP socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.bind((ip, 0))  # 绑定到指定的 IP 地址
        # Set the time-to-live for the socket
    ttl = struct.pack('b', 1)
    sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl)
        # Send the SSDP broadcast
    sock.sendto(ssdp_message1.encode("utf-8"), multicast_group)
    sock.close()
    time.sleep(1)
        # Create a UDP socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.bind((ip, 0))  # 绑定到指定的 IP 地址
        # Set the time-to-live for the socket
    sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl)
        # Send the SSDP broadcast
    sock.sendto(ssdp_message2.encode("utf-8"), multicast_group)
    sock.close()
    time.sleep(1)
        # Create a UDP socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.bind((ip, 0))  # 绑定到指定的 IP 地址
        # Set the time-to-live for the socket
    sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl)
        # Send the SSDP broadcast
    sock.sendto(ssdp_message3.encode("utf-8"), multicast_group)
    sock.close()
    time.sleep(1)
        # Create a UDP socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.bind((ip, 0))  # 绑定到指定的 IP 地址
        # Set the time-to-live for the socket
    sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl)
        # Send the SSDP broadcast
    sock.sendto(ssdp_message4.encode("utf-8"), multicast_group)
    sock.close()
    time.sleep(1)
        # Create a UDP socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.bind((ip, 0))  # 绑定到指定的 IP 地址
        # Set the time-to-live for the socket
    sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl)
        # Send the SSDP broadcast
    sock.sendto(ssdp_message5.encode("utf-8"), multicast_group)
    sock.close()
    time.sleep(1)
        # Create a UDP socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.bind((ip, 0))  # 绑定到指定的 IP 地址
        # Set the time-to-live for the socket
    sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl)
        # Send the SSDP broadcast
    sock.sendto(ssdp_message6.encode("utf-8"), multicast_group)
    sock.close()
    time.sleep(1)


class MyHandler(http.server.SimpleHTTPRequestHandler):
    def log_message(self, format, *args):
        # Override the log_message method to suppress log messages
        pass
    def do_POST(self):
        content_length = int(self.headers['Content-Length'])
        post_data = self.rfile.read(content_length).decode('utf-8')
        data = ET.fromstring(post_data)
        current_uri_element = data.find(".//CurrentURI")
        if current_uri_element is not None:
            current_uri_value = current_uri_element.text
            print("Current URI:", current_uri_value)
        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        self.end_headers()
        self.wfile.write(b'POST request received successfully')


def start_web_server():
    handler = MyHandler   # 它使用 MyHandler 来处理请求。
    httpd = socketserver.TCPServer(("0.0.0.0", port), handler)

    print(f"Web server is running on http://localhost:{port}")

    try:
        httpd.serve_forever()
    except KeyboardInterrupt:
        pass
    finally:
        httpd.server_close()
    print('一次http结束')


if __name__ == "__main__":
    ip = getLocalIp()
    print(ip)
    # Start the SSDP server
    while True:
        send_ssdp_broadcast()

 

 2rsp.py对手机的请求做出返回,获取视频链接


#!/usr/bin/env python
# encoding: utf-8
import socket
import datetime
from random import randint
from urllib import parse
import traceback
import _thread
from socketserver import ThreadingMixIn
from http.server import HTTPServer, BaseHTTPRequestHandler
import json
import xml.etree.ElementTree as ET


class PlayStatus:
    playing = None
    stoped = True
    url = ""
    meta = ""


class xmlReqParser:
    def __init__(self, data):
        self.data = data

    def CurrentURI(self):
        root = ET.fromstring(self.data)
        namespaces = {'s': 'http://schemas.xmlsoap.org/soap/envelope/'}
        value = root.findtext('s:Body//CurrentURI', None, namespaces)
        return value

    def CurrentURIMetaData(self):
        root = ET.fromstring(self.data)
        namespaces = {'s': 'http://schemas.xmlsoap.org/soap/envelope/'}
        value = root.findtext('s:Body//CurrentURIMetaData', None, namespaces)
        return value


class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        try:
            req = parse.urlparse(self.path)
            path = req.path
            print(path)
            query = parse.parse_qs(req.query)
            if path.startswith('/info'):
                return self.info(query)
            if path.startswith('/dlna/info.xml'):
                return self.respdesc()
            if path.startswith('/dlna/AVTransport_scpd.xml'):
                return self.AVTransport_scpd()
            if path.startswith('/dlna/RenderingControl_scpd.xml'):
                return self.RenderingControl_scpd()

            return self.index()
        except Exception as e:
            traceback.print_exc()
            self.send_error(500, str(e), str(e))

    def do_POST(self):
        try:
            req = parse.urlparse(self.path)
            path = req.path
            query = parse.parse_qs(req.query)
            if path.startswith('/play'):
                return self.play(query)
            if path.startswith('/pause'):
                return self.pause(query)
            if path.startswith('/stop'):
                return self.stop(query)
            if path.startswith('/position'):
                return self.position(query)
            if path.startswith('/seek'):
                return self.seek(query)
            if path.startswith('/dlna/_urn:schemas-upnp-org:service:AVTransport_control'):
                print('-----POST消息 视频链接数据')
                body = self.rfile.read(int(self.headers['content-length']))
                data1 = body.decode()
                print('AVT数据', data1)
                self.execPlay(data1)   # 处理
                return

            return self.notfound()
        except Exception as e:
            traceback.print_exc()
            self.send_error(500, str(e), str(e))

    def do_SUBSCRIBE(self):
        print(self.headers)
        print('do_SUBSCRIBE')
        self.send_response(200)
        self.send_header('TIMEOUT', 'Second-3600')
        self.send_header('SID', 'uuid:f392-a153-571c-e10b')
        self.send_header('Content-Length', '0')
        self.end_headers()

    def respdesc(self):
        data = xmlreplayer.desc()
        self.send_response(200)
        self.send_header('Content-type', 'text/xml')
        self.send_header('Access-Control-Allow-Origin', '*')
        self.end_headers()
        self.wfile.write(data.encode())

    def AVTransport_scpd(self):
        data = xmlreplayer.AVTransport_scpd()
        self.send_response(200)
        self.send_header('Content-type', 'text/xml')
        self.send_header('Access-Control-Allow-Origin', '*')
        self.end_headers()
        self.wfile.write(data.encode())

    def RenderingControl_scpd(self):
        data = xmlreplayer.RenderingControl_scpd()
        self.send_response(200)
        self.send_header('Content-type', 'text/xml')
        self.send_header('Access-Control-Allow-Origin', '*')
        self.end_headers()
        self.wfile.write(data.encode())

    def execPlay(self, data):
        if 'GetTransportInfo' in data:
            data = xmlreplayer.trans()
            self.send_response(200)
            self.send_header('Content-type', 'text/xml')
            self.send_header('Access-Control-Allow-Origin', '*')
            self.end_headers()
            self.wfile.write(data.encode())
            return
        if 'u:Stop' in data:
            if PlayStatus.playing:
                PlayStatus.playing.kill()
                PlayStatus.stoped = True
                print('local stop ', PlayStatus.url)
            data = xmlreplayer.stop()
            self.send_response(200)
            self.send_header('Content-type', 'text/xml')
            self.send_header('Access-Control-Allow-Origin', '*')
            self.end_headers()
            self.wfile.write(data.encode())
            return
        if 'u:Pause' in data:
            data = xmlreplayer.pause()
            self.send_response(200)
            self.send_header('Content-type', 'text/xml')
            self.send_header('Access-Control-Allow-Origin', '*')
            self.end_headers()
            self.wfile.write(data.encode())
            return
        if 'u:Play' in data:
            data = xmlreplayer.playresp()
            self.send_response(200)
            self.send_header('Content-type', 'text/xml')
            self.send_header('Access-Control-Allow-Origin', '*')

            self.end_headers()
            self.wfile.write(data.encode())
            return
        if 'u:Seek' in data:
            data = xmlreplayer.seekresp()
            self.send_response(200)
            self.send_header('Content-type', 'text/xml')
            self.send_header('Access-Control-Allow-Origin', '*')
            self.end_headers()
            self.wfile.write(data.encode())
            return
        if 'u:GetMediaInfo' in data:
            data = xmlreplayer.mediainfo()
            self.send_response(200)
            self.send_header('Content-type', 'text/xml')
            self.send_header('Access-Control-Allow-Origin', '*')
            self.end_headers()
            self.wfile.write(data.encode())
            return
        if 'u:GetPositionInfo' in data:
            data = xmlreplayer.postioninfo()
            self.send_response(200)
            self.send_header('Content-type', 'text/xml')
            self.send_header('Access-Control-Allow-Origin', '*')
            self.end_headers()
            self.wfile.write(data.encode())
            return
        reqParser = xmlReqParser(data)
        print('数据全', data)
        url = reqParser.CurrentURI()
        meta = reqParser.CurrentURIMetaData()
        if url is None:
            print(self.headers)
            print(data)
            self.notfound()
            return
        print('获取到视频链接', url)
        # ret = subprocess.Popen('{} "{}"'.format(player, url), shell=True)
        # print(ret)
        if PlayStatus.playing:
            PlayStatus.playing.kill()
        # PlayStatus.playing = ret  # type: ignore
        PlayStatus.stoped = False
        PlayStatus.url = url
        PlayStatus.meta = meta or ""
        data = xmlreplayer.setUriResp()
        self.send_response(200)
        self.send_header('Content-type', 'text/xml')
        self.send_header('Access-Control-Allow-Origin', '*')
        self.end_headers()
        self.wfile.write(data.encode())

    def index(self):
        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        self.send_header('Access-Control-Allow-Origin', '*')
        self.end_headers()
        with open("index.html", "rb") as f:
            self.wfile.write(f.read())

    def notfound(self):
        self.send_response(404)
        self.send_header('Content-type', 'text/plain')
        self.send_header('Access-Control-Allow-Origin', '*')
        self.end_headers()
        self.wfile.write(b'404 not found')

    def info(self, query):
        self.send_response(200)
        self.send_header('Content-type', 'application/json')
        self.send_header('Access-Control-Allow-Origin', '*')
        self.end_headers()
        self.wfile.write(json.dumps(dlna.getInfos()).encode())

    def play(self, query):
        url = query.get('url')
        if url is None:
            return self.err('error params')
        url = url[0]
        device = dlna.getDevice(url)
        if device is None:
            return self.err('no device')
        playUrl = query.get('playUrl')
        if playUrl is None or playUrl[0] is None:
            # recover play
            ret = device.play()
            self.ok(ret.decode())
            return
        playUrl = playUrl[0]
        print('remote play ', playUrl)
        ret = device.setPlayUrl(playUrl)
        device.play()
        return self.ok(ret.decode())

    def pause(self, query):
        url = query.get('url')
        if url is None:
            return self.err('error params')
        url = url[0]
        device = dlna.getDevice(url)
        if device is None:
            return self.err('no device')
        ret = device.pause()
        return self.ok(ret.decode())

    def stop(self, query):
        url = query.get('url')
        if url is None:
            return self.err('error params')
        url = url[0]
        device = dlna.getDevice(url)
        if device is None:
            return self.err('no device')
        ret = device.stop()
        return self.ok(ret.decode())

    def position(self, query):
        url = query.get('url')
        if url is None:
            return self.err('error params')
        url = url[0]
        device = dlna.getDevice(url)
        if device is None:
            return self.err('no device')
        ret = device.getPosition()
        return self.ok(ret.decode())

    def seek(self, query):
        url = query.get('url')
        if url is None:
            return self.err('error params')
        url = url[0]
        sk = query.get('seek')
        if sk is None:
            return self.err('error params')
        sk = sk[0]
        device = dlna.getDevice(url)
        if device is None:
            return self.err('no device')
        ret = device.seek(sk)
        return self.ok(ret.decode())

    def err(self, err):
        self.send_response(200)
        self.send_header('Content-type', 'application/json')
        self.send_header('Access-Control-Allow-Origin', '*')
        self.end_headers()
        self.wfile.write(json.dumps({'code': -1, 'msg': err}).encode())

    def ok(self, msg):
        self.send_response(200)
        self.send_header('Content-type', 'application/json')
        self.send_header('Access-Control-Allow-Origin', '*')
        self.end_headers()
        self.wfile.write(json.dumps({'code': 0, 'msg': msg}).encode())


class XmlReplay:
    def __init__(self, ip, port, name):
        self.ip = ip
        self.port = port
        self.name = name

    def alive(self):
        GMT_FORMAT = '%a, %d %b %Y %H:%M:%S GMT'
        date = datetime.datetime.now(datetime.timezone.utc).strftime(GMT_FORMAT)
        st = 'urn:schemas-upnp-org:device:MediaRenderer:1'
        return '\r\n'.join(
            [
                'HTTP/1.1 200 OK',
                'CACHE-CONTROL: max-age=60',
                'EXT:',
                'DATE: {}'.format(date),
                'LOCATION: http://{}:{}/dlna/info.xml'.format(self.ip, self.port),
                'SERVER: simple python dlna server',
                'ST: {}'.format(st),
                'USN: uuid:{}'.format(uuid),
                '',
                '',
            ]
        )

    def desc(self):
        return '''<root
    xmlns="urn:schemas-upnp-org:device-1-0">
    <specVersion>
        <major>1</major>
        <minor>0</minor>
    </specVersion>
    <device>
        <deviceType>urn:schemas-upnp-org:device:MediaRenderer:1</deviceType>
        <presentationURL>/</presentationURL>
        <friendlyName>{}</friendlyName>
        <manufacturer>python dlna server</manufacturer>
        <manufacturerURL>https://github.com/suconghou/dlna-python</manufacturerURL>
        <modelDescription>python dlna</modelDescription>
        <modelName>python dlna</modelName>
        <modelURL>https://github.com/suconghou/dlna-python</modelURL>
        <UPC>000000000000</UPC>
        <UDN>uuid:{}</UDN>
        <serviceList>
            <service>
                <serviceType>urn:schemas-upnp-org:service:AVTransport:1</serviceType>
                <serviceId>urn:upnp-org:serviceId:AVTransport</serviceId>
                <SCPDURL>/dlna/AVTransport_scpd.xml</SCPDURL>
                <controlURL>/dlna/_urn:schemas-upnp-org:service:AVTransport_control</controlURL>
                <eventSubURL>/dlna/_urn:schemas-upnp-org:service:AVTransport_event</eventSubURL>
            </service>
            <service>
                <serviceType>urn:schemas-upnp-org:service:RenderingControl:1</serviceType>
                <serviceId>urn:upnp-org:serviceId:RenderingControl</serviceId>
                <SCPDURL>/dlna/RenderingControl_scpd.xml</SCPDURL>
                <controlURL>/dlna/_urn:schemas-upnp-org:service:RenderingControl_control</controlURL>
                <eventSubURL>/dlna/_urn:schemas-upnp-org:service:RenderingControl_event</eventSubURL>
            </service>
        </serviceList>
    </device>
    <URLBase>http://{}:{}</URLBase>
</root>'''.format(
            self.name, uuid, self.ip, self.port
        )

    def trans(self):
        return '''<?xml version="1.0" encoding="UTF-8"?>
        <s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
          <s:Body>
            <u:GetTransportInfoResponse xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
              <CurrentTransportState>{}</CurrentTransportState>
              <CurrentTransportStatus>OK</CurrentTransportStatus>
              <CurrentSpeed>1</CurrentSpeed>
            </u:GetTransportInfoResponse>
          </s:Body>
        </s:Envelope>'''.format(
            'PLAYING'
            if PlayStatus.stoped == False
            else 'STOPED'
            if PlayStatus.url
            else 'NO_MEDIA_PRESENT'
        )

    def stop(self):
        return '''<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
	<s:Body>
		<u:StopResponse xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"/>
	</s:Body>
</s:Envelope>'''

    def pause(self):
        return '''<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
	<s:Body>
		<u:PauseResponse xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"/>
	</s:Body>
</s:Envelope>'''

    def mediainfo(self):
        return '''<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope
 xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body><u:GetMediaInfoResponse xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
 <NrTracks>0</NrTracks>
 <MediaDuration>02:00:00</MediaDuration>
 <CurrentURI>{}</CurrentURI>
 <CurrentURIMetaData>{}</CurrentURIMetaData>
 <NextURI></NextURI>
 <NextURIMetaData></NextURIMetaData>
 <PlayMedium>NETWORK</PlayMedium>
 <RecordMedium>NOT_IMPLEMENTED</RecordMedium>
 <WriteStatus>NOT_IMPLEMENTED</WriteStatus>
</u:GetMediaInfoResponse>
</s:Body>
</s:Envelope>'''.format(
            htmlEncode(PlayStatus.url), htmlEncode(PlayStatus.meta)
        )

    def postioninfo(self):
        x = randint(1, 9)
        return '''<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
	<s:Body>
		<u:GetPositionInfoResponse xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
			<Track>0</Track>
			<TrackDuration>02:00:00</TrackDuration>
			<TrackMetaData></TrackMetaData>
			<TrackURI>{}</TrackURI>
			<RelTime>00:00:0{}</RelTime>
			<AbsTime>00:00:0{}</AbsTime>
			<RelCount>2147483647</RelCount>
			<AbsCount>2147483647</AbsCount>
		</u:GetPositionInfoResponse>
	</s:Body>
</s:Envelope>'''.format(
            htmlEncode(PlayStatus.url), x, x
        )

    def setUriResp(self):
        return '''<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
	<s:Body>
		<u:SetAVTransportURIResponse xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"/>
	</s:Body>
</s:Envelope>'''

    def playresp(self):
        return '''<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
	<s:Body>
		<u:PlayResponse xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"/>
	</s:Body>
</s:Envelope>'''

    def seekresp(self):
        return "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body><u:SeekResponse xmlns:u=\"urn:schemas-upnp-org:service:AVTransport:1\"></u:SeekResponse></s:Body></s:Envelope>"

    def AVTransport_scpd(self):
        text = '''<?xml version="1.0" encoding="utf-8"?>
<scpd xmlns="urn:schemas-upnp-org:service-1-0">
  <specVersion>
    <major>1</major>
    <minor>0</minor>
  </specVersion>
  <actionList>
    <action>
      <name>Play</name>
      <argumentList>
        <argument>
          <name>InstanceID</name>
          <direction>in</direction>
          <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
        </argument>
        <argument>
          <name>Speed</name>
          <direction>in</direction>
          <relatedStateVariable>TransportPlaySpeed</relatedStateVariable>
        </argument>
      </argumentList>
    </action>
    <action>
      <name>Stop</name>
      <argumentList>
        <argument>
          <name>InstanceID</name>
          <direction>in</direction>
          <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
        </argument>
      </argumentList>
    </action>
    <action>
      <name>GetMediaInfo</name>
      <argumentList>
        <argument>
          <name>InstanceID</name>
          <direction>in</direction>
          <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
        </argument>
        <argument>
          <name>NrTracks</name>
          <direction>out</direction>
          <relatedStateVariable>NumberOfTracks</relatedStateVariable>
          <defaultValue>0</defaultValue>
        </argument>
        <argument>
          <name>MediaDuration</name>
          <direction>out</direction>
          <relatedStateVariable>CurrentMediaDuration</relatedStateVariable>
        </argument>
        <argument>
          <name>CurrentURI</name>
          <direction>out</direction>
          <relatedStateVariable>AVTransportURI</relatedStateVariable>
        </argument>
        <argument>
          <name>CurrentURIMetaData</name>
          <direction>out</direction>
          <relatedStateVariable>AVTransportURIMetaData</relatedStateVariable>
        </argument>
        <argument>
          <name>NextURI</name>
          <direction>out</direction>
          <relatedStateVariable>NextAVTransportURI</relatedStateVariable>
        </argument>
        <argument>
          <name>NextURIMetaData</name>
          <direction>out</direction>
          <relatedStateVariable>NextAVTransportURIMetaData</relatedStateVariable>
        </argument>
        <argument>
          <name>PlayMedium</name>
          <direction>out</direction>
          <relatedStateVariable>PlaybackStorageMedium</relatedStateVariable>
        </argument>
        <argument>
          <name>RecordMedium</name>
          <direction>out</direction>
          <relatedStateVariable>RecordStorageMedium</relatedStateVariable>
        </argument>
        <argument>
          <name>WriteStatus</name>
          <direction>out</direction>
          <relatedStateVariable>RecordMediumWriteStatus</relatedStateVariable>
        </argument>
      </argumentList>
    </action>
    <action>
      <name>SetAVTransportURI</name>
      <argumentList>
        <argument>
          <name>InstanceID</name>
          <direction>in</direction>
          <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
        </argument>
        <argument>
          <name>CurrentURI</name>
          <direction>in</direction>
          <relatedStateVariable>AVTransportURI</relatedStateVariable>
        </argument>
        <argument>
          <name>CurrentURIMetaData</name>
          <direction>in</direction>
          <relatedStateVariable>AVTransportURIMetaData</relatedStateVariable>
        </argument>
      </argumentList>
    </action>
    <action>
      <name>GetTransportInfo</name>
      <argumentList>
        <argument>
          <name>InstanceID</name>
          <direction>in</direction>
          <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
        </argument>
        <argument>
          <name>CurrentTransportState</name>
          <direction>out</direction>
          <relatedStateVariable>TransportState</relatedStateVariable>
        </argument>
        <argument>
          <name>CurrentTransportStatus</name>
          <direction>out</direction>
          <relatedStateVariable>TransportStatus</relatedStateVariable>
        </argument>
        <argument>
          <name>CurrentSpeed</name>
          <direction>out</direction>
          <relatedStateVariable>TransportPlaySpeed</relatedStateVariable>
        </argument>
      </argumentList>
    </action>
    <action>
      <name>Pause</name>
      <argumentList>
        <argument>
          <name>InstanceID</name>
          <direction>in</direction>
          <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
        </argument>
      </argumentList>
    </action>
    <action>
      <name>Seek</name>
      <argumentList>
        <argument>
          <name>InstanceID</name>
          <direction>in</direction>
          <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
        </argument>
        <argument>
          <name>Unit</name>
          <direction>in</direction>
          <relatedStateVariable>A_ARG_TYPE_SeekMode</relatedStateVariable>
        </argument>
        <argument>
          <name>Target</name>
          <direction>in</direction>
          <relatedStateVariable>A_ARG_TYPE_SeekTarget</relatedStateVariable>
        </argument>
      </argumentList>
    </action>
    <action>
      <name>GetPositionInfo</name>
      <argumentList>
        <argument>
          <name>InstanceID</name>
          <direction>in</direction>
          <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
        </argument>
        <argument>
          <name>Track</name>
          <direction>out</direction>
          <relatedStateVariable>CurrentTrack</relatedStateVariable>
        </argument>
        <argument>
          <name>TrackDuration</name>
          <direction>out</direction>
          <relatedStateVariable>CurrentTrackDuration</relatedStateVariable>
        </argument>
        <argument>
          <name>TrackMetaData</name>
          <direction>out</direction>
          <relatedStateVariable>CurrentTrackMetaData</relatedStateVariable>
        </argument>
        <argument>
          <name>TrackURI</name>
          <direction>out</direction>
          <relatedStateVariable>CurrentTrackURI</relatedStateVariable>
        </argument>
        <argument>
          <name>RelTime</name>
          <direction>out</direction>
          <relatedStateVariable>RelativeTimePosition</relatedStateVariable>
        </argument>
        <argument>
          <name>AbsTime</name>
          <direction>out</direction>
          <relatedStateVariable>AbsoluteTimePosition</relatedStateVariable>
        </argument>
        <argument>
          <name>RelCount</name>
          <direction>out</direction>
          <relatedStateVariable>RelativeCounterPosition</relatedStateVariable>
        </argument>
        <argument>
          <name>AbsCount</name>
          <direction>out</direction>
          <relatedStateVariable>AbsoluteCounterPosition</relatedStateVariable>
        </argument>
      </argumentList>
    </action>
  </actionList>
  <serviceStateTable>
    <stateVariable sendEvents="no">
      <name>TransportState</name>
      <dataType>string</dataType>
      <allowedValueList>
        <allowedValue>STOPPED</allowedValue>
        <allowedValue>PAUSED_PLAYBACK</allowedValue>
        <allowedValue>PLAYING</allowedValue>
        <allowedValue>TRANSITIONING</allowedValue>
        <allowedValue>NO_MEDIA_PRESENT</allowedValue>
      </allowedValueList>
      <defaultValue>NO_MEDIA_PRESENT</defaultValue>
    </stateVariable>
    <stateVariable sendEvents="no">
      <name>TransportStatus</name>
      <dataType>string</dataType>
      <allowedValueList>
        <allowedValue>OK</allowedValue>
        <allowedValue>ERROR_OCCURRED</allowedValue>
      </allowedValueList>
      <defaultValue>OK</defaultValue>
    </stateVariable>
    <stateVariable sendEvents="no">
      <name>TransportPlaySpeed</name>
      <dataType>string</dataType>
      <defaultValue>1</defaultValue>
    </stateVariable>
    <stateVariable sendEvents="no">
      <name>NumberOfTracks</name>
      <dataType>ui4</dataType>
      <allowedValueRange>
        <minimum>0</minimum>
        <maximum>4294967295</maximum>
      </allowedValueRange>
      <defaultValue>0</defaultValue>
    </stateVariable>
    <stateVariable sendEvents="no">
      <name>CurrentMediaDuration</name>
      <dataType>string</dataType>
      <defaultValue>00:00:00</defaultValue>
    </stateVariable>
    <stateVariable sendEvents="no">
      <name>AVTransportURI</name>
      <dataType>string</dataType>
    </stateVariable>
    <stateVariable sendEvents="no">
      <name>AVTransportURIMetaData</name>
      <dataType>string</dataType>
    </stateVariable>
    <stateVariable sendEvents="no">
      <name>PlaybackStorageMedium</name>
      <dataType>string</dataType>
      <allowedValueList>
        <allowedValue>NONE</allowedValue>
        <allowedValue>NETWORK</allowedValue>
      </allowedValueList>
      <defaultValue>NONE</defaultValue>
    </stateVariable>
    <stateVariable sendEvents="no">
      <name>CurrentTrack</name>
      <dataType>ui4</dataType>
      <allowedValueRange>
        <minimum>0</minimum>
        <maximum>4294967295</maximum>
        <step>1</step>
      </allowedValueRange>
      <defaultValue>0</defaultValue>
    </stateVariable>
    <stateVariable sendEvents="no">
      <name>CurrentTrackDuration</name>
      <dataType>string</dataType>
      <defaultValue>00:00:00</defaultValue>
    </stateVariable>
    <stateVariable sendEvents="no">
      <name>CurrentTrackMetaData</name>
      <dataType>string</dataType>
    </stateVariable>
    <stateVariable sendEvents="no">
      <name>CurrentTrackURI</name>
      <dataType>string</dataType>
    </stateVariable>
    <stateVariable sendEvents="no">
      <name>RelativeTimePosition</name>
      <dataType>string</dataType>
      <defaultValue>00:00:00</defaultValue>
    </stateVariable>
    <stateVariable sendEvents="no">
      <name>AbsoluteTimePosition</name>
      <dataType>string</dataType>
      <defaultValue>00:00:00</defaultValue>
    </stateVariable>
    <stateVariable sendEvents="no">
      <name>NextAVTransportURI</name>
      <dataType>string</dataType>
    </stateVariable>
    <stateVariable sendEvents="no">
      <name>NextAVTransportURIMetaData</name>
      <dataType>string</dataType>
    </stateVariable>
    <stateVariable sendEvents="no">
      <name>CurrentTransportActions</name>
      <dataType>string</dataType>
    </stateVariable>
    <stateVariable sendEvents="no">
      <name>RecordStorageMedium</name>
      <dataType>string</dataType>
      <allowedValueList>
        <allowedValue>NOT_IMPLEMENTED</allowedValue>
      </allowedValueList>
      <defaultValue>NOT_IMPLEMENTED</defaultValue>
    </stateVariable>
    <stateVariable sendEvents="no">
      <name>RecordMediumWriteStatus</name>
      <dataType>string</dataType>
      <allowedValueList>
        <allowedValue>NOT_IMPLEMENTED</allowedValue>
      </allowedValueList>
      <defaultValue>NOT_IMPLEMENTED</defaultValue>
    </stateVariable>
    <stateVariable sendEvents="no">
      <name>RelativeCounterPosition</name>
      <dataType>i4</dataType>
      <defaultValue>2147483647</defaultValue>
    </stateVariable>
    <stateVariable sendEvents="no">
      <name>AbsoluteCounterPosition</name>
      <dataType>i4</dataType>
      <defaultValue>2147483647</defaultValue>
    </stateVariable>
    <stateVariable sendEvents="yes">
      <name>LastChange</name>
      <dataType>string</dataType>
    </stateVariable>
    <stateVariable sendEvents="no">
      <name>A_ARG_TYPE_InstanceID</name>
      <dataType>ui4</dataType>
    </stateVariable>
    <stateVariable sendEvents="no">
      <name>A_ARG_TYPE_SeekMode</name>
      <dataType>string</dataType>
      <allowedValueList>
        <allowedValue>TRACK_NR</allowedValue>
        <allowedValue>REL_TIME</allowedValue>
        <allowedValue>ABS_TIME</allowedValue>
        <allowedValue>ABS_COUNT</allowedValue>
        <allowedValue>REL_COUNT</allowedValue>
        <allowedValue>FRAME</allowedValue>
      </allowedValueList>
      <defaultValue>REL_TIME</defaultValue>
    </stateVariable>
    <stateVariable sendEvents="no">
      <name>A_ARG_TYPE_SeekTarget</name>
      <dataType>string</dataType>
    </stateVariable>
  </serviceStateTable>
</scpd>'''
        return text


    def RenderingControl_scpd(self):
        text = '''<scpd xmlns="urn:schemas-upnp-org:service-1-0">
    <specVersion>
        <major>1</major>
        <minor>0</minor>
    </specVersion>
    <actionList>
        <action>
            <name>GetMute</name>
            <argumentList>
                <argument>
                    <name>InstanceID</name>
                    <direction>in</direction>
                    <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
                </argument>
                <argument>
                    <name>Channel</name>
                    <direction>in</direction>
                    <relatedStateVariable>A_ARG_TYPE_Channel</relatedStateVariable>
                </argument>
                <argument>
                    <name>CurrentMute</name>
                    <direction>out</direction>
                    <relatedStateVariable>Mute</relatedStateVariable>
                </argument>
            </argumentList>
        </action>
        <action>
            <name>GetVolume</name>
            <argumentList>
                <argument>
                    <name>InstanceID</name>
                    <direction>in</direction>
                    <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
                </argument>
                <argument>
                    <name>Channel</name>
                    <direction>in</direction>
                    <relatedStateVariable>A_ARG_TYPE_Channel</relatedStateVariable>
                </argument>
                <argument>
                    <name>CurrentVolume</name>
                    <direction>out</direction>
                    <relatedStateVariable>Volume</relatedStateVariable>
                </argument>
            </argumentList>
        </action>
        <action>
            <name>GetVolumeDB</name>
            <argumentList>
                <argument>
                    <name>InstanceID</name>
                    <direction>in</direction>
                    <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
                </argument>
                <argument>
                    <name>Channel</name>
                    <direction>in</direction>
                    <relatedStateVariable>A_ARG_TYPE_Channel</relatedStateVariable>
                </argument>
                <argument>
                    <name>CurrentVolume</name>
                    <direction>out</direction>
                    <relatedStateVariable>VolumeDB</relatedStateVariable>
                </argument>
            </argumentList>
        </action>
        <action>
            <name>GetVolumeDBRange</name>
            <argumentList>
                <argument>
                    <name>InstanceID</name>
                    <direction>in</direction>
                    <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
                </argument>
                <argument>
                    <name>Channel</name>
                    <direction>in</direction>
                    <relatedStateVariable>A_ARG_TYPE_Channel</relatedStateVariable>
                </argument>
                <argument>
                    <name>MinValue</name>
                    <direction>out</direction>
                    <relatedStateVariable>VolumeDB</relatedStateVariable>
                </argument>
                <argument>
                    <name>MaxValue</name>
                    <direction>out</direction>
                    <relatedStateVariable>VolumeDB</relatedStateVariable>
                </argument>
            </argumentList>
        </action>
        <action>
            <name>ListPresets</name>
            <argumentList>
                <argument>
                    <name>InstanceID</name>
                    <direction>in</direction>
                    <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
                </argument>
                <argument>
                    <name>CurrentPresetNameList</name>
                    <direction>out</direction>
                    <relatedStateVariable>PresetNameList</relatedStateVariable>
                </argument>
            </argumentList>
        </action>
        <action>
            <name>SelectPreset</name>
            <argumentList>
                <argument>
                    <name>InstanceID</name>
                    <direction>in</direction>
                    <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
                </argument>
                <argument>
                    <name>PresetName</name>
                    <direction>in</direction>
                    <relatedStateVariable>A_ARG_TYPE_PresetName</relatedStateVariable>
                </argument>
            </argumentList>
        </action>
        <action>
            <name>SetMute</name>
            <argumentList>
                <argument>
                    <name>InstanceID</name>
                    <direction>in</direction>
                    <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
                </argument>
                <argument>
                    <name>Channel</name>
                    <direction>in</direction>
                    <relatedStateVariable>A_ARG_TYPE_Channel</relatedStateVariable>
                </argument>
                <argument>
                    <name>DesiredMute</name>
                    <direction>in</direction>
                    <relatedStateVariable>Mute</relatedStateVariable>
                </argument>
            </argumentList>
        </action>
        <action>
            <name>SetVolume</name>
            <argumentList>
                <argument>
                    <name>InstanceID</name>
                    <direction>in</direction>
                    <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
                </argument>
                <argument>
                    <name>Channel</name>
                    <direction>in</direction>
                    <relatedStateVariable>A_ARG_TYPE_Channel</relatedStateVariable>
                </argument>
                <argument>
                    <name>DesiredVolume</name>
                    <direction>in</direction>
                    <relatedStateVariable>Volume</relatedStateVariable>
                </argument>
            </argumentList>
        </action>
    </actionList>
    <serviceStateTable>
        <stateVariable sendEvents="no">
            <name>GreenVideoGain</name>
            <dataType>ui2</dataType>
            <allowedValueRange>
                <minimum>0</minimum>
                <maximum>100</maximum>
                <step>1</step>
            </allowedValueRange>
        </stateVariable>
        <stateVariable sendEvents="no">
            <name>BlueVideoBlackLevel</name>
            <dataType>ui2</dataType>
            <allowedValueRange>
                <minimum>0</minimum>
                <maximum>100</maximum>
                <step>1</step>
            </allowedValueRange>
        </stateVariable>
        <stateVariable sendEvents="no">
            <name>VerticalKeystone</name>
            <dataType>i2</dataType>
            <allowedValueRange>
                <minimum>-32768</minimum>
                <maximum>32767</maximum>
                <step>1</step>
            </allowedValueRange>
        </stateVariable>
        <stateVariable sendEvents="no">
            <name>GreenVideoBlackLevel</name>
            <dataType>ui2</dataType>
            <allowedValueRange>
                <minimum>0</minimum>
                <maximum>100</maximum>
                <step>1</step>
            </allowedValueRange>
        </stateVariable>
        <stateVariable sendEvents="no">
            <name>Volume</name>
            <dataType>ui2</dataType>
            <allowedValueRange>
                <minimum>0</minimum>
                <maximum>100</maximum>
                <step>1</step>
            </allowedValueRange>
        </stateVariable>
        <stateVariable sendEvents="no">
            <name>Loudness</name>
            <dataType>boolean</dataType>
        </stateVariable>
        <stateVariable sendEvents="no">
            <name>A_ARG_TYPE_InstanceID</name>
            <dataType>ui4</dataType>
        </stateVariable>
        <stateVariable sendEvents="no">
            <name>RedVideoGain</name>
            <dataType>ui2</dataType>
            <allowedValueRange>
                <minimum>0</minimum>
                <maximum>100</maximum>
                <step>1</step>
            </allowedValueRange>
        </stateVariable>
        <stateVariable sendEvents="no">
            <name>ColorTemperature</name>
            <dataType>ui2</dataType>
            <allowedValueRange>
                <minimum>0</minimum>
                <maximum>65535</maximum>
                <step>1</step>
            </allowedValueRange>
        </stateVariable>
        <stateVariable sendEvents="no">
            <name>Sharpness</name>
            <dataType>ui2</dataType>
            <allowedValueRange>
                <minimum>0</minimum>
                <maximum>100</maximum>
                <step>1</step>
            </allowedValueRange>
        </stateVariable>
        <stateVariable sendEvents="no">
            <name>A_ARG_TYPE_PresetName</name>
            <dataType>string</dataType>
            <allowedValueList>
                <allowedValue>FactoryDefaults</allowedValue>
                <allowedValue>InstallationDefaults</allowedValue>
                <allowedValue>Vendor defined</allowedValue>
            </allowedValueList>
        </stateVariable>
        <stateVariable sendEvents="no">
            <name>RedVideoBlackLevel</name>
            <dataType>ui2</dataType>
            <allowedValueRange>
                <minimum>0</minimum>
                <maximum>100</maximum>
                <step>1</step>
            </allowedValueRange>
        </stateVariable>
        <stateVariable sendEvents="no">
            <name>BlueVideoGain</name>
            <dataType>ui2</dataType>
            <allowedValueRange>
                <minimum>0</minimum>
                <maximum>100</maximum>
                <step>1</step>
            </allowedValueRange>
        </stateVariable>
        <stateVariable sendEvents="no">
            <name>Mute</name>
            <dataType>boolean</dataType>
        </stateVariable>
        <stateVariable sendEvents="yes">
            <name>LastChange</name>
            <dataType>string</dataType>
        </stateVariable>
        <stateVariable sendEvents="no">
            <name>A_ARG_TYPE_Channel</name>
            <dataType>string</dataType>
            <allowedValueList>
                <allowedValue>Master</allowedValue>
                <allowedValue>LF</allowedValue>
                <allowedValue>RF</allowedValue>
            </allowedValueList>
        </stateVariable>
        <stateVariable sendEvents="no">
            <name>HorizontalKeystone</name>
            <dataType>i2</dataType>
            <allowedValueRange>
                <minimum>-32768</minimum>
                <maximum>32767</maximum>
                <step>1</step>
            </allowedValueRange>
        </stateVariable>
        <stateVariable sendEvents="no">
            <name>VolumeDB</name>
            <dataType>i2</dataType>
            <allowedValueRange>
                <minimum>-32768</minimum>
                <maximum>32767</maximum>
            </allowedValueRange>
        </stateVariable>
        <stateVariable sendEvents="no">
            <name>PresetNameList</name>
            <dataType>string</dataType>
        </stateVariable>
        <stateVariable sendEvents="no">
            <name>Contrast</name>
            <dataType>ui2</dataType>
            <allowedValueRange>
                <minimum>0</minimum>
                <maximum>100</maximum>
                <step>1</step>
            </allowedValueRange>
        </stateVariable>
        <stateVariable sendEvents="no">
            <name>Brightness</name>
            <dataType>ui2</dataType>
            <allowedValueRange>
                <minimum>0</minimum>
                <maximum>100</maximum>
                <step>1</step>
            </allowedValueRange>
        </stateVariable>
    </serviceStateTable>
</scpd>
'''
        return text


def getLocalIp():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.connect(("119.29.29.29", 80))
    ip = s.getsockname()[0]
    s.close()
    return ip


class Dlna:
    def __init__(self):
        self.devices = {}
        self.infos = {}

    def start(self):
        # ListenWorker(self.onFound).start()
        pass

    def onFound(self, url, info, item):
        self.infos[url] = info
        self.devices[url] = item

    def getInfos(self):
        return self.infos

    def getDevice(self, url):
        return self.devices.get(url)


def htmlEncode(text):
    d = {"&": "&amp;", "<": "&lt;", ">": "&gt;", "'": "'", '"': '&quot;'}
    for k, v in d.items():
        text = text.replace(k, v)
    return text


class ThreadingSimpleServer(ThreadingMixIn, HTTPServer):
    pass


# ===============================================================================
# uuid = "27d6877e-{}-ea12-abdf-cf8d50e36d54".format(randint(1000, 9999))
uuid = "27d6877e-6677-ea12-abdf-cf8d50e36d54"
localIp = getLocalIp()
host = (localIp, 8889)
dlna_name = "dlna({}:{})".format(localIp, host[1])
xmlreplayer = XmlReplay(localIp, host[1], dlna_name)
dlna = Dlna()
dlna.start()
server = ThreadingSimpleServer(host, Handler)

def local(ip, port):
    ThreadingSimpleServer((ip, port), Handler).serve_forever()

_thread.start_new_thread(local, ('127.0.0.1', host[1]))
print("Starting server, listen at: %s:%s" % host)
server.serve_forever()


# http://localhost:8889/dlna/info.xml























 

 运行结果

手机app投屏搜索到

 

代码运行输出里看视频链接

到此,获取到投屏视频的播放链接
获取到芒果TV投屏的播放链接:
http://mobile-shadow.api.mgtv.com/v1/video/shadow.m3u8?tea=TRp4。。。efe35d&ftcx=ab2ea0demg_androidP1
获取到百度网盘投屏的播放链接:
https://pan.baidu.com/api/streaming?check_blue=1&type=M3U8_AUTO_720&fsid=29855。。。qc69B7/GzlTXUYA=




 

 播放链接

 某种m3u8,某些工具可以播放这种链接,正在研究

 

 

 代码参考

 

 

代码参考,如果你也在研究,点点star
https://github.com/suconghou/dlna-python
https://github.com/Hans155922/DLNA_URL
https://github.com/jarryleo/watch_together
https://github.com/VideoTogether/VideoTogether

2024-12-02

作者:黑音

物联沃分享整理
物联沃-IOTWORD物联网 » python dlna 投屏

发表回复