Full_Black_List

Supprime totalement les sujets des pseudo blacklistés depuis la blacklist JVC.

2026-04-20 या दिनांकाला. सर्वात नवीन आवृत्ती पाहा.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey, Greasemonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

You will need to install an extension such as Tampermonkey to install this script.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्क्रिप्ट व्यवस्थापक एक्स्टेंशन इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्क्रिप्ट व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्टाईल व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

// ==UserScript==
// @name         Full_Black_List
// @namespace    Full_Black_List
// @version      0.91.0
// @description  Supprime totalement les sujets des pseudo blacklistés depuis la blacklist JVC.
// @author       Atlantis
// @match        *://www.jeuxvideo.com/recherche/forums/0-*
// @match        *://www.jeuxvideo.com/forums/0-*
// @match        *://www.jeuxvideo.com/forums/42-*
// @match        *://www.jeuxvideo.com/forums/1-*
// @match        *://www.jeuxvideo.com/forums/message*
// @match        *://www.jeuxvideo.com/messages-prives/message.php*
// @match        *://www.jeuxvideo.com/messages-prives/indesirables.php
// @match        *://www.jeuxvideo.com/sso/blacklist.php
// @match        *://www.jeuxvideo.com/login*
// @run-at       document-end
// @icon         https://images.emojiterra.com/microsoft/fluent-emoji/15.1/128px/1f6ab_color.png
// @license      MIT
// @grant        unsafeWindow
// ==/UserScript==

// FONCTIONS RESEAU FETCH :
//   GET : fonctionSynchBLForums() : blacklist.php => LocalStorage
//   GET : getBLListMP() : GET BlackList MP et Hash Tempo
//   POST : deleteBlacklistMP() : BlackListForum => Strike BlackListMP
//   POST : deleteBlacklistMPALL() : Strike ALL BlackListMP
//   GET : fetchForumBlacklist() : ADD ou DEL blacklist forum
//   GET : fetchForumBlacklist() : ADD ou DEL blacklist forum

// CODE PAR PAGE :
//           /login                            => Vide le Local torage
//   FOFO    /forums/0-* (liste sujets)        => Masque sujets via BlackList dans LOCAL STORAGE
//   FOFO    /forums/1- /42-                   => Masque messages BL + Synch BL Fofo => localStorage
//   MP      /messages-prives/message.php      => masque messages BL + Synch : BL localStorage <=> BL MP <=> BL Fofo
//   MP      /messages-prives/indesirables.php => Synck Suppresion MP vers Forum
//   COMPTE  /sso/blacklist.php                => Gestion BL Forum - MP + Boutons Import / Export / Reset


//CSS HIDE BlackList
const cssForum = document.createElement('style');
//CSS MP/PAGE HIDE
cssForum.textContent = `
/* Hide block*/
.msg-pseudo-blacklist,
.messageUser--blacklisted {
    display : none;
}

/* Hide block COLOR CORRECTION*/
.container__messages--isAlternateColor > [id^=message-]:nth-child(odd of [id^=message-]:not(:has(.messageUser--blacklisted))),
.container__messages--isAlternateColor > [id^=message-]:nth-child(odd of [id^=message-]:not(:has(.messageUser--blacklisted)))> .messageUser {
    --background-color: var(--jv-block-even-bg-color);
    --border-color    : var(--jv-border-even-color)
}

.container__messages--isAlternateColor > [id^=message-]:nth-child(even of [id^=message-]:not(:has(.messageUser--blacklisted))),
.container__messages--isAlternateColor > [id^=message-]:nth-child(even of [id^=message-]:not(:has(.messageUser--blacklisted)))> .messageUser {
    --background-color: var(--jv-block-bg-color);
    --border-color    : var(--jv-border-color)
}


/* Hide Quote*/
.messageUser .message__blockquote--blacklist { 
    background: rgba(155, 155, 155, .1);
    padding-bottom: 20px;
}
.messageUser .message__blockquote--blacklist > * {
    display:none;
}

/* Force Show block and Quotes*/
.container__messages.show-blacklist .messageUser--blacklisted { display: block; }
.container__messages.show-blacklist .messageUser .message__blockquote--blacklist > * {
    padding-bottom: none;
    display: block;
}

/*CSS CAPTCHA */
iframe.captcha-overlay {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100%;
    z-index: 9999;
    background: #fff;
    border: none;
}

/*CSS BOUTON*/
#bl-import,
#bl-export,
#bl-clear {
    border-radius:6px;
}

#show-msg {
    margin-left: 1rem;
    min-width:5rem;
}


#show-topic {
    border-radius:6px;
    min-width: 4rem;
}
#bl-refresh {
    border-radius:6px;
    min-width: 3.5rem;
}
#show-blacklist {
    border-radius:6px;
    min-width: 2rem;
}

/*CSS LIST SUJET FORCE SHOW*/
/* Force Show Topic */
.tablesForum.show-blacklist .tablesForum__bodyRow {
    display: grid !important;
}

`;

//CSS LIST SUJET HIDDEN BY PSEUDO
function addBlacklistCSSList(user) {
    cssForum.textContent += `
    /* Hide Topic */
    .tablesForum__bodyRow:has( .tablesForum__authorLink[href*="/profil/${user}?"]) {
        --topic-bl: 1;
        display: none;
        background-color: var(--jv-block-highlighted-bg-color) !important ;
    }`;
}



document.head.appendChild(cssForum);
//CSS FORUM END

//GreasyMonkey FELLBACK Fetch
const nativeFetch = typeof unsafeWindow !== 'undefined' ? unsafeWindow.fetch : fetch;

///// FONTIONS FETCH GET HASH //////
async function fetchGetForumHash(url = 'https://www.jeuxvideo.com/forums/0-51-0-1-0-1-0-blabla-18-25-ans.htm') {
    const res = await fetch(url);
    const html = await res.text();
    const doc = new DOMParser().parseFromString(html, 'text/html');
    const payload64 = doc.documentElement.innerHTML.match(/forumsAppPayload\s*=\s*["']([^"']+)["']/)?.[1];
    return payload64 ? JSON.parse(atob(payload64)).ajaxModerationToken : null;
}

///// Captch Solve ////////
async function resolveCaptcha(url) {
    const iframe = document.createElement('iframe');
    iframe.src = `https://www.jeuxvideo.com/sso/settings.php`;
    iframe.className = 'captcha-overlay';
    document.body.appendChild(iframe);
    iframe.onload = async () => {
        if (iframe.contentDocument.getElementById('page-compte')) {
            iframe.remove();
            const checkRes = await nativeFetch(url);
            if (checkRes.ok) fonctionSynchBLForums();
        }
    };
}

///// FONTIONS FETCH GET DOC //////
async function fetchParseDom(url) {
    const res = await nativeFetch(url);
    if (res.status === 403) {
        return resolveCaptcha(url);
    }
    const html = await res.text();
    return new DOMParser().parseFromString(html, 'text/html');
}

///// FONTIONS FETCH GET BLACKLIST TO LOCAL STORAGE //////
// /sso/blacklist.php
async function fonctionSynchBLForums() {
    const docFetched = await fetchParseDom(`https://www.jeuxvideo.com/sso/blacklist.php`);
    const pseudos = docFetched.querySelectorAll('#blacklist span');

    // /SSO/BLACKLIST.PHP => VERS_LOCAL_STORAGE
    const pseudoList = [...pseudos].map(span => span.textContent.trim().toLowerCase());
    localStorage.setItem('fullBlacklistJVC', JSON.stringify(pseudoList));
    console.log('[BL] LocalStorage mis à jour :', pseudoList);
}



///// FONTION FETCH GET BLACKLIST MP AND HASH //////
// /indesirables.php
async function getBLListMP() {
    const docFetched = await fetchParseDom(`https://www.jeuxvideo.com/messages-prives/indesirables.php`);
    const listItems = docFetched.querySelectorAll('#blacklist .mp_delete_blacklist');

    const indexIdHashMP = {};
    listItems.forEach(user => {
        const idAlias = user.dataset.id;
        const hashTempo = user.dataset.hash;
        indexIdHashMP[idAlias] = hashTempo; // { [idAlias] : hashTempo }
    });
    return indexIdHashMP;
}

