＜音泉＞の新着をprograms.xml からXSLTで抽出してダウンロードする

音泉といえば TBS ラジオの番組かと思っていたら、インターネットラジオ配信サイトのことらしい。
「[＜音泉＞のコンテンツを自動録音(保存)する。](http://qiita.com/zakky/items/bd81b20ed0d1b0aca42c)」によると、その音泉の公開コンテンツの一覧が、`http://www.onsen.ag/app/programs.xml` で公開されているという。

この XML データを眺めていると program の category に new という直があって、この直が 1 のとき、新着を表しているらしい。

XML からデータを抽出するなら XPATH で条件を指定して、いっそのこと XSLT 処理すればよいのでは……、ということで、XSLT の手習いとしてテンプレートを書いてみた。

* データは `xsl:value-of` で出力できる。

* 抽出条件は以下の通り。
    `xsl:if` を使えば、条件にマッチしたときだけ処理を行うことができる。

  * `is_app` が `0` のときは、`*_url` にはデータが入っていない。
  * `category/new` が `1` の時だけデータを出力したい。


* `up_date` の時刻部分は不要で、日付部分だけ取り出したい。
    `select` のところは式がかける。`substring` 関数を使えばよい。

* そのままでは値が空白区切りで出力される。
    あとでシェルスクリプトで処理するため、区切りが空白では、値に空白が入ったときに扱いにくい。
    改行を区切りとするには、`xsl:text` で改行を生成すればよい。

`program` の `title`, `up_date` の日付部分、データの URL を順に出力し、レコードの区切りを `//` としている。


```xml:programs.xslt 
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="text" encoding="utf-8"/>

  <xsl:template match="/programs">
    <xsl:apply-templates select="program"/>
  </xsl:template> 

  <xsl:template match="program">
    <xsl:variable name="is_app" select="is_app"/>
    <xsl:variable name="is_new" select="category/new"/>
    <xsl:variable name="movie_url" select="movie_url"/>
    <xsl:variable name="iphone_url" select="iphone_url"/>
    <xsl:variable name="android_url" select="android_url"/>
    <xsl:if test="is_app='1' and is_new='1'">
      <xsl:value-of select="title"/>
      <xsl:text>
</xsl:text>
      <xsl:value-of select="substring(up_date, 0, 11)"/> 
      <xsl:text>
</xsl:text>
      <xsl:value-of select="movie_url"/> 
      <xsl:if test="iphone_url != movie_url">
        <xsl:text>
</xsl:text>
        <xsl:value-of select="iphone_url"/> 
      </xsl:if>
      <xsl:if test="android_url != iphone_url">
        <xsl:text>
</xsl:text>
        <xsl:value-of select="android_url"/> 
      </xsl:if>
      <xsl:text>
//
</xsl:text>
    </xsl:if>
  </xsl:template> 

</xsl:stylesheet>
```

このテンプレートを使って programs.xml を xsltproc で処理する。 
実行結果は以下のようになる。

```
$ xsltproc programs.xslt programs.xml
千本木彩花・和多田美咲・赤尾ひかるのようこそ！グリーンハーベスト
2017-01-14
http://onsen.b-ch.com/radio/youkoso170114Xi4p.mp4
//
幼女戦記 ラジオの悪魔
2017-01-14
http://onsen.b-ch.com/radio/youjo170114Xi4p.mp3
//
```

ここまで来れば、あとはシェルスクリプトでダウンロード処理が書ける。

```get-programs.sh 
#!/bin/sh

ONSEN_DIR=onsen
case "$0" in
    ./*) SCRIPTNAME="$(pwd)/${0#./}";;
    /*)  SCRIPTNAME="$0";;
    *)   SCRIPTNAME="$(pwd)/$0";;
esac
SCRIPTDIR="${SCRIPTNAME%/*}"

stylesheet=$SCRIPTDIR/programs.xslt

if which aria2c >/dev/null; then
fetch()
{
    aria2c -x4 "$@"
}
else
fetch()
{
    wget "$@"
}
fi

[ -d "$ONSEN_DIR" ] || mkdir -p "$ONSEN_DIR"
cd "$ONSEN_DIR"
trap "mv programs.xml programs.xml.old" EXIT HUP INT
fetch -q http://www.onsen.ag/app/programs.xml
[ $? -eq 0 ] || { echo "programs.xml: get failed"; exit 1; }
xsltproc "$stylesheet" programs.xml |
while read program; do
  read date
  mkdir -p "$program/$date"
  while read url; do
    [ "$url" = "//" ] && break
    filename="$program/$date/${url##*/}"
    [ -f "$filename" ] || fetch -q -o "$filename" "$url"
  done
done
```

get-programs.sh と programs.xslt を同じディレクトリに配置して起動すれば、ONSEN_DIR で指定したディレクトリに、タイトル/公開日付 でサブディレクトリを作成し、そこにファイルをダウンロードする。
すでにファイルがあるときは、二重にダウンロードはしない。

aria2c は、複数のセッションを使って高速にダウンロードができる軽量ダウンローダーである。
aria2c が存在しないときは wget を使うようにシェル関数 fetch を定義している。