初投稿です( ^ω^)・・・
はじめに
Spotifyをターミナルから操作できたら便利だと思い、BashでCLIツールを作成してみました。この記事では、特にOAuth認証の実装、エラー処理、デバイス管理における工夫点を詳しく解説します。
OAuth認証の実装
SpotifyのWeb APIを利用するためには、OAuth 2.0による認証が必要です。認証フローを理解することが重要なので、まず基本的な流れを説明します。
OAuth 2.0の基本フロー
-
アプリケーション登録
- Spotify Developer Dashboardでアプリを登録
- クライアントIDとシークレットを取得
- リダイレクトURIを設定(ローカルの場合
http://localhost:8888/callback
)
-
認証トークンの取得
# 認証用URLの生成 SPOTIFY_AUTH_URL="https://accounts.spotify.com/authorize" SCOPE="user-read-playback-state user-modify-playback-state playlist-read-private" auth_url="${SPOTIFY_AUTH_URL}?client_id=${CLIENT_ID}&response_type=code&redirect_uri=${REDIRECT_URI}&scope=${SCOPE}" echo "以下のURLにアクセスして認証を行ってください:" echo "$auth_url"
-
アクセストークンの管理
# トークン管理の実装
store_tokens() {
local access_token="$1"
local refresh_token="$2"
local expires_in="$3"
# トークンの暗号化(OpenSSL使用)
encrypt_token "$access_token" "${TOKEN_DIR}/access_token"
encrypt_token "$refresh_token" "${TOKEN_DIR}/refresh_token"
# 有効期限の保存(現在時刻 + expires_in)
echo $(($(date +%s) + expires_in)) > "${TOKEN_DIR}/expiry"
# ファイルのパーミッション設定
chmod 600 "${TOKEN_DIR}"/*
}
セキュリティ上の注意点
-
環境変数の取り扱い
- クライアントIDとシークレットは必ず環境変数で管理
-
.env
ファイルはGitの管理対象外に - 環境変数ファイルのパーミッションを制限(600)
-
トークンの安全な保存
# セキュアなトークン保存のための関数
encrypt_token() {
local token="$1"
local output_file="$2"
# 暗号化キーの生成(環境変数を利用)
local key=$(echo -n "${SPOTIFY_CLIENT_SECRET}${SPOTIFY_CLIENT_ID}" | sha256sum | cut -d' ' -f1)
# OpenSSLによる暗号化(AES-256-CBC)
echo -n "$token" | openssl enc -aes-256-cbc -salt -pbkdf2 \
-pass "pass:${key}" \
-out "$output_file"
# ファイルパーミッションの設定
chmod 600 "$output_file"
}
エラー処理の実装
APIとの通信では様々なエラーが発生する可能性があります。以下、主要なエラーパターンとその対処法を説明します。
1. APIリクエストのラッパー関数
spotify_api_call() {
local method="$1"
local endpoint="$2"
local data="$3"
local max_retries=3
local retry_count=0
local base_wait_time=2
while [ $retry_count -lt $max_retries ]; do
# アクセストークンの有効性確認
ensure_valid_token
# APIリクエストの実行
response=$(curl -s -X "$method" \
-H "Authorization: Bearer $(get_access_token)" \
${data:+-d "$data"} \
"https://api.spotify.com/v1/$endpoint")
local status_code=$(echo "$response" | jq -r '.error.status // 0')
case $status_code in
0) # 成功
echo "$response"
return 0
;;
401) # 認証エラー
refresh_access_token
;;
429) # レート制限
wait_rate_limit "$response"
;;
5*) # サーバーエラー
exponential_backoff $retry_count $base_wait_time
;;
*) # その他のエラー
log_error "$status_code" "$response"
return 1
;;
esac
retry_count=$((retry_count + 1))
done
echo "最大リトライ回数(${max_retries}回)を超えました" >&2
return 1
}
2. レート制限への対応
Spotifyでは1時間あたり約1000リクエストの制限があります。これを超えると429エラーが返されます。
wait_rate_limit() {
local response="$1"
local retry_after=$(echo "$response" | jq -r '.error.retry_after // 5')
echo "レート制限に達しました。${retry_after}秒待機します..." >&2
sleep "$retry_after"
}
3. エラーログの実装
log_error() {
local status_code="$1"
local response="$2"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
local message=$(echo "$response" | jq -r '.error.message // "Unknown error"')
printf "[%s] Error %d: %s\n" "$timestamp" "$status_code" "$message" >> "${LOG_DIR}/error.log"
}
デバイス管理とUX設計
CLIツールの使いやすさを考慮し、以下のような工夫を施しました。
1. インタラクティブなデバイス選択
select_device() {
local devices=$(spotify_api_call "GET" "me/player/devices")
# デバイス一覧の表示
echo "利用可能なデバイス:"
echo "$devices" | jq -r '.devices[] | "\(.id): \(.name) (\(.type))\(.is_active?" [現在アクティブ]":"")"' | \
awk '{printf "%3d: %s\n", NR, $0}'
# 前回使用したデバイスの提案
local last_device=$(get_last_device)
if [ -n "$last_device" ]; then
local device_name=$(echo "$devices" | jq -r ".devices[] | select(.id == \"$last_device\") | .name")
if [ -n "$device_name" ]; then
read -p "前回使用したデバイス($device_name)を使用しますか? [Y/n] " use_last
[[ "$use_last" =~ ^[Yy]?$ ]] && echo "$last_device" && return 0
fi
fi
# デバイスの選択
while true; do
read -p "デバイス番号を選択してください: " device_number
if [[ "$device_number" =~ ^[0-9]+$ ]]; then
local selected_id=$(echo "$devices" | jq -r ".devices[$(($device_number-1))].id")
if [ -n "$selected_id" ]; then
save_last_device "$selected_id"
echo "$selected_id"
return 0
fi
fi
echo "無効な選択です。もう一度試してください。" >&2
done
}
2. 直感的なコマンド体系
CLIのコマンド設計は、一貫性と使いやすさを重視しました:
# メインコマンド
spotify-cli COMMAND [OPTIONS]
# サブコマンド一覧
play [URI] # 再生(URIは省略可能)
pause # 一時停止
next # 次の曲
prev # 前の曲
vol [0-100] # 音量調整
device # デバイス選択
status # 現在の再生状況
# オプション
--device, -d ID # デバイスを指定
--verbose, -v # 詳細出力
--quiet, -q # 出力を最小限に
3. シェルエイリアスの提案
# ~/.bashrcや~/.zshrcに追加するエイリアス
alias sp="spotify-cli"
alias sp-play="spotify-cli play"
alias sp-pause="spotify-cli pause"
alias sp-next="spotify-cli next"
alias sp-prev="spotify-cli prev"
alias sp-vol="spotify-cli vol"
# 音量調整のショートカット
sp-vol-up() { spotify-cli vol $(($(spotify-cli vol-get) + 10)) }
sp-vol-down() { spotify-cli vol $(($(spotify-cli vol-get) - 10)) }
今後の改善計画
-
よく聴く曲の統計情報
- Spotify APIの
/me/top/tracks
エンドポイントを使用 - 期間別(短期・中期・長期)の再生回数を集計
- ジャンルやアーティスト別の分析グラフ生成
- Spotify APIの
-
プレイリストの検索・管理
- あいまい検索の実装(fzfとの連携)
- プレイリストのエクスポート/インポート機能
- プレイリストの自動バックアップ
-
楽曲の詳細情報表示
- BPM、キー、時間などの音楽的特徴の表示
- 類似曲のレコメンド機能
- 歌詞の表示(可能な場合)
まとめ
BashでSpotify CLIツールを作成する過程で、以下の点が特に勉強になりました:
- OAuth認証の実装方法と安全なトークン管理
- APIエラーへの適切な対処方法
- CLIツールのUX設計における重要なポイント