///// FONTION DEL PSEUDO MP //////
async function deleteBlacklistMP(idAlias, indexIdHashMP) {
    const hashTempo = indexIdHashMP[idAlias]; // { [idAlias] : hashTempo  }
    if (!hashTempo) return; //pas de hash indexe
    await fetch(`https://www.jeuxvideo.com/messages-prives/ajax/ajax_mp_blacklist_delete.php`, {
        method: 'POST',
        body: new URLSearchParams({ id: idAlias, hash: hashTempo })
    });
}


///// FONTION DEL ALL PSEUDO MP //////
async function deleteBlacklistMPALL(indexIdHashMP, callBackProgress) {
    for (const idAlias in indexIdHashMP) {
        const hashTempo = indexIdHashMP[idAlias]; // { [idAlias] : hashTempo }
        // Effectuer la fetch de suppression (EN MP)
        await fetch(`https://www.jeuxvideo.com/messages-prives/ajax/ajax_mp_blacklist_delete.php`, {
            method: 'POST',
            body: new URLSearchParams({ id: idAlias, hash: hashTempo })
        });
        callBackProgress?.(); // Call Back avancement.
    }
}


////// RETURN ID ALIAS AND HASH BY MESSAGE ID /////////
function getHashIdByMessage(msgId) {
     const payload = JSON.parse(atob(unsafeWindow.jvc.forumsAppPayload));
     const blacklistUrl = payload.listMessage.find(f => f.id === +msgId)?.actions.blacklist.url;
     const fullblacklistUrl = new URL(blacklistUrl, location.origin);

    return {
        idAlias      : fullblacklistUrl.searchParams.get('alias_id'),
        hashModForum : fullblacklistUrl.searchParams.get('ajax_hash'),
    };
}


///// FONTION BL FORUM //////
async function fetchForumBlacklist(idAlias, hashModForum, action = 'add') {
    const params = new URLSearchParams({ alias_id: idAlias, ajax_hash: hashModForum, action : action });
    await fetch(`https://www.jeuxvideo.com/forums/author/blacklist?${params}`, {
        method: 'POST'
    });
}


///// SCRIPT PAR PAGE //////
//3_______PAGE_DE______CONNEXION___(Login)___
if (location.href.includes('/login')) {
    localStorage.removeItem('fullBlacklistJVC'); // Efface LocalStorage => EN CAS DE DECONNEXION
}

//5_______LISTE_SUJET_____
if (location.href.includes('/forums/0-')) {

    //HTML
    document.querySelector('.js-pagination-top')?.insertAdjacentHTML('afterend', `
        <div class="container__pagination" style="display: flex; justify-content: center;">
            <button id="show-topic" class="btn btn-secondary"
                  title="">
                MSG BL
            </button>&nbsp;
            <button id="bl-refresh" class="btn btn-secondary"
                  title="Actualiser la blacklist des Sujets">
                Actu
            </button>&nbsp;
            <a href="/sso/blacklist.php" style="outline:none;" target="_blank">
                <span id="show-blacklist" class="btn btn-secondary"
                      title="Voir/Editer/Exporter la BlackList">
                    BL
                </span>
            </a>
        </div>
    `);
    //HTML-JS-IMPERATIF
    let countBlBtn;
    const showTopicBtn = document.querySelector('#show-topic');
    showTopicBtn.addEventListener('mouseenter', () => {
        countBlBtn = 0;
        const countBlock = document.querySelectorAll('.tablesForum__bodyRow');
        for (const li of countBlock) {
            if (getComputedStyle(li).getPropertyValue('--topic-bl') === '1') countBlBtn++;
        }
        showTopicBtn.title = `${countBlBtn} topic(s) filtrés (Voir)`;
    });
    showTopicBtn.addEventListener('click', () => {
        document.querySelector('.tablesForum')?.classList.add('show-blacklist');
        showTopicBtn.textContent = `(${countBlBtn}) BL`;
    });
    document.querySelector('#bl-refresh').addEventListener('click', async () => {
        await fonctionSynchBLForums();
        alert('Filtrage des topics actualisés avec la blacklist JVC ✅');
        location.reload();
    });

}

