🎧

Spotify APIを使い曲の再生機能を実装する

2024/08/26に公開

開発環境

  • macOS
  • VSCode
  • Rails 7.1.3.3
  • ruby-3.2.3
  • PostgreSQL 16.2

行いたいこと

  • Spotify APIを使い曲の再生機能を実装する。





Spotify APIを利用するにあたって...

・Spotifyのアカウントを作成する。
・Dashboardからアプリの登録CLIENT IDCLIENT SECRET IDの取得をする。
・取得したIDを環境変数として.envファイルに記載する。

こちらの手順で行いました⇩
https://zenn.dev/tteaoocl/articles/6cce2e7615c11c

Gem をインストールする

・以下を追記しbundle install

Gemfile
gem 'rspotify'

環境変数を読み取れるように記載する

.envファイルに記載したCLIENT IDCLIENT SECRET IDを読み取れる様に正しく記載。

config/initializers/rspotify.rb
require 'rspotify'
RSpotify.authenticate(ENV['SPOTIFY_CLIENT_ID'], ENV['SPOTIFY_SECRET_ID'])
gem 'dotenv-rails'がなければインストール

.envファイルを簡単に読み取るため
・以下を追記しbundle install

Gemfile
gem 'dotenv-rails'

テーブル・カラム・モデルを追加、記載する

・曲の表示方法は開催されたライブイベント一覧参加したアーティスト一覧披露した曲一覧のように
 遷移させたい。
live_event,artist,music,live_events_artistテーブルカラムモデルを追加する。

models/live_event.rb
class LiveEvent < ApplicationRecord
  has_many :live_events_artists
  has_many :artists, through: :live_events_artists
  has_many :musics
end
models/artist.rb
class Artist < ApplicationRecord
  has_many :live_events_artists
  has_many :live_events, through: :live_events_artists
end
models/music.rb
class Music < ApplicationRecord
  belongs_to :artist
  belongs_to :live_event
end
models/live_events_artist.rb
class LiveEventsArtist < ApplicationRecord
  belongs_to :live_event
  belongs_to :artist
end

コントローラーを記載する

・ライブイベントの一覧表示 / 指定されたライブイベントの表示

live_events_controller.rb
class LiveEventsController < ApplicationController
  def index
    @live_events = LiveEvent.all
  end

  def show
    @live_event = LiveEvent.find(params[:id])
  end
end

・ライブイベントにアーティストの一覧表示 / 曲の一覧表示 / 指定したアーティストと曲の表示

musics_controller.rb
class MusicsController < ApplicationController
  # アーティストを取得、ライブイベントを取得
  def index
    @artist = Artist.find(params[:artist_id])
    @live_event = LiveEvent.find(params[:live_event_id]) if params[:live_event_id].present?
    
    # 特定のライブイベントに関連する曲のみを取得、ライブイベントが指定されていない場合は、アーティストの全ての曲を取得
    if @live_event
      @musics = @artist.musics.where(live_event_id: @live_event.id)
    else
      @musics = @artist.musics
    end
    
    # 曲の情報を整形
    @musics = @musics.map do |music|
      {
        name: music.name,
        artist: music.artist_name,
        id: music.spotify_track_id,
        live_event_id: music.live_event_id
      }
    end
  end
  
  # アーティストを取得、Spotify track IDで曲を検索
  def show
    @artist = Artist.find(params[:artist_id])
    @music = Music.find_by(spotify_track_id: params[:id])
  end
end

viewファイルを記載する

・ライブイベントを取得しリンクで一覧表示(装飾は省略)

views/live_events/index.html.erb
<h1>開催ライブ一覧</h1>
<% @live_events.each do |live_event| %>
  <div>
    <%= link_to live_event_path(live_event), class: 'btn btn-slash' do %>
      <span><%= live_event.name %></span>
    <% end %>
  </div>
<% end %>

・アーティストを取得しリンクで一覧表示(装飾は省略)

views/live_events/show.html.erb
<h4><%= @live_event.name %></h4>
<% if @live_event.artists.any? %>
  <% @live_event.artists.each do |artist| %>
    <%= link_to artist_musics_path(artist, live_event_id: @live_event.id), class: 'btn btn-slash' do %>
      <span><%= artist.name %></span>
    <% end %>
  <% end %>
<% else %>
  <p>アーティストは登録されていません。</p>
<% end %>

・曲を取得しリンクで一覧表示(装飾は省略)

views/musics/index.html.erb
<h4><%= @artist.name %></h4>
<% if @musics && @musics.any? %>
  <% @musics.each_with_index do |music, index| %>
    <%= link_to artist_music_path(@artist, music[:id], live_event_id: params[:live_event_id])class:'text-decoration-none text-dark d-flex align-items-center w-100' do %>
      <h5 class="mb-0 me-3 flex-grow-1">
        <%= "#{index + 1}. #{music[:name]}" %>
      </h5>
    <% end %>
  <% end %>
