Skip to content

Instantly share code, notes, and snippets.

@je3kmz
Forked from saiten/rec_radiko.sh
Last active February 8, 2024 01:40
Show Gist options
  • Save je3kmz/1e53c81baafb820d9b18bf10be0840d2 to your computer and use it in GitHub Desktop.
Save je3kmz/1e53c81baafb820d9b18bf10be0840d2 to your computer and use it in GitHub Desktop.
簡易radiko録音ツール。要wget,ffmpeg,xmllint
#!/bin/sh
pid=$$
date=`env TZ=JST-09 date '+%Y-%m-%d-%H_%M'`
tmpdir=/tmp
#######################################
# Extract login JSON value
# Arguments:
# (pipe)Login result JSON
# Key
# Returns:
# None
#######################################
extract_login_value() {
name=$1
# for gawk
#value=$(cat - | gawk -v "name=${name}" 'BEGIN { FS = "\n"; } { regex = "\""name"\"[ ]*:[ ]*(\"[0-9a-zA-Z]+\"|[0-9]*)"; if (!match($0, regex, v)) { exit 0; } val=v[1]; if (match(val, /\"([0-9a-zA-Z]*)\"/, v)) { val=v[1]; } print val; }')
value=$(cat - \
| awk -v "name=${name}" '
BEGIN {
FS = "\n";
}
{
# Extract key and value
regex = "\""name"\"[ ]*:[ ]*(\"[0-9a-zA-Z]+\"|[0-9]*)";
if (!match($1, regex)) {
exit 0;
}
str = substr($0, RSTART, RLENGTH);
# Extract value
regex = "\""name"\"[ ]*:[ ]*";
match(str, regex);
str = substr(str, RSTART + RLENGTH);
# String value
if (match(str, /^\"[0-9a-zA-Z]+\"/)) {
print substr(str, RSTART + 1, RLENGTH - 2);
exit 0;
}
# Numeric value
if (match(str, /^[0-9]*/)) {
print substr(str, RSTART, RLENGTH);
exit 0;
}
}')
echo "${value}"
return 0
}
quit()
{
echo authkey not found
logout
exit 1
}
#_authkey=bcd151073c03b352e1ef2fd66c32209da9ca0afa
wget -q -O $tmpdir/playerCommon.js$pid https://radiko.jp/apps/js/playerCommon.js || quit
_authkey=`grep pc_html5 $tmpdir/playerCommon.js$pid | awk -F\' '{print$4}'`
unlink $tmpdir/playerCommon.js$pid
logout()
{
wget --quiet -O /dev/null --post-data=radiko_session=${auth2_url_param} https://radiko.jp/v4/api/member/logout 2> /dev/null
}
channel=`echo $1 | tr '[[a-z]]' '[[A-Z]]'`
if [ $# -eq 1 ]; then
output=${channel}_${date}.aac
elif [ $# -eq 2 ]; then
output=$2
elif [ $# -eq 3 ]; then
output=$2
rectime="-t "$3
elif [ $# -eq 4 ]; then
output=$2
mail=$3
pass=$4
elif [ $# -eq 5 ]; then
output=$2
mail=$3
pass=$4
rectime="-t "$5
else
echo "usage : "`basename $0`" channel_name [outputfile] [mail] [pass] [recordingtime(sec)]"
exit 1
fi
areafree=0
if [ -n "$mail" ]; then
auth2_url_param=""
login=$(wget -O $tmpdir/login.$pid --server-response --post-data=mail=$mail\&pass=$pass https://radiko.jp/ap/member/webapi/member/login 2> /dev/stdout)
areafree=$(cat $tmpdir/login.$pid | extract_login_value "areafree")
radiko_session=$(cat $tmpdir/login.$pid | extract_login_value "radiko_session")
if [ -n "`echo $login | sed -n -e '/200 OK/p'`" ]; then
# ログイン確認
if [ $areafree -eq 1 ]; then
auth2_url_param="?radiko_session=${radiko_session}"
fi
fi
rm -f $tmpdir/login.$pid
fi
# 認証
AUTH1="$(wget -q -S -O /dev/null --header "X-Radiko-App: pc_html5" --header "X-Radiko-App-Version: 0.0.1" --header "X-Radiko-Device: pc" --header "X-Radiko-User: dummy_user" https://radiko.jp/v2/api/auth1 2> /dev/stdout)"
ret=$?
if test $ret -gt 0
then
quit
fi
authtoken=$(echo "${AUTH1}" | awk 'tolower($0) ~/x-radiko-authtoken: / {print substr($0,23,length($0)-22)}')
offset=$(echo "${AUTH1}" | awk 'tolower($0) ~/x-radiko-keyoffset: / {print substr($0,23,length($0)-22)}')
length=$(echo "${AUTH1}" | awk 'tolower($0) ~/x-radiko-keylength: / {print substr($0,23,length($0)-22)}')
partialkey=`echo $_authkey | dd bs=1 skip=$offset count=$length 2> /dev/null | openssl base64`
wget --quiet --no-check-certificate --server-response\
--header="X-Radiko-AuthToken: "$authtoken\
--header="X-Radiko-PartialKey: "$partialkey\
--header="X-Radiko-User: dummy_user"\
--header="X-Radiko-Device: pc"\
-O/dev/null\
https://radiko.jp/v2/api/auth2${auth2_url_param} 2> /dev/null
urilist=$(wget -q -O - https://radiko.jp/v2/station/stream_smh_multi/${channel}.xml | xmllint --xpath "/urls/url[@areafree='${areafree}']/playlist_create_url/text()" -)
for x in `echo $urilist`
do
ffprobe -hide_banner -v error -headers 'X-Radiko-Authtoken: '${authtoken} ${x}?station_id=${channel}
ret=$?
if test 0 -eq $ret
then
URL=${x}
break
fi
done
#lsid=$(head -c 100 /dev/random | openssl base64 | tr -dc '0-9A-Fa-f' | tr '[:upper:]' '[:lower:]' | cut -c 1-32)
### live
ffmpeg -hide_banner -v error -headers 'X-Radiko-AuthToken: '${authtoken} \
-i ${URL}\
-metadata:s language=jpn \
${rectime} -bsf:a aac_adtstoasc -acodec copy "${output}"
ret=$?
if test 1 -eq $ret
then
echo ffmpeg error
logout
exit 1
fi
# ログアウト
logout
exit
#!/bin/sh
pid=$$
date=`env TZ=JST-09 date '+%Y-%m-%d-%H_%M'`
tmpdir=/tmp
#######################################
# Extract login JSON value
# Arguments:
# (pipe)Login result JSON
# Key
# Returns:
# None
#######################################
extract_login_value() {
name=$1
# for gawk
#value=$(cat - | gawk -v "name=${name}" 'BEGIN { FS = "\n"; } { regex = "\""name"\"[ ]*:[ ]*(\"[0-9a-zA-Z]+\"|[0-9]*)"; if (!match($0, regex, v)) { exit 0; } val=v[1]; if (match(val, /\"([0-9a-zA-Z]*)\"/, v)) { val=v[1]; } print val; }')
value=$(cat - \
| awk -v "name=${name}" '
BEGIN {
FS = "\n";
}
{
# Extract key and value
regex = "\""name"\"[ ]*:[ ]*(\"[0-9a-zA-Z]+\"|[0-9]*)";
if (!match($1, regex)) {
exit 0;
}
str = substr($0, RSTART, RLENGTH);
# Extract value
regex = "\""name"\"[ ]*:[ ]*";
match(str, regex);
str = substr(str, RSTART + RLENGTH);
# String value
if (match(str, /^\"[0-9a-zA-Z]+\"/)) {
print substr(str, RSTART + 1, RLENGTH - 2);
exit 0;
}
# Numeric value
if (match(str, /^[0-9]*/)) {
print substr(str, RSTART, RLENGTH);
exit 0;
}
}')
echo "${value}"
return 0
}
quit()
{
echo authkey not found
logout
exit 1
}
#_authkey=bcd151073c03b352e1ef2fd66c32209da9ca0afa
wget -q -O $tmpdir/playerCommon.js$pid https://radiko.jp/apps/js/playerCommon.js || quit
_authkey=`grep pc_html5 $tmpdir/playerCommon.js$pid | awk -F\' '{print$4}'`
unlink $tmpdir/playerCommon.js$pid
logout()
{
wget --quiet -O /dev/null --post-data=radiko_session=${auth2_url_param} https://radiko.jp/v4/api/member/logout 2> /dev/null
}
channel=`echo $1 | tr '[[a-z]]' '[[A-Z]]'`
if [ $# -eq 3 ]; then
output=${channel}_${2}-${3}.aac
start_time=$2
end_time=$3
elif [ $# -eq 4 ]; then
start_time=$2
end_time=$3
output=$4
elif [ $# -eq 6 ]; then
start_time=$2
end_time=$3
output=$4
mail=$5
pass=$6
else
echo "usage : "`basename $0`" channel_name starttime(YYYYMMDDHHMMSS) endingtime(YYYYMMDDHHMMSS) [outputfile] [mail] [pass]"
exit 1
fi
areafree=0
if [ -n "$mail" ]; then
auth2_url_param=""
login=$(wget -O $tmpdir/login.$pid --server-response --post-data=mail=$mail\&pass=$pass https://radiko.jp/ap/member/webapi/member/login 2> /dev/stdout)
areafree=$(cat $tmpdir/login.$pid | extract_login_value "areafree")
radiko_session=$(cat $tmpdir/login.$pid | extract_login_value "radiko_session")
if [ -n "`echo $login | sed -n -e '/200 OK/p'`" ]; then
# ログイン確認
if [ $areafree -eq 1 ]; then
auth2_url_param="?radiko_session=${radiko_session}"
fi
fi
rm -f $tmpdir/login.$pid
fi
# 認証
AUTH1="$(wget -q -S -O /dev/null --header "X-Radiko-App: pc_html5" --header "X-Radiko-App-Version: 0.0.1" --header "X-Radiko-Device: pc" --header "X-Radiko-User: dummy_user" https://radiko.jp/v2/api/auth1 2> /dev/stdout)"
ret=$?
if test $ret -gt 0
then
quit
fi
authtoken=$(echo "${AUTH1}" | awk 'tolower($0) ~/x-radiko-authtoken: / {print substr($0,23,length($0)-22)}')
offset=$(echo "${AUTH1}" | awk 'tolower($0) ~/x-radiko-keyoffset: / {print substr($0,23,length($0)-22)}')
length=$(echo "${AUTH1}" | awk 'tolower($0) ~/x-radiko-keylength: / {print substr($0,23,length($0)-22)}')
partialkey=`echo $_authkey | dd bs=1 skip=$offset count=$length 2> /dev/null | openssl base64`
wget --quiet --no-check-certificate --server-response\
--header="X-Radiko-AuthToken: "$authtoken\
--header="X-Radiko-PartialKey: "$partialkey\
--header="X-Radiko-User: dummy_user"\
--header="X-Radiko-Device: pc"\
-O/dev/null\
https://radiko.jp/v2/api/auth2${auth2_url_param} 2> /dev/null
urilist=$(echo https://radiko.jp/v2/api/ts/playlist.m3u8 ; wget -q -O - https://radiko.jp/v2/station/stream_smh_multi/${channel}.xml | xmllint --xpath "/urls/url[@areafree='${areafree}']/playlist_create_url/text()" -)
for x in `echo $urilist`
do
ffprobe -hide_banner -v error -headers 'X-Radiko-Authtoken: '${authtoken} ${x}?station_id=${channel}
ret=$?
if test 0 -eq $ret
then
URL=${x}
break
fi
done
lsid=$(head -c 100 /dev/random | openssl base64 | tr -dc '0-9A-Fa-f' | tr '[:upper:]' '[:lower:]' | cut -c 1-32)
### timefree
ffmpeg -hide_banner -v error -headers 'X-Radiko-AuthToken: '${authtoken} \
-i ${URL}?station_id=${channel}\&l=15\&ft=${start_time}\&to=${end_time}\&start_at=${start_time}\&end_at=${end_time}\&seek=${start_time}\&lsid=${lsid}\&type=c \
-metadata:s language=jpn \
-bsf:a aac_adtstoasc -acodec copy "${output}"
ret=$?
if test 1 -eq $ret
then
echo ffmpeg error
logout
exit 1
fi
# ログアウト
logout
exit
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment