試験運用中なLinux備忘録・旧記事

はてなダイアリーで公開していた2007年5月-2015年3月の記事を保存しています。

複数のオーディオファイルをまとめたファイルをマウントして再生する(無圧縮tarボールを推奨)

Wine上のfoobar2000では、複数のオーディオファイルを含むZIPファイルを開くことでプレイリストに一覧が表示され、頭出しもできるが、このような機能を持たないプレーヤでも同様のことを行えないか、ということで、「色々な種類の圧縮ファイルをマウントして中身にアクセスする」で使用したarchivemountを使用した例として試してみた。

  1. 一連の流れを行うシェルスクリプト
  2. ZIPファイル中のCP932日本語ファイル名について
  3. 負荷・実用性について

一連の流れを行うシェルスクリプト

  1. 圧縮ファイルをマウント
  2. プレーヤでマウントポイント以下を再生
  3. プレーヤ終了後にマウント解除

という流れを自動化するシェルスクリプトを作成した。archivemountがインストールされている前提で、スクリプト中ではチェックしていないので注意。
[任意]ファイル名: play-archive.sh

#! /bin/bash

## players
PLAYERS=(audacious totem)
## default
PLAYER_NO=0
MOUNTPOINT=~/mnt


usage()
{
  local x i=0
  local players_list_str=""  # 0:player1|1:player2|2:player3...
  for x in ${PLAYERS[*]}; do
    players_list_str=${players_list_str}$(printf "|%d:%s" ${i} ${x})
    i=$((${i} + 1))
  done
  printf "Usage: %s [-h] [-m MOUNTPOINT] [-p PLAYER] [-w] [-z] archivefile
  -h             print help
  -m MOUNTPOINT  mount on MOUNTPOINT (default %s)
  -p PLAYER      use PLAYER (%s)
  -w             writable mode
  -z             use Zenity file selection dialog\n" $(basename $0) ${MOUNTPOINT} ${players_list_str/|/} >&2
}
die()
{
  echo "ERROR: "$1 >&2
  exit 1
}

WRITABLE=0
USE_ZENITY=0
ARCHIVEFILE=""
while getopts 'hm:p:wz' OPT
do
  case ${OPT} in
   m)
    MOUNTPOINT=${OPTARG}
    ;;
   p)
    PLAYER_NO=$((${OPTARG//[^0-9]/}))
    if [ ${PLAYER_NO} -gt $((${#PLAYERS[@]} - 1)) ]; then
      printf "ERROR: Illegal player number(%d) [max %d]\n" ${PLAYER_NO} $((${#PLAYERS[@]} - 1)) >&2
      exit 1
    fi
    ;;
   w)
    WRITABLE=1
    ;;
   z)
    ARCHIVEFILE=$(zenity --file-selection)
    if [ $? -ne 0 ]; then exit 1; fi  # cancel
    USE_ZENITY=1
    ;;
   ?)
    usage
    exit 1
    ;;
  esac
done
shift $((${OPTIND} - 1))

FUSERMOUNT_OPTS=""
if [ ${WRITABLE} -eq 0 ]; then FUSERMOUNT_OPTS="${FUSERMOUNT_OPTS}	-o	ro"; fi
if [ ${USE_ZENITY} -eq 0 ]; then ARCHIVEFILE=$1; fi
IFS="	"
# check whether ${MOUNTPOINT} is in use (archivemount returns 0 even if in use)
grep	"archivemount $(echo	${MOUNTPOINT})"	/etc/mtab	>/dev/null && die	"${MOUNTPOINT} is in use"
# mount
archivemount	${FUSERMOUNT_OPTS}	${ARCHIVEFILE}	${MOUNTPOINT} || die	"mount failed"
# play
${PLAYERS[${PLAYER_NO}]}	${MOUNTPOINT} || die	"cannot launch ${PLAYERS[${PLAYER_NO}]}"
# unmount
fusermount	-u	${MOUNTPOINT} || die	"unmount failed"

以下はオプションなどについて。

  • 既定ではファイルを読み取り専用でマウントするが、-wオプションを付けたときには書き込みも許可する
  • -zオプションを付けると、入力ファイルをzenityGUIファイル選択ダイアログを使用して指定可能
  • -mオプションでマウントポイントを指定できる
  • -pオプションで、プレーヤをリストから番号によって選択できる
  • プレーヤは配列PLAYERSに追加できるが、Amarokの場合、起動した後(終了するまで待たずに)シェルに戻ってしまうので、使えない。また、プレーヤは引数をディレクトリ指定で受け付け、サブディレクトリも開いてプレイリスト登録するものである必要がある。

以下、スクリプト作成中の覚え書きなど。

  • 「'hm:p:wz'」の部分は、-h/-m(値付き)/-p(値付き)/-w/-zの5つのオプションのみを受け付け、それ以外は不正なオプションとして受け付けないような指定で、「:」が右に付いている「m:」「p:」というのは、-m-pオプションには値が必要ということを知らせる指定。また、この文字列はgetoptコマンドやC言語getopt()系関数でも同様の書式で、マニュアルページ中ではいずれも「optstring」で表される部分。
  • マウントしたいファイルのパス名にスペースがあるとうまくいかなかったが、シェルの区切り文字としてスペースを使用せずにタブのみを使用するよう、環境変数IFSを指定することで回避。
  • 「for x in ${PLAYERS[*]}」の部分で、配列PLAYERSの各要素を変数xに代入して処理している
  • 「${#PLAYERS[@]}」は、配列PLAYERSの長さ(上のソースでは「2」)
  • 「$((」と「))」で囲まれた部分は算術式として評価される(数値演算するときに使用)
  • 「${OPTARG//[^0-9]/}」のところではプレーヤ番号指定で受け取る番号を変数に入れるときに数字以外を捨てるようにしているのだが、負の値が入ったときには「-2」が「2」のように絶対値の形で入るため、完全ではないが、それほど問題にはならないと思われる
  • 「while getopts ...」という部分から「shift」の行までで、bash組み込みのコマンドライン引数解析機能を使用したまとまり(決まった形)となっている。

参考URL:
http://sourceforge.jp/magazine/07/07/20/019211 - getopts組み込みコマンドの使用例

ZIPファイル中のCP932日本語ファイル名について

普通にファイルを圧縮した場合は問題なく表示されるが、
Wine上のfoobar2000で日本語ファイル名のオーディオファイルを含むZipファイルを開いたときの不具合とその対処法」でWine上のfoobar2000に合わせて、中のファイル名エンコーディングをCP932にしたZIPファイルをマウントした場合は、日本語ファイル名が化ける。「当たり前」と言えば当たり前なのだが、場合によっては注意。

負荷・実用性について

tarボール(無圧縮)にすると最も軽いが、それ以外での運用は難しいかもしれない。形式によってはCPU負荷がかなりかかり、特にファイル読み込み時が重い。再生中に音切れすることもある。また、合計ファイルサイズの大きすぎるものも扱いにくい。
実用性に関しては、無圧縮tarボールで重いと感じるかどうかによりそう。
同じことを実現する別の方法としては、指定したファイルを一時ディレクトリに展開してしまってこれを再生するという方法も考えられる。メモリが十分にあればtmpfs上に展開されるようにするのもよいかもしれない(CPU負荷やディスクアクセスを減らせる)。