Skip to content

Instantly share code, notes, and snippets.

@probonopd
Last active April 17, 2020 00:54
Show Gist options
  • Save probonopd/9893084d982893c4c7b7 to your computer and use it in GitHub Desktop.
Save probonopd/9893084d982893c4c7b7 to your computer and use it in GitHub Desktop.
Play a YouTube video on a Samsung Smart TV using UPNP
<?xml version="1.0" encoding="UTF-8"?>
<DIDL-Lite xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sec="http://www.sec.co.kr/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/">
<item id="f-0" parentID="0" restricted="0">
<dc:title>Video</dc:title>
<dc:creator>vGet</dc:creator>
<upnp:class>object.item.videoItem</upnp:class>
<res protocolInfo="http-get:*:video/mp4:DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01700000000000000000000000000000" sec:URIType="public">$URI</res>
</item>
</DIDL-Lite>
#!/bin/sh
#
# Download helper
#
if [ ! -e "/usr/local/bin/youtube-dl" ] ; then
sudo wget "https://yt-dl.org/downloads/latest/youtube-dl" -O /usr/local/bin/youtube-dl
sudo chmod a+x /usr/local/bin/youtube-dl
fi
#
# Determine URI
#
# URI="http://download.wavetlan.com/SVV/Media/HTTP/H264/Talkinghead_Media/H264_test1_Talkinghead_mp4_480x360.mp4"
if [ "${1:0:18}" == "http://www.youtube" ] ; then
echo "Parsing YouTube URL"
URI=$(youtube-dl -g "$1")
else
if [ "${1:0:4}" == "http" ] ; then
URI=$1
else
URI=$(youtube-dl -g --default-search "auto" "$1")
fi
fi
echo $URI
#
# Set URI
#
cat > /tmp/foo <<EOF
POST /smp_22_ HTTP/1.1
Accept: application/json, text/plain, */*
Soapaction: "urn:schemas-upnp-org:service:AVTransport:1#SetAVTransportURI"
Content-Type: text/xml;charset="UTF-8"
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:SetAVTransportURI xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
<InstanceID>0</InstanceID>
<CurrentURI>$URI</CurrentURI>
<CurrentURIMetaData>&lt;DIDL-Lite xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sec="http://www.sec.co.kr/"&gt;&lt;item id="f-0" parentID="0" restricted="0"&gt;&lt;dc:title&gt;Video&lt;/dc:title&gt;&lt;dc:creator&gt;vGet&lt;/dc:creator&gt;&lt;upnp:class&gt;object.item.videoItem&lt;/upnp:class&gt;&lt;res protocolInfo="http-get:*:video/mp4:DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01700000000000000000000000000000" sec:URIType="public"&gt;$URI&lt;/res&gt;&lt;/item&gt;&lt;/DIDL-Lite&gt;</CurrentURIMetaData>
</u:SetAVTransportURI>
</s:Body>
</s:Envelope>
EOF
echo "==="
cat /tmp/foo | unix2dos | nc 192.168.0.13 7676
#
# Send PLAY
#
cat > /tmp/foo <<EOF
POST /smp_22_ HTTP/1.1
Accept: application/json, text/plain, */*
Soapaction: "urn:schemas-upnp-org:service:AVTransport:1#Play"
Content-Type: text/xml;charset="UTF-8"
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:Play xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
<InstanceID>0</InstanceID>
<Speed>1</Speed>
</u:Play>
</s:Body>
</s:Envelope>
EOF
echo "==="
cat /tmp/foo | unix2dos | nc 192.168.0.13 7676
# HTTP replay reverse engineering how to play a YouTube video on a Samsung Smart TV
# by controlling it over UPNP
# I used debian
sudo apt-get install tcpdump tcpslice tcptrace
mkdir replay
cd replay
# Capture packets (can also be done on the Mac)
tcpdump -i eth0 recorded.pcap
# Now run an application on the same computer that plays
# something on the Samsung TV
# I used vGet Cast (DLNA Controller)
# Convert to one file per HTTP session
tcpslice -w full.pcap recorded.pcap
tcptrace -e full.pcap
# Find the file to set the URL and replay it
FILE=$(grep -l -r SetAVTransportURI . | tail -n 1)
HOST=$(cat $FILE | grep "Host:" | cut -d " " -f 2 | sed -e 's|:| |g')
echo $FILE
cat $FILE | nc $HOST
# FIXME:
# If the TV was switched off before, I get "HTTP/1.1 412 Precondition Failed"
# Find the file to start Play and replay it
FILE=$(grep -l -r Play . | tail -n 1)
HOST=$(cat $FILE | grep "Host:" | cut -d " " -f 2 | sed -e 's|:| |g')
echo $FILE
cat $FILE | nc $HOST
###
unix2dos can be used to get "CRLF line terminators"
@tiendaik
Copy link

tiendaik commented Aug 31, 2018

If I have many url in many res tag, which url will be played first?

Copy link

ghost commented Jul 2, 2019

it only works with local files, doesn't work with online streaming

@probonopd
Copy link
Author

For me it also worked with online streams last time I had tested. See https://github.com/probonopd/video2smarttv

Copy link

ghost commented Jul 2, 2019

Thanks! Do you know any source for objective-c to support this feature?

@probonopd
Copy link
Author

No, I had cobbled this together myself.

@probonopd
Copy link
Author

Definitely still works with online streams including YouTube.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment