Get Media on OnlyFans

Get all media on OF

// ==UserScript==
// @name         Get Media on OnlyFans
// @namespace    http://tampermonkey.net/
// @version      0.11
// @description  Get all media on OF
// @author       Paul
// @match        https://onlyfans.com/*
// @grant        none
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    // Set to keep track of loaded media URLs to avoid duplicates
    const mediaUrls = new Set();

    // Function to download a given URL with a specified filename
    function downloadUrl(url, filename) {
        console.log(`Starting download: ${url} as ${filename}`);
        fetch(url)
            .then(response => response.blob())
            .then(blob => {
                const a = document.createElement('a');
                const objectUrl = window.URL.createObjectURL(blob);
                a.href = objectUrl;
                a.download = filename;
                document.body.appendChild(a);
                a.click();
                window.URL.revokeObjectURL(objectUrl);
                document.body.removeChild(a);
                console.log(`Download complete: ${url}`);
            })
            .catch(error => console.error('Error downloading:', error));
    }

    // Function to generate a unique filename based on the current timestamp
    function generateUniqueFilename(baseName, extension) {
        const timestamp = new Date().toISOString().replace(/[-:.]/g, '');
        return `${baseName}_${timestamp}.${extension}`;
    }

    // Function to add a download button next to a video element
    function addVideoDownloadButton(mediaElement, url, baseName) {
        if (mediaElement.nextSibling && mediaElement.nextSibling.classList && mediaElement.nextSibling.classList.contains('OF-video-download-button')) {
            console.log(`Download button already exists for: ${url}`);
            return; // Skip if the download button already exists
        }
        const filename = generateUniqueFilename(baseName, 'mp4');
        const button = document.createElement('button');
        button.innerText = 'Download';
        button.classList.add('OF-video-download-button');
        button.style.position = 'fixed';
        button.style.zIndex = '9999';
        button.style.marginLeft = '50%';
        button.style.marginTop = '0%';
        button.style.display = 'inline-block';
        button.style.backgroundColor = '#f39c12'; // Background color for visibility
        button.style.color = '#fff'; // Text color for contrast
        button.style.border = 'none';
        button.style.padding = '5px 10px';
        button.style.cursor = 'pointer';
        button.style.fontSize = '14px';
        button.style.borderRadius = '5px';
        button.addEventListener('click', () => downloadUrl(url, filename));
        mediaElement.parentNode.insertBefore(button, mediaElement.nextSibling);
        console.log(`Added download button for: ${url}`);
    }

    // Function to add a download button next to an img element
    function addImgDownloadButton(mediaElement, url, baseName) {
        if (mediaElement.nextSibling && mediaElement.nextSibling.classList && mediaElement.nextSibling.classList.contains('OF-img-download-button')) {
            console.log(`Download button already exists for: ${url}`);
            return; // Skip if the download button already exists
        }
        const filename = generateUniqueFilename(baseName, 'jpg');
        const button = document.createElement('button');
        button.innerText = 'Download';
        button.classList.add('OF-img-download-button');
        button.style.position = 'sticky';
        button.style.zIndex = '9999';
        button.style.marginLeft = '10%';
        button.style.marginTop = '10%';
        button.style.display = 'inline-block';
        button.style.backgroundColor = '#f39c12'; // Background color for visibility
        button.style.color = '#fff'; // Text color for contrast
        button.style.border = 'none';
        button.style.padding = '5px 10px';
        button.style.cursor = 'pointer';
        button.style.fontSize = '14px';
        button.style.borderRadius = '5px';
        button.addEventListener('click', () => downloadUrl(url, filename));
        mediaElement.parentNode.insertBefore(button, mediaElement.nextSibling);
        console.log(`Added download button for: ${url}`);
    }

    // Function to process images with class 'pswp__img'
    function processImages() {
        const images = document.querySelectorAll('img.pswp__img');
        images.forEach(image => {
            const imageUrl = image.src;
            if (imageUrl && !mediaUrls.has(imageUrl)) {
                mediaUrls.add(imageUrl);
                addImgDownloadButton(image, imageUrl, 'image');
            }
        });
    }

    // Function to process video elements
    function processVideos() {
        const videos = document.querySelectorAll('video');
        videos.forEach(video => {
            const videoUrl = video.src;
            if (videoUrl && !mediaUrls.has(videoUrl)) {
                mediaUrls.add(videoUrl);
                addVideoDownloadButton(video, videoUrl, 'video');
            } else if (!videoUrl) {
                console.warn('Video element has no src:', video);
            }
        });
    }

    // Run the functions initially
    console.log('Initial run: processing images and videos');
    processImages();
    processVideos();

    // Create a MutationObserver to watch for changes in the DOM
    const observer = new MutationObserver((mutations) => {
        mutations.forEach((mutation) => {
            if (mutation.addedNodes.length > 0) {
                console.log('DOM mutation detected: processing new images and videos');
                processImages();
                processVideos();
            }
        });
    });

    // Start observing the document for changes
    observer.observe(document.body, { childList: true, subtree: true });
    console.log('Started observing DOM for changes');

})();