You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Updated the script to use sorting and DictReader. Not clean code but works. Was considering making async too for speed, this has been running for 3 days lol. But i have like 10k songs so yk. This sorts by date, oldest first added in playlist.
fromsysimportargvimportcsvimporturllib.parse, urllib.requestimportjsonfromtimeimportsleepimportrequestsimportos# Checking if the command is correctiflen(argv) >1andargv[1]:
passelse:
print(
"\nCommand usage:\npython3 convertsongs.py yourplaylist.csv\nMore info at https://github.com/therealmarius/Spotify-2-AppleMusic"
)
exit()
# Function to get contents of file if it existsdefget_connection_data(f, prompt):
ifos.path.exists(f):
withopen(f, "r") asfile:
returnfile.read().rstrip("\n")
else:
returninput(prompt)
defcreate_apple_music_playlist(session, playlist_name):
url="https://amp-api.music.apple.com/v1/me/library/playlists"data= {
"attributes": {
"name": playlist_name,
"description": "A new playlist created via API",
}
}
# test if playlist exists and create it if notresponse=session.get(url)
ifresponse.status_code==200:
forplaylistinresponse.json()["data"]:
ifplaylist["attributes"]["name"] ==playlist_name:
print(f"Playlist {playlist_name} already exists!")
returnplaylist["id"]
response=session.post(url, json=data)
ifresponse.status_code==201:
sleep(1.5)
returnresponse.json()["data"][0]["id"]
else:
raiseException(
f"Error {response.status_code} while creating playlist {playlist_name}!"
)
returnNone# Getting user's data for the connectiontoken=get_connection_data(
"token.dat", "\nPlease enter your Apple Music Authorization (Bearer token):\n"
)
media_user_token=get_connection_data(
"media_user_token.dat", "\nPlease enter your media user token:\n"
)
cookies=get_connection_data("cookies.dat", "\nPlease enter your cookies:\n")
# playlist_identifier = input("\nPlease enter the playlist identifier:\n")# function to escape apostrophesdefescape_apostrophes(s):
returns.replace("'", "\\'")
# Function to get the iTunes ID of a songdefget_itunes_id(title, artist, album):
BASE_URL="https://itunes.apple.com/search?country=FR&media=music&entity=song&limit=5&term="# Search the iTunes catalog for a songtry:
# Search for the title + artist + albumurl=BASE_URL+urllib.parse.quote(title+" "+artist+" "+album)
request=urllib.request.Request(url)
response=urllib.request.urlopen(request)
data=json.loads(response.read().decode("utf-8"))
# If no result, search for the title + artistifdata["resultCount"] ==0:
url=BASE_URL+urllib.parse.quote(title+" "+artist)
request=urllib.request.Request(url)
response=urllib.request.urlopen(request)
data=json.loads(response.read().decode("utf-8"))
# If no result, search for the title + albumifdata["resultCount"] ==0:
url=BASE_URL+urllib.parse.quote(title+" "+album)
request=urllib.request.Request(url)
response=urllib.request.urlopen(request)
data=json.loads(response.read().decode("utf-8"))
# If no result, search for the titleifdata["resultCount"] ==0:
url=BASE_URL+urllib.parse.quote(title)
request=urllib.request.Request(url)
response=urllib.request.urlopen(request)
data=json.loads(response.read().decode("utf-8"))
except:
returnprint("An error occured with the request.")
# Try to match the song with the resultstry:
response=urllib.request.urlopen(request)
data=json.loads(response.read().decode("utf-8"))
foreachindata["results"]:
# Trying to match with the exact track name, the artist name and the album nameif (
each["trackName"].lower() ==title.lower()
andeach["artistName"].lower() ==artist.lower()
andeach["collectionName"].lower() ==album.lower()
):
returneach["trackId"]
# Trying to match with the exact track name and the artist nameelif (
each["trackName"].lower() ==title.lower()
andeach["artistName"].lower() ==artist.lower()
):
returneach["trackId"]
# Trying to match with the exact track name and the album nameelif (
each["trackName"].lower() ==title.lower()
andeach["collectionName"].lower() ==album.lower()
):
returneach["trackId"]
# Trying to match with the exact track name and the artist name, in the case artist name are different between Spotify and Apple Musicelifeach["trackName"].lower() ==title.lower() and (
each["artistName"].lower() inartist.lower()
orartist.lower() ineach["artistName"].lower()
):
returneach["trackId"]
# Trying to match with the exact track name and the album name, in the case album name are different between Spotify and Apple Musicelifeach["trackName"].lower() ==title.lower() and (
each["collectionName"].lower() inalbum.lower()
oralbum.lower() ineach["collectionName"].lower()
):
returneach["trackId"]
# Trying to match with the exact track nameelifeach["trackName"].lower() ==title.lower():
returneach["trackId"]
# Trying to match with the track name, in the case track name are different between Spotify and Apple Musicelif (
title.lower() ineach["trackName"]
oreach["trackName"].lower() intitle.lower()
):
returneach["trackId"]
try:
# If no result, return the first resultreturndata["results"][0]["trackId"]
except:
# If no result, return NonereturnNoneexcept:
# The error is handled later in the codereturnNone# Function to add a song to a playlistdefadd_song_to_playlist(session, song_id, playlist_id, playlist_name):
try:
request=session.post(
f"https://amp-api.music.apple.com/v1/me/library/playlists/{playlist_id}/tracks",
json={"data": [{"id": f"{song_id}", "type": "songs"}]},
)
# Checking if the request is successfulifrequests.codes.ok:
print(f"Song {song_id} added to playlist {playlist_name}!")
returnTrue# If not, print the error codeelse:
print(
f"Error {request.status_code} while adding song {song_id} to playlist {playlist_name}!"
)
returnFalseexcept:
print(
f"HOST ERROR: Apple Music might have blocked the connection during the add of {song_id} to playlist {playlist_name}!\nPlease wait a few minutes and try again.\nIf the problem persists, please contact the developer."
)
returnFalsedefget_playlist_track_ids(session, playlist_id):
# test if song is already in playlisttry:
response=session.get(
f"https://amp-api.music.apple.com/v1/me/library/playlists/{playlist_id}/tracks"
)
ifresponse.status_code==200:
# print(response.json()['data'])return [
track["attributes"]["playParams"]["catalogId"]
fortrackinresponse.json()["data"]
]
elifresponse.status_code==404:
return []
else:
raiseException(
f"Error {response.status_code} while getting playlist {playlist_id}!"
)
returnNoneexcept:
raiseException(f"Error while getting playlist {playlist_id}!")
returnNonefromdatetimeimportdatetimedefparse_date(date_string):
returndatetime.strptime(date_string, "%Y-%m-%dT%H:%M:%SZ")
# Opening sessiondefcreate_playlist_and_add_song(file):
withrequests.Session() ass:
s.headers.update(
{
"Authorization": f"{token}",
"media-user-token": f"{media_user_token}",
"Cookie": f"{cookies}".encode("utf-8"),
"Host": "amp-api.music.apple.com",
"Accept-Encoding": "gzip, deflate, br",
"Referer": "https://music.apple.com/",
"Origin": "https://music.apple.com",
"Content-Length": "45",
"Connection": "keep-alive",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-site",
"TE": "trailers",
}
)
# Getting the playlist nameplaylist_name=os.path.basename(file)
playlist_name=playlist_name.split(".")
playlist_name=playlist_name[0]
playlist_name=playlist_name.replace("_", " ")
playlist_identifier=create_apple_music_playlist(s, playlist_name)
playlist_track_ids=get_playlist_track_ids(s, playlist_identifier)
print(playlist_track_ids)
# Opening the inputed CSV filewithopen(str(file), encoding="utf-8") asfile:
data=list(csv.DictReader(file))
data.sort(key=lambdarow: parse_date(row["Added At"]))
converted=0failed=0n=0forn, rowinenumerate(data):
# Trying to get the iTunes ID of the songtitle, artist, album= (
escape_apostrophes(row["Track Name"]),
escape_apostrophes(row["Artist Name(s)"]),
escape_apostrophes(row["Album Name"]),
)
track_id=get_itunes_id(title, artist, album)
# If the song is found, add it to the playlistiftrack_id:
ifstr(track_id) inplaylist_track_ids:
print(f"\nN°{n} | {title} | {artist} | {album} => {track_id}")
print(f"Song {track_id} already in playlist {playlist_name}!")
failed+=1continueprint(f"\nN°{n} | {title} | {artist} | {album} => {track_id}")
sleep(0.5)
ifadd_song_to_playlist(s, track_id, playlist_identifier, playlist_name):
converted+=1else:
failed+=1# If not, write it in a fileelse:
print(f"N°{n} | {title} | {artist} | {album} => NOT FOUND")
withopen(f"{playlist_name}_noresult.txt", "a+", encoding="utf-8") asf:
f.write(f"{title} | {artist} | {album} => NOT FOUND")
f.write("\n")
failed+=1sleep(1.5)
# Printing the stats reportconverted_percentage=round(converted/n*100) ifn>0else100print(
f"\n - STAT REPORT -\nPlaylist Songs: {n}\nConverted Songs: {converted}\nFailed Songs: {failed}\nPlaylist converted at {converted_percentage}%"
)
if__name__=="__main__":
iflen(argv) >1andargv[1]:
if".csv"inargv[1]:
create_playlist_and_add_song(argv[1])
else:
# get all csv files in the directory argv[1]files= [
fforfinos.listdir(argv[1])
ifos.path.isfile(os.path.join(argv[1], f))
]
# loop through all csv filesforfileinfiles:
if".csv"infile:
create_playlist_and_add_song(os.path.join(argv[1], file))
# Developped by @therealmarius on GitHub# Based on the work of @simonschellaert on GitHub# Github project page: https://github.com/therealmarius/Spotify-2-AppleMusic
The text was updated successfully, but these errors were encountered:
Updated the script to use sorting and DictReader. Not clean code but works. Was considering making async too for speed, this has been running for 3 days lol. But i have like 10k songs so yk. This sorts by date, oldest first added in playlist.
The text was updated successfully, but these errors were encountered: