Skip to content

Instantly share code, notes, and snippets.

@tai-fukaya
Created January 18, 2020 13:37
Show Gist options
  • Save tai-fukaya/7129c16b723130f692b72052dc6edd92 to your computer and use it in GitHub Desktop.
Save tai-fukaya/7129c16b723130f692b72052dc6edd92 to your computer and use it in GitHub Desktop.
Transfer albums from Apple Music to Spotify
import csv
file_path = 'apple-music-album-list.txt'
target_path = 'apple-music/apple-music-album-list.csv'
album_map = {}
with open(file_path) as f:
lines = [s.strip() for s in f.readlines()]
for line in lines:
data = line.split('\x1f')
if len(data) < 5:
print(data)
continue
key = f"{data[0]} / {data[1]}"
album = {
'title': data[0],
'artist': data[1],
'count': data[2],
'release_date': data[3],
'date_added': data[4]
}
if key not in album_map.keys():
album_map[key] = album
print(len(album_map.keys()))
with open(target_path, mode='w') as f:
writer = csv.DictWriter(f, ['title', 'artist', 'count', 'release_date', 'date_added'])
writer.writeheader()
writer.writerows(album_map.values())

Apple Music のアルバムを、Spotifyに移行するためのツール
説明が不親切なので、よくわかんないところは、ググってください

XCodeで、Projectを作る

Xcodeをインストールして、FirstViewController.swiftにTransportAlbum.swiftの内容をコピペ
MPMediaQueryを使うのに、権限の設定が必要かも?

スマホを接続して、実行すると、Outputにアルバム一覧が表示されます。

Artist: 5000
Playlist: 500
Album: 7500
Song: 75000
1/Rapt In Fantasy/石野 卓球/49/2016-08-11 22:20:07
2/Fetish/石野 卓球/39/2016-08-11 22:20:07
3/因你而在/林俊傑/38/2014-10-14 07:15:58
4/Monkhide/Burnt Friedman/37/2018-09-03 23:38:33
5/冥明/蘇運瑩/35/2016-01-04 00:34:38
# ここから、下をコピペしてファイルに保存する
午夜列車上的告別�路壹 & Cee�243�2016-06-22 21:00:00�2016-12-10 19:00:18
原野�莫西子诗�231�2020-01-18 21:37:22�2015-12-06 08:47:47
Broken Machine (Deluxe)�Nothing But Thieves�229�2017-09-08 21:00:00�2017-09-08 19:37:40
Nothing But Thieves (Deluxe)�Nothing But Thieves�222�2015-07-24 21:00:00�2016-08-05 22:56:41
LUNATIQUE�石野 卓球�221�2016-08-03 16:00:00�2016-08-11 22:20:07

SpotifyのAPIを使う

python3ができる環境にする

最初に、認証が必要

https://qiita.com/propella/items/9137ffd29d3ff496bd39
app.jsの、scope変数に、user-library-modifyを追加する

git clone git@github.com:spotify/web-api-auth-examples.git
cd web-api-auth-examples
npm install
node authorization_code/app.js

client_id, client_tokenが表示されるので、メモしておく

python convert_csv.py
python search_spotify_album.py

3種類ファイルが生成されます。
foundがアーティスト名、アルバム名が一致したデータ。
unmatchが、アルバム名が一致したけど、アーティスト名があわなかったデータ。
unknownが、どちらもあってないデータ。

apple-music/merge-album-list.csvファイルを作成して、spotifyに移行したいアルバム情報をそれぞれのファイルからコピペしてください。

Spotifyのアカウントにアルバムを追加する

認証したアカウントに、アルバムがまるっと追加されます

python save_spotify_album.py

おわり

