Respawn Lot Message Delete

Suppression msg lot

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Respawn Lot Message Delete
// @version      5.9.2
// @description  Suppression msg lot
// @namespace    Respawn Lot Message Delete
// @author       Craftbukkit debug par ROMANCE_DAWN adapt for payload
// @require      https://update.greasyfork.org/scripts/578578/1827981/JVCGetPayLoad.js
// @icon         https://images.emojiterra.com/microsoft/fluent-emoji/15.1/128px/1f5d1_color.png
// @match        https://www.jeuxvideo.com/profil/*?mode=historique_forum*
// @license MIT
// ==/UserScript==

//Global Variables
let nMessageAlreadyDelete;
let nMessageNonDelete;
let nMessageDelete;
let freshHash;

//Show Update UI
function hydrateUI(nPage) {
    document.getElementById("papage").innerHTML = `
            <b>Vidage Message :</b><br>
            Message supprimé : ${nMessageDelete} <br>
            Message déjà supprimé : ${nMessageAlreadyDelete} <br>
            Message non supprimé : ${nMessageNonDelete} <br>
            Page n°${nPage}<br><br>`;
}

const sleep = ms => new Promise(r => setTimeout(r, ms));

const monthList = ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre"];


//Fetch 403 / 429 - JSON / HTML
async function fetchGetPage403(url) {
    const jsonHeaders = { 'Accept': 'application/json', 'X-Requested-With': 'XMLHttpRequest' };
    for (let attempt = 1; attempt <= 6; attempt++) {
        await sleep(500);
        const response = await fetch(url, { headers : jsonHeaders });
        if (response.status === 403 || response.status === 429) {
            console.log(`Rate limit ${response.status}, attente 3s (essai ${attempt}/6)`);
            await sleep(3000);
            continue;
        }
        return response;
    }
    return null;
}

// Get_Hash_By_Fetch
async function fechGetHash() {
    const response = await fetch('https://www.jeuxvideo.com/forums/0-36-0-1-0-1-0-guerre-des-consoles.htm');
    const data = await response.text();
    const jsonData = getJsonPayloadRaw(data);
    return jsonData?.ajaxModerationToken;
}

//REQUEST DELETE MESSAGE
async function requestDeleteMessage(idMessages, retryOnce = true) {
    const reponse = await fetch(`https://www.jeuxvideo.com/forums/message/delete?ids=${idMessages.join(',')}&type=delete&ajax_hash=${freshHash}`, { method: 'POST' });
    if (!reponse.ok && retryOnce) {
        freshHash = await fechGetHash();
        return requestDeleteMessage(idMessages, false);
    }
    return reponse;
}

async function videPage(nPage, data) {
    //Lecture champs User
    const [yearMin, monthMin, dayMin] = document.getElementById('mindate').value.split('-');
    const [yearMax, monthMax, dayMax] = document.getElementById('maxdate').value.split('-');
    let minDate = new Date(yearMin, monthMin - 1, dayMin).getTime(); //TimeStamp Min
    let maxDate = new Date(yearMax, monthMax - 1, dayMax).getTime(); //TimeStamp Max


    let jsonData;
    try { 
        jsonData = JSON.parse(data); //Json from serv
    } catch { 
        jsonData = getJsonPayloadRaw(data); //FallBack Html Payload
    }

    const messages = jsonData?.listMessage ?? [];

    const messageToDelete = [];
    for (const message of messages) {
        if (message.stateMessage === 'msg-visible') {
            const idMessage = message.id;

            // publishedDate format: "19 sptembre 1999 à 00:00:00"
            const [day, monthStr, year] = message.publishedDate.split(' ');
            const messageTimestamp = new Date(year, monthList.indexOf(monthStr), day).getTime();

            if (!monthList.includes(monthStr)) throw new Error('Mois invalide => Annulation'); //Guard

            // DATES MATCH => DELETE
            if (messageTimestamp >= minDate && messageTimestamp <= maxDate) {
                /*
                const deletedMessage = await requestDeleteMessage([idMessage]);
                if (!deletedMessage?.ok) {
                    throw new Error(`Échec suppression message ${idMessage}`);
                }
                nMessageDelete++;
                */
                messageToDelete.push(idMessage);
            } else {
                nMessageNonDelete++;
            }
        } else {
            nMessageAlreadyDelete++;
        }
    }

    // SUPPRESSION EN UNE SEULE REQUETTE POUR EVITER DE SPAM
    if (messageToDelete.length) {
        const deletedMessage = await requestDeleteMessage(messageToDelete);
        if (!deletedMessage?.ok) {
            throw new Error(`Échec suppression de (${messageToDelete.length} messages)`);
        }
        nMessageDelete += messageToDelete.length;
    }
    hydrateUI(nPage);

    const nextPage = jsonData?.pagerView?.next?.url;
    if (nextPage) {
        console.log(nextPage);
        const response = await fetchGetPage403(nextPage);
        const nextData = await response.text();
        await videPage(nPage + 1, nextData);
    } else {
        alert('Dernière Page Traité')
    }
}

document.querySelector(".titre-bloc").insertAdjacentHTML('beforeend', `
    <div style="font-size: 1.2rem;"><br>  -> Du : 
    <input type="date" id="mindate" value="1970-01-01" class="form-control" style="width: 230px; font-weight: 600; font-size: 1rem; display: inline-flex; margin: 5px;">
     au 
    <input type="date" id="maxdate" value="1998-01-01" class="form-control" style="width: 230px; font-weight: 600; font-size: 1rem; display: inline-flex; margin: 5px;">
    <button class="btn icon-bin" title="Tout supprimer" id="viderAll" style="display: inline-flex; align-items: center; font-size: 1.1rem; height: 2.2rem;">Vider</button></div>`);

document.getElementById("viderAll").onclick = async function() {
    if (confirm("Le script va commencer de la page en cours\n/!\ Êtes-vous sûr de vouloir tout supprimer ? /!\\ ")) {

        this.style.display = 'none';
        document.getElementById('forum-main-col').style.display = 'none';
        document.getElementById('mindate').disabled = true;
        document.getElementById('maxdate').disabled = true;

        nMessageDelete = 0;
        nMessageAlreadyDelete = 0;
        nMessageNonDelete = 0;
        const nPage = 1;

        document.querySelector(".titre-head-bloc").insertAdjacentHTML("afterend", "<span id='papage' style='display: block;'></span>");
        hydrateUI(nPage);

        //Get hash from forum (Le hash de suppression nest plus dans lhisto on va le chercher sur les forums).
        freshHash = await fechGetHash();

        const startUrl = location.href;

        const response = await fetchGetPage403(startUrl);
        const startData = await response.text();
        await videPage(nPage, startData);
    }
};