この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
テントの中から失礼します、CX事業本部のてんとタカハシです!
Spotify が完全に仕事のお供になっています。というのと、Rust 書きたいな〜という気分から、Rust で Spotify Web API を叩いて遊んでみましたので、記事にしようと思います。
今回は、生で API を叩くのではなく、Rust で Spotify Web API をラップした rspotify という ライブラリを使用します。こちらのライブラリですが、ドキュメントに各エンドポイントのサンプルコードが置いてあり、とても親切です。
Developers.IO では、過去に Spotify Web APIの使い方 という記事が公開されていますので、併せて参考にして頂けると良いのかなと思います。Spotify for Developers にてアプリの新規作成を行う手順については、UI が新しくなっていたりするので、改めてこの記事でご紹介しようと思います。
また、下記のリポジトリにソースコード一式を置いていますので、併せて参考にして頂ければと思います。
前提
- Spotify のアカウントが作成済みであること
- Spotify のプレミアムプランが登録済みであること
- Spotify のアプリが PC (Mac) にインストールされていること
- Rust がインストール済みであること
環境
$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.15.6
BuildVersion: 19G2021
$ cargo version
cargo 1.46.0 (149022b1d 2020-07-17)
$ rustc --version
rustc 1.46.0 (04488afe3 2020-08-24)
Spotify Web API で何ができるの
下記ができます。詳細は API の ドキュメント をご参照ください。
- 楽曲の検索
- プレイヤーの操作(楽曲の再生や停止、スキップなど)
- プレイリストの操作(作成や楽曲の追加など)
- ユーザーの試聴傾向に基づいた情報の取得
- などなど
尚、エンドポイントの中には、Beta 版のものが存在しています。例えば、プレイヤーの操作に関するものは全て Beta 版です。今回ご紹介する実装でも、Beta 版のエンドポイントを使用していたりするので、ある日突然動作しなくなる可能性があります。ご注意ください。
Spotify Web API を使用するための準備
Spotify Web API を叩くために必要な Client ID を取得したり、Redirect URI の設定を行います。
Spotify for Developers にログインする
Spotify for Developers にログインします。
アプリを新規作成する
ログインするとダッシュボードが表示されます。「CREATE AN APP」ボタンをクリックしてください。
※ 私の環境では既に2つアプリを作成済みのため、下記のような画面となっております
ダイアログが表示されますので、App name、App description を入力した後、チェックボックスにチェックを入れて、「CREATE」ボタンをクリックしてください。
すると、アプリが作成されて、下記の画面に遷移します。画面左側に Client ID が表示されます。また、その下の「SHOW CLIENT SECRET」をクリックすることで、Client Secret が表示されます。これら2つの情報は、API を叩く際に必要となります。
Redirect URI を設定する
API を叩くために1つだけ設定が必要になります。画面右上にある「EDIT SETTINGS」ボタンをクリックしてください。すると、設定ダイアログが表示されますので、Redirect URIs の入力欄に http://127.0.0.1:8080/
と入力した後、「ADD」ボタンをクリックしてください。その後、ダイアログの下部までスクロールして、「SAVE」ボタンをクリックしてください。
これで、Spotify for Developers 画面上での設定は完了となります。
実装前の準備
Rust のプロジェクトを作成する
ここでは、rust-spotify
という名前にします。
$ cargo new rust-spotify
使用するクレートを設定する
Cargo.toml
内の dependencies を下記に変更してください。
Cargo.toml
[package]
...
[dependencies]
rspotify = { version = "0.10"}
tokio = { version = "0.2", features = ["full"] }
環境変数を設定する
先ほど、Spotify for Developers にて取得した Client ID、Client Secret と Redirect URI を環境変数に設定します。ここで設定した環境変数を rspotify が読み込んで、API を叩く際に使用されます。環境変数ではなく、.env
ファイルを読み込ませる方法もありますが、今回は説明を省きます。
export CLIENT_ID="<SPOTIFY_CLIENT_ID>"
export CLIENT_SECRET="<SPOTIFY_CLIENT_SECRET>"
export REDIRECT_URI="http://127.0.0.1:8080/"
実装
今回は Spotify Web API を使用して、下記をやってみようと思います。
- アーティストの情報を検索する
- 指定したアーティストの楽曲人気 TOP10 を表示する
- 指定した楽曲を再生する
それぞれを1ファイルとして src/bin
の中に実装していきます。
アーティストの情報を検索する
実装は下記になります。引数で検索するアーティスト名を受け取るようにしています。
src/bin/search_artist.rs
extern crate rspotify;
use std::env;
use rspotify::client::Spotify;
use rspotify::oauth2::{SpotifyClientCredentials, SpotifyOAuth};
use rspotify::senum::{Country, SearchType};
use rspotify::util::get_token;
#[tokio::main]
async fn main() {
let args: Vec<String> = env::args().collect();
if args.len() == 1 {
println!("Usage: cargo run --bin search_artist <ARTIST_NAME>");
return;
}
let artist_name = &args[1];
let mut oauth = SpotifyOAuth::default().scope("user-read-private").build();
match get_token(&mut oauth).await {
Some(token_info) => {
let client_credential = SpotifyClientCredentials::default()
.token_info(token_info)
.build();
let spotify = Spotify::default()
.client_credentials_manager(client_credential)
.build();
// Reference: https://developer.spotify.com/documentation/web-api/reference/search/search/
let result = spotify
.search(
// q: 検索キーワード
artist_name,
// type: 検索タイプ(album, artist, playlist, track, etc.)
SearchType::Artist,
// limit: 取得するデータの最大数
1,
// offset: 取得するデータの開始位置
0,
// market: 指定した国名コードで再生可能なコンテンツのみを返す
Some(Country::Japan),
// include_external: audio を指定すると関連するオーディオコンテンツがレスポンスに含まれる
None,
)
.await
.unwrap();
match result {
rspotify::model::search::SearchResult::Artists(artists) => {
let artist = &artists.items[0];
println!("artist: {}\nid: {}\npopularity: {}", artist.name, artist.id, artist.popularity);
},
err => println!("search error!{:?}", err),
}
}
None => println!("auth failed"),
};
}
下記で実行します。ここでは、DA PUMP
を検索しようと思います。
$ cargo run --bin search_artist "DA PUMP"
すると、ブラウザが開いて下記のページが表示されるので、「同意する」ボタンをクリックします。
すると、ページが表示できなくなりますが、これでOKです。この状態でページの URL をコピーします。
ターミナルが下記のようになっているので、コピーした URL を貼り付けて Enter します。
Opened https://accounts.spotify.com/authorize?state=<STATE>&scope=user-read-private&response_type=code&client_id=<CLIENT_ID>&redirect_uri=http:%2F%2F127.0.0.1:8080%2F& in your browser
Enter the URL you were redirected to:
すると、検索した DA PUMP の ID と 人気度が表示されます(APIから様々な情報が取得されるので、ここでは絞って表示しています)。
artist: DA PUMP
id: 3NRXKeatDxKe4apH6XawKX
popularity: 53
この ID を使って、次は DA PUMP の楽曲人気 TOP10 を表示しましょう。
指定したアーティストの楽曲人気 TOP10 を表示する
実装は下記になります。先ほどと同様に、引数でアーティストの ID を受け取るようにしています。
src/bin/artist_top_tracks.rs
extern crate rspotify;
use std::env;
use rspotify::client::Spotify;
use rspotify::oauth2::SpotifyClientCredentials;
use rspotify::senum::Country;
#[tokio::main]
async fn main() {
let args: Vec<String> = env::args().collect();
if args.len() == 1 {
println!("Usage: cargo run --bin artist_top_tracks <ARTIST_ID>");
return;
}
let artist_id = &args[1];
let client_credential = SpotifyClientCredentials::default().build();
let spotify = Spotify::default()
.client_credentials_manager(client_credential)
.build();
// Reference: https://developer.spotify.com/documentation/web-api/reference/artists/get-artists-top-tracks/
let result = spotify
.artist_top_tracks(
// id: artist の Spotify ID
artist_id,
// country: 国名コード
Country::Japan
)
.await
.unwrap();
println!("# {} Top Tracks", result.tracks[0].artists[0].name);
for track in result.tracks.iter() {
println!("{}: {} ({})", track.name, track.popularity, track.id.as_deref().unwrap_or("none"));
}
}
下記で実行します。
$ cargo run --bin artist_top_tracks "3NRXKeatDxKe4apH6XawKX"
すると、下記が表示されます。少し見づらいですが、曲名と人気度、楽曲の ID を表示しています。やっぱり、if... と U.S.A. が人気なんですね。個人的には、Dragon Screamer 推しです。
# DA PUMP Top Tracks
if...: 53 (78LQTUp1f8APWgFNZNOD5y)
U.S.A.: 53 (4qZyuyqLoZ3CaH79rGvJFR)
P.A.R.T.Y. 〜ユニバース・フェスティバル〜: 51 (7Avl3ZmZf5B80YSzfmdYuT)
Dragon Screamer: 43 (623pmkD6sclgLBQrrPqyz4)
Heart on Fire: 42 (5PLlnPQROKe1P9Vjrlxjvq)
Fantasista〜ファンタジスタ〜: 42 (2MMVhnZEo1ldxODbqqm96K)
桜: 42 (5B36byNsxLer31rJz1jlKT)
Feelin' Good 〜It's PARADISE〜: 40 (0g1NHilvp8AHX4HN8Ua26i)
if...: 38 (156j6p6VwT2OYzEmeDKjUG)
ごきげんだぜっ!〜Nothing But Something〜: 37 (0co9GJXSCrqVfIYjaihBjj)
次は楽曲の ID を使用して、Spotify アプリ上で楽曲を再生してみましょう。
指定した楽曲を再生する
実装は下記になります。これまでと同様に、引数で楽曲の ID を受け取るようにしています。
src/bin/play_track.rs
extern crate rspotify;
use std::env;
use rspotify::client::Spotify;
use rspotify::model::offset::for_position;
use rspotify::oauth2::{SpotifyClientCredentials, SpotifyOAuth};
use rspotify::util::get_token;
#[tokio::main]
async fn main() {
let args: Vec<String> = env::args().collect();
if args.len() == 1 {
println!("Usage: cargo run --bin play_track <TRACK_ID>");
return;
}
let track_id = &args[1];
let track_uri = "spotify:track:".to_string() + track_id;
let mut oauth = SpotifyOAuth::default()
.scope("user-modify-playback-state,user-read-playback-state")
.build();
match get_token(&mut oauth).await {
Some(token_info) => {
let client_credential = SpotifyClientCredentials::default()
.token_info(token_info)
.build();
let spotify = Spotify::default()
.client_credentials_manager(client_credential)
.build();
// Reference: https://developer.spotify.com/documentation/web-api/reference/player/get-a-users-available-devices/
let result = spotify.device().await.unwrap();
let mut device_id = "";
for device in result.devices.iter() {
if let rspotify::senum::DeviceType::Computer = device._type {
if device.is_active == true {
device_id = &device.id;
}
}
}
// Reference: https://developer.spotify.com/documentation/web-api/reference/player/start-a-users-playback/
match spotify
.start_playback(
// device_id: 対象とするデバイスのID
Some(device_id.to_string()),
// context_uri: 再生する album, artist, playlist の指定
None,
// uris: 再生する track のリストを指定
Some(vec![track_uri]),
// offset: album, playlist, track の再生を開始する位置
for_position(0),
// position_ms: track の再生を開始する位置
None
)
.await
{
Ok(_) => println!("start playback successful"),
Err(_) => eprintln!("start playback failed"),
}
}
None => println!("auth failed"),
}
}
楽曲を再生するには、Spotify のアプリをアクティブな状態にしておく必要があります。Spotify のアプリを開いて、テキトーな曲を再生 & 停止してください。
その後で、プログラムを実行します。
$ cargo run --bin play_track "623pmkD6sclgLBQrrPqyz4"
先ほどと同様に、ブラウザが開いてページが表示されるので、「同意する」ボタンをクリックします。
ページが遷移したら、URL をコピーして、ターミナルに貼り付けて Enter します。
Opened https://accounts.spotify.com/authorize?client_id=<CLIENT_ID>&response_type=code&redirect_uri=http:%2F%2F127.0.0.1:8080%2F&scope=user-modify-playback-state,user-read-playback-state&state=<STATE>& in your browser
Enter the URL you were redirected to:
成功すると、start playback successful
の表示と共に、僕が推している Dragon Screamer が流れます。
start playback failed
と表示された場合は、再度 Spotify のアプリがアクティブになっているか確認してから、プログラムを実行してみてください。
以上でお遊びは終わりになります。
おわりに
楽しかった。
Python で spotipy を使って Spotify Web API を叩いたことはあるのですが、今回は不慣れな Rust ということで苦戦しました。少しおかしな実装になっているかもしれませんが、ご了承ください(勉強します)。
今回はお試しで API を叩いてみましたが、Raspberry Pi とボタンとかの部品を組み合わせて、それっぽいものを作るのが次の目標です。とはいえ、現状仕事では全然使わない知識なので、完成がいつになるかは不明です。何かできたら記事にしようと思います。
今回は以上になります。最後まで読んで頂きありがとうございました!