Skip to content

Instantly share code, notes, and snippets.

@schollz
Last active February 12, 2023 21:00
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save schollz/195603b0791c044ca78b0d783d214375 to your computer and use it in GitHub Desktop.
Save schollz/195603b0791c044ca78b0d783d214375 to your computer and use it in GitHub Desktop.
Download a Spotify playlist to mp3

To get the playlist tracks, you'll first need the playlist ID. To get the playlist ID, just right-click the playlist and goto Share -> Playlist URL. The URL will be something like

https://open.spotify.com/user/X/playlist/Y?si=Z

The playlist ID you need is Y.

Take that playlist ID and goto the Spotify Developer page. At the bottom click Get Token and choose the playlist permissions, and then sign-in so it fills out your token. You'll be asked to specify the Scopes, just select the ones that have to do with playlists.

Now in the Spotify Developer page, enter in the playlist ID under playlist_id, set the limit to 100. To get the results then, just click Try It, the button at the bottom. Now you'll see a bunch of JSON below, just copy that into a file and save it as spotify_playlist.json or something.

Pre-requisites for this script:

pip install youtube-dl requests-html

And then to run

python getplaylist.py ./spotifyplaylist.json
import json
import sys
from getsong import *
if __name__ == "__main__":
playlist_json = json.load(open(sys.argv[1], "rb"))
for song in playlist_json["items"]:
try:
title = song["track"]["name"] + " " + song["track"]["artists"][0]["name"]
download_song(title)
except Exception as e:
print(e)
from __future__ import unicode_literals
from urllib.parse import quote
import json
import sys
import youtube_dl
from requests_html import HTMLSession
def find_between(s, first, last):
try:
start = s.index(first) + len(first)
end = s.index(last, start)
return s[start:end]
except ValueError:
return ""
class MyLogger(object):
def debug(self, msg):
print(msg)
pass
def warning(self, msg):
pass
def error(self, msg):
print(msg)
def my_hook(d):
print(d["status"])
if d["status"] == "finished":
print("Done downloading, now converting ...")
def download_youtube(youtubeID):
ydl_opts = {
"format": "bestaudio/best",
"postprocessors": [
{
"key": "FFmpegExtractAudio",
"preferredcodec": "mp3",
"preferredquality": "192",
}
],
"logger": MyLogger(),
"progress_hooks": [my_hook],
}
with youtube_dl.YoutubeDL(ydl_opts) as ydl:
ydl.download(["https://www.youtube.com/watch?v={}".format(youtubeID)])
def find_youtube_id(searchTerm):
session = HTMLSession()
r = session.get(
"https://www.youtube.com/results?search_query={}".format(quote(searchTerm))
)
jsonData = json.loads(
find_between(
r.text, 'ytInitialData"] =', 'window["ytInitialPlayerResponse'
).strip()[:-1]
)
ids = []
videosData = jsonData["contents"]["twoColumnSearchResultsRenderer"][
"primaryContents"
]["sectionListRenderer"]["contents"][0]["itemSectionRenderer"]["contents"]
for videoData in videosData:
description = ""
if "videoRenderer" not in videoData:
continue
if "videoId" not in videoData["videoRenderer"]:
continue
if "descriptionSnippet" not in videoData["videoRenderer"]:
continue
if "runs" not in videoData["videoRenderer"]["descriptionSnippet"]:
continue
for run in videoData["videoRenderer"]["descriptionSnippet"]["runs"]:
description += run["text"]
print(description)
if "Provided to YouTube" in description:
ids.append(videoData["videoRenderer"]["videoId"])
return ids
def download_song(song):
try:
ids = find_youtube_id(song)
if len(ids) > 0:
download_youtube(ids[0])
except Exception as e:
print(e)
if __name__ == "__main__":
download_song(sys.argv[1])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment