// ==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);
});
})();