last.fmのAPIでどんなことができるか調べてみた

事業開発部の酒匂です。Spotifyを使い始めた時にlast.fmと連携できることを知ったのですが、どんなサービスだろうと気になっておりました。調べてみたら、無料で使えるWEB APIがありましたので使ってみることにします。

last.fmとは

ウェブサイトのAbout Last.fmを見ると、"Last.fm is a music service that learns what you love."
ここに記載されているようなSpotifyやYoutube、Google Play Music, SoundCloudなどの音楽サービスで自分が聴いた音楽をログしていって、以下を実現するものです。

  • Share Your Taste
  • Explore Your Listening History
  • Discover New Music
  • Meet Your Musical Soulmates

https://www.last.fm/

音楽の視聴データを蓄積して分析していくことで、「このアーティストを聴いている人は、あのアーティストも聴いている」とか、「この曲が好きならば、あの曲も好きなはずだ」といった傾向は見えてくるでしょうけど、「このバンドのヴォーカルが以前に所属してバンド」とか、「この曲のPVはあの曲のオマージュになっている」とか、データ分析だけでは見えてこない部分でのレコメンドといいますか、発見が音楽サービスなどによってできると面白いなと思ったりします。

話をAPIに戻します。

WEB APIを使うための準備

API Keyの発行

下記のページへアクセスして各項目を入力し、API keyの発行を行います。とりあへずCallback URLは空欄にしておきました。

https://www.last.fm/api/account/create

「Here are the details of your new API account.」と表示されているページへ遷移するので、下記の情報を控えておきます。

  • Application name
  • API key
  • Shared secret

WEB APIの使い方

API Keyを指定することで実行可能なAPIをコールしてみます。

下記のcurlの実行例は見やすさを重視するためにhttp以降に改行を入れておりますが、実際に実行する際には改行を外してください。

geo.getTopArtists

このAPIは指定した国でポピュラーなアーティストを返してくれるものです。

アーティスト名だけを列挙してみます。

curl -X GET \
-H "Content-Type: application/json" \
-d '{}' \
'http://ws.audioscrobbler.com/2.0/?\
method=geo.gettopartists\
&country=japan\
&api_key={発行したAPI Keyを指定}\
&format=json' | jq '.topartists.artist[].name'

アーティスト名を取得できました。

"The Beatles"
"宇多田ヒカル"
"Perfume"
"Radiohead"
"椎名林檎"
"スピッツ"
"ASIAN KUNG-FU GENERATION"
"くるり"
"サカナクション"
"David Bowie"
"Oasis"
"U2"
"Queen"
"BUMP OF CHICKEN"
"東京事変"
"Daft Punk"
"Mr.Children"
"Coldplay"
"Red Hot Chili Peppers"
"Michael Jackson"
"RADWIMPS"
"フジファブリック"
"Beck"
"星野源"
"Jamiroquai"
"Nirvana"
"松任谷由実"
"電気グルーヴ"
"Led Zeppelin"
"相対性理論"
"YUKI"
"Stevie Wonder"
"Björk"
"Aphex Twin"
"Suchmos"
"チャットモンチー"
"JUDY AND MARY"
"Maroon 5"
"Supercar"
"Linkin Park"
"Blur"
"BABYMETAL"
"Bob Dylan"
"坂本龍一"
"The Rolling Stones"
"L'Arc~en~Ciel"
"Yellow Magic Orchestra"
"ONE OK ROCK"
"New Order"
"山下達郎"

ちなみにjqを使ってレスポンス結果を絞る方法については下記ブログが参考になるかもしれません

jqを活用してAPIレスポンス等から欲しい情報だけを抽出する【中級編】

geo.getTopTracks

今度は、先週時点で指定した国でポピュラーな曲を返してくれるものです。

曲名だけだと分かりにくいので、アーティスト名も返すようにします。 それと、先ほどみたいにデフォルトだとレスポンス件数が50なので、10に減らしました。

curl -X GET \
-H "Content-Type: application/json" \
-d '{}' \
'http://ws.audioscrobbler.com/2.0/?\
method=geo.getTopTracks\
&country=japan\
&api_key={発行したAPI Keyを指定}\
&format=json\
&limit=10' | jq '.tracks.track[] | .name, .artist.name'