import csv
import time
import spotipy
import spotipy.util as util
username = '<user_id>'
scope = 'user-library-modify'
token = util.prompt_for_user_token(username, scope)
spotify = spotipy.Spotify(auth=token)
spotify.trace_out = True
spotify.trace = True
album_list_path = 'apple-music/merge-album-list.csv'
album_list = []
with open(album_list_path) as f:
reader = csv.DictReader(f)
album_list = [row for row in reader]
print(len(album_list))
for idx in range(0, len(album_list), 30):
time.sleep(.1)
albums = album_list[idx:idx+30]
album_ids = [x.get('id') for x in albums]
result = spotify.current_user_saved_albums_add(albums=album_ids)
import csv
import time
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials
client_id = '<client_id>'
client_secret = '<client_secret>'
client_credentials_manager = spotipy.oauth2.SpotifyClientCredentials(client_id, client_secret)
spotify = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
file_path = 'apple-music/apple-music-album-list.csv'
found_albums_path = 'apple-music/album-found.csv'
unmatch_artist_path = 'apple-music/album-unmatch.csv'
unknown_album_path = 'apple-music/album-unknown.csv'
album_list = []
with open(file_path) as f:
reader = csv.DictReader(f)
album_list = [row for row in reader]
print(len(album_list))
found_album_list = []
unmatch_artist_list = []
unknown_album_list = []
for i, album in enumerate(album_list):
time.sleep(.1)
title = album.get('title')
artist = album.get('artist')
if not title:
continue
result = spotify.search(title, limit=20, type='album', market='JP')
print(f"{i}: {title} / {artist} ({result.get('albums', {}).get('total')})")
# print(result)
albums = result.get('albums', {}).get('items', [])
is_found = False
albums_by_unknown = []
unknown = []
for album in albums:
album_type = album.get('album_type')
artists = [x.get('name').lower() for x in album.get('artists', [])]
name = album.get('name')
release_date = album.get('release_date')
uri = album.get('uri')
album_item = {
'am_title': title,
'am_artist': artist,
'id': album.get('id'),
'name': name,
'artist': ' / '.join(artists),
'release_date': release_date,
'uri': uri
}
if title.lower() == name.lower():
if artist.lower() in artists:
found_album_list.append(album_item)
is_found = True
break
else:
albums_by_unknown.append(album_item)
else:
unknown.append(album_item)
if not is_found:
if len(albums_by_unknown) > 0:
unmatch_artist_list.extend(albums_by_unknown)
else:
unknown_album_list.extend(unknown)
print(len(found_album_list))
print(len(unmatch_artist_list))
print(len(unknown_album_list))
with open(found_albums_path, mode='w') as f:
writer = csv.DictWriter(f, ['am_title', 'am_artist', 'id', 'name', 'artist', 'release_date', 'uri'])
writer.writeheader()
writer.writerows(found_album_list)
with open(unmatch_artist_path, mode='w') as f:
writer = csv.DictWriter(f, ['am_title', 'am_artist', 'id', 'name', 'artist', 'release_date', 'uri'])
writer.writeheader()
writer.writerows(unmatch_artist_list)
with open(unknown_album_path, mode='w') as f:
writer = csv.DictWriter(f, ['am_title', 'am_artist', 'id', 'name', 'artist', 'release_date', 'uri'])
writer.writeheader()
writer.writerows(unknown_album_list)
import UIKit
import MediaPlayer
class AlbumItem {
var persistentID: MPMediaEntityPersistentID = 0
var title: String = ""
var artist: String = ""
var playCount: Int = 0
var playTime: TimeInterval = 0
var dateAdded: Date = Date()
var releaseDate: Date = Date()
init() {}
}
class FirstViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .yellow
let status = MPMediaLibrary.authorizationStatus()
switch status {
case .authorized:
self.completion()
break
case .notDetermined:
MPMediaLibrary.requestAuthorization { status in
if status == .authorized {
self.completion()
}
}
break
case .denied, .restricted:
break
}
}
func completion() {
let artistsQuery = MPMediaQuery.artists()
let artists = artistsQuery.collections
print("Artist: " + String(artists!.count))
let playlistsQuery = MPMediaQuery.playlists()
let playlists = playlistsQuery.collections
print("Playlist: " + String(playlists!.count))
let albumsQuery = MPMediaQuery.albums()
let albums = albumsQuery.collections
print("Album: " + String(albums!.count))
let songsQuery = MPMediaQuery.songs()
let songs = songsQuery.items
print("Song: " + String(songs!.count))
let formatter = DateFormatter()
formatter.locale = NSLocale(localeIdentifier: "ja_JP") as Locale
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
var refinedSongs = [MPMediaItem]()
var refinedAlbums = [MPMediaEntityPersistentID:AlbumItem]()
for song in songs! {
refinedSongs.append(song)
let albumPID = song.albumPersistentID
if (refinedAlbums.index(forKey: albumPID) == nil) {
let album = AlbumItem()
album.persistentID = albumPID
album.title = song.albumTitle ?? ""
album.artist = song.albumArtist ?? ""
album.dateAdded = song.dateAdded
album.releaseDate = song.releaseDate ?? Date()
refinedAlbums[albumPID] = album
}
let album = refinedAlbums[albumPID]
album?.playCount += song.playCount
album?.playTime += Double(song.playCount) * song.playbackDuration
}
refinedSongs.sort(by: {
$0.playCount > $1.playCount
})
for i in 0...9 {
let op:[String] = [String(i+1), refinedSongs[i].title ?? "", refinedSongs[i].artist ?? "", String(refinedSongs[i].playCount), formatter.string(from: refinedSongs[i].dateAdded)]
print(op.joined(separator: "/"))
}
var sortedAlbums = refinedAlbums.sorted(by: {
$0.1.playCount > $1.1.playCount
})
for obj in sortedAlbums {
let album = obj.value
let op:[String] = [album.title, album.artist, String(album.playCount), formatter.string(from: album.releaseDate), formatter.string(from: album.dateAdded)]
print(op.joined(separator: "\u{1f}"))
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment