Skip to content

Instantly share code, notes, and snippets.

@FGRibreau
Created June 24, 2024 20:03
Show Gist options
  • Save FGRibreau/420b5da7289969e5746298356a49423c to your computer and use it in GitHub Desktop.
Save FGRibreau/420b5da7289969e5746298356a49423c to your computer and use it in GitHub Desktop.
Download all Suno (app.suno.ai) songs displayed on a page
// open your javascript console and paste this
copy([...$('[role="grid"]')[Object.keys($('[role="grid"]')).filter(x => x.startsWith('__reactProps'))[0]].children[0].props.values[0][1].collection].filter(x => x.value.audio_url).map(x => x.value.audio_url).join(' '))
// now you have a list of mp3 urls directly in your clipboard that you can pass to wget or a url downloader
@smontlouis
Copy link

thanks !

@gadelkareem
Copy link

gadelkareem commented Sep 12, 2024

Modified it a bit to download the video and rename the file:

//  open your javascript console and paste this
copy([...$('[role="grid"]')[Object.keys($('[role="grid"]')).filter(x => x.startsWith('__reactProps'))[0]].children[0].props.values[0][1].collection]
  .filter(x => x.value.audio_url || x.value.video_url)
  .map(x => {
    const title = x.value.title.trim() || x.value.id ;
    const audio = x.value.audio_url ? `${title}.mp3|${x.value.audio_url}` : '';
    const video = x.value.video_url ? `${title}.mp4|${x.value.video_url}` : '';
    return [audio, video].filter(Boolean).join("\n");
  })
  .join("\n")
)
// now you have a list of mp3 urls directly in your clipboard that you can pass to wget or a url downloader

Script to download and rename

# Usage: python suno-downloader.py <path-to-js-output-file>
import requests
import os
import sys

def download_file(url, filename):
    response = requests.get(url, stream=True)
    response.raise_for_status()
    with open(filename, 'wb') as file:
        for chunk in response.iter_content(chunk_size=8192):
            file.write(chunk)

def main():
    js_file = sys.argv[1]
    with open(js_file, 'r') as file:
        js_output = file.read()


    # Split the input string into individual file entries
    file_entries = js_output.split("\n")

    # Create a directory to store the downloaded files
    if not os.path.exists('downloads'):
        os.makedirs('downloads')

    names = ()
    # Process each file entry
    for entry in file_entries:
        try:
            i = 0
            print(f"Processing: {entry}")
            filename, url = entry.split('|')
            print(f"Downloading: {filename}")
            org_name =  os.path.splitext(filename)[0]
            ext = os.path.splitext(filename)[1]
            # make sure the file name is unique
            while filename in names:
                i += 1
                name = org_name + "_" + str(i)
                filename = name + ext

            names = names + (filename,)




            download_file(url, os.path.join('downloads', filename))
            print(f"Successfully downloaded: {filename}")
        except Exception as e:
            print(f"Failed to download {entry}. Error: {str(e)}")

    print("Download process completed.")

if __name__ == "__main__":
    main()

@SurfingTurtles
Copy link

SurfingTurtles commented Sep 16, 2024

@gadelkareem Hi! I've figured out how to do the console part and get the filename/url combo list in my clipboard, but how do I then use the .py code to finish the task? I'm using IDLE on Mac to place the .py but am not sure how the clipboard text connects to the .py part.

@gadelkareem
Copy link

@SurfingTurtles Put the coppied text inside a txt file then run the python python3 suno-downloader.py output.txt

@Godjiro
Copy link

Godjiro commented Oct 12, 2024

@SurfingTurtles Put the coppied text inside a txt file then run the python python3 suno-downloader.py output.txt

Can not figure, what name the txt file should be? I created file output.txt - i got answer [Errno 2] No such file or directory
Where to get "suno-downloader"? or smth?

@gadelkareem
Copy link

rename the text file you created to suno-downloader.py and make sure to install python

@jagamypriera
Copy link

jagamypriera commented Nov 12, 2024

Here is a script to download and rename files in Bash.

#!/bin/bash

# Read the file line by line
while IFS="|" read -r filename url; do
    # Use curl to download the file
    curl -o "$filename" "$url"

    # Wait for 1 second
    sleep 1
done < input.txt

@M1XZG
Copy link

M1XZG commented Feb 11, 2025

I'd like to offer an updated js snippet to the work done by @gadelkareem , this one will handle the renaming of multiple song names. Don't we all just love how SUNO always spends double our credits making 2 songs fo every prompt.

I found the original code above was a bit problematic because it would try to name the songs the same which doesn't work well when bulk downloading.

This code will give multiple songs of the same name a number such as songname_2, songname_3 etc. The first song name is untouched.

Example:

Virtual Rainfall.mp3|https://cdn1.suno.ai/b75f73f7-e535-4e40-982b-b59342ac1291.mp3
Virtual Rainfall.mp4|https://cdn1.suno.ai/b75f73f7-e535-4e40-982b-b59342ac1291.mp4
Virtual Rainfall_2.mp3|https://cdn1.suno.ai/923ea8f2-bcfa-4c19-b75e-1218618fde52.mp3
Virtual Rainfall_2.mp4|https://cdn1.suno.ai/923ea8f2-bcfa-4c19-b75e-1218618fde52.mp4
// open your javascript console and paste this
copy([...$('[role="grid"]')[Object.keys($('[role="grid"]')).filter(x => x.startsWith('__reactProps'))[0]].children[0].props.values[0][1].collection]
  .filter(x => x.value.audio_url || x.value.video_url)
  .reduce((acc, x) => {
    const title = x.value.title.trim() || x.value.id;
    acc.titles[title] = (acc.titles[title] || 0) + 1;
    const uniqueTitle = acc.titles[title] > 1 ? `${title}_${acc.titles[title]}` : title;
    const audio = x.value.audio_url ? `${uniqueTitle}.mp3|${x.value.audio_url}` : '';
    const video = x.value.video_url ? `${uniqueTitle}.mp4|${x.value.video_url}` : '';
    acc.urls.push([audio, video].filter(Boolean).join("\n"));
    return acc;
  }, { urls: [], titles: {} }).urls.join("\n")
)
// now you have a list of mp3 urls directly in your clipboard that you can pass to wget or a url downloader

I hope this helps.

@M1XZG
Copy link

M1XZG commented Feb 11, 2025

If you want a slightly improved download script that @jagamypriera created, this one will let you specify any input file you like but it also handles duplicate filenames by appending a number to the song name.

example:

Stardust Reverberation.mp3
Stardust Reverberation.mp4
Stardust Reverberation_2.mp3
Stardust Reverberation_2.mp4
#!/bin/bash

# Check if the input file is provided
if [ -z "$1" ]; then
    echo "Usage: $0 <input_file>"
    exit 1
fi

input_file="$1"

# Read the file line by line
while IFS="|" read -r filename url; do
    # Check if the file already exists
    if [[ -e "$filename" ]]; then
        base="${filename%.*}"
        ext="${filename##*.}"
        counter=2
        while [[ -e "${base}_${counter}.${ext}" ]]; do
            ((counter++))
        done
        filename="${base}_${counter}.${ext}"
    fi

    # Print the song name being downloaded
    echo "Downloading $filename"

    # Use curl to download the file
    curl -o "$filename" "$url"

    # Wait for 1 second
    sleep 1
done < "$input_file"

I hope this helps someone.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment