// ==UserScript==
// @name Fake Profiles Manager
// @namespace http://tampermonkey.net/
// @version 3.9
// @description Banlist collaborative avec confirmation et récupération du nom via fil d'Ariane ou H1
// @match *://sexemodel.com/*
// @match *://www.sexemodel.com/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
const AIRTABLE_TOKEN = "patpbe8APun8JckNM.bd007388d8f9807a82733510209428202ea2a43af6d5b805b667933cd45a64bf";
const AIRTABLE_BASE = "appUf8jMiwrXzpsP7";
const AIRTABLE_TABLE = "BanList";
let bannedList = [];
async function fetchBanListFromAirtable() {
try {
const url = `https://api.airtable.com/v0/${AIRTABLE_BASE}/${AIRTABLE_TABLE}?pageSize=100`;
const res = await fetch(url, {
headers: { Authorization: `Bearer ${AIRTABLE_TOKEN}` }
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
return data.records
.filter(r => r.fields.Active === true)
.map(r => ({
airtableId: r.id,
id: r.fields.ProfilID,
name: r.fields.ProfilName || "",
date: r.createdTime
}));
} catch (e) {
console.warn("⚠️ Erreur Airtable : ", e);
return [];
}
}
function showQuickNotif(message) {
const notif = document.createElement('div');
notif.textContent = message;
Object.assign(notif.style, {
position: 'fixed',
top: '20px',
right: '20px',
background: '#4caf50',
color: '#fff',
padding: '10px 15px',
borderRadius: '5px',
fontWeight: 'bold',
zIndex: '999999',
boxShadow: '0 2px 6px rgba(0,0,0,0.3)'
});
document.body.appendChild(notif);
setTimeout(() => notif.remove(), 700);
}
async function pushBanToAirtable(profilID, profilName) {
try {
const url = `https://api.airtable.com/v0/${AIRTABLE_BASE}/${AIRTABLE_TABLE}`;
const record = {
fields: {
ProfilID: profilID,
ProfilName: profilName,
Active: true
}
};
const res = await fetch(url, {
method: 'POST',
headers: {
Authorization: `Bearer ${AIRTABLE_TOKEN}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ records: [record] })
});
const json = await res.json();
if (json.error) {
console.error("❌ Erreur Airtable :", json.error);
alert("❌ Erreur Airtable : " + json.error.message);
} else {
console.log("✅ Ajouté à Airtable :", json);
bannedList.push({
airtableId: json.records[0].id,
id: profilID,
name: profilName,
date: json.records[0].createdTime
});
document.querySelectorAll(`a[href*="${profilID}"]`).forEach(a => {
const card = a.closest('div');
if (card) card.style.display = 'none';
});
showQuickNotif(`✅ Profil banni : ${profilName}`);
}
} catch (e) {
console.error("❌ Exception Airtable :", e);
alert("❌ Erreur connexion Airtable");
}
}
async function deactivateBan(airtableRecordId) {
try {
const url = `https://api.airtable.com/v0/${AIRTABLE_BASE}/${AIRTABLE_TABLE}`;
const res = await fetch(url, {
method: 'PATCH',
headers: {
Authorization: `Bearer ${AIRTABLE_TOKEN}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
records: [{
id: airtableRecordId,
fields: { Active: false }
}]
})
});
const json = await res.json();
if (json.error) {
console.error("❌ Erreur déban Airtable :", json.error);
alert("❌ Erreur déban Airtable : " + json.error.message);
} else {
console.log("✅ Déban Airtable :", json);
showQuickNotif('🔄 Profil débanni');
}
} catch (e) {
console.error("❌ Exception déban :", e);
alert("❌ Erreur connexion Airtable (déban)");
}
}
function isBanned(id) {
return bannedList.some(item => item.id === id);
}
const style = document.createElement('style');
style.textContent = `
.fakeBtnThumbnail, .fakeBtnProfile {
background:#e00;color:#fff;font-weight:bold;border:2px solid #fff;
border-radius:5px;padding:5px 8px;cursor:pointer;font-size:14px;
box-shadow:0 0 5px rgba(0,0,0,0.5);z-index:9999;position:relative;
}
.fakeBtnThumbnail {position:absolute;bottom:5px;right:5px;}
.fakeBtnThumbnail:hover, .fakeBtnProfile:hover {background:#c00;}
#banConfirmPanel {
position:fixed;top:0;left:0;right:0;bottom:0;
background:rgba(0,0,0,0.5);
display:flex;justify-content:center;align-items:center;z-index:10001;
}
#banConfirmPanel .inner {
background:#fff;padding:20px;border-radius:8px;text-align:center;min-width:250px;
}
#banManager {
position:fixed;top:50px;right:200px;background:#fff;border:1px solid #ccc;
padding:10px;max-height:400px;overflow:auto;z-index:10002;
}
#banManager h3{margin-top:0;}
#banManager ul{padding:0;list-style:none;}
#banManager li{margin-bottom:5px;font-size:13px;}
#banManager button{margin-left:10px;}
`;
document.head.appendChild(style);
function showConfirmPanel(profileID, profileName) {
const old = document.getElementById('banConfirmPanel');
if (old) old.remove();
const panel = document.createElement('div');
panel.id = 'banConfirmPanel';
panel.innerHTML = `
<div class="inner">
<p>Confirmer le ban du profil :</p>
<p><b>${profileName}</b> (ID: ${profileID})</p>
<button id="confirmBan">✅ Confirmer</button>
<button id="cancelBan">❌ Annuler</button>
</div>`;
document.body.appendChild(panel);
panel.querySelector('#confirmBan').onclick = async () => {
await pushBanToAirtable(profileID, profileName);
panel.remove();
};
panel.querySelector('#cancelBan').onclick = () => panel.remove();
}
function showBanManager() {
const existing = document.getElementById('banManager');
if (existing) { existing.remove(); return; }
const panel = document.createElement('div');
panel.id = 'banManager';
panel.innerHTML = `<h3>Banlist collaborative</h3>`;
const list = document.createElement('ul');
if (bannedList.length === 0) {
const li = document.createElement('li');
li.textContent = "Aucun profil banni pour le moment.";
list.appendChild(li);
} else {
bannedList.forEach(item => {
const li = document.createElement('li');
li.textContent = `${item.name || "(sans nom)"} [${item.id}] (ban le ${new Date(item.date).toLocaleString()})`;
const btn = document.createElement('button');
btn.textContent = 'Déban';
btn.onclick = async () => {
await deactivateBan(item.airtableId);
li.remove();
};
li.appendChild(btn);
list.appendChild(li);
});
}
panel.appendChild(list);
document.body.appendChild(panel);
}
function addFakeButtonsToListing() {
const links = document.querySelectorAll('a[href*="/escort/"]');
const seen = new Set();
links.forEach(link => {
const m = link.href.match(/\/escort\/([^\/]+)-(\d+)/);
if (!m) return;
const name = decodeURIComponent(m[1]).replace(/-/g, ' ');
const id = m[2];
if (seen.has(id)) return;
seen.add(id);
const card = link.closest('div');
if (!card) return;
if (isBanned(id)) { card.style.display = 'none'; return; }
if (getComputedStyle(card).position === 'static') card.style.position = 'relative';
const btn = document.createElement('button');
btn.textContent = 'FAKE';
btn.className = 'fakeBtnThumbnail';
btn.onclick = (e) => {
e.preventDefault();
e.stopPropagation();
showConfirmPanel(id, name);
};
card.appendChild(btn);
});
}
function addFakeButtonToProfile(id) {
let nameText = "(inconnu)";
const breadcrumbActive = document.querySelector('.breadcrumbs a.element.active');
if (breadcrumbActive && breadcrumbActive.textContent.trim()) {
nameText = breadcrumbActive.textContent.trim();
} else {
const h1 = document.querySelector('h1');
if (h1 && h1.innerText && h1.innerText.trim()) {
nameText = h1.innerText.trim();
}
}
const header = document.querySelector('h1') || document.querySelector('.breadcrumbs');
if (!header) return;
const btn = document.createElement('button');
btn.textContent = 'FAKE';
btn.className = 'fakeBtnProfile';
btn.onclick = () => showConfirmPanel(id, nameText);
header.appendChild(btn);
}
function addGlobalUI() {
const panel = document.createElement('div');
panel.style.position = 'fixed';
panel.style.top = '50px';
panel.style.right = '10px';
panel.style.background = 'rgba(255,255,255,0.9)';
panel.style.padding = '8px';
panel.style.border = '1px solid #ccc';
panel.style.zIndex = '10000';
panel.style.opacity = '0.6';
panel.style.fontSize = '12px';
panel.innerHTML = `<button id="manageList">📋 Gérer banlist</button>`;
panel.onmouseenter = () => panel.style.opacity = '1';
panel.onmouseleave = () => panel.style.opacity = '0.6';
document.body.appendChild(panel);
panel.querySelector('#manageList').onclick = showBanManager;
}
(async () => {
bannedList = await fetchBanListFromAirtable();
const profileMatch = window.location.pathname.match(/\/escort\/([^\/]+)-(\d+)/);
if (profileMatch) {
const id = profileMatch[2];
if (isBanned(id)) {
document.body.innerHTML = '<div style="padding:2em;font-size:16px;background:#fee;">Ce profil est marqué comme fake.</div>';
} else {
addFakeButtonToProfile(id);
}
} else {
addFakeButtonsToListing();
}
addGlobalUI();
})();
})();