曲名の後についているものが、アーティスト名です。

"花束を君に"
"宇多田ヒカル"
"ロビンソン"
"スピッツ"
"道"
"宇多田ヒカル"
"桜流し"
"宇多田ヒカル"
"ばらの花"
"くるり"
"Don't Look Back in Anger"
"Oasis"
"真夏の通り雨"
"宇多田ヒカル"
"Paranoid Android"
"Radiohead"
"Smells Like Teen Spirit"
"Nirvana"
"Wonderwall"
"Oasis"

artist.search

アーティスト名に対して検索し、検索ワードに関連の高いもの順に返してくれるものです。

まずは、検索に引っかかりやすそうな"U2"で検索してみます。

curl -X GET \
-H "Content-Type: application/json" \
-d '{}' \
'http://ws.audioscrobbler.com/2.0/\
method=artist.search\
&artist=u2\
&api_key={発行したAPI Keyを指定}\
&format=json\
&limit=10' | jq '.results.artistmatches.artist[].name'

やはり"U2"がトップに返ってきました

"U2"
"U2 and Green Day"
"LMC vs. U2"
"U2 & Coco Freeman"
"U2 Akiyama"
"Bossa N' U2"
"Green Day & U2"
"U2 feat. Green Day"
"UT2004"
"Mary J. Blige & U2"

次に"ed"で検索してみます。

curl -X GET \
-H "Content-Type: application/json" \
-d '{}' \
'http://ws.audioscrobbler.com/2.0/\
method=artist.search\
&artist=ed\
&api_key={発行したAPI Keyを指定}\
&format=json\
&limit=10' | jq '.results.artistmatches.artist[].name'

"Edguy"、"Edge of Sanity"が結果に含まれておりました。

"Ed Sheeran"
"Editors"
"Eddie Vedder"
"Edward Sharpe & The Magnetic Zeros"
"Edguy"
"Eldo"
"Édith Piaf"
"Edvard Grieg"
"Edge of Sanity"
"Mt Eden"

artist.getSimilar

似たアーティストを返してくれるものです。

私の好きな"stratovarius"を指定してみました。

curl -X GET \
-H "Content-Type: application/json" \
-d '{}' \
'http://ws.audioscrobbler.com/2.0/?\
method=artist.getSimilar\
&artist=stratovarius\
&api_key={発行したAPI Keyを指定}\
&format=json\
&limit=10' | jq '.similarartists.artist[].name'

結果に"Kotipelto"、"Sonata Arctica"が返ってくるのは、しっくりきます。"Revolution Renaissance"はstratovarius関連ですね。

"Kotipelto"
"Sonata Arctica"
"Helloween"
"HammerFall"
"Edguy"
"Gamma Ray"
"Revolution Renaissance"
"Cain's Offering"
"Avantasia"
"Freedom Call"

ちなみに"nightwish"を指定した場合の下記の結果もしっくりきます。

"Tarja"
"Epica"
"Within Temptation"
"Xandria"
"After Forever"
"Delain"
"Sirenia"
"Leaves' Eyes"
"ReVamp"
"Amberian Dawn"

album.search

今度はアルバム名に対して検索し、検索ワードに関連の高いもの順に返してくれるものです。

"image"を指定して検索してみます。

curl -X GET \
-H "Content-Type: application/json" \
-d '{}' \
'http://ws.audioscrobbler.com/2.0/?\
method=album.search\
&album=images\
&api_key={発行したAPI Keyを指定}\
&format=json\
&limit=10' | jq '.results.albummatches.album[] | .name, .artist'

アルバム名、アーティスト名を返すようにしております。 もしかして、と思いましたが、"Images and Words"がトップに返ってきました。

"Images and Words"
"Dream Theater"
"Images du Futur"
"Suuns"
"Images Of Sigrid"
"Poni Hoax"
"Images"
"Jean Michel Jarre"
"Voices & Images"
"Camouflage"
"Images & Words"
"Dream Theater"
"Debussy: Images"
"Simon Trpčeski"
"A Heap of Broken Images"
"Blue Sky Black Death"
"Images"
"You'll Never Get to Heaven"
"Stored Images"
"Suicide Commando"

chart.getTopArtists