//5B______LISTE_SUJET ET_RECHERCHE_________
if (location.href.includes('/forums/0-') || location.href.includes('/recherche/forums/0-')) {

    const listeLocalStorage = localStorage.getItem('fullBlacklistJVC')?.toLowerCase();
    if (!listeLocalStorage) fonctionSynchBLForums().then(() => location.reload());

    const blacklistParsedStorage = JSON.parse(listeLocalStorage);

    for (const user of blacklistParsedStorage) {
        //AJOUTER PSEUDO EN CSS
        addBlacklistCSSList(user);

        //Doublage Div pour eviter bug alternance couleur
        setTimeout(() => {
            document.querySelectorAll('.tablesForum__bodyRow').forEach(bodyRow => {
               const author = bodyRow.querySelector('.tablesForum__authorLink');
               if (author.textContent.trim().toLowerCase() === user) {
                   bodyRow.insertAdjacentHTML("afterend", `<li class="topic-ghost-block" style="display:none;"></li>`);
               }
            });
        }, 700);
    }
}

//6_______TOPIC_MASQUAGE_________
if (location.href.includes('/forums/1-') || location.href.includes('/forums/42-') || location.href.includes('/forums/message/')) {

    //HTML
    document.querySelector('#forums-topic-resolve')?.insertAdjacentHTML('afterend', `
        <button id="show-msg" class="btn btn-secondary"
             title="">
            MSG BL
        </button>
    `);

    //HTML-JS-IMPERATIF
    const showMsgBtn = document.querySelector('#show-msg');
    let countBlBtn = 0;
    showMsgBtn?.addEventListener('mouseenter', () => {
        countBlBtn = document.querySelectorAll('.messageUser--blacklisted').length;
        showMsgBtn.title = `${countBlBtn} message(s) filtrés (Voir)`;
    });
    showMsgBtn?.addEventListener('click', () => {
        document.querySelector('.container__messages')?.classList.add('show-blacklist');
        showMsgBtn.textContent = `(${countBlBtn}) BL`;
    });

    //JS Conteneur
    const scopeForumBlocs = document.querySelector('.container__messages');
    scopeForumBlocs.addEventListener('click', async(e) => {
        const btnPicto = e.target.closest('button[title="Blacklister"]');
        const btnCancel = e.target.closest('.messageUser--blacklisted .messageUser__link[aria-label^="Retirer"]');
        if (e.target.closest('#jvchat-main')) return; //dont touche if jvchat
        if (btnPicto) {
            sessionStorage.setItem('pendingActionSynchAlias', 'true');

            e.preventDefault(); e.stopImmediatePropagation();

            const messageId = btnPicto.closest('div[id^="message-"]').id.split('-')[1];
            const { idAlias, hashModForum } = getHashIdByMessage(messageId);
            await fetchForumBlacklist(idAlias, hashModForum);
            location.reload();


        } else if (btnCancel) {
            sessionStorage.setItem('pendingActionSynchAlias', 'true');
            /*
            const messageId = btnCancel.closest('div[id^="hidden-"]').id.split('-')[1];
            */
            setTimeout(() => location.reload(), 1000);
        }
    }, { capture: true });


    //Class_for_Hides_Quotes
    function hidePseudoQuotes() {
        const listeLocalStorage = localStorage.getItem('fullBlacklistJVC')?.toLowerCase();
        const blacklistParsedStorage = JSON.parse(listeLocalStorage || "[]");

        document.querySelectorAll(".message__blockquote > p:first-of-type").forEach(p => {
            const txtQuotClean = p.textContent.replace(/\s+/g, ' ');
            const pseudoIRC = txtQuotClean.match(/<([^>]+)>/)?.[1]?.toLowerCase(); //IRC
            const pseudoForum = txtQuotClean.match(/(\S+)\s+a écrit :/)?.[1]?.toLowerCase(); //FOFO
            if (blacklistParsedStorage.includes(pseudoForum) || blacklistParsedStorage.includes(pseudoIRC)) {
                p.closest(".message__blockquote").classList.add("message__blockquote--blacklist");
            }
        });
    }
    setTimeout(hidePseudoQuotes, 1000);

    // Mise à jour de la Blacklist du script APRES actualisation
    if (sessionStorage.getItem('pendingActionSynchAlias')) {
        fonctionSynchBLForums().then(hidePseudoQuotes);
        sessionStorage.removeItem('pendingActionSynchAlias');
    }

}

