1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#! /bin/sh
#
# Automated broadcast downloader script for tou.tv Akamai-hosted content.
# Make executable (chmod +x), and invoke without argument for usage info.
#
# Requires:
#
# - A bourne shell (tested to GNU bash 4.2.37 & dash 0.5.7.3)
# - GNU Wget (tested on 1.12)
# - GNU Sed (tested on 4.2.1)
# - OpenSSL (tested on 1.0.0c)
# - GNU Coreutils (for od, tested on 8.2): if you know a more portable way
#   to do this without relying on something heavier like cPython, please 
#   drop me a line.
#
# Also requires read-write access to current working directory.
#
# Sylvain <fourmanoit@gmail.com>, 2013, 
# directly based on an early implementation by Raphael Nadeau.
#
# History
# -------
# 2013-02-05: Add optional ffmpeg/avconv lossless transcoding, 
#             as per Kristoffer Laurin-Racicot suggestion.
# 2013-02-04: Add check to prevent download overwrite.
# 2013-02-04: Initial release.
#
#-------------------------------------------------------------------------------
# Constants
#
UA="Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us)"
UA="$UA AppleWebKit/531.21.10 (KHTML, like Gecko)"
UA="$UA Version/4.0.4 Mobile/7B348b Safari/531.21.10"

LOC="http://api.radio-canada.ca/validationMedia/v1/Validation.html"
LOC="${LOC}?output=json&appCode=thePlatform&deviceType=ipad&"
LOC="${LOC}connectionType=wifi"

#-------------------------------------------------------------------------------
# Utils
#
usage() {
    {
    cat<<EOF
Usage: `basename $0` URI

where URI is the location of the broadcast on the tou.tv website. Example:

`basename $0` http://www.tou.tv/decouverte/S2012E20

EOF
    } 1>&2
}

die() {
    echo 'error:' $* 1>&2
    exit 1
}

log() {
    echo `date` - $* 1>&2
}

#-------------------------------------------------------------------------------
# Main routine
#
# Test for needed programs availability
for PROG in wget sed openssl od wc dd; do
    which $PROG > /dev/null 2>&1
    test $? -eq 1 && die "${PROG} not found in your PATH"
done

test `sed --version | sed '/GNU/!d' | wc -l` -ge 1 || die 'sed must be GNU sed'

# Test for ffmpeg/avconv availability
for TRANS in ffmpeg avconv dd; do
    which $TRANS > /dev/null 2>&1 && break
done
if test $TRANS = dd ; then
    EXT=.ts
else
    EXT=.mkv
fi

# Parse the command line
test $# -eq 1 || { usage; die "not called with a single URI"; }

# Check for free output slot
OUTPUT=`echo $1 | \
   sed 's,http://www.tou.tv,,;s/[^a-zA-Z0-9]\+/_/g;\
        s,^_\+,,;s,_\+$,,;s/.*/\L&/'`$EXT

test -e $OUTPUT && die "output file '${OUTPUT}' already exists, bailing out."

if test $TRANS = dd ; then
    TRANS="dd of=$OUTPUT"
else
    TRANS="$TRANS -i - -codec copy $OUTPUT"
fi

log 'retrieving the media ID...'
ID_MEDIA=`wget -q $1 -O - | sed '/idMedia/!d;s/^.*idMedia\":\"//;s/\".*//'`

log 'retrieving primary playlist location...'
PLAYLIST=`wget -q "${LOC}&idMedia=${ID_MEDIA}" -O - | \
   sed 's/.*\"url\":\"//;s/\".*//'`

log 'retrieving access cookies and best secondary playlist...'
COOKIES=cookies$$.txt
PLAYLIST_2=`wget -q --user-agent="$UA" \
    --header="referer: $1" \
    --keep-session-cookies --save-cookies=$COOKIES $PLAYLIST -O - | \
   sed 's/.*BANDWIDTH=//;s/,RESOLUTION=.*//;s/,CODECS=.*//;/^#/d;N;s/\n/ /' | \
   sort -n | sed '$!d;s/[0-9]\+ //'`
trap 'rm $COOKIES' EXIT

log 'retrieving secondary playlist...'
alias dl="wget -q --user-agent='$UA' --header='referer: $1' \
             --load-cookies $COOKIES -O - "
STREAM=`dl $PLAYLIST_2`

log 'retrieving decryption key...'
KEY_URL=`echo "$STREAM" | sed '/EXT-X-KEY/!d;s/.*URI="//;s/".*//'`
KEY=`dl $KEY_URL | od -tx1 -w16 -Ax | sed '1!d;s/000000 //;s/ //g'`

log "dumping stream to $OUTPUT..."
SEGMENTS=`echo "$STREAM" | sed '/^http/!d'`
N=`echo "$SEGMENTS" | wc -l`
log "$N segments to retrieve"
echo "$SEGMENTS" | (
    IDX=1
    while read SEGMENT ; do
       log "fetching & decrypting segment $IDX/$N..."
       dl $SEGMENT
       IDX=$(( IDX + 1))
    done
    
) | openssl aes-128-cbc -d -nosalt \
    -iv 00000000000000000000000000000001 -K $KEY | \
    $TRANS
log "done, stream dumped to $OUTPUT."

#-------------------------------------------------------------------------------
# That's all, folks!