Created
June 2, 2023 15:36
-
-
Save takemikami/fe148d8a474a598115399a3b82636fbd to your computer and use it in GitHub Desktop.
音響特徴に寄せたアイマス楽曲のプレイリストを登録するスクリプト
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 音響特徴に寄せたアイマス楽曲のプレイリストを登録するスクリプト | |
# | |
# 前提: | |
# 以下の環境変数を設定(.envファイルに記載) | |
# SPOTIPY_CLIENT_ID: spotify web apiのID | |
# SPOTIPY_CLIENT_SECRET: spotify web apiのシークレットキー | |
# TARGET_PLAYLIST_ID: 更新するプレイリストのID | |
# 以下の依存ライブラリをインストール | |
# pip install spotipy | |
# pip install python-dotenv | |
# pip install numpy | |
# pip install pandas | |
# | |
# 実行方法: | |
# python imaspotify.py [ブランド名] [音響特徴] | |
# 例) シャニマスのenergyに寄せた楽曲をプレイリストに登録する | |
# python imaspotify.py ShinyColors energy | |
import json | |
import math | |
import os.path | |
import sys | |
import time | |
import numpy as np | |
import pandas as pd | |
import spotipy | |
from dotenv import load_dotenv | |
from spotipy.oauth2 import SpotifyClientCredentials, SpotifyOAuth | |
load_dotenv() | |
features = [ | |
'danceability', | |
'energy', | |
'key', | |
'loudness', | |
'mode', | |
'speechiness', | |
'acousticness', | |
'instrumentalness', | |
'liveness', | |
'valence', | |
'tempo' | |
] | |
def get_spotify_client(): | |
return spotipy.Spotify(client_credentials_manager=SpotifyClientCredentials()) | |
def get_spotify_oauth(): | |
scope = "playlist-modify-private" | |
os.environ["SPOTIPY_REDIRECT_URI"] = "http://localhost:8080/" | |
spotify = spotipy.Spotify(auth_manager=SpotifyOAuth(scope=scope)) | |
return spotify | |
def get_features_fromplaylist(spotify, playlist_id): | |
filename = f"playlist_features_{playlist_id}.json" | |
if os.path.exists(filename): | |
with open(filename, "r") as f: | |
items = json.loads(f.read()) | |
return items | |
time.sleep(10) | |
items = [] | |
# get tracks from playlist | |
for t in range(10): | |
offset = 100 * t | |
results = spotify.playlist_items(playlist_id, offset=offset) | |
items.extend(results['items']) | |
if results["offset"] + results["limit"] > results["total"]: | |
break | |
# get features from tracks | |
id_idx_map = {e['track']['id']: i for i, e in enumerate(items)} | |
number_of_sublist = math.ceil(len(id_idx_map.keys()) / 30) | |
list_set = np.array_split(list(id_idx_map.keys()), number_of_sublist) | |
counter = 0 | |
for t, l in enumerate(list_set): | |
res2 = spotify.audio_features(l) | |
for e in res2: | |
items[counter]["features"] = e | |
counter += 1 | |
with open(filename, "w") as f: | |
f.write(json.dumps(items)) | |
return items | |
def convert_to_dataframe(items): | |
columns = ['id', 'name', 'artist', *[*features]] | |
data = [ | |
[ | |
e['track']['id'], | |
e['track']['name'], | |
', '.join([a.get('name', '') for a in e['track'].get('artists', [])]), # [0].get('name', ''), | |
*[*[e['features'][f] for f in features]] | |
] | |
for i, e in enumerate(items) | |
] | |
df = pd.DataFrame(data, columns=columns) | |
return df | |
def get_feature_dataframe(spotify, brand: str="all") -> pd.DataFrame: | |
playlists = [] | |
if brand == "all" or brand == "765": | |
playlists.append('3mWR84C5UUyoJIf6d2CF9R') | |
if brand == "all" or brand == "ShinyColors": | |
playlists.append('0vKD0u46kcm0PxIzzmbBD9') | |
if brand == "all" or brand == "CinderellaGirls": | |
playlists.append('1OL47KFL8HGi5OtGdsd0Tt') | |
if brand == "all" or brand == "MillionLive": | |
playlists.extend([ | |
'328b2gee1LdKta0gurnDES', # Unit | |
'66JxoB4JzYeITPyBZa2UP2', # Solo | |
]) | |
if brand == "all" or brand == "SideM": | |
playlists.append('5KAAHcj9bJV2rkuR8x4FUn') | |
df_list = list() | |
for playlist_id in playlists: | |
items = get_features_fromplaylist(spotify, playlist_id) | |
df_list.append(convert_to_dataframe(items)) | |
return pd.concat(df_list, ignore_index=True).drop_duplicates() | |
def get_feature_topK(spotify, feature, brand="all", k=20): | |
df = get_feature_dataframe(spotify, brand) | |
df_feature = df.sort_values(feature, ascending=False).head(k) | |
return df_feature | |
def update_playlist(spotify_oauth, playlist_id, track_ids): | |
items = [f"spotify:track:{id}" for id in track_ids] | |
spotify_oauth.playlist_replace_items(playlist_id, items) | |
if __name__ == '__main__': | |
if len(sys.argv) < 3: | |
print(f"usage: python imaspotify.py [all|765|ShinyColors|CinderellaGirls|MillionLive|SideM] [{'|'.join(features)}]") | |
exit(1) | |
brand = sys.argv[1] | |
feature = sys.argv[2] | |
# get tracks | |
spotify = get_spotify_client() | |
df = get_feature_topK(spotify, feature, brand) | |
print(df[["name", "artist", feature]]) | |
# update playlist | |
playlist_id = os.environ["TARGET_PLAYLIST_ID"] | |
spotify_oauth = get_spotify_oauth() | |
update_playlist(spotify_oauth, playlist_id, df["id"].values) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment