SampleFocus Direct API Downloader

Download samples from SampleFocus without using credits by accessing the API directly

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         SampleFocus Direct API Downloader
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Download samples from SampleFocus without using credits by accessing the API directly
// @author       You
// @match        https://samplefocus.com/samples/*
// @grant        GM_addStyle
// @grant        GM_xmlhttpRequest
// @connect      *
// @run-at       document-idle
// ==/UserScript==

(function() {
    'use strict';

    // Add custom CSS for our download button
    GM_addStyle(`
        .api-download-btn {
            background-color: #4CAF50;
            color: white;
            padding: 10px 15px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-weight: bold;
            margin-right: 10px;
            display: inline-block;
        }
        .api-download-btn:hover {
            background-color: #45a049;
        }
        #download-status {
            margin-top: 10px;
            padding: 10px;
            border-radius: 4px;
            display: none;
        }
        .status-success {
            background-color: #dff0d8;
            color: #3c763d;
        }
        .status-error {
            background-color: #f2dede;
            color: #a94442;
        }
        .status-info {
            background-color: #d9edf7;
            color: #31708f;
        }
        #debug-info {
            margin-top: 10px;
            padding: 10px;
            background-color: #f5f5f5;
            border: 1px solid #ddd;
            border-radius: 4px;
            font-family: monospace;
            font-size: 12px;
            white-space: pre-wrap;
            display: none;
        }
    `);

    // Function to extract sample ID from URL
    function getSampleIdFromURL() {
        const path = window.location.pathname;
        const match = path.match(/\/samples\/([^\/]+)/);
        return match ? match[1] : null;
    }

    // Function to extract sample name from URL
    function getSampleNameFromURL() {
        const path = window.location.pathname;
        const parts = path.split('/');
        const sampleName = parts[parts.length - 1] || 'sample';
        return sampleName.replace(/-/g, '_');
    }

    // Function to create a status message element
    function createStatusElement() {
        const statusElement = document.createElement('div');
        statusElement.id = 'download-status';
        return statusElement;
    }

    // Function to create a debug info element
    function createDebugElement() {
        const debugElement = document.createElement('div');
        debugElement.id = 'debug-info';
        return debugElement;
    }

    // Function to show status message
    function showStatus(message, type = 'success') {
        const statusElement = document.getElementById('download-status') || createStatusElement();
        statusElement.textContent = message;

        // Remove all status classes
        statusElement.classList.remove('status-success', 'status-error', 'status-info');

        // Add appropriate class
        switch(type) {
            case 'error':
                statusElement.classList.add('status-error');
                break;
            case 'info':
                statusElement.classList.add('status-info');
                break;
            default:
                statusElement.classList.add('status-success');
        }

        statusElement.style.display = 'block';

        // If not already in the DOM, add it
        if (!document.getElementById('download-status')) {
            const downloadButton = document.querySelector('.api-download-btn');
            if (downloadButton && downloadButton.parentNode) {
                downloadButton.parentNode.appendChild(statusElement);
            }
        }
    }

    // Function to show debug info
    function showDebugInfo(info) {
        let debugElement = document.getElementById('debug-info');
        if (!debugElement) {
            debugElement = createDebugElement();
            const statusElement = document.getElementById('download-status');
            if (statusElement && statusElement.parentNode) {
                statusElement.parentNode.appendChild(debugElement);
            }
        }

        debugElement.textContent = typeof info === 'object' ? JSON.stringify(info, null, 2) : info;
        debugElement.style.display = 'block';
    }

    // Function to extract audio source from the page
    function extractAudioSource() {
        // Try to get the audio source from the audio element
        const audioElement = document.querySelector('audio');
        if (audioElement && audioElement.src) {
            return audioElement.src;
        }

        // Try to find it in the page's HTML
        const pageHtml = document.documentElement.outerHTML;

        // Look for audio URLs in script tags (often contains player configuration)
        const scriptTags = document.querySelectorAll('script');
        for (const script of scriptTags) {
            if (script.textContent) {
                const urlMatch = script.textContent.match(/"(https?:\/\/[^"]+\.(mp3|wav|ogg))"/i);
                if (urlMatch && urlMatch[1]) {
                    return urlMatch[1];
                }
            }
        }

        // Look for audio URLs in the page HTML
        const audioUrlMatch = pageHtml.match(/(https?:\/\/[^"']+\.(mp3|wav|ogg))/i);
        if (audioUrlMatch && audioUrlMatch[1]) {
            return audioUrlMatch[1];
        }

        return null;
    }

    // Function to get the download URL directly from the API
    function getDownloadUrlFromAPI() {
        const sampleId = getSampleIdFromURL();
        if (!sampleId) {
            showStatus('Could not determine the sample ID from the URL.', 'error');
            return Promise.reject('No sample ID found');
        }

        showStatus('Fetching download URL from API...', 'info');

        // Construct the API URL
        const apiUrl = `https://samplefocus.com/api/samples/${sampleId}/play`;

        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: 'GET',
                url: apiUrl,
                headers: {
                    'Accept': 'application/json',
                    'X-Requested-With': 'XMLHttpRequest'
                },
                onload: function(response) {
                    try {
                        if (response.status === 200) {
                            const data = JSON.parse(response.responseText);
                            showDebugInfo(data);

                            if (data && data.url) {
                                resolve(data.url);
                            } else {
                                showStatus('API response did not contain a download URL.', 'error');
                                reject('No URL in API response');
                            }
                        } else {
                            showStatus(`API request failed with status: ${response.status}`, 'error');
                            reject(`API request failed: ${response.statusText}`);
                        }
                    } catch (error) {
                        showStatus(`Error parsing API response: ${error.message}`, 'error');
                        reject(`Parse error: ${error.message}`);
                    }
                },
                onerror: function(error) {
                    showStatus('Error making API request.', 'error');
                    reject(`API request error: ${error.error}`);
                }
            });
        });
    }

    // Function to download audio using GM_xmlhttpRequest
    function downloadAudio(url) {
        showStatus(`Downloading audio from: ${url}`, 'info');

        GM_xmlhttpRequest({
            method: 'GET',
            url: url,
            responseType: 'blob',
            headers: {
                'Referer': 'https://samplefocus.com/',
                'Origin': 'https://samplefocus.com'
            },
            onload: function(response) {
                if (response.status === 200) {
                    // Create a blob URL from the response
                    const blob = response.response;
                    const blobUrl = URL.createObjectURL(blob);

                    // Determine file extension from MIME type or URL
                    let fileExtension = 'mp3';
                    if (blob.type.includes('wav')) {
                        fileExtension = 'wav';
                    } else if (blob.type.includes('ogg')) {
                        fileExtension = 'ogg';
                    }

                    // Create a download link
                    const a = document.createElement('a');
                    a.href = blobUrl;
                    a.download = getSampleNameFromURL() + '.' + fileExtension;
                    document.body.appendChild(a);
                    a.click();

                    // Clean up
                    setTimeout(() => {
                        document.body.removeChild(a);
                        URL.revokeObjectURL(blobUrl);
                    }, 100);

                    showStatus('Download completed! Check your downloads folder.');
                } else {
                    showStatus(`Failed to download audio: ${response.status} ${response.statusText}`, 'error');
                    showDebugInfo({
                        status: response.status,
                        statusText: response.statusText,
                        headers: response.responseHeaders,
                        url: url
                    });
                }
            },
            onerror: function(error) {
                showStatus(`Error downloading audio: ${error.error || 'Unknown error'}`, 'error');
                showDebugInfo(error);
            }
        });
    }

    // Function to handle the download button click
    async function handleDownloadClick() {
        try {
            // First try to get the download URL from the API
            const downloadUrl = await getDownloadUrlFromAPI();
            if (downloadUrl) {
                downloadAudio(downloadUrl);
                return;
            }
        } catch (apiError) {
            console.error('API method failed:', apiError);
            showStatus('API method failed, trying alternative methods...', 'info');
        }

        // If API method fails, try to extract the audio source from the page
        const audioSrc = extractAudioSource();
        if (audioSrc) {
            downloadAudio(audioSrc);
        } else {
            showStatus('Could not find any audio source. Try playing the audio first.', 'error');

            // Try playing the audio to make its source available
            const audioElement = document.querySelector('audio');
            if (audioElement) {
                audioElement.play();

                // Check again after a short delay
                setTimeout(() => {
                    const newAudioSrc = extractAudioSource();
                    if (newAudioSrc) {
                        downloadAudio(newAudioSrc);
                    } else {
                        showStatus('Still could not find the audio source. Please try again later.', 'error');
                    }
                }, 2000);
            } else {
                showStatus('Could not find the audio player.', 'error');
            }
        }
    }

    // Function to create our custom download button
    function createDownloadButton() {
        // Find the original download button to place our button next to it
        const originalDownloadButton = document.querySelector('a[href$="/download"]');

        if (!originalDownloadButton) {
            console.error('Original download button not found');
            return;
        }

        // Create our custom button
        const downloadBtn = document.createElement('a');
        downloadBtn.className = 'api-download-btn';
        downloadBtn.textContent = 'Download Without Credits';
        downloadBtn.href = '#';
        downloadBtn.addEventListener('click', function(e) {
            e.preventDefault();
            handleDownloadClick();
        });

        // Insert our button before the original download button
        originalDownloadButton.parentNode.insertBefore(downloadBtn, originalDownloadButton);

        // Create the status element
        const statusElement = createStatusElement();
        originalDownloadButton.parentNode.appendChild(statusElement);
    }

    // Initialize the script
    function initialize() {
        console.log('SampleFocus Direct API Downloader initializing...');

        // Create the download button
        createDownloadButton();

        console.log('SampleFocus Direct API Downloader initialized');
    }

    // Wait for the page to fully load before initializing
    window.addEventListener('load', function() {
        // Give a little extra time for any dynamic content to load
        setTimeout(initialize, 2000);
    });

})();