4月28日に「Speee もくもく会 #39」に行って先頃から作成しているSpotifyのプレイリスト自動生成モジュールの作業をしてきました。
以前より気になっていたイベントですが、初参加枠がすぐ埋まってしまうのでなかなか参加出来ずにいました。今回初めて参加する事が出来ました。会場はその名の通り、Speeeさんのオフィスでした。オフィスには多くの本が並んでおり、勉強熱心な方には良いオフィスだと思いました。
また折りをみて参加したいと思います。
仕様を大きく変更しました。前のコードではlast.fmのAPIのデータを収録したDBを経由していましたが、メンテナンスコストが負担になっていたので、DBを経由せずにAPIを直接参照するように切り替えました。
また、API参照の部分をべた書きすると、今度は本体部分のメンテナンスがし辛くなってしまったので、API参照の部分は別ファイルを参照する方式にしました。
では、まずは本体部分です。
import spotipy
import re
import get_similar_track_sandbox
from spotify_token import Spotify_token
api_key =
username =
def input_artist():
artist = input("検索したいアーティスト名を入力して下さい")
page = 1
search_song_list(artist, page)
def search_song_list(artist, page):
list = get_similar_track_sandbox.get_search_song_list(artist, api_key, page)
for i in range(len(list)):
song_list = list[i]
song = song_list["name"]
print(song)
yes_or_no = input("この中に探したい曲はありましたか?(y/n)")
#yes_or_no = "y"
if yes_or_no == "y":
search_track(artist)
elif yes_or_no == "n":
page = page + 1
search_song_list(artist, page)
else:
print("正しい入力ではありません")
def search_track(artist):
song = input("曲名を入力して下さい")
create_playlist(artist, song)
def create_playlist(artist, song):
playlist = []
first_input = (artist, song)
playlist.append(first_input)
k = 0
genarate_playlist(first_input, artist, song, playlist, k)
def genarate_playlist(first_input, artist, song, playlist, k):
track = get_similar_track_sandbox.get_similar_track(artist, song, api_key)
similar_artist_list = get_similar_track_sandbox.similar_artist_search(artist, api_key)
playlist_limit = 15
for i in range(len(similar_artist_list)):
similar_artist = similar_artist_list[i]
for j in range(len(track)):
if len(playlist) >= playlist_limit:
break
else:
song_list = track[j]
similar_song = song_list["name"]
similar_song_artist = song_list["artist"]["name"]
match = song_list["match"]
match = float(match)
result = (similar_song_artist, similar_song)
if match < 0.1:
continue
elif result in playlist:
continue
elif similar_song_artist == similar_artist:
playlist.append(result)
else:
continue
try:
if len(playlist) < playlist_limit -1:
print(playlist)
k = k + 1
search_word = playlist[k]
artist = search_word[0]
song = search_word[1]
genarate_playlist(first_input, artist, song, playlist, k)
else:
print(playlist)
get_empty_Spotify_playlist(first_input, playlist)
except IndexError:
print(playlist)
page = 1
list = get_similar_track_sandbox.get_search_song_list(artist, api_key, page)
print(list)
song_list = list[0]
song = song_list["name"]
k = 1
search_word = (artist, song)
playlist.append(search_word)
genarate_playlist(first_input, artist, song, playlist, k)
def get_empty_Spotify_playlist(first_input, playlist):
playlist_name = first_input[0] + "の" + first_input[1] + "から始まるおすすめプレイリスト"
ST = Spotify_token(username)
token = ST.set()
sp = spotipy.Spotify(auth=token)
sp.trace = False
playlistts = sp.user_playlist_create(username, playlist_name)
playlist_id = playlistts["id"]
song_ids = []
for i in range(len(playlist)):
search_str = playlist[i]
s_artist = search_str[0]
s_song = search_str[1]
search_str = s_artist + " " + s_song
result = sp.search(search_str, limit=1)
for item in result["tracks"]["items"]:
print(item["artists"][0]["name"])
print(item["name"])
print(type(item["name"]))
print(item["id"])
api_song = item["name"]
api_song = re.sub("\t", "", api_song)
if api_song == s_song:
print("OK")
song_id = item["id"]
song_ids.append(song_id)
else:
continue
playlist_input(playlist_id, song_ids)
def playlist_input(playlist_id, song_ids):
ST = Spotify_token(username)
token = ST.set()
if token:
sp = spotipy.Spotify(auth=token)
sp.trace = False
results = sp.user_playlist_add_tracks(username, playlist_id, song_ids)
print(results)
else:
print("Can't get token for", username)
if __name__ == '__main__':
input_artist()
次に、API参照部分です。
import urllib.request
import urllib.parse
import json
def get_search_song_list(artist, api_key, page):
artist = urllib.parse.quote(artist)
artist_api1 = "http://ws.audioscrobbler.com/2.0/?method=artist.gettoptracks&artist="
artist_api2 = "&autocorrect=1&page="
page = str(page)
artist_api3 = "&api_key="
artist_api4 = "&format=json"
call_api = artist_api1 + artist + artist_api2 + page + artist_api3 + api_key + artist_api4
print(call_api)
address_json = urllib.request.urlopen(call_api)
data = json.loads(address_json.read())
track = data["toptracks"]
list = track["track"]
return list
def get_similar_track(artist, song, api_key):
artist = urllib.parse.quote(artist)
song = urllib.parse.quote(song)
track_api1 = "http://ws.audioscrobbler.com/2.0/?method=track.getsimilar&artist="
track_api2 = "&track="
track_api3 = "&autocorrect=1&api_key="
track_api4 = "&format=json"
call_api = track_api1 + artist + track_api2 + song + track_api3 + api_key + track_api4
print(call_api)
address_json = urllib.request.urlopen(call_api)
data = json.loads(address_json.read())
similartracks = data["similartracks"]
track = similartracks["track"]
return track
def similar_artist_search(artist, api_key):
artist = urllib.parse.quote(artist)
artist_api1 = "http://ws.audioscrobbler.com/2.0/?method=artist.getsimilar&artist="
artist_api2 = "&autocorrect=1&api_key="
artist_api3 = "&format=json"
call_api = artist_api1 + artist + artist_api2 + api_key + artist_api3
print(call_api)
address_json = urllib.request.urlopen(call_api)
data = json.loads(address_json.read())
similarartists = data["similarartists"]
artist_list = similarartists["artist"]
similar_artist_list = []
artist = urllib.parse.unquote(artist)
similar_artist_list.append(artist)
for i in range(len(artist_list)):
list = artist_list[i]
similar_artist = list["name"]
match = list["match"]
match = float(match)
if match > 0.1:
similar_artist_list.append(similar_artist)
else:
break
return similar_artist_list
では、ここに乃木坂46の新曲「シンクロニシティ」を入れてみます。
システムに基づくプレイリストは以下の通りです。
[('乃木坂46', 'シンクロニシティ'), ('乃木坂46', '制服のマネキン'), ('乃木坂46', '君の名は希望'), ('乃木坂46', '命は美しい'), ('HKT48', '桜、みんなで食べた'), ('HKT48', '12秒'), ('E-Girls', 'ごめんなさいのKissing You'), ('E-Girls', 'Mr.Snowman'), ('山本彩', '夢のdead body'), ('山本彩', 'ジャングルジム'), ('高橋みなみ', 'Jane Doe'), ('高橋みなみ', '右肩'), ('E-Girls', 'E.G. Anthem -WE ARE VENUS-'), ('AKB48', '希望的リフレイン'), ('AKB48', 'overture')]
では、実際に出来たSpotifyプレイリストを見てみましょう。
HKT48と山本彩さんの楽曲が入っていません。これは、Spotifyでは配信されていない為です。E-girlsの「E.G. Anthem -WE ARE VENUS-」が入っていませんが、Spotifyでの表記が若干異なることから入らなかったようです。ちなみに、Google Play Musicではリスト曲全て配信されています。
自分としては、Google Play MusicのAPIが出ることを切に願っています。
今後は24時間以内に再生した楽曲を除去する機能を搭載し、プレイリストの自動生成を何度も用いても同じ曲が再生されないような仕組み作りを行います。
Last.fmという音楽系のAPIがあります。オライリーの本で「Audioscrobbler」として紹介されているものです。このデータを用いてSpotifyのプレイリストを作成するモジュールが完成しました。
import psycopg2
import psycopg2.extras
import spotipy
import spotipy.util as util
import pprint
import re
from spotify_token import Spotify_token
host_name =
port_number =
dbname =
rolename =
passwd =
username =
# API式に切り替える時にアーティスト名から検索可能な曲名の一覧を出す
def get_artist_similar():
conn = psycopg2.connect(database=dbname, host=host_name, port=port_number, user=rolename, password=passwd)
cur = conn.cursor()
cur.execute("SELECT to_artist FROM similar_artist WHERE from_artist = %s AND match_index > 0.01 ORDER BY match_index DESC", (artist,))
'''conn.query("SELECT * FROM similar_artist")'''
similar_artist_list = cur.fetchall()
conn.close()
return similar_artist_list
def get_most_similar_song():
conn = psycopg2.connect(database=dbname, host=host_name, port=port_number, user=rolename, password=passwd)
cur = conn.cursor()
similar_artist_list = get_artist_similar()
playlist = []
playlist.append(first_input)
if similar_artist_list == []:
print("類似するアーティストが登録されていないか、打ち間違いの可能性があります。")
else:
cur.execute(
"SELECT to_artist, to_song FROM similar_track WHERE from_artist = %s AND from_song = %s AND match_index = 1.0",
first_input)
similar_tracklist = cur.fetchall()
if similar_tracklist == []:
cur.execute("SELECT from_artist, from_song FROM similar_track WHERE from_artist = ?", (artist,))
similar_tracklist = cur.fetchall()
similar_track = similar_tracklist[0]
playlist.append(similar_track)
return playlist
else:
similar_track = similar_tracklist[0]
playlist.append(similar_track)
return playlist
conn.close()
def generate_playlist():
conn = psycopg2.connect(database=dbname, host=host_name, port=port_number, user=rolename, password=passwd)
cur = conn.cursor()
similar_artist_list = get_artist_similar()
playlist = get_most_similar_song()
for i in range(len(similar_artist_list) - 1):
if len(playlist) == 10:
return playlist
else:
similar_artist = similar_artist_list[i]
search_word = (first_input[0], first_input[1], similar_artist[0])
cur.execute("SELECT to_artist, to_song FROM similar_track WHERE from_artist = %s AND from_song = %s AND to_artist = %s AND match_index > 0.01 ORDER BY match_index DESC", search_word)
similar_tracklist = cur.fetchall()
for j in range(len(similar_tracklist) - 1):
trackdata = similar_tracklist[j]
if trackdata in playlist:
continue
else:
playlist.append(trackdata)
print(playlist)
conn.close()
def playlist_print():
playlist = generate_playlist()
print(playlist)
get_empty_Spotify_playlist(playlist)
return playlist
def get_empty_Spotify_playlist(playlist):
playlist_name = artist + "の" + song + "から始まるおすすめプレイリスト"
ST = Spotify_token(username)
token = ST.set()
sp = spotipy.Spotify(auth=token)
sp.trace = False
playlistts = sp.user_playlist_create(username, playlist_name)
pprint.pprint(playlistts)
playlist_id = playlistts["id"]
print(playlist_id)
song_ids = []
for i in range(len(playlist)):
search_str = playlist[i]
s_artist = search_str[0]
s_song = search_str[1]
search_str = s_artist + " " + s_song
result = sp.search(search_str, limit=1)
print(result)
for item in result["tracks"]["items"]:
print(item["artists"][0]["name"])
print(item["name"])
print(item["id"])
api_song = item["name"]
api_song = re.sub("\t", "", api_song)
print(api_song)
song_id = item["id"]
print(song_id)
song_ids.append(song_id)
print(song_ids)
playlist_input(playlist_id, song_ids)
def playlist_input(playlist_id, song_ids):
ST = Spotify_token(username)
token = ST.set()
if token:
sp = spotipy.Spotify(auth=token)
sp.trace = False
results = sp.user_playlist_add_tracks(username, playlist_id, song_ids)
print(results)
else:
print("Can't get token for", username)
if __name__ == '__main__':
artist = input("検索したいアーティスト名を入力して下さい")
song = input("次にアーティストの楽曲名を入力して下さい")
first_input = (artist, song)
playlist_print()
なお、後半のSpotifyとの接続は以下の記事を参考にしました。
現状、以下の現象を確認しています。
・DBに未収録の楽曲はプレイリストが出来ない
・入力を間違えるとエラーになる
・Spotifyに配信されていない楽曲が混ざると、出来るプレイリストが想定と違う
なお、今後はDBでは無くAPIを直接参照するように改修します。また、アーティスト名を入れたあとに曲名を表示されるようにします。
最近、フロント側のビュー画面の改修に関する仕事を引き受けているので雑感です。
ビュー部分はhtmlのタグのコーディングなので、ほかの言語と違いエラー文が出てきません。そのため、レイアウト崩壊が起きると、どこをどのように修正したら良いのか良く分からなくなります。
直感的には「こうしたい」という思いはあるけれど、それをどう実現させるのかが分からないという感じですね。
地道に本を使って頑張りたいと思います。
先日、乃木坂46の「Against」のPVが公開されました。
(※以下のリンクは2018年4月25日のCD発売後リンク切れとなっている可能性があります。)
1期生だけのPVですが、最後の「生生星」体制の曲となっています。生生星とは、1stシングル「ぐるぐるカーテン」から4thシングル「君の名は希望」まで続いた体制で(2ndシングル「おいでシャンプー」を除く)フロント3人の名前(生田絵梨花、生駒里奈、星野みなみ)を取ってそう呼ばれています。
デビュー時は3人とも中高生でしたが、最年少の星野みなみさんも20歳になりすっかり大人の雰囲気を出しています。
自分自身は生田さんをずっと推してきたので、生生星の並びがもう見られないのは寂しさがあります。
卒業記念のセンターを除き、センター経験者が初めて卒業することになった乃木坂46は大きな転換点を迎えている感じがします。シンクロニシティ以後どうなっていくのか、今後も注目していきたいと思います。
4月8日に「アイノラ交響楽団『第15回定期演奏会 “シベリウスと伊福部 昭の世界 ~ 北方の舞踏 ~”』」があったので行ってきました。
アマチュア・オーケストラのコンサートながら、フィンランド大使館等の後援が付いていたので気になって行ってみました。
曲目は
・伊福部昭:マリンバとオーケストラのためのラウダ・コンチェルタータ
・シベリウス:音詩「エン・サガ」
でした。また、アンコールとして
・シベリウス:舞踏間奏曲「パンとエコー」作品53a
・シベリウス:アンダンテ・フェスティーヴォ
が演奏されました。
伊福部昭は日本を代表する作曲家で、映画「ゴジラ」のテーマ曲が大変有名です。前半はやや迫力に欠けるところがありましたが、終盤に掛けては非常に聴き応えがあったと思います。休憩を挟んで、フィンランドを代表する作曲家のシベリウスの「エン・サガ」と交響曲第3番の演奏がありました。自分としては、一番「エン・サガ」が印象に残りました。
この曲は今まで触れた事がありませんでしたが、今後自分のお気に入り曲の1つとなる気がします。
また、楽器を再開しようと思いました。