<% else %>
  <div class="alert alert-warning" role="alert" style="background-color: #f8f9fa;background-colortransparent;">
    音楽が見つかりませんでした。
  </div>
<% end %>

・曲の再生ページ(Spotify 埋め込みプレイヤー)

views/musics/show.html.erb
<iframe src="https://open.spotify.com/embed/track/<%= @music.spotify_track_id %>"
        width="300"
        height="380"
        frameborder="0"
        allowtransparency="true"
        allow="encrypted-media"
</iframe>

routes.rbの記載

・適宜必要なルートを記載する。

config/routes.rb
# artistsリソースの中に musicsリソースをネストする
resources :artists do
  resources :musics, only: [:index, :show]
end
# アーティストごとに関連する音楽に対してアクセスするルート(開催ライブ一覧⇨アーティスト)
config/routes.rb
# 限定的なルーティング
resources :musics, only: [:index, :show]
# (アーティスト⇨曲一覧⇨曲の再生)
config/routes.rb
# live_eventsリソースの中に musicsリソースをネストする
 resources :live_events, only: [:index, :show, :new, :create] do
    resources :musics, only: [:index, :show]
  end
# ライブイベントごとに関連する音楽の一覧に対してアクセスするルート

挙動の確認

今回実装した挙動です

Image from Gyazo


以上でSpotify APIを使用した曲の再生機能の実装は完了です。






本番環境の場合は環境変数を記載(Herokuの場合)

.envに記載したCLIENT IDCLIENT SECRET IDをHeroku側にも設定する
・Herokuのダッシュボードから、設定設定変数 価値に値を入力し追加
Image from Gyazo
価値に値を入力し追加
Image from Gyazo
環境変数を記載(.envが参照できるように正しく記載)
Image from Gyazo
・今回は以下の2つを登録しました。
[鍵]SPOTIFY_CLIENT_ID  [価値]取得したCLIENT ID
[鍵]SPOTIFY_SECRET_ID  [価値]取得したCLIENT SECRET ID

データベースにライブイベント、アーティスト、曲を追加する流れ(Herokuのデータベース PostgreSQL)

・ライブイベントの作成 ⇨ アーティストの作成 ⇨ ライブイベントにアーティストを追加

INSERT INTO live_events (name, date, created_at, updated_at)
VALUES ('YOASOBI LIVE IN THE USA (2024/4/18.21)', '2023-08-10', NOW(), NOW());
                   ↑                       ↑
           [登録したいライブイベント名]       [データ追加年月日]

・アーティストの追加

INSERT INTO artists (name, created_at, updated_at) 
VALUES ('YOASOBI', NOW(), NOW());
            ↑
    [登録したいアーティスト名]

・ライブイベントにアーティストを追加

INSERT INTO live_events_artists (live_event_id, artist_id)
SELECT 100, id FROM artists WHERE name IN ('YOASOBI');
        ↑
[追加したいライブイベントID]

YOASOBI LIVE IN THE USA (2024/4/18.21)というライブイベントに YOASOBIというアーティストが追加される。

・アーティストのidを取得 ⇨ Spotify_track_idの取得 ⇨ musicsテーブルに保存

rails consoleからアーティストのidを取得する。

artist_name = 'YOASOBI'

artists = RSpotify::Artist.search(artist_name)
if artists.any?
  puts "アーティストが見つかりました:"
  artists.each do |artist|
    puts "アーティスト名: #{artist.name}, Spotify ID: #{artist.id}"
  end
else
  puts "アーティストは見つかりませんでした。"
end

・取得したアーティストのidで、アーティストのSpotify_track_idを全曲取得する。

# RSpotifyでアーティストを検索
artist = RSpotify::Artist.find('取得したアーティストid')

if artist
  puts "アーティスト名: #{artist.name}"
  puts "曲一覧:"

  albums = artist.albums(limit: 50)

  albums.each do |album|
    puts "アルバム名: #{album.name}"
    
    tracks = album.tracks(limit: 50)

    tracks.each do |track|
      puts "  曲名: #{track.name}, Spotify ID: #{track.id}"
    end
    puts "-" * 100
  end
else
  puts "曲は見つかりませんでした。"
end

・musicsテーブルに保存する

INSERT INTO musics (name, spotify_track_id, artist_id, artist_name, live_event_id, created_at, updated_at)
VALUES 
    ('[曲名]', '[spotify_track_id]', [artist_id], '[artist_name]', [live_event_id], NOW(), NOW());

以上です。






GitHubで編集を提案

Discussion