Skip to content

Instantly share code, notes, and snippets.

@dansleboby
Last active November 20, 2025 09:49
Show Gist options
  • Select an option

  • Save dansleboby/b8dacd07ed09dfcd851f7f42f6594136 to your computer and use it in GitHub Desktop.

Select an option

Save dansleboby/b8dacd07ed09dfcd851f7f42f6594136 to your computer and use it in GitHub Desktop.

Revisions

  1. dansleboby revised this gist May 25, 2025. No changes.
  2. dansleboby revised this gist Dec 11, 2024. 1 changed file with 4 additions and 4 deletions.
    8 changes: 4 additions & 4 deletions get_subtitle_files.js
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,7 @@
    // ==UserScript==
    // @name Suno Aligned Words Fetcher with Auth
    // @namespace http://tampermonkey.net/
    // @version 1.1
    // @version 1.2
    // @description Fetch aligned words with auth and add a button under the image on Suno pages.
    // @author Your Name
    // @match https://suno.com/song/*
    @@ -44,8 +44,8 @@

    // Function to add a button under the image
    function addButton(imageSrc, alignedWords) {
    const imageElements = document.querySelectorAll(`img[src*="${imageSrc}"]`);
    console.log(imageElements);
    const imageElements = document.querySelectorAll(`img[src*="${imageSrc}"].w-full.h-full`);
    console.log(imageSrc, imageElements);

    imageElements.forEach(function(imageElement, k) {
    console.log(k, imageElement);
    @@ -129,7 +129,7 @@
    function main() {
    const urlParts = window.location.href.split('/');
    const songId = urlParts[urlParts.length - 1]; // Get song ID from URL
    const imageSrcPattern = `suno.ai/image_large_${songId}.jpeg`;
    const imageSrcPattern = songId;

    // Get the token from the cookie
    const sessionToken = getCookie('__session');
  3. dansleboby created this gist Oct 23, 2024.
    150 changes: 150 additions & 0 deletions get_subtitle_files.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,150 @@
    // ==UserScript==
    // @name Suno Aligned Words Fetcher with Auth
    // @namespace http://tampermonkey.net/
    // @version 1.1
    // @description Fetch aligned words with auth and add a button under the image on Suno pages.
    // @author Your Name
    // @match https://suno.com/song/*
    // @grant none
    // ==/UserScript==

    (function() {
    'use strict';
    const file_type = "lrc"; // lrc ou srt

    // Helper function to get the value of a cookie by name
    function getCookie(name) {
    const value = `; ${document.cookie}`;
    const parts = value.split(`; ${name}=`);
    if (parts.length === 2) return parts.pop().split(';').shift();
    }

    // Helper function to fetch aligned words data with Bearer token
    async function fetchAlignedWords(songId, token) {
    const apiUrl = `https://studio-api.prod.suno.com/api/gen/${songId}/aligned_lyrics/v2/`;
    try {
    const response = await fetch(apiUrl, {
    method: 'GET',
    headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
    }
    });
    const data = await response.json();
    if (data && data.aligned_words) {
    console.log('Aligned words:', data.aligned_words);
    return data.aligned_words;
    } else {
    console.error('No aligned words found.');
    }
    } catch (error) {
    console.error('Error fetching aligned words:', error);
    }
    }

    // Function to add a button under the image
    function addButton(imageSrc, alignedWords) {
    const imageElements = document.querySelectorAll(`img[src*="${imageSrc}"]`);
    console.log(imageElements);

    imageElements.forEach(function(imageElement, k) {
    console.log(k, imageElement);
    if (imageElement) {
    const button = document.createElement('button');
    button.innerText = 'Download '+file_type;
    button.style.marginTop = '10px';
    button.style.zIndex = '9999';
    button.style.position = 'absolute';
    button.style.bottom = '0';
    button.style.left = '0';
    button.style.right = '0';
    button.style.background = 'gray';
    button.style.borderRadius = '5px';
    button.style.padding = '10px 6px';

    button.addEventListener('click', () => {
    const srtContent = file_type === 'srt' ? convertToSRT(alignedWords) : convertToLRC(alignedWords);
    const blob = new Blob([srtContent], { type: 'text/'+file_type });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'aligned_words.'+file_type;
    a.click();
    URL.revokeObjectURL(url); // Clean up the URL object
    });

    imageElement.parentNode.appendChild(button);
    } else {
    console.error('Image not found.');
    }
    });
    }

    // Function to convert aligned words to SRT format
    function convertToSRT(alignedWords) {
    let srtContent = '';
    alignedWords.forEach((wordObj, index) => {
    const startTime = formatTime(wordObj.start_s);
    const endTime = formatTime(wordObj.end_s);
    srtContent += `${index + 1}\n`;
    srtContent += `${startTime} --> ${endTime}\n`;
    srtContent += `${wordObj.word}\n\n`;
    });
    return srtContent;
    }

    // Helper function to format time into SRT format (HH:MM:SS,MS)
    function formatTime(seconds) {
    const date = new Date(0);
    date.setMilliseconds(seconds * 1000); // Convert seconds to milliseconds
    const hours = String(date.getUTCHours()).padStart(2, '0');
    const minutes = String(date.getUTCMinutes()).padStart(2, '0');
    const secs = String(date.getUTCSeconds()).padStart(2, '0');
    const milliseconds = String(date.getUTCMilliseconds()).padStart(3, '0');
    return `${hours}:${minutes}:${secs},${milliseconds}`;
    }

    // Function to convert aligned words to LRC format
    function convertToLRC(alignedWords) {
    let lrcContent = '';
    alignedWords.forEach(wordObj => {
    const time = formatLrcTime(wordObj.start_s);
    lrcContent += `${time}${wordObj.word}\n`;
    });
    return lrcContent;
    }

    // Helper function to format time into LRC format [mm:ss.xx]
    function formatLrcTime(seconds) {
    const date = new Date(0);
    date.setMilliseconds(seconds * 1000); // Convert seconds to milliseconds
    const minutes = String(date.getUTCMinutes()).padStart(2, '0');
    const secs = String(date.getUTCSeconds()).padStart(2, '0');
    const hundredths = String(Math.floor(date.getUTCMilliseconds() / 10)).padStart(2, '0'); // Convert milliseconds to hundredths of a second
    return `[${minutes}:${secs}.${hundredths}]`;
    }


    // Main function to run the script
    function main() {
    const urlParts = window.location.href.split('/');
    const songId = urlParts[urlParts.length - 1]; // Get song ID from URL
    const imageSrcPattern = `suno.ai/image_large_${songId}.jpeg`;

    // Get the token from the cookie
    const sessionToken = getCookie('__session');
    if (!sessionToken) {
    console.error('Session token not found in cookies.');
    return;
    }

    // Fetch aligned words and add the button
    fetchAlignedWords(songId, sessionToken).then((alignedWords) => {
    if (alignedWords) {
    addButton(imageSrcPattern, alignedWords);
    }
    });
    }

    setTimeout(function() { main(); }, 5000);
    })();