トップアーティストのチャートを返してくれるものです。

curl -X GET \
-H "Content-Type: application/json" \
-d '{}' \
'http://ws.audioscrobbler.com/2.0/?\
method=chart.gettopartists
&api_key={発行したAPI Keyを指定}
&format=json
&limit=10' | jq 

以下のような情報を返してくれるようです。アーティスト名とリスナー数が主な情報でしょうか。

{
  "artists": {
    "artist": [
      {
        "name": "Drake",
        "playcount": "120939459",
        "listeners": "3234039",
        "mbid": "b49b81cc-d5b7-4bdd-aadb-385df8de69a6",
        "url": "https://www.last.fm/music/Drake",
        "streamable": "0",
        "image": [
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/34s/e405e4f480290925399bbcc7dc62069b.png",
            "size": "small"
          },
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/64s/e405e4f480290925399bbcc7dc62069b.png",
            "size": "medium"
          },
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/174s/e405e4f480290925399bbcc7dc62069b.png",
            "size": "large"
          },
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/300x300/e405e4f480290925399bbcc7dc62069b.png",
            "size": "extralarge"
          },
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/300x300/e405e4f480290925399bbcc7dc62069b.png",
            "size": "mega"
          }
        ]
      },
      {
        "name": "Kendrick Lamar",
        "playcount": "87532062",
        "listeners": "1350090",
        "mbid": "381086ea-f511-4aba-bdf9-71c753dc5077",
        "url": "https://www.last.fm/music/Kendrick+Lamar",
        "streamable": "0",
        "image": [
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/34s/62ed7e3228934c8fcc4987255acab57b.png",
            "size": "small"
          },
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/64s/62ed7e3228934c8fcc4987255acab57b.png",
            "size": "medium"
          },
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/174s/62ed7e3228934c8fcc4987255acab57b.png",
            "size": "large"
          },
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/300x300/62ed7e3228934c8fcc4987255acab57b.png",
            "size": "extralarge"
          },
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/300x300/62ed7e3228934c8fcc4987255acab57b.png",
            "size": "mega"
          }
        ]
      },
      {
        "name": "The Weeknd",
        "playcount": "66609909",
        "listeners": "1159883",
        "mbid": "c8b03190-306c-4120-bb0b-6f2ebfc06ea9",
        "url": "https://www.last.fm/music/The+Weeknd",
        "streamable": "0",
        "image": [
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/34s/171cf3803fde5d649bbf47aef8af0657.png",
            "size": "small"
          },
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/64s/171cf3803fde5d649bbf47aef8af0657.png",
            "size": "medium"
          },
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/174s/171cf3803fde5d649bbf47aef8af0657.png",
            "size": "large"
          },
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/300x300/171cf3803fde5d649bbf47aef8af0657.png",
            "size": "extralarge"
          },
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/300x300/171cf3803fde5d649bbf47aef8af0657.png",
            "size": "mega"
          }
        ]
      },
      {
        "name": "Kanye West",
        "playcount": "212868576",
        "listeners": "4256648",
        "mbid": "164f0d73-1234-4e2c-8743-d77bf2191051",
        "url": "https://www.last.fm/music/Kanye+West",
        "streamable": "0",
        "image": [
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/34s/5b514365ee544c9363ed758b80d1f6fd.png",
            "size": "small"
          },
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/64s/5b514365ee544c9363ed758b80d1f6fd.png",
            "size": "medium"
          },
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/174s/5b514365ee544c9363ed758b80d1f6fd.png",
            "size": "large"
          },
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/300x300/5b514365ee544c9363ed758b80d1f6fd.png",
            "size": "extralarge"
          },
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/300x300/5b514365ee544c9363ed758b80d1f6fd.png",
            "size": "mega"
          }
        ]
      },
      {
        "name": "Post Malone",
        "playcount": "11374038",
        "listeners": "376495",
        "mbid": "",
        "url": "https://www.last.fm/music/Post+Malone",
        "streamable": "0",
        "image": [
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/34s/9b3ca042775c847efca395e6ad701392.png",
            "size": "small"
          },
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/64s/9b3ca042775c847efca395e6ad701392.png",
            "size": "medium"
          },
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/174s/9b3ca042775c847efca395e6ad701392.png",
            "size": "large"
          },
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/300x300/9b3ca042775c847efca395e6ad701392.png",
            "size": "extralarge"
          },
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/300x300/9b3ca042775c847efca395e6ad701392.png",
            "size": "mega"
          }
        ]
      },
      {
        "name": "Radiohead",
        "playcount": "481608205",
        "listeners": "4639180",
        "mbid": "a74b1b7f-71a5-4011-9441-d0b5e4122711",
        "url": "https://www.last.fm/music/Radiohead",
        "streamable": "0",
        "image": [
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/34s/9b109fcab6c48f5714c8554a31ab9943.png",
            "size": "small"
          },
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/64s/9b109fcab6c48f5714c8554a31ab9943.png",
            "size": "medium"
          },
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/174s/9b109fcab6c48f5714c8554a31ab9943.png",
            "size": "large"
          },
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/300x300/9b109fcab6c48f5714c8554a31ab9943.png",
            "size": "extralarge"
          },
          {
            "#text": "https://lastfm-img2.akamaized.net/i/u/300x300/9b109fcab6c48f5714c8554a31ab9943.png",
            "size": "mega"
          }
        ]
      },

tag.getTopTags

使用回数が多い順にLast.fm全体のタグ情報を返してくれるものです。

curl -X GET \
-H "Content-Type: application/json" \
-d '{}' \
'http://ws.audioscrobbler.com/2.0/?\
method=tag.getTopTags\
&api_key={発行したAPI Keyを指定}\
&format=json' | jq 

タグ名と回数が返ってきました。("reach"が何を意味するのかは不明です。)

{
  "toptags": {
    "@attr": {
      "offset": 0,
      "num_res": 50,
      "total": 2667307
    },
    "tag": [
      {
        "name": "rock",
        "count": 3924270,
        "reach": 392524
      },
      {
        "name": "electronic",
        "count": 2326448,
        "reach": 250876
      },
      {
        "name": "seen live",
        "count": 2120334,
        "reach": 81574
      },
      {
        "name": "alternative",
        "count": 2064744,
        "reach": 259618
      },
      {
        "name": "indie",
        "count": 1990632,
        "reach": 250683
      },
      {
        "name": "pop",
        "count": 1919280,
        "reach": 221675
      },
      {
        "name": "female vocalists",
        "count": 1582878,
        "reach": 167090
      },
      {
        "name": "metal",
        "count": 1242149,
        "reach": 154387
      },
      {
        "name": "alternative rock",
        "count": 1137146,
        "reach": 165629
      },
      {
        "name": "classic rock",
        "count": 1135739,
        "reach": 136380
      },
      {
        "name": "jazz",
        "count": 1130800,
        "reach": 145346
      },
      {
        "name": "experimental",
        "count": 1028729,
        "reach": 137204
      },
      {
        "name": "ambient",
        "count": 1028430,
        "reach": 142001
      },
      {
        "name": "folk",
        "count": 899477,
        "reach": 145837
      },
      {
        "name": "punk",
        "count": 862979,
        "reach": 140557
      },
      {
        "name": "indie rock",
        "count": 861194,
        "reach": 132020
      },
      {
        "name": "Hip-Hop",
        "count": 836179,
        "reach": 124482
      },
      {
        "name": "hard rock",
        "count": 833754,
        "reach": 113271
      },
      {
        "name": "instrumental",
        "count": 824853,
        "reach": 121936
      },
      {
        "name": "singer-songwriter",
        "count": 822081,
        "reach": 107362
      },
      {
        "name": "black metal",
        "count": 801542,
        "reach": 60665
      },
      {
        "name": "dance",
        "count": 786503,
        "reach": 130590
      },
      {
        "name": "80s",
        "count": 765999,
        "reach": 99552
      },
      {
        "name": "Progressive rock",
        "count": 702998,
        "reach": 94650
      },
      {
        "name": "death metal",
        "count": 692904,
        "reach": 70264
      },
      {
        "name": "british",
        "count": 676376,
        "reach": 92286
      },
      {
        "name": "hardcore",
        "count": 675583,
        "reach": 96151
      },
      {
        "name": "heavy metal",
        "count": 671502,
        "reach": 88995
      },
      {
        "name": "soul",
        "count": 655906,
        "reach": 98924
      },
      {
        "name": "chillout",
        "count": 641737,
        "reach": 102752
      },
      {
        "name": "electronica",
        "count": 624491,
        "reach": 100937
      },
      {
        "name": "Classical",
        "count": 553786,
        "reach": 73051
      },
      {
        "name": "Soundtrack",
        "count": 542929,
        "reach": 82807
      },
      {
        "name": "industrial",
        "count": 542641,
        "reach": 82276
      },
      {
        "name": "blues",
        "count": 538282,
        "reach": 94611
      },
      {
        "name": "rap",
        "count": 534479,
        "reach": 99845
      },
      {
        "name": "punk rock",
        "count": 528719,
        "reach": 96324
      },
      {
        "name": "thrash metal",
        "count": 473535,
        "reach": 61559
      },
      {
        "name": "acoustic",
        "count": 468652,
        "reach": 109055
      },
      {
        "name": "psychedelic",
        "count": 464717,
        "reach": 76496
      },
      {
        "name": "metalcore",
        "count": 462411,
        "reach": 65952
      },
      {
        "name": "90s",
        "count": 461294,
        "reach": 56212
      },
      {
        "name": "japanese",
        "count": 447124,
        "reach": 47545
      },
      {
        "name": "post-rock",
        "count": 433149,
        "reach": 63916
      },
      {
        "name": "german",
        "count": 416020,
        "reach": 58576
      },
      {
        "name": "Progressive metal",
        "count": 415491,
        "reach": 61264
      },
      {
        "name": "funk",
        "count": 412029,
        "reach": 81075
      },
      {
        "name": "hip hop",
        "count": 408497,
        "reach": 74705
      },
      {
        "name": "new wave",
        "count": 407612,
        "reach": 62899
      },
      {
        "name": "trance",
        "count": 403118,
        "reach": 63758
      }
    ]
  }
}

