Skip to content

Instantly share code, notes, and snippets.

@uru2
Last active January 29, 2026 08:33
Show Gist options
  • Select an option

  • Save uru2/d1c24cd510e06ef92f0e62201b3826b8 to your computer and use it in GitHub Desktop.

Select an option

Save uru2/d1c24cd510e06ef92f0e62201b3826b8 to your computer and use it in GitHub Desktop.
放送局と日時からradikoの番組に関する情報を取得するサンプル
#!/bin/sh
# 放送局と日時からradikoの番組に関する情報を取得するサンプル
#
# ライセンスはUnlicense(https://unlicense.org/)にしますので
# 必要な箇所をかいつまんでの利用や別の処理系で実装するなりご自由に
#
# usage: radiko_program_info.sh {station_id} {[%Y%m%d]%H%M[%S]}
# 日時は以下の指定が可能
# %H%M (時分のみ、日付は実行日で補完)
# %H%M%S (時分秒のみ、日付は実行日で補完)
# %Y%m%d%H%M (年月日時分)
# %Y%m%d%H%M%S (年月日時分秒)
set -eu
to_unixtime() {
utime=$(echo "$1" \
| awk '{
date_str = $1;
if (match(date_str, /[^0-9]/)) {
# Invalid character
print -1;
exit;
}
if (length(date_str) != 12 && length(date_str) != 14) {
# Invalid length
print -1;
exit;
}
# Split datetime parts
year = substr(date_str, 1, 4) - 0;
month = substr(date_str, 5, 2) - 0;
day = substr(date_str, 7, 2) - 0;
hour = substr(date_str, 9, 2) - 0;
minute = substr(date_str, 11, 2) - 0;
second = (length(date_str) == 14) ? substr(date_str, 13, 2) - 0 : 0;
# Validation parts
if ((year < 1970) || (month < 1) || (month > 12) || (hour < 0) || (hour > 23) \
|| (minute < 0) || (minute > 59) || (second < 0) || (second > 59)) {
print -1;
exit;
}
split("31 0 31 30 31 30 31 31 30 31 30 31", days_of_month);
days_of_month[2] = (year % 4 != 0) ? 28 : (year % 100 != 0) ? 29 : (year % 400 != 0) ? 28 : 29;
if (day > days_of_month[month]) {
print -1;
exit;
}
# To UNIX time
if (month < 3) {
month+= 12;
year--;
}
tz_offset = 32400; # JST(UTC+9)
utime = (365 * year + int(year / 4) - int(year / 100) + int(year / 400) + int(306 * (month + 1) / 10) - 428 + day - 719163) \
* 86400 + (hour * 3600) + (minute * 60) + second - tz_offset;
print utime;
exit;
}')
if [ "${utime}" = '-1' ]; then
return 1
fi
echo "${utime}"
return 0
}
to_datetime() {
datetime=$(echo "$1" \
| awk '{
ut = $0 + 32400; # JST(UTC+9)
# hour, minute, second
tm = ut;
second = tm % 60;
tm = int(tm / 60);
minute = tm % 60;
tm = int(tm / 60);
hour = int(tm % 24);
# year, month, day
year = 1970;
left_days = int(ut / 86400) + 1;
while (left_days > 0) {
is_leap = (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0));
year_days = (is_leap == 0) ? 365 : 366;
if (left_days > year_days) {
year++;
left_days -= year_days;
continue;
}
split("31 28 31 30 31 30 31 31 30 31 30 31", days_of_month);
days_of_month[2] = (is_leap == 0) ? 28 : 29;
month = 1;
day = 0;
for (i = 1; i <= 12; i++) {
if (days_of_month[i] >= left_days) {
day = left_days;
left_days = 0;
break;
}
left_days -= days_of_month[i];
month++;
}
}
printf("%04d%02d%02d%02d%02d%02d", year, month, day, hour, minute, second);
}')
echo "${datetime}"
return 0
}
station_id=$1
program_datetime=
# 番組開始日時
if [ "${#2}" = "14" ]; then
# 年月日時分秒
program_datetime=$2
elif [ "${#2}" = "12" ]; then
# 年月日時分
program_datetime="${2}00"
elif [ "${#2}" = "6" ]; then
# 時分秒
program_datetime="$(date +%Y%m%d)${2}"
elif [ "${#2}" = "4" ]; then
# 時分
program_datetime="$(date +%Y%m%d)${2}00"
fi
# 番組表の日付
# 00:00-04:59は前日扱いなので5時間分(=18000秒)引いて日付部だけ得る
program_date=$(to_datetime "$(($(to_unixtime "${program_datetime}") - 18000))" | cut -c 1-8)
# 放送局情報一覧の取得
stations_res=$(curl -s https://radiko.jp/v3/station/region/full.xml)
# 放送局エリアID (番組情報一覧取得で使います)
area_id=$(echo "${stations_res}" \
| xmllint --xpath "/region/stations/station[id='${station_id}']/area_id/text()" -)
# 放送日および放送局がある都道府県の番組情報一覧の取得
programs_res=$(curl -s "https://api.radiko.jp/program/v3/date/${program_date}/area/${area_id}.xml")
# ここからが抽出処理、エラーが出ても無視します
# 指定日時に一番近い番組情報を参照
# 放送局名
station_name=$(echo "${stations_res}" \
| xmllint --xpath "/region/stations/station[id='${station_id}']/name/text()" - 2> /dev/null) \
|| true
echo "放送局名: ${station_name}"
# 放送局URL
station_url=$(echo "${stations_res}" \
| xmllint --xpath "/region/stations/station[id='${station_id}']/href/text()" - 2> /dev/null) \
|| true
echo "放送局URL: ${station_url}"
# 番組開始日時 (radiko番組表上での日時)
program_from_datetime=$(echo "${programs_res}" \
| xmllint --xpath "string((/radiko/stations/station[@id='${station_id}']/progs/prog[@ft<='${program_datetime}'])[last()]/@ft)" - 2> /dev/null) \
|| true
echo "番組開始日時: ${program_from_datetime}"
# 番組終了日時 (radiko番組表上での日時)
program_to_datetime=$(echo "${programs_res}" \
| xmllint --xpath "string((/radiko/stations/station[@id='${station_id}']/progs/prog[@ft<='${program_datetime}'])[last()]/@to)" - 2> /dev/null) \
|| true
echo "番組終了日時: ${program_to_datetime}"
# 番組放送秒数 (radiko番組表上での秒数)
program_seconds=$(echo "${programs_res}" \
| xmllint --xpath "string((/radiko/stations/station[@id='${station_id}']/progs/prog[@ft<='${program_datetime}'])[last()]/@dur)" - 2> /dev/null) \
|| true
echo "番組放送秒数: ${program_seconds}"
# 番組名
program_name=$(echo "${programs_res}" \
| xmllint --xpath "(/radiko/stations/station[@id='${station_id}']/progs/prog[@ft<='${program_datetime}'])[last()]/title/text()" - 2> /dev/null) \
|| true
echo "番組名: ${program_name}"
# URL
program_url=$(echo "${programs_res}" \
| xmllint --xpath "(/radiko/stations/station[@id='${station_id}']/progs/prog[@ft<='${program_datetime}'])[last()]/url/text()" - 2> /dev/null) \
|| true
echo "URL: ${program_url}"
# 出演者
program_performer=$(echo "${programs_res}" \
| xmllint --xpath "(/radiko/stations/station[@id='${station_id}']/progs/prog[@ft<='${program_datetime}'])[last()]/pfm/text()" - 2> /dev/null) \
|| true
echo "出演者: ${program_performer}"
# 概要
program_description=$(echo "${programs_res}" \
| xmllint --xpath "(/radiko/stations/station[@id='${station_id}']/progs/prog[@ft<='${program_datetime}'])[last()]/desc/text()" - 2> /dev/null) \
|| true
echo "概要: ${program_description}"
# 情報 (HTMLタグあり)
program_information=$(echo "${programs_res}" \
| xmllint --xpath "(/radiko/stations/station[@id='${station_id}']/progs/prog[@ft<='${program_datetime}'])[last()]/info/text()" - 2> /dev/null) \
|| true
echo "情報: ${program_information}"
# 画像URL
program_image_url=$(echo "${programs_res}" \
| xmllint --xpath "(/radiko/stations/station[@id='${station_id}']/progs/prog[@ft<='${program_datetime}'])[last()]/img/text()" - 2> /dev/null) \
|| true
echo "画像URL: ${program_image_url}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment