Combines Kemono Browser and Leak Finder Overlay with verified archive checkers and query engines from the FMHY NSFW Leaks list.
// ==UserScript==
// @name Stash Check
// @namespace stash-check
// @version 1.0
// @description Combines Kemono Browser and Leak Finder Overlay with verified archive checkers and query engines from the FMHY NSFW Leaks list.
// @author brainbaker
// @license MIT
// @match *://*.patreon.com/*
// @match *://*.fanbox.cc/*
// @match *://*.pixiv.net/*
// @match *://*.discord.com/*
// @match *://*.fantia.jp/*
// @match *://*.boosty.to/*
// @match *://*.dlsite.com/*
// @match *://*.gumroad.com/*
// @match *://*.subscribestar.com/*
// @match *://*.subscribestar.adult/*
// @match *://*.onlyfans.com/*
// @match *://*.fansly.com/*
// @match *://*.candfans.com/*
// @match *://*.fantrie.com/*
// @connect kemono.cr
// @connect coomer.st
// @connect pawchive.st
// @connect pawchive.pw
// @connect fansly.com
// @connect fapello.com
// @connect leaknudes.com
// @connect hotleak.vip
// @connect nudostar.tv
// @connect faponic.com
// @grant GM.xmlHttpRequest
// @grant GM_xmlhttpRequest
// @grant GM.openInTab
// @grant GM_openInTab
// @grant GM_addStyle
// @grant GM_setValue
// @grant GM_getValue
// @run-at document-idle
// ==/UserScript==
(function () {
'use strict';
// --- Polyfills & Helpers ---
const gmXHR = (typeof GM !== 'undefined' && GM.xmlHttpRequest) ? GM.xmlHttpRequest : (typeof GM_xmlhttpRequest !== 'undefined' ? GM_xmlhttpRequest : null);
const gmOpenTab = (typeof GM !== 'undefined' && GM.openInTab) ? GM.openInTab : (typeof GM_openInTab !== 'undefined' ? GM_openInTab : window.open);
if (!gmXHR) {
console.error('[Stash Check] GM.xmlHttpRequest is required for live status verification.');
}
const MAX_RETRIES = 2;
const REQUEST_TIMEOUT = 10000;
let currentCheckSessionId = 0;
// SFW Favoring platforms
const SFW_PLATFORMS = ['patreon', 'discord', 'fanbox', 'pixiv', 'fantia', 'boosty', 'dlsite', 'gumroad', 'subscribestar'];
// --- Utility Functions ---
function select(query, attribute = null) {
const el = document.querySelector(query);
return attribute ? el?.getAttribute(attribute) : el?.innerHTML;
}
function extract(string, prefix, suffix) {
if (string == null) return null;
let begIndex = string.indexOf(prefix);
if (begIndex === -1) return null;
else begIndex += prefix.length;
let endIndex = string.indexOf(suffix, begIndex);
if (endIndex === -1) endIndex = undefined;
return string.slice(begIndex, endIndex);
}
function extractNextUrlPath(prefix, suffix = "/") {
return extract(window.location.pathname, (prefix === "/") ? "/" : `/${prefix}/`, suffix);
}
function concatOrFalsy(...args) {
for (let arg of args) {
if (!arg) return arg;
}
return args.join("");
}
function compileURL({ domains, service, userID = null, postID = null } = {}) {
let obj = {};
for (let domain of domains) {
let redirectURL = `https://${domain}/${service}`;
if (userID) {
redirectURL += `/user/${userID}`;
if (postID) {
redirectURL += `/post/${postID}`;
}
} else continue;
obj[domain.split(".").at(-2).toUpperCase()] = redirectURL;
}
return obj;
}
// --- Platform Extraction Methods ---
function extractURLFromPatreon() {
return compileURL({
domains: ["kemono.cr", "pawchive.st"],
service: "patreon",
userID: extract(select("#__NEXT_DATA__"), '"creator":{"data":{"id":"', '"') ??
extract(select("body"), '\\"https://www.patreon.com/api/user/', "\\"),
postID: extractNextUrlPath("posts")?.split("-")?.at(-1)
});
}
function extractURLFromFanbox() {
return compileURL({
domains: ["kemono.cr", "pawchive.st"],
service: "fanbox",
userID: extract(select('meta[property="og:image"]', "content"), "/creator/", "/") ??
extract(select(".styled__StyledUserIcon-sc-1upaq18-10[style]", "style"), "/user/", "/") ??
extract(select('a[href^="https://www.pixiv.net/users/"]', "href"), "/users/", "/"),
postID: extractNextUrlPath("posts")
});
}
function extractURLFromPixiv() {
return compileURL({
domains: ["kemono.cr", "pawchive.st"],
service: "fanbox",
userID: extractNextUrlPath("users") ??
select("button[data-gtm-user-id]", "data-gtm-user-id") ??
select("a.user-details-icon[href]", "href")?.split("/").at(-1)
});
}
function extractURLFromDiscord() {
const pathname = window.location.pathname.split("/");
const serverID = /\d/.test(pathname[2]) ? `${pathname[2]}/${pathname?.[3] ?? ""}` : null;
return serverID ? {
"KEMONO": `https://kemono.cr/discord/server/${serverID}`
} : {};
}
function extractURLFromFantia() {
return compileURL({
domains: ["kemono.cr"],
service: "fantia",
userID: extractNextUrlPath("fanclubs") ?? extract(select(".fanclub-header > a[href]", "href"), "/fanclubs/", "/"),
postID: extractNextUrlPath("posts") ?? extractNextUrlPath("products")
});
}
function extractURLFromBoosty() {
return compileURL({
domains: ["kemono.cr"],
service: "boosty",
userID: extractNextUrlPath("/"),
postID: extractNextUrlPath("posts")
});
}
function extractURLFromDlsite() {
return compileURL({
domains: ["kemono.cr"],
service: "dlsite",
userID: extractNextUrlPath("maker_id", ".html") ?? extract(select(".maker_name[itemprop=brand] > a", "href"), "/maker_id/", "."),
postID: concatOrFalsy("RE", extractNextUrlPath("product_id")?.replace(/\D/g, ""))
});
}
function extractURLFromGumroad() {
const json = select("div#app[data-page]", "data-page");
return compileURL({
domains: ["kemono.cr"],
service: "gumroad",
userID: extract(json, '"external_id":"', '"') ?? extract(json, '"seller":{"id":"', '"'),
postID: select('meta[property="product:retailer_item_id"]', "content")
});
}
function extractURLFromSubscribeStar() {
return compileURL({
domains: ["kemono.cr"],
service: "subscribestar",
userID: select('img[data-type="avatar"][alt]', "alt")?.toLowerCase(),
postID: extractNextUrlPath("posts")
});
}
function extractURLFromOnlyFans() {
return compileURL({
domains: ["coomer.st"],
service: "onlyfans",
userID: select("#content .g-avatar[href]", "href")?.split("/")[1],
postID: select("div.b-post:not(.is-not-post-page)", "id")?.replace(/\D/g, "")
});
}
async function extractURLFromFansly() {
let userID = null;
const userName = select("div.feed-item-name a.username-wrapper", "href")?.split("/").at(-1) ??
select("meta[property='og:title']", "content")?.slice(10) ??
window.location.pathname.match(/^\/(?:profile\/)?([^/]+)/)?.[1];
if (userName && !['explore', 'home', 'notifications', 'messages', 'settings'].includes(userName)) {
try {
const res = await new Promise((resolve) => {
makeRequest({ method: "GET", url: `https://apiv3.fansly.com/api/v1/account?usernames=${userName}`, onload: resolve, onerror: () => resolve(null) });
});
if (res && res.status === 200) {
userID = JSON.parse(res.responseText)?.response?.[0]?.id ?? null;
}
} catch (e) {}
}
return compileURL({
domains: ["coomer.st"],
service: "fansly",
userID: userID ?? userName,
postID: extractNextUrlPath("post")
});
}
function extractURLFromCandFans() {
return compileURL({
domains: ["coomer.st"],
service: "candfans",
userID: extract(select("meta[property='og:image']", "content"), "/user/", "/") ?? window.location.pathname.split("/")[1],
postID: extractNextUrlPath("show")
});
}
function extractURLFromFantrie() {
const ignored = ['my', 'home', 'settings', 'notifications', 'lists', 'chats', 'bookmarks', 'explore'];
const parts = window.location.pathname.split('/');
const username = (parts.length > 1 && parts[1] && !ignored.includes(parts[1])) ? parts[1] : null;
return compileURL({
domains: ["coomer.st"],
service: "onlyfans",
userID: username
});
}
// --- Clean Display Name Extractor ---
function getCleanDisplayName(service, handle) {
let name = handle;
if (service === 'patreon') {
const h1 = document.querySelector('h1')?.textContent?.trim();
if (h1 && h1.length < 40) return h1;
const ogTitle = select('meta[property="og:title"]', 'content');
if (ogTitle) {
let clean = ogTitle.replace(/^Get more from\s+/i, '').replace(/\s+on Patreon$/i, '').replace(/\s*\|\s*Patreon$/i, '').trim();
if (clean && clean.length < 35) return clean;
}
const parts = window.location.pathname.split('/').filter(p => p && !['posts', 'about', 'membership', 'collection', 'community', 'home', 'user'].includes(p.toLowerCase()));
if (parts.length > 0 && !/\d{6,}/.test(parts[0])) return parts[0];
} else if (service === 'gumroad') {
const sub = window.location.hostname.split('.')[0];
if (sub && !['www', 'app', 'gumroad', 'discover'].includes(sub.toLowerCase())) {
return sub;
}
const ogTitle = select('meta[property="og:title"]', 'content');
if (ogTitle) {
let clean = ogTitle.replace(/^(Subscribe to|Buy from|Support|Follow)\s+/i, '').split('|')[0].trim();
if (clean && clean.length < 30) return clean;
}
} else if (service === 'fanbox') {
const h1 = document.querySelector('h1')?.textContent?.trim();
if (h1 && h1.length < 35) return h1;
}
return name || service;
}
// --- Inject Styles ---
function injectStyles() {
if (document.getElementById('klf-ultimate-styles')) return;
const style = document.createElement('style');
style.id = 'klf-ultimate-styles';
style.textContent = `
#klf-overlay {
position: fixed;
bottom: 20px;
right: 20px;
width: 290px;
background-color: #161618;
border: 1px solid #38383e;
border-radius: 10px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.75);
color: #f0f0f0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
font-size: 13px;
z-index: 9999999;
overflow: hidden;
transition: width 0.2s ease, opacity 0.2s ease;
user-select: none;
}
#klf-overlay-header {
padding: 10px 12px;
background: linear-gradient(135deg, #28282e, #1f1f24);
border-bottom: 1px solid #38383e;
cursor: grab;
display: flex;
justify-content: space-between;
align-items: center;
}
#klf-overlay-header:active {
cursor: grabbing;
}
#klf-overlay-header .klf-title {
margin: 0;
font-size: 13px;
font-weight: 700;
color: #fff;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: flex;
align-items: center;
gap: 6px;
}
#klf-overlay-header .klf-controls {
display: flex;
align-items: center;
gap: 8px;
}
.klf-nsfw-toggle {
display: flex;
align-items: center;
gap: 4px;
font-size: 10px;
font-weight: 700;
color: #ffaa00;
cursor: pointer;
background: rgba(255, 170, 0, 0.15);
padding: 2px 6px;
border-radius: 4px;
border: 1px solid rgba(255, 170, 0, 0.35);
text-transform: uppercase;
letter-spacing: 0.3px;
}
.klf-nsfw-toggle input {
cursor: pointer;
margin: 0;
}
#klf-overlay-header .klf-btn-icon {
background: rgba(255, 255, 255, 0.1);
border: none;
border-radius: 4px;
color: #ddd;
width: 22px;
height: 22px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
font-size: 11px;
transition: background 0.2s, color 0.2s;
}
#klf-overlay-header .klf-btn-icon:hover {
background: #ff4757;
color: #fff;
}
#klf-overlay-body {
max-height: 420px;
overflow-y: auto;
transition: max-height 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
#klf-overlay.collapsed #klf-overlay-body {
max-height: 0 !important;
overflow: hidden;
}
#klf-overlay-body::-webkit-scrollbar {
width: 5px;
}
#klf-overlay-body::-webkit-scrollbar-track {
background: #1a1a1c;
}
#klf-overlay-body::-webkit-scrollbar-thumb {
background: #444;
border-radius: 3px;
}
.klf-section {
border-bottom: 1px solid #28282e;
}
.klf-section:last-child {
border-bottom: none;
}
.klf-section-title {
padding: 6px 12px;
background-color: #1e1e22;
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
color: #999;
display: flex;
justify-content: space-between;
align-items: center;
}
.klf-list {
list-style: none;
padding: 4px 8px;
margin: 0;
}
.klf-list li {
margin: 2px 0;
}
.klf-list li.klf-hidden-sfw {
display: none !important;
}
.klf-list a {
text-decoration: none;
display: flex;
justify-content: space-between;
align-items: center;
padding: 6px 8px;
border-radius: 6px;
color: #ccc;
transition: background 0.15s, color 0.15s, transform 0.1s;
}
.klf-list a:hover {
background-color: #2a2a30;
color: #fff;
transform: translateX(2px);
}
.klf-site-name {
display: flex;
align-items: center;
gap: 6px;
font-weight: 500;
}
.klf-note {
font-size: 10px;
color: #888;
}
.klf-badge {
padding: 2px 6px;
border-radius: 4px;
font-size: 10px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.3px;
}
.klf-badge.found {
background-color: rgba(46, 213, 115, 0.2);
color: #2ed573;
border: 1px solid rgba(46, 213, 115, 0.4);
}
.klf-badge.incomplete {
background-color: rgba(255, 171, 0, 0.2);
color: #ffab00;
border: 1px solid rgba(255, 171, 0, 0.4);
}
.klf-badge.not-found, .klf-badge.missing {
background-color: rgba(255, 71, 87, 0.15);
color: #ff4757;
border: 1px solid rgba(255, 71, 87, 0.3);
}
.klf-badge.pending {
background-color: rgba(164, 176, 190, 0.15);
color: #a4b0be;
border: 1px solid rgba(164, 176, 190, 0.3);
}
.klf-badge.search {
background-color: rgba(30, 144, 255, 0.15);
color: #1e90ff;
border: 1px solid rgba(30, 144, 255, 0.3);
}
.klf-toolbar {
padding: 8px 10px;
background-color: #1c1c20;
border-top: 1px solid #28282e;
display: flex;
gap: 6px;
}
.klf-btn {
flex: 1;
background: #2f3542;
color: #fff;
border: 1px solid #444;
border-radius: 5px;
padding: 6px 4px;
font-size: 11px;
font-weight: 600;
cursor: pointer;
text-align: center;
transition: background 0.2s, border-color 0.2s;
}
.klf-btn:hover {
background: #3742fa;
border-color: #5352ed;
}
`;
document.head.appendChild(style);
}
// --- Overlay UI Creation & Dragging ---
function createOrGetOverlay(displayName, service) {
injectStyles();
let overlay = document.getElementById('klf-overlay');
const isSfwPlatform = SFW_PLATFORMS.includes((service || '').toLowerCase());
// On SFW platforms, always default NSFW option to unchecked/disabled on page load
let showNsfw = isSfwPlatform ? false : true;
if (!overlay) {
overlay = document.createElement('div');
overlay.id = 'klf-overlay';
overlay.className = 'collapsed';
overlay.innerHTML = `
<div id="klf-overlay-header">
<h3 class="klf-title"><span id="klf-service-icon">⚡</span> <span id="klf-username-display">${displayName}</span></h3>
<div class="klf-controls">
<button class="klf-btn-icon" id="klf-toggle-collapse" title="Toggle Expand">◀</button>
</div>
</div>
<div id="klf-overlay-body">
<div class="klf-section" id="klf-sec-live">
<div class="klf-section-title">
<span>Live Leak Checks</span>
<label class="klf-nsfw-toggle" id="klf-nsfw-holder" style="display: none;" title="Toggle adult/NSFW leak sources">
<input type="checkbox" id="klf-nsfw-checkbox" ${showNsfw ? 'checked' : ''}>
<span>NSFW</span>
</label>
</div>
<ul class="klf-list" id="klf-list-live"></ul>
</div>
<div class="klf-section" id="klf-sec-search">
<div class="klf-section-title">
<span>Other Sites & Forums</span>
</div>
<ul class="klf-list" id="klf-list-search"></ul>
</div>
</div>
<div class="klf-toolbar">
<button class="klf-btn" id="klf-btn-open-found" title="Open all verified/found links in new tabs">Open All Found</button>
<button class="klf-btn" id="klf-btn-search-all" title="Open all search query links in new tabs">Search All Sites</button>
</div>
`;
document.body.appendChild(overlay);
const header = overlay.querySelector('#klf-overlay-header');
const toggleBtn = overlay.querySelector('#klf-toggle-collapse');
const nsfwCheckbox = overlay.querySelector('#klf-nsfw-checkbox');
nsfwCheckbox.addEventListener('change', (e) => {
applySfwFilter(service);
});
header.addEventListener('click', (e) => {
if (e.target.closest('button') || e.target.closest('label') || e.target.closest('input')) return;
if (header._didMove) return;
overlay.classList.toggle('collapsed');
toggleBtn.textContent = overlay.classList.contains('collapsed') ? '◀' : '▼';
});
toggleBtn.addEventListener('click', () => {
overlay.classList.toggle('collapsed');
toggleBtn.textContent = overlay.classList.contains('collapsed') ? '◀' : '▼';
});
overlay.querySelector('#klf-btn-open-found').addEventListener('click', () => {
const foundLinks = overlay.querySelectorAll('#klf-list-live li:not(.klf-hidden-sfw) a[data-status="found"], #klf-list-live li:not(.klf-hidden-sfw) a[data-status="incomplete"]');
if (foundLinks.length === 0) {
alert('No verified found leaks yet!');
return;
}
foundLinks.forEach((a) => {
if (a.href) gmOpenTab(a.href, true);
});
});
overlay.querySelector('#klf-btn-search-all').addEventListener('click', () => {
const searchLinks = overlay.querySelectorAll('#klf-list-search li:not(.klf-hidden-sfw) a');
if (searchLinks.length === 0) {
alert('No search links visible!');
return;
}
searchLinks.forEach((a) => {
if (a.href) gmOpenTab(a.href, true);
});
});
makeDraggable(overlay, header);
} else {
document.getElementById('klf-username-display').textContent = displayName;
document.getElementById('klf-list-live').innerHTML = '';
document.getElementById('klf-list-search').innerHTML = '';
const nsfwCheckbox = document.getElementById('klf-nsfw-checkbox');
if (nsfwCheckbox) nsfwCheckbox.checked = showNsfw;
}
const nsfwHolder = document.getElementById('klf-nsfw-holder');
if (nsfwHolder) {
nsfwHolder.style.display = isSfwPlatform ? 'flex' : 'none';
}
overlay.style.display = 'block';
return overlay;
}
function makeDraggable(overlay, header) {
let isDragging = false;
let startX, startY, initialRight, initialBottom;
header.addEventListener('mousedown', (e) => {
if (e.target.closest('button') || e.target.closest('label') || e.target.closest('input')) return;
isDragging = true;
header._didMove = false;
startX = e.clientX;
startY = e.clientY;
const rect = overlay.getBoundingClientRect();
initialRight = window.innerWidth - rect.right;
initialBottom = window.innerHeight - rect.bottom;
e.preventDefault();
});
document.addEventListener('mousemove', (e) => {
if (!isDragging) return;
const dx = e.clientX - startX;
const dy = e.clientY - startY;
if (Math.abs(dx) > 3 || Math.abs(dy) > 3) {
header._didMove = true;
}
let newRight = initialRight - dx;
let newBottom = initialBottom - dy;
newRight = Math.max(10, Math.min(window.innerWidth - overlay.offsetWidth - 10, newRight));
newBottom = Math.max(10, Math.min(window.innerHeight - overlay.offsetHeight - 10, newBottom));
overlay.style.right = `${newRight}px`;
overlay.style.bottom = `${newBottom}px`;
});
document.addEventListener('mouseup', () => {
isDragging = false;
});
}
function applySfwFilter(service) {
const isSfwPlatform = SFW_PLATFORMS.includes((service || '').toLowerCase());
const checkbox = document.getElementById('klf-nsfw-checkbox');
const showNsfw = checkbox ? checkbox.checked : !isSfwPlatform;
const allListItems = document.querySelectorAll('#klf-list-live li, #klf-list-search li');
allListItems.forEach(li => {
const a = li.querySelector('a');
const siteKey = a ? (a.dataset.sitekey || '') : '';
if (isSfwPlatform && !showNsfw) {
if (siteKey.startsWith('kemono') || siteKey.startsWith('pawchive')) {
li.classList.remove('klf-hidden-sfw');
} else {
li.classList.add('klf-hidden-sfw');
}
} else {
li.classList.remove('klf-hidden-sfw');
}
});
const searchSec = document.getElementById('klf-sec-search');
if (searchSec) {
const visibleSearch = searchSec.querySelectorAll('li:not(.klf-hidden-sfw)').length;
searchSec.style.display = visibleSearch > 0 ? 'block' : 'none';
}
const searchAllBtn = document.getElementById('klf-btn-search-all');
if (searchAllBtn) {
searchAllBtn.style.display = (isSfwPlatform && !showNsfw) ? 'none' : 'block';
}
}
function addLinkItem(sectionId, siteName, url, note = '', initialStatus = 'search', badgeText = null) {
const list = document.getElementById(`klf-list-${sectionId}`);
if (!list) return null;
const li = document.createElement('li');
const a = document.createElement('a');
const siteKey = siteName.toLowerCase().replace(/[^a-z0-9]/g, '') + (note ? '_' + note.toLowerCase().replace(/[^a-z0-9]/g, '') : '');
a.href = url;
a.target = '_blank';
a.rel = 'noopener noreferrer';
a.dataset.sitekey = siteKey;
a.dataset.status = initialStatus;
const displayNote = note ? ` <span class="klf-note">(${note})</span>` : '';
const badge = badgeText || initialStatus.toUpperCase();
a.innerHTML = `
<span class="klf-site-name">${siteName}${displayNote}</span>
<span class="klf-badge ${initialStatus}">${badge}</span>
`;
a.addEventListener('click', (e) => {
if (e.ctrlKey) {
e.preventDefault();
gmOpenTab(url, true);
}
});
li.appendChild(a);
list.appendChild(li);
return { a, li };
}
function updateLinkStatus(siteName, note, status, customBadgeText = null) {
const siteKey = siteName.toLowerCase().replace(/[^a-z0-9]/g, '') + (note ? '_' + note.toLowerCase().replace(/[^a-z0-9]/g, '') : '');
const a = document.querySelector(`a[data-sitekey="${siteKey}"]`);
if (a) {
a.dataset.status = status;
const badge = a.querySelector('.klf-badge');
if (badge) {
badge.className = `klf-badge ${status}`;
badge.textContent = customBadgeText || status.toUpperCase();
}
}
}
function makeRequest(details, retryCount = 0, sessionId = currentCheckSessionId) {
if (!gmXHR) return;
gmXHR({
method: details.method || 'GET',
url: details.url,
headers: details.headers || { 'Accept': 'text/css' },
timeout: REQUEST_TIMEOUT,
onload(res) {
if (sessionId !== currentCheckSessionId) return;
if (details.onload) details.onload(res);
},
onerror(err) {
if (sessionId !== currentCheckSessionId) return;
if (retryCount < MAX_RETRIES) {
setTimeout(() => makeRequest(details, retryCount + 1, sessionId), 1000);
} else if (details.onerror) {
details.onerror(err);
}
},
ontimeout() {
if (sessionId !== currentCheckSessionId) return;
if (retryCount < MAX_RETRIES) {
setTimeout(() => makeRequest(details, retryCount + 1, sessionId), 1000);
} else if (details.onerror) {
details.onerror({ status: 408 });
}
}
});
}
function verifyArchiveEndpoint(siteName, url, note, sessionId) {
try {
const parsedUrl = new URL(url);
let checkUrl = null;
let isPost = parsedUrl.pathname.includes('/post/');
if (parsedUrl.pathname.startsWith('/discord/server/')) {
const serverId = parsedUrl.pathname.split('/')[3];
checkUrl = `https://${parsedUrl.hostname}/api/v1/discord/server/${serverId}`;
} else {
checkUrl = `https://${parsedUrl.hostname}/api/v1${parsedUrl.pathname}${isPost ? '' : '/profile'}`;
}
makeRequest({
method: 'GET',
url: checkUrl,
headers: { 'Accept': 'text/css' },
onload(res) {
if (sessionId !== currentCheckSessionId) return;
if (parsedUrl.pathname.startsWith('/discord/server/')) {
if (res.status === 200) {
updateLinkStatus(siteName, note, 'found', 'FOUND');
} else {
updateLinkStatus(siteName, note, 'missing', 'MISSING');
}
} else {
if (res.status === 200 || res.status === 202) {
updateLinkStatus(siteName, note, isPost ? 'incomplete' : 'found', isPost ? 'POST FOUND' : 'FOUND');
} else if (res.status === 404) {
updateLinkStatus(siteName, note, 'missing', 'NOT FOUND');
} else {
updateLinkStatus(siteName, note, 'missing', `ERR ${res.status}`);
}
}
},
onerror() { updateLinkStatus(siteName, note, 'missing', 'OFFLINE'); }
}, 0, sessionId);
} catch (e) {
updateLinkStatus(siteName, note, 'missing', 'ERROR');
}
}
// --- Live Leak Checks: kemono, coomer, hotleak, nudostar, fapello, leaknudes, faponic ---
function runLiveLeakChecks(handle, service, archives, sessionId) {
// 1. Kemono (STRICTLY only for Kemono platforms: patreon, discord, fantia, boosty, gumroad, subscribestar, fanbox, pixiv, dlsite)
if (archives["KEMONO"]) {
addLinkItem('live', 'Kemono', archives["KEMONO"], '', 'pending', 'CHECKING');
verifyArchiveEndpoint('Kemono', archives["KEMONO"], '', sessionId);
}
if (archives["PAWCHIVE"]) {
addLinkItem('live', 'Pawchive', archives["PAWCHIVE"], '', 'pending', 'CHECKING');
makeRequest({
method: 'GET',
url: archives["PAWCHIVE"],
headers: { 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' },
onload(res) {
const finalUrl = res.finalUrl || '';
const isFound = res.status === 200 && !finalUrl.includes('/artists');
updateLinkStatus('Pawchive', '', isFound ? 'found' : 'missing', isFound ? 'FOUND' : 'MISSING');
}
}, 0, sessionId);
}
// 2. Coomer (STRICTLY only for Coomer platforms: onlyfans, fansly, candfans, fantrie)
if (archives["COOMER"]) {
addLinkItem('live', 'Coomer', archives["COOMER"], '', 'pending', 'CHECKING');
verifyArchiveEndpoint('Coomer', archives["COOMER"], '', sessionId);
}
// 3. Hotleak
const hotleakUrl = `https://hotleak.vip/${handle}`;
addLinkItem('live', 'Hotleak', hotleakUrl, '', 'pending', 'CHECKING');
makeRequest({
method: 'HEAD',
url: hotleakUrl,
onload(res) {
updateLinkStatus('Hotleak', '', res.status === 200 ? 'found' : 'not-found', res.status === 200 ? 'FOUND' : 'NOT FOUND');
},
onerror() { updateLinkStatus('Hotleak', '', 'not-found', 'OFFLINE'); }
}, 0, sessionId);
// 4. Nudostar
const nudostarUrl = `https://nudostar.tv/models/${handle}/`;
addLinkItem('live', 'Nudostar', nudostarUrl, '', 'pending', 'CHECKING');
makeRequest({
method: 'HEAD',
url: nudostarUrl,
onload(res) {
updateLinkStatus('Nudostar', '', res.status === 200 ? 'found' : 'not-found', res.status === 200 ? 'FOUND' : 'NOT FOUND');
},
onerror() { updateLinkStatus('Nudostar', '', 'not-found', 'OFFLINE'); }
}, 0, sessionId);
// 5. Fapello
const fapelloUrl = `https://fapello.com/${handle}/`;
addLinkItem('live', 'Fapello', fapelloUrl, '', 'pending', 'CHECKING');
makeRequest({
method: 'GET',
url: fapelloUrl,
onload(res) {
const isFound = res.status === 200 && (res.finalUrl || '').includes(handle);
updateLinkStatus('Fapello', '', isFound ? 'found' : 'not-found', isFound ? 'FOUND' : 'NOT FOUND');
},
onerror() { updateLinkStatus('Fapello', '', 'not-found', 'OFFLINE'); }
}, 0, sessionId);
if (handle.includes('_')) {
const altUser = handle.replace(/_/g, '-');
const fapelloAltUrl = `https://fapello.com/${altUser}/`;
addLinkItem('live', 'Fapello', fapelloAltUrl, 'Alt Handle', 'pending', 'CHECKING');
makeRequest({
method: 'GET',
url: fapelloAltUrl,
onload(res) {
const isFound = res.status === 200 && (res.finalUrl || '').includes(altUser);
updateLinkStatus('Fapello', 'Alt Handle', isFound ? 'found' : 'not-found', isFound ? 'FOUND' : 'NOT FOUND');
}
}, 0, sessionId);
}
// 6. LeakNudes
const leakNudesUrl = `https://leaknudes.com/model/${handle}`;
addLinkItem('live', 'LeakNudes', leakNudesUrl, '', 'pending', 'CHECKING');
makeRequest({
method: 'GET',
url: leakNudesUrl,
onload(res) {
const isFound = res.status === 200 && res.finalUrl === leakNudesUrl;
updateLinkStatus('LeakNudes', '', isFound ? 'found' : 'not-found', isFound ? 'FOUND' : 'NOT FOUND');
},
onerror() { updateLinkStatus('LeakNudes', '', 'not-found', 'OFFLINE'); }
}, 0, sessionId);
// 7. Faponic
const faponicUrl = `https://faponic.com/${handle}/`;
addLinkItem('live', 'Faponic', faponicUrl, '', 'pending', 'CHECKING');
makeRequest({
method: 'GET',
url: faponicUrl,
onload(res) {
const isFound = res.status === 200 && !(res.responseText || '').includes('<title>404 | Faponic</title>');
updateLinkStatus('Faponic', '', isFound ? 'found' : 'not-found', isFound ? 'FOUND' : 'NOT FOUND');
},
onerror() { updateLinkStatus('Faponic', '', 'not-found', 'OFFLINE'); }
}, 0, sessionId);
}
// --- Populate Other Sites & Forums ---
function populateOtherSitesAndForums(handle) {
const u = encodeURIComponent(handle);
const searchSites = [
{ name: 'Bunkr Albums', url: `https://balbums.st/?search=${u}`, note: 'Album Query' },
{ name: 'TopFapGirls', url: `https://www.topfapgirls1.com/search/?q=${u}`, note: 'Search' },
{ name: 'EroThots', url: `https://erothots.co/search/?q=${u}`, note: 'Media Query' },
{ name: 'OSosedki', url: `https://ososedki.com/search?q=${u}`, note: 'Archive Query' },
{ name: 'RedditPlug', url: `https://redditplug.com/?s=${u}`, note: 'Mega/Bypass' },
{ name: 'TurboVid Library', url: `https://turbovid.cr/library?q=${u}`, note: 'Video Query' },
{ name: 'xxxTube', url: `https://x-x-x.tube/search/${u}/`, note: 'Tube Query' },
{ name: 'ThotHub', url: `https://thothub.to/search/${u}/`, note: 'KVS Query' },
{ name: 'NobodyHome', url: `https://nobodyhome.tv/index.php?search=${u}`, note: 'Protected Query' },
{ name: 'OnlyFans421', url: `https://duckduckgo.com/?q=site%3Arentry.org+${u}`, note: 'Rentry Bypass' },
// Forums requiring signup placed at the lowest positions
{ name: 'SimpCity Forum', url: `https://simpcity.cr/search/search?keywords=${u}`, note: 'Requires Signup' },
{ name: 'ViperGirls Forum', url: `https://vipergirls.to/search.php?do=process&query=${u}`, note: 'Requires Signup' }
];
searchSites.forEach(site => {
addLinkItem('search', site.name, site.url, site.note, 'search', 'SEARCH');
});
}
// --- Detect Creator Data & Archives ---
async function getCreatorData() {
const host = window.location.hostname;
let archives = {};
let handle = null;
let service = null;
if (host.includes('onlyfans.com') || host.includes('fantrie.com')) {
service = host.includes('onlyfans') ? 'onlyfans' : 'fantrie';
archives = extractURLFromOnlyFans();
if (service === 'fantrie') {
archives = extractURLFromFantrie();
}
const ignored = ['my', 'home', 'settings', 'notifications', 'lists', 'chats', 'bookmarks', 'explore', 'action'];
const parts = window.location.pathname.split('/');
handle = (parts.length > 1 && parts[1] && !ignored.includes(parts[1])) ? parts[1] : null;
if (!handle && archives["COOMER"]) handle = archives["COOMER"].split('/').at(-1);
} else if (host.includes('fansly.com')) {
service = 'fansly';
archives = await extractURLFromFansly();
const ignored = ['explore', 'home', 'notifications', 'messages', 'settings'];
const matches = window.location.pathname.match(/^\/(?:profile\/)?([^/]+)/);
handle = (matches && matches[1] && !ignored.includes(matches[1])) ? matches[1] : null;
if (!handle && archives["COOMER"]) handle = archives["COOMER"].split('/').at(-1);
} else if (host.includes('patreon.com')) {
service = 'patreon';
archives = extractURLFromPatreon();
handle = archives["KEMONO"]?.split('/').at(-1) || extractNextUrlPath("user") || window.location.pathname.split('/').at(-1);
} else if (host.includes('fanbox.cc')) {
service = 'fanbox';
archives = extractURLFromFanbox();
handle = host.split('.')[0] !== 'www' ? host.split('.')[0] : extractNextUrlPath('@');
} else if (host.includes('pixiv.net')) {
service = 'pixiv';
archives = extractURLFromPixiv();
handle = extractNextUrlPath("users") || archives["KEMONO"]?.split('/').at(-1);
} else if (host.includes('discord.com')) {
service = 'discord';
archives = extractURLFromDiscord();
handle = archives["KEMONO"]?.split('/').at(-1);
} else if (host.includes('fantia.jp')) {
service = 'fantia';
archives = extractURLFromFantia();
handle = extractNextUrlPath("fanclubs");
} else if (host.includes('boosty.to')) {
service = 'boosty';
archives = extractURLFromBoosty();
handle = extractNextUrlPath("/");
} else if (host.includes('dlsite.com')) {
service = 'dlsite';
archives = extractURLFromDlsite();
handle = extractNextUrlPath("maker_id", ".html");
} else if (host.includes('gumroad.com')) {
service = 'gumroad';
archives = extractURLFromGumroad();
handle = select('meta[property="og:title"]', "content") || "Gumroad Creator";
} else if (host.includes('subscribestar.com') || host.includes('subscribestar.adult')) {
service = 'subscribestar';
archives = extractURLFromSubscribeStar();
handle = select('img[data-type="avatar"][alt]', "alt")?.toLowerCase() || window.location.pathname.split('/')[1];
} else if (host.includes('candfans.com')) {
service = 'candfans';
archives = extractURLFromCandFans();
handle = window.location.pathname.split('/')[1];
}
if (!handle || handle === 'www') return null;
const displayName = getCleanDisplayName(service, handle);
return { handle, displayName, service, archives };
}
// --- Main Loop ---
let lastCheckedHandle = null;
let lastUrl = location.href;
async function mainLoop() {
const data = await getCreatorData();
const overlay = document.getElementById('klf-overlay');
if (data && data.handle && data.handle !== lastCheckedHandle) {
lastCheckedHandle = data.handle;
currentCheckSessionId++;
const sessionId = currentCheckSessionId;
createOrGetOverlay(data.displayName, data.service);
// 1. Run Live Leak Checks
runLiveLeakChecks(data.handle, data.service, data.archives, sessionId);
// 2. Populate Other Sites & Forums
populateOtherSitesAndForums(data.handle);
// 3. Apply SFW / NSFW filter
applySfwFilter(data.service);
} else if (data && data.handle && overlay && overlay.style.display === 'none') {
overlay.style.display = 'block';
} else if (!data && overlay) {
overlay.style.display = 'none';
lastCheckedHandle = null;
}
}
setTimeout(mainLoop, 1000);
new MutationObserver(() => {
if (location.href !== lastUrl) {
lastUrl = location.href;
setTimeout(mainLoop, 800);
}
}).observe(document.body, { subtree: true, childList: true });
})();