track.getSimilar

リスニングデータに基づいて似ていると判断されるものを返してくれるものです。面白そうです。

ImpellitteriのScreaming Symphonyというアルバムには似た曲が多いので、試してみました。

curl -X GET \
-H "Content-Type: application/json" \
-d '{}' \
'http://ws.audioscrobbler.com/2.0/?\
method=track.getsimilar\
&artist=Impellitteri\
&track=Father Forgive Them\
&api_key={発行したAPI Keyを指定}\
&format=json\
&limit=10' | jq '.similartracks.track[] | .name, .artist.name'

曲名、アーティスト名の順に表示しております。最初の2曲は、見事同じアルバムに収録されている曲でした。

"I'll Be With You"
"Impellitteri"
"Kingdom of Light"
"Impellitteri"
"Crystal Ball"
"Yngwie Malmsteen"
"Rising Force"
"Yngwie Malmsteen"
"The Ninja"
"Cacophony"
"The Dance of Kashani"
"Joe Stump"
"Evil Beasts Below"
"Joe Stump"
"Manic Distortion"
"John Norum"
"Scarified"
"Racer X"
"Too Young to Die, Too Drunk to Live"
"Alcatrazz"

Tribeのpayphoneという曲は、とある邦楽と似ているので検索してみました。

curl -X GET \
-H "Content-Type: application/json" \
-d '{}' \
'http://ws.audioscrobbler.com/2.0/?\
method=track.getsimilar\
&artist=tribe\
&track=payphone\
&api_key={発行したAPI Keyを指定}\
&format=json\
&limit=10' | jq '.similartracks.track[] | .name, .artist.name'

データに基づいた結果なので、データがないのかヒットしませんでした。どれも同じアーティストの曲が返ってきました。

"Easter Dinner"
"Tribe"
"Serenade"
"Tribe"
"Smoke (Part.1)"
"Tribe"
"Adhar 2"
"Tribe"
"Village Choir"
"Tribe"
"Feel the Way I Do"
"Tribe"
"Harmonic Sitar"
"Tribe"
"Hut Ritual"
"Tribe"
"Celebrates"
"Tribe"

おわりに

最近は仕事で全文検索に触れることがあり、検索処理や、そもそもどうやってサイト訪問者に商品などを見つけてもらうか?といったことに興味を持っているので、今回みたいに色々検索するのは面白いです。