//7_____PARTIE__MP__________________
if (location.href.includes('/messages-prives/message.php')) {

    //JS Conteneur
    // [1] Ajout d'un event sur les boutons "blacklist MP" pour quils agissent aussi sur la blacklist forum
    const scopeMPBlocs = document.querySelector('.conteneur-messages-pagi');
    scopeMPBlocs.addEventListener('click', (e) => {
        const btnPicto = e.target.closest('.picto-msg-tronche');
        if (e.target.closest('#jvchat-main')) return; //dont touche if jvchat
        if (btnPicto) {
            const idAlias = btnPicto.dataset.url.match(/add_blacklist=(\d+)/)[1];
            sessionStorage.setItem('pendingActionSynchAlias', idAlias);
        }
    }, { capture: true });

    // [2] localStorage => simulation de clic sur bouton "blacklist MP"
    const listeLocalStorage = localStorage.getItem('fullBlacklistJVC')?.toLowerCase();
    if (!listeLocalStorage) fonctionSynchBLForums().then(() => location.reload());

    // Liste pseudos en minuscules
    const blacklistParsedStorage = JSON.parse(listeLocalStorage);
    document.querySelectorAll('.bloc-pseudo-msg').forEach(pseudoblock => {
        const pseudo = pseudoblock.textContent.trim().toLowerCase();
        if (blacklistParsedStorage.includes(pseudo)) {
            pseudoblock.closest('.bloc-message-forum').querySelector('.picto-msg-tronche')?.click();
        }
    });

    // [3] Appel black list MP => Synch Fofo
    let idAlias = sessionStorage.getItem('pendingActionSynchAlias');
    if (idAlias) {
      (async () => {
        // Fetch recuperer hash forum
        const hashModForum = await fetchGetForumHash();

        // AjoutBL_Forum
        await fetchForumBlacklist(idAlias, hashModForum);
        await fonctionSynchBLForums();
        //Clean
        sessionStorage.removeItem('pendingActionSynchAlias'); // Supprime ID => Il vient d'etre traité.
      })();
    }

    // [4] Cacher les messages déjà blacklistés
    document.querySelectorAll('.msg-pseudo-blacklist').forEach(block =>
        block.insertAdjacentHTML("afterend", `<div class="bloc-message-block" style="display:none;"></div>`)
    );

}

//8_____PAGE_BLACKLIST_MP__________________
if (location.href.includes('/messages-prives/indesirables.php')) {

    // Une suppression dans la BlackList MP => Suppression BL Forum + Suppression LocalStorage
    let hashModForum;
    document.querySelector('#indesirables').addEventListener('click', async (e) => {
        const buttonDel = e.target.closest('.mp_delete_blacklist');
        if (buttonDel) {
            if (!hashModForum) {
                hashModForum = await fetchGetForumHash();
            }
            await fetchForumBlacklist(buttonDel.dataset.id, hashModForum, 'delete');
            localStorage.removeItem('fullBlacklistJVC');
        }
    });
}

