Greasy Fork is available in English.

Soundcloud - Add External Download Button

adds a button on main page and song page to download song automatically from https://soundcloudmp3.org/

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         Soundcloud - Add External Download Button
// @namespace    https://zachhardesty.com
// @author       Zach Hardesty <[email protected]> (https://github.com/zachhardesty7)
// @description  adds a button on main page and song page to download song automatically from https://soundcloudmp3.org/
// @copyright    2019-2026, Zach Hardesty (https://zachhardesty.com/)
// @license      GPL-3.0-only; http://www.gnu.org/licenses/gpl-3.0.txt
// @version      2.2.1

// @homepageURL  https://github.com/zachhardesty7/tamper-monkey-scripts-collection/raw/master/soundcloud-download-button.user.js
// @homepage     https://github.com/zachhardesty7/tamper-monkey-scripts-collection/raw/master/soundcloud-download-button.user.js
// @homepageURL  https://openuserjs.org/scripts/zachhardesty7/Soundcloud_-_Add_External_Download_Button
// @homepage     https://openuserjs.org/scripts/zachhardesty7/Soundcloud_-_Add_External_Download_Button
// @supportURL   https://github.com/zachhardesty7/tamper-monkey-scripts-collection/issues


// @match        https://soundcloud.com/*
// @match        https://loader.to/*
// @require      https://update.greatest.deepsurf.us/scripts/419640/1776135/onElementReady.js
// ==/UserScript==

/* global onElementReady */

// #region - test page links (to add external download button to)
// song: https://soundcloud.com/user-342593999-672340495/the-quietude
// song (w/ existing download icon): https://soundcloud.com/neilcic/mouth-sounds
// profile (w/ sets, w/ & w/o existing download icon): https://soundcloud.com/noisia
// set: https://soundcloud.com/noisia/sets/the-resonance-vii
// feed: https://soundcloud.com/feed
// #endregion

const SELECTOR_SONG_LIST_ITEM = ".soundList__item"
// FIXME: triggers twice for some reason, but still seems to work fine
const SELECTOR_SONG_PAGE = ".listenEngagement__footer"

/**
 * adds button to soundcloud
 *
 * @param {HTMLElement} el - most recently added children (for lazy load)
 */
function addSoundcloudDownloadButton(el) {
  const link = window.location.href
  let songLink = link
  const button = document.createElement("button")
  button.textContent = "External Download"

  // if on soundcloud home feed and song node is not a playlist, append small SC styled button
  if (
    el.matches(SELECTOR_SONG_LIST_ITEM) &&
    !(
      /** @type {HTMLAnchorElement | null} */ (
        el.querySelector(".soundTitle__title")
      )?.href.includes("/sets/")
    )
  ) {
    button.className = "mp3-button sc-button sc-button-small"
    el.querySelector(".soundActions .sc-button-group")?.append(button)
    songLink =
      /** @type {HTMLAnchorElement | null} */ (el.querySelector(".soundTitle__title"))
        ?.href || link

    // else if on individual song page (and not playlist), append SC styled button
  } else if (
    el.matches(SELECTOR_SONG_PAGE) &&
    (!link.includes("/sets/") || link.includes("?in="))
  ) {
    const toolbar = document.querySelector(".soundActions div:first-child")
    button.className = "mp3-button sc-button sc-button-medium"
    toolbar?.append(button)
  }

  el.querySelector(".mp3-button")?.addEventListener("click", () => {
    window.open(`https://loader.to/?link=${songLink}&f=1&s=1&e=1&r=ddownr`, "_blank")
  })
}

function mp3() {
  const { href } = window.location
  if (href.includes("loader.to")) {
    // auto-run download when page loads soundcloud mp3
    onElementReady(
      "#ds .card .section:last-of-type > progress",
      { findOnce: false },
      (progress) => {
        const timer = setInterval(() => {
          if (!(progress instanceof HTMLProgressElement)) {
            clearInterval(timer)
            throw new TypeError("soundcloud-download-button: expected progress element")
          }

          if (progress.value === 1000) {
            /** @type {HTMLAnchorElement | null} */
            const button = document.querySelector("#ds .card .section:last-of-type > a")
            button?.click()
            clearInterval(timer)
          }
        }, 100)
      },
    )
  } else {
    onElementReady(
      `:is(${SELECTOR_SONG_LIST_ITEM}, ${SELECTOR_SONG_PAGE})`,
      { findOnce: true },
      addSoundcloudDownloadButton,
    )
  }
}

mp3()