Onlyfans/Fansly/Fantrie "leak" finder

Checks some sites for OF/Fansly/Fantrie "leaks"

// ==UserScript==
// @name         Onlyfans/Fansly/Fantrie "leak" finder
// @namespace    http://tampermonkey.net/
// @version      0.6
// @description  Checks some sites for OF/Fansly/Fantrie "leaks"
// @author       You
// @match        https://onlyfans.com/*
// @match        *coomer.su/*
// @match        *fapello.com/*
// @match        https://fansly.com/*
// @match        https://fantrie.com/*
// @grant        GM.xmlHttpRequest
// @license      Unlicense
// ==/UserScript==

(function() {
    'use strict';

    const MAX_RETRY_COUNT = 5;
    const RETRY_DELAY_MS = 1000;

    const username = getUsernameFromUrl();

    function getUsernameFromUrl() {
        const hostname = window.location.hostname;
        const pathname = window.location.pathname;
        if (hostname === 'onlyfans.com' || hostname === 'fantrie.com') {
            return pathname.split('/')[1];
        }
        if (hostname === 'fansly.com') {
            const matches = pathname.match(/^\/([^/]+)/);
            return matches ? matches[1] : '';
        }
        return '';
    }

    function fetchWithRetry(url, onSuccess, onError, retryCount = 0) {
        GM.xmlHttpRequest({
            method: 'GET',
            url,
            onload(response) {
                if (response.status === 200) {
                    onSuccess(response);
                } else if (retryCount < MAX_RETRY_COUNT) {
                    setTimeout(() => fetchWithRetry(url, onSuccess, onError, retryCount + 1), RETRY_DELAY_MS);
                } else {
                    console.error('Max retry attempts reached');
                    onError && onError(response);
                }
            },
            onerror(error) {
                console.error('Error fetching data:', error);
                if (retryCount < MAX_RETRY_COUNT) {
                    setTimeout(() => fetchWithRetry(url, onSuccess, onError, retryCount + 1), RETRY_DELAY_MS);
                } else {
                    console.error('Max retry attempts reached');
                    onError && onError(error);
                }
            }
        });
    }

    function fetchUserProfileFansly(username) {
        const apiUrl = `https://apiv3.fansly.com/api/v1/account?usernames=${username}`;
        fetchWithRetry(apiUrl, (response) => {
            const data = JSON.parse(response.responseText);
            if (data.success && data.response.length > 0) {
                fetchUserProfileCoomer(data.response[0].id, "fansly");
            } else {
                console.log(`User ${username} not found`);
            }
        });
    }

    function fetchUserProfileCoomer(username, service) {
        const apiUrl = `https://coomer.su/api/v1/${service}/user/${username}/profile`;
        fetchWithRetry(apiUrl, (response) => {
            const profileUrl = `https://coomer.su/${service}/user/${username}`;
            addLinkToMenu(profileUrl, 'Coomer.su');
        }, null, 0, 404);
    }

    function fetchUserProfileFapello(username) {
        const apiUrl = `https://fapello.com/${username}/`;
        fetchWithRetry(apiUrl, (response) => {
            if (response.finalUrl === apiUrl) {
                addLinkToMenu(apiUrl, 'Fapello');
            } else {
                console.log(`Request was redirected`);
            }
        });
    }

    function fetchUserProfileLeakNudes(username) {
        const apiUrl = `https://leaknudes.com/model/${username}`;
        fetchWithRetry(apiUrl, (response) => {
            if (response.finalUrl === apiUrl) {
                addLinkToMenu(apiUrl, 'LeakNudes');
            } else {
                console.log(`Request was redirected`);
            }
        });
    }

    function addLinkToMenu(link, displayText) {
        const hostname = window.location.hostname;
        let menuElement;

        if (hostname === 'fansly.com') {
            menuElement = document.querySelector('.follow-profile');
            if (menuElement) {
                const clonedElement = menuElement.cloneNode(true);
                clonedElement.querySelector("xd-localization-string").innerText = displayText;
                const aElement = document.createElement('a');
                aElement.setAttribute('href', link);
                aElement.appendChild(clonedElement);
                menuElement.after(aElement);
            } else {
                console.error('Follow button not found');
            }
        } else if (hostname === 'fantrie.com') {
            menuElement = document.querySelectorAll('.left-menus')[1];
            if (menuElement) {
                const aElement = document.createElement('a');
                aElement.setAttribute('href', link);
                aElement.textContent = displayText;
                menuElement.appendChild(aElement);
            } else {
                console.error('Left menus element not found');
            }
        } else {
            menuElement = document.querySelector('.l-header__menu.m-native-custom-scrollbar.m-scrollbar-y.m-invisible-scrollbar');
            if (menuElement) {
                const aElement = document.createElement('a');
                aElement.setAttribute('href', link);
                aElement.textContent = displayText;
                aElement.style.marginRight = "10px";
                if (menuElement.querySelectorAll('a').length > 0) {
                    menuElement.appendChild(document.createElement('br'));
                }
                menuElement.appendChild(aElement);
            } else {
                console.error('Menu element not found');
            }
        }
    }

    function waitForElement(selector, callback) {
        const observer = new MutationObserver((mutations, observer) => {
            const element = document.querySelector(selector);
            if (element) {
                observer.disconnect();
                callback(element);
            }
        });
        observer.observe(document.body, { childList: true, subtree: true });
    }

    if (username) {
        const fetchFunctions = [
            () => fetchUserProfileFansly(username),
            () => fetchUserProfileCoomer(username, "onlyfans"),
            () => fetchUserProfileFapello(username),
            () => fetchUserProfileLeakNudes(username)
        ];
        const alternateUsername = username.includes("_") ? username.replaceAll("_", "-") : null;

        if (window.location.hostname === 'fansly.com') {
            waitForElement('.profile-details', () => {
                fetchFunctions.forEach(fetch => fetch());
                if (alternateUsername) {
                    fetchUserProfileFapello(alternateUsername);
                }
            });
        } else if (window.location.hostname === 'fantrie.com') {
            waitForElement('.left-menus', () => {
                fetchFunctions.slice(2).forEach(fetch => fetch());
            });
        } else {
            waitForElement('.l-header__menu.m-native-custom-scrollbar.m-scrollbar-y.m-invisible-scrollbar', () => {
                fetchFunctions.forEach(fetch => fetch());
                if (alternateUsername) {
                    fetchUserProfileFapello(alternateUsername);
                }
            });
        }
    }
})();