Skip to content

Instantly share code, notes, and snippets.

@rickt
Created May 18, 2022 21:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rickt/3ae6e20e348791a61480139de51a1584 to your computer and use it in GitHub Desktop.
Save rickt/3ae6e20e348791a61480139de51a1584 to your computer and use it in GitHub Desktop.
widevine downloader & decrypter
#! /bin/bash
#
# rough and ready bash script to download & decrypt a widevine-encrypted video via MPD URL
# this will work with (for example) channel5 UKTV
#
# assumptions:
# 1) the following binaries are in your $PATH:
# curl, ffmpeg, head, jq, mp4decrypt, yt-dlp
#
# this script requires 2x arguments:
# 1) output filename (no spaces! example: Question.Team.S01E08)
# 2) the MPD URL
# check arguments
if [ $# -lt 2 ]; then
echo "Error! you must specify 2x arguments:"
echo " 1) output filename w/no spaces e.g. Question.Team.S01E08"
echo " 2) MPD URL in double quotes"
exit 1
fi
# args are good, lets do this
OUTPUT=$1
MPDURL=$2
# get the MPD
echo "" && echo -n "*** Getting MPD, License URL & PSSH... "
MPDSRC=./mpdsrc.xml
rm -f $MPDSRC 2> /dev/null
curl -s "$MPDURL" -o $MPDSRC
# get the widevine license URL
LICURL=`grep 'bc:licenseAcquisitionUrl' $MPDSRC | head -1 | awk -FlicenseAcquisitionUrl '{print $2}' | sed -e 's/=\"//g' -e 's/\">//g' -e 's/ .*//g' -e 's/\"//g'`
# get the pssh
PSSH=`grep pssh $MPDSRC | head -1 | awk -Fpssh\> '{print $2}' | sed -e 's/cenc//g' -e 's/<\/://g'`
echo " done." && echo ""
# use a bash 'here script' to create the JSON to talk to the keys API
KEYSJSON="./keysapi.json"
rm -f $KEYSJSON 2> /dev/null
cat <<EOF > $KEYSJSON
{
"cache": false,
"license": "$LICURL",
"pssh": "$PSSH"
}
EOF
# talk to the keys API to get the decryption key
echo -n "*** Talking to the keys API server... "
KEYSAPIURL="http://getwvkeys.cc/api"
DECRYPTIONKEY=`curl -s -H "Content-Type: application/json" -H "Referer: http://getwvkeys.cc" -X POST -d @$KEYSJSON $KEYSAPIURL | jq -r '.keys' | grep key | awk -F\" '{print $4}'`
echo " done." && echo ""
# make a temp folder
TMPFOLDER="tmp_$$"
mkdir -p "./$TMPFOLDER"
echo "*** Downloading video & audio using yt-dlp..." && echo ""
# download the encrypted video & audio files
yt-dlp --no-warnings --quiet --progress -N 16 --allow-u "$MPDURL" -P $TMPFOLDER -o "encrypted_$OUTPUT"
echo "*** Downloading video & audio using yt-dlp... done."
# decrypt the video
echo "" && echo -n "*** Decrypting video... "
mp4decrypt --key $DECRYPTIONKEY $TMPFOLDER/*mp4 $TMPFOLDER/decrypted_$OUTPUT.mp4
echo " done." # && echo ""
# decrypt the audio
echo "" && echo -n "*** Decrypting audio... "
mp4decrypt --key $DECRYPTIONKEY $TMPFOLDER/*m4a $TMPFOLDER/decrypted_$OUTPUT.m4a
echo " done." # && echo ""
# combine the decrypted video and audio files
rm -f $OUTPUT.FINAL.mp4 2> /dev/null
echo "" && echo -n "*** Combining decrypted video & audio... "
ffmpeg -loglevel quiet -hide_banner -i $TMPFOLDER/decrypted_$OUTPUT.mp4 -i $TMPFOLDER/decrypted_$OUTPUT.m4a -acodec copy -vcodec copy ./$OUTPUT.FINAL.mp4
echo " done." # && echo ""
# did the ffmpeg completely properly?
RETVAL=$?
if [ $RETVAL -ne 0 ]; then
echo "Error! Check stuff!"
exit 1
fi
# it did, we can remove the temp files
rm -rf $TMPFOLDER 2> /dev/null
# get size of completed file
SIZE=`ls -lh $OUTPUT.FINAL.mp4 | awk '{print $5}'`
# fin
echo "" && echo "*** Finished video: $OUTPUT.FINAL.mp4 ($SIZE)" && echo ""
# EOF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment