1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

BashでSpotify CLIツールを作りたいで:OAuth認証・エラー処理・デバイス管理の工夫

Last updated at Posted at 2024-12-01

初投稿です( ^ω^)・・・

はじめに

Spotifyをターミナルから操作できたら便利だと思い、BashでCLIツールを作成してみました。この記事では、特にOAuth認証の実装、エラー処理、デバイス管理における工夫点を詳しく解説します。

OAuth認証の実装

SpotifyのWeb APIを利用するためには、OAuth 2.0による認証が必要です。認証フローを理解することが重要なので、まず基本的な流れを説明します。

OAuth 2.0の基本フロー

  1. アプリケーション登録

    • Spotify Developer Dashboardでアプリを登録
    • クライアントIDとシークレットを取得
    • リダイレクトURIを設定(ローカルの場合 http://localhost:8888/callback
  2. 認証トークンの取得

    # 認証用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"
    
  3. アクセストークンの管理

# トークン管理の実装
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}"/*
}

セキュリティ上の注意点

  1. 環境変数の取り扱い

    • クライアントIDとシークレットは必ず環境変数で管理
    • .envファイルはGitの管理対象外に
    • 環境変数ファイルのパーミッションを制限(600)
  2. トークンの安全な保存

# セキュアなトークン保存のための関数
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)) }

今後の改善計画

  1. よく聴く曲の統計情報

    • Spotify APIの/me/top/tracksエンドポイントを使用
    • 期間別(短期・中期・長期)の再生回数を集計
    • ジャンルやアーティスト別の分析グラフ生成
  2. プレイリストの検索・管理

    • あいまい検索の実装(fzfとの連携)
    • プレイリストのエクスポート/インポート機能
    • プレイリストの自動バックアップ
  3. 楽曲の詳細情報表示

    • BPM、キー、時間などの音楽的特徴の表示
    • 類似曲のレコメンド機能
    • 歌詞の表示(可能な場合)

まとめ

BashでSpotify CLIツールを作成する過程で、以下の点が特に勉強になりました:

  1. OAuth認証の実装方法と安全なトークン管理
  2. APIエラーへの適切な対処方法
  3. CLIツールのUX設計における重要なポイント

参考文献

  1. Spotify Web API Reference
  2. OAuth 2.0 RFC
  3. The Art of Unix Programming
  4. Command Line Interface Guidelines
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?