//9_____PAGE_BLACKLIST_Forums_SYNCH_________________
if (location.href.includes('/sso/blacklist.php')) {

    async function fonctionSynchBLForumsNoFetch() { //lit les pseudo visible sur la page
        await new Promise(resolve => setTimeout(resolve, 1000)); //delais pour capturer la page à jour

        let pseudos = document.querySelectorAll('#blacklist span');
        let pseudoList = [...pseudos].map(span => span.textContent.trim().toLowerCase());
        localStorage.setItem('fullBlacklistJVC', JSON.stringify(pseudoList));
        console.log('[BL] LocalStorage mis à jour :', pseudoList);
    }

    fonctionSynchBLForumsNoFetch(); // Liste Page vers LocalStorage

    let indexIdHashMP; // { [idAlias] : hashTempo , [idAlias2] : hashTempo2 , ... }
    // Suppression par pseudo
    document.querySelector('#blacklist').addEventListener('click', async (e) => {
        const cross = e.target.closest('.icon-cross-entypo');
        if (cross) {
            const idAlias = cross.closest('li')?.dataset.idAlias;
            if (!indexIdHashMP) {
                indexIdHashMP = await getBLListMP();
            }
            await deleteBlacklistMP(idAlias, indexIdHashMP);
            fonctionSynchBLForumsNoFetch();
        }
    });


    //9b_____PAGE_BLACKLIST_Forums_GESTION_IMPORT_EXPORT_________________

    // CREATION_HTML_BOUTON_PERSO__
    const container = document.querySelector('#page-compte .layout__content');
    container.insertAdjacentHTML('beforeend', `
        <ul>
            <button id="bl-import" title="Importer BlackList depuis un Fichier" class="btn btn-secondary">
                Importer
            </button>&nbsp;
            <button id="bl-export" title="Exporter BlackList JVC en Fichier" class="btn btn-secondary">
                Exporter
            </button>
        </ul>
        <ul>
            <button id="bl-clear" title="Vider toute la blacklist JVC + MP + Script" class="btn btn-danger">
                Vider BL Forum et MP
            </button>
        </ul>
    `);

    // ATTACH_LISTENER_IMPORT
    document.querySelector('#bl-import').addEventListener('click', () => {
        const input = document.createElement('input');
        input.type = 'file';
        input.accept = '.json';
        input.addEventListener('change', async () => {
            const fileJson = input.files[0];
            if (!fileJson) return;

            let blacklistjson;
            try {
                blacklistjson = JSON.parse(await fileJson.text());
            } catch {
                return alert("Fichier JSON invalide.");
            }

            // REQUÊTES D’AJOUT UN À UNE FOFO
            document.querySelector('#bl-import').textContent = 'Load...';

            const hashModForum = await fetchGetForumHash();
            let count = 1;
            for (const obj of blacklistjson) {
                await fetchForumBlacklist(obj.id, hashModForum);
                document.querySelector('#bl-import').textContent = `Load (${count++})`;
            }
            window.location.reload();
        });
        input.click();
    });

    // ATTACH_LISTENER_EXPORT
    document.querySelector('#bl-export').addEventListener('click', () => {
        const blacklistItems = document.querySelectorAll('#blacklist li');
        const idList = [...blacklistItems].map(li => ({
            id: li.dataset.idAlias,
            pseudo: li?.textContent.trim()
        }));

        const blob = new Blob([JSON.stringify(idList, null, 2)], { type: 'application/json' });
        const url = URL.createObjectURL(blob);
        const link = document.createElement('a');
        link.href = url;
        link.download = 'Blacklist_JVC.json';
        link.click();
        URL.revokeObjectURL(url); // LIBERE LA MEMOIRE apres telechargement
    });

    // ATTACH_LISTENER_SUPPRESSION
    document.querySelector('#bl-clear').addEventListener('click', async () => {
        if (!window.confirm('⚠️ Supprimer toute la blacklist (JVC + MP + Script) ? ⚠️')) return;

        document.querySelector('#bl-clear').textContent = 'Loading...';
        let listItems = document.querySelectorAll('#blacklist li');

        // Nettoyage de TOUT pseudo blacklistes
        let count = 1;
        // AjoutBL_Forum
        const hashModForum = await fetchGetForumHash();
        for (const liItem of listItems) {
            const idAlias = liItem.dataset.idAlias;
            await fetchForumBlacklist(idAlias, hashModForum, 'delete');
            document.querySelector('#bl-clear').textContent = `Loading (${count})`;
            count++;
        }

        // Nettoyage de TOUT pseudo blacklistes en MP
        let countMP = 1
        const indexIdHashMP = await getBLListMP(); // { [idAlias] : hashTempo , ... }
        await deleteBlacklistMPALL(indexIdHashMP, () => { // supprime côté MP
            document.querySelector('#bl-clear').textContent = `Loading (OK) (MP : ${countMP})`;
            countMP++;
        });
        window.location.reload();
    });
}


/*
MIT License

Copyright (c) 2026 Atlantis (https://github.com/Lantea-Git)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/