Greasy Fork 支持简体中文。

Epidemic Sound Downloader

Unlocks the Trial banner and enables the download button functionality.

// ==UserScript==
// @name         Epidemic Sound Downloader
// @description  Unlocks the Trial banner and enables the download button functionality.
// @icon         https://www.epidemicsound.com/staticfiles/legacy/20/images/es-favicon.png
// @version      1.0
// @author       afkarxyz
// @namespace    https://github.com/afkarxyz/misc-scripts/
// @supportURL   https://github.com/afkarxyz/misc-scripts/issues
// @license      MIT
// @match        https://www.epidemicsound.com/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    const downloadedURLs = new Set();
    let isDownloadInProgress = false;
    let lastClickedTrackInfo = null;
    let mp3UrlFound = null;

    const enforceScrollbar = () => {
        const style = document.createElement('style');
        style.textContent = `
            html, body {
                overflow: auto !important;
            }
            ::-webkit-scrollbar {
                display: block !important;
            }
        `;
        document.head.appendChild(style);
    };

    const hideBackdrop = () => {
        document.querySelectorAll("[class*='_backdrop_']").forEach((element) => {
            element.style.display = 'none';
        });
    };

    enforceScrollbar();
    hideBackdrop();

    const bannerObserver = new MutationObserver(() => {
        enforceScrollbar();
        hideBackdrop();
    });

    bannerObserver.observe(document.body, { childList: true, subtree: true });

    const networkObserver = new PerformanceObserver((list) => {
        list.getEntries().forEach((entry) => {
            if (entry.name.toLowerCase().endsWith('.mp3') && !downloadedURLs.has(entry.name)) {
                mp3UrlFound = entry.name;

                if (isDownloadInProgress && lastClickedTrackInfo) {
                    handleDownload(entry.name, lastClickedTrackInfo);
                    downloadedURLs.add(entry.name);
                }
            }
        });
    });

    networkObserver.observe({ entryTypes: ['resource'] });

    function getAllTags(trackRow) {
        const tagsContainers = trackRow.querySelectorAll('._tagsContainer_1bq37_13');
        const allTags = [];

        tagsContainers.forEach(container => {
            const tagElements = container.querySelectorAll('._tag_1bq37_13 span');
            tagElements.forEach(tag => {
                const tagText = tag.textContent.trim();
                if (tagText) {
                    allTags.push(tagText);
                }
            });
        });

        return allTags;
    }

    function getTrackInfo(trackRow) {
        const titleElement = trackRow.querySelector('._title_1kwly_6 a');
        const tags = getAllTags(trackRow);

        return {
            title: titleElement ? titleElement.textContent.trim() : '',
            tags: tags
        };
    }

    function setupDownloadButtons() {
        document.querySelectorAll('[aria-label="Download"]').forEach(button => {
            if (button.dataset.initialized) return;
            button.dataset.initialized = 'true';

            button.addEventListener('click', function(e) {
                const trackRow = this.closest('[data-cy-trackrow="true"]');

                if (trackRow) {
                    lastClickedTrackInfo = getTrackInfo(trackRow);
                    isDownloadInProgress = true;

                    if (mp3UrlFound && !downloadedURLs.has(mp3UrlFound)) {
                        handleDownload(mp3UrlFound, lastClickedTrackInfo);
                        downloadedURLs.add(mp3UrlFound);
                    } else {
                        const playButton = trackRow.querySelector('[title="Play"]');
                        if (playButton) {
                            playButton.click();
                        }

                        setTimeout(() => {
                            if (isDownloadInProgress) {
                                isDownloadInProgress = false;
                                lastClickedTrackInfo = null;
                            }
                        }, 5000);
                    }
                }
            });
        });
    }

    function setupPlayButtons() {
        document.querySelectorAll('[title="Play"]').forEach(button => {
            if (button.dataset.initialized) return;
            button.dataset.initialized = 'true';

            button.addEventListener('click', function(e) {
                const trackRow = this.closest('[data-cy-trackrow="true"]');
                if (trackRow) {
                    lastClickedTrackInfo = getTrackInfo(trackRow);
                    mp3UrlFound = null;
                }
            });
        });
    }

    async function handleDownload(url, trackInfo) {
        try {
            const response = await fetch(url);
            const blob = await response.blob();
            const link = document.createElement('a');
            link.href = URL.createObjectURL(blob);

            const tagsString = trackInfo.tags.join(', ');
            const filename = `${tagsString} - ${trackInfo.title}.mp3`;
            link.download = filename;

            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);

            URL.revokeObjectURL(link.href);
            isDownloadInProgress = false;
            lastClickedTrackInfo = null;
            mp3UrlFound = null;
        } catch (error) {
            isDownloadInProgress = false;
            lastClickedTrackInfo = null;
            mp3UrlFound = null;
        }
    }

    const buttonObserver = new MutationObserver(() => {
        setupDownloadButtons();
        setupPlayButtons();
    });

    buttonObserver.observe(document.body, { childList: true, subtree: true });

    setupDownloadButtons();
    setupPlayButtons();
})();