// ==UserScript==
// @name Surlignage Post
// @namespace http://tampermonkey.net/
// @version 0.8.7
// @description Version de Test. Met en évidence l'auteur (OP), les citations, les PEMT, vos messages et les DDB sur tous les forums JVC.
// @author FaceDePet
// @match *://www.jeuxvideo.com/forums/*-*-*-*-*-*-*-*.htm
// @connect *.jeuxvideo.com
// @icon https://cdn-icons-png.flaticon.com/512/4698/4698417.png
// @grant GM_xmlhttpRequest
// @run-at document-end
// @license MIT
// ==/UserScript==
(function() {
'use strict';
class JVCTopicEnhancer {
constructor() {
this.CACHE_KEY_OP = 'jvcTopicEnhancerCacheOP';
this.CACHE_KEY_POSTS = 'jvcUserPostsCache';
this.CACHE_KEY_DDB = 'jvcDdbStatusCache';
this.MAX_CACHED_POSTS_PER_TOPIC = 20;
this.pemtColors = ['#45a093', '#5c8fba', '#896a9e', '#c77e4d', '#c06158'];
this.init();
}
async init() {
this.topicId = this.getTopicId();
if (!this.topicId) return;
this.currentPage = this.getCurrentPageNumber();
this.currentUser = this.getCurrentUsername();
this.addPostListener();
try {
const [opUsername, userMessages] = await Promise.all([
this.getOpUsername(),
this.currentUser ? this.getAllUserMessageContents() : []
]);
this.opUsername = opUsername;
this.currentUserMessages = userMessages;
} catch (error) {
console.error("JVC Enhancer: Erreur lors de la récupération des données.", error);
return;
}
this.highlightRules = [
{ name: 'Original Poster', condition: (author) => author === this.opUsername },
{ name: 'User Mention', condition: (author, el) => this.isUserMentioned(author, el) },
{ name: 'Self', condition: (author) => author === this.currentUser }
];
this.injectStyles();
this.processMessages();
this.checkFirstMessagesReportStatus();
}
// --- Fonctions de Parsing et de Récupération ---
getTopicId() {
const match = window.location.href.match(/\/forums\/\d+-\d+-(\d+)-/);
return match ? match[1] : null;
}
getCurrentPageNumber() {
const match = window.location.href.match(/-(\d+)-0-1-0-/);
return match ? parseInt(match[1], 10) : 1;
}
async getOpUsername() {
const cache = JSON.parse(sessionStorage.getItem(this.CACHE_KEY_OP)) || {};
if (cache[this.topicId]) return cache[this.topicId];
let newOpUsername = (this.currentPage === 1) ?
this.parseOpUsernameFromDocument(document) :
await this.fetchOpUsernameFromPageOne();
if (newOpUsername) {
cache[this.topicId] = newOpUsername;
sessionStorage.setItem(this.CACHE_KEY_OP, JSON.stringify(cache));
}
return newOpUsername;
}
parseOpUsernameFromDocument(doc, isApi = false) {
const selector = isApi ? '.post .bloc-pseudo-msg' : '.bloc-message-forum .bloc-pseudo-msg';
return doc.querySelector(selector)?.textContent.trim() || null;
}
fetchOpUsernameFromPageOne() {
return this.fetchApiPageContent(1).then(doc => this.parseOpUsernameFromDocument(doc, true));
}
fetchApiPageContent(pageNumber) {
return new Promise((resolve, reject) => {
const url = window.location.href.replace(`-${this.currentPage}-0-1-0-`, `-${pageNumber}-0-1-0-`).replace('www.jeuxvideo.com', 'api.jeuxvideo.com');
GM_xmlhttpRequest({
method: "GET",
url,
onload: (res) => resolve(new DOMParser().parseFromString(res.responseText, "text/html")),
onerror: (err) => reject(err)
});
});
}
fetchUrlContent(url) {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "GET",
url,
onload: (res) => resolve(res.responseText),
onerror: (err) => reject(err)
});
});
}
async getAllUserMessageContents() {
const cachedPosts = this.loadUserPostsFromCache();
let pagePosts = this.parseMessagesFromDocument(document);
let prevPagePosts = [];
if (this.currentPage > 1) {
try {
const prevPageDoc = await this.fetchApiPageContent(this.currentPage - 1);
prevPagePosts = this.parseMessagesFromDocument(prevPageDoc, true);
} catch (e) {
console.error("JVC Enhancer: Impossible de charger la page N-1.", e);
}
}
return [...new Set([...cachedPosts, ...pagePosts, ...prevPagePosts])];
}
parseMessagesFromDocument(doc, isApi = false) {
const messages = [];
const sel = {
msg: isApi ? '.post' : '.bloc-message-forum',
pseudo: isApi ? '.bloc-pseudo-msg' : '.bloc-pseudo-msg',
content: isApi ? '.message' : '.txt-msg'
};
doc.querySelectorAll(sel.msg).forEach(msg => {
if (msg.querySelector(sel.pseudo)?.textContent.trim() === this.currentUser) {
const contentElement = msg.querySelector(sel.content);
if (contentElement) {
const clone = contentElement.cloneNode(true);
clone.querySelectorAll('blockquote.blockquote-jv').forEach(bq => bq.remove());
const ownText = this.normalizeText(clone.textContent);
if (ownText) messages.push(ownText);
}
}
});
return messages;
}
// --- Fonctions de Cache et d'Événements ---
addPostListener() {
const postButton = document.querySelector('.postMessage');
if (postButton) {
postButton.addEventListener('click', () => {
const messageTextarea = document.querySelector('#message_topic, .messageEditor__edit');
if (messageTextarea && messageTextarea.value && this.topicId) {
this.saveUserPostToCache(this.normalizeText(messageTextarea.value));
}
}, true);
}
}
saveUserPostToCache(normalizedText) {
try {
const cache = JSON.parse(localStorage.getItem(this.CACHE_KEY_POSTS)) || {};
if (!cache[this.topicId]) cache[this.topicId] = [];
cache[this.topicId].unshift(normalizedText);
cache[this.topicId] = cache[this.topicId].slice(0, this.MAX_CACHED_POSTS_PER_TOPIC);
localStorage.setItem(this.CACHE_KEY_POSTS, JSON.stringify(cache));
} catch (e) {
console.error("JVC Enhancer: Erreur de sauvegarde du cache.", e);
}
}
loadUserPostsFromCache() {
try {
const cache = JSON.parse(localStorage.getItem(this.CACHE_KEY_POSTS)) || {};
return cache[this.topicId] || [];
} catch (e) {
console.error("JVC Enhancer: Erreur de lecture du cache.", e);
return [];
}
}
// --- Logique de Surlignage ---
isUserMentioned(author, el) {
if (!this.currentUser || author === this.currentUser) return false;
const content = el.querySelector('.txt-msg');
if (!content) return false;
const normText = this.normalizeText(content.textContent);
if (normText.includes(this.normalizeText(this.currentUser))) return true;
for (const quote of el.querySelectorAll('blockquote.blockquote-jv')) {
const cleanQuote = this.normalizeText(quote.textContent.replace(/^Le .+? :/s, ''));
if (cleanQuote && this.currentUserMessages.some(msg => cleanQuote.includes(msg))) return true;
}
return false;
}
normalizeText(text) {
return text ? text.toLowerCase().replace(/\s+/g, ' ').trim() : '';
}
getCurrentUsername() {
return document.querySelector('.headerAccount__pseudo')?.textContent.trim() || null;
}
injectStyles() {
const styles = `
/* Surlignages Importants */
.jvc-enhancer-mention { background-color: rgba(230, 195, 92, 0.07); border-left: 2px solid rgba(230, 195, 92, 0.75); }
.jvc-enhancer-op-mention { background-color: rgba(157, 105, 212, 0.07); border-left: 2px solid rgba(157, 105, 212, 0.75); }
/* Surlignages Discrets */
.jvc-enhancer-self { box-shadow: inset 0 0 0 1px rgba(128, 128, 128, 0.2); }
html:not(.theme-light) .jvc-enhancer-self { box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1); }
.jvc-enhancer-pemt { border-right-width: 2px; border-right-style: solid; }
/* Surlignages pour DDB */
.jvc-enhancer-ddb-reported { background-color: rgba(220, 53, 69, 0.07) !important; }
.jvc-enhancer-ddb-administered { background-color: rgba(25, 135, 84, 0.07) !important; }
/* Styles des Badges */
.bloc-avatar-msg { position: relative; }
.jvc-enhancer-avatar-badge {
position: absolute; bottom: -12px; left: 50%; transform: translateX(-50%); z-index: 2;
padding: 2px 6px; font-size: 9px; font-weight: bold; border-radius: 5px;
white-space: nowrap; text-transform: uppercase; letter-spacing: 0.5px;
backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
border: 1px solid rgba(255, 255, 255, 0.1); box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
}
.badge-mention { background-color: rgba(230, 195, 92, 0.4); color: #212529; }
.badge-op-mention { background-color: rgba(157, 105, 212, 0.4); color: white; }
.badge-op, .badge-self, .badge-pemt { background-color: rgba(80, 80, 80, 0.5); color: rgba(255, 255, 255, 0.8); }
`;
const styleSheet = document.createElement("style");
styleSheet.innerText = styles;
document.head.appendChild(styleSheet);
}
processMessages() {
const messages = Array.from(document.querySelectorAll('.bloc-message-forum'));
messages.forEach(el => {
const author = el.querySelector('.bloc-pseudo-msg')?.textContent.trim();
if (!author) return;
const isOp = this.highlightRules[0].condition(author);
const isMention = this.highlightRules[1].condition(author, el);
const isSelf = this.highlightRules[2].condition(author);
let hClass = '', bText = '', bClass = '';
if (isSelf) { hClass = 'jvc-enhancer-self'; bText = 'VOUS'; bClass = 'badge-self'; }
else if (isOp && isMention) { hClass = 'jvc-enhancer-op-mention'; bText = 'OP (CITÉ)'; bClass = 'badge-op-mention'; }
else if (isOp) { hClass = 'jvc-enhancer-op'; bText = 'OP'; bClass = 'badge-op'; }
else if (isMention) { hClass = 'jvc-enhancer-mention'; bText = 'CITÉ'; bClass = 'badge-mention'; }
if (hClass) el.classList.add(hClass);
if (bText) this.createAvatarBadge(el, bText, bClass);
});
this.processPEMT(messages);
}
processPEMT(messages) {
let pemtGroupIndex = 0;
for (let i = 0; i < messages.length - 1; i++) {
const time = messages[i].querySelector('.bloc-date-msg a')?.textContent.match(/\d{2}:\d{2}:\d{2}$/)?.[0];
if (!time) continue;
const group = [messages[i]];
for (let j = i + 1; j < messages.length; j++) {
if (messages[j].querySelector('.bloc-date-msg a')?.textContent.match(/\d{2}:\d{2}:\d{2}$/)?.[0] === time) {
group.push(messages[j]);
} else {
break;
}
}
if (group.length > 1) {
const color = this.pemtColors[pemtGroupIndex % this.pemtColors.length];
group.forEach(msg => {
msg.classList.add('jvc-enhancer-pemt');
msg.style.borderRightColor = color;
if (!msg.querySelector('.jvc-enhancer-avatar-badge')) {
this.createAvatarBadge(msg, 'PEMT', 'badge-pemt');
}
});
pemtGroupIndex++;
i += group.length - 1;
}
}
}
createAvatarBadge(el, text, bClass, color = null) {
if (el.querySelector(`.jvc-enhancer-avatar-badge`)) return;
const container = el.querySelector('.bloc-avatar-msg');
if (!container) return;
const badge = document.createElement('span');
badge.className = `jvc-enhancer-avatar-badge ${bClass}`;
badge.textContent = text;
if (color) badge.style.backgroundColor = `${color}66`;
container.appendChild(badge);
}
async checkFirstMessagesReportStatus() {
if (this.currentPage !== 1) return;
const firstTwoMessages = Array.from(document.querySelectorAll('.bloc-message-forum')).slice(0, 2);
const ddbCache = JSON.parse(sessionStorage.getItem(this.CACHE_KEY_DDB)) || {};
for (const messageElement of firstTwoMessages) {
const reportIcon = messageElement.querySelector('.picto-msg-exclam');
const messageId = messageElement.dataset.id;
if (!reportIcon || !messageId) continue;
if (ddbCache[messageId]) {
this.applyDdbHighlight(messageElement, ddbCache[messageId]);
continue;
}
const selectorUrl = reportIcon.dataset.selector;
if (!selectorUrl) continue;
const reportUrl = new URL(selectorUrl, "https://www.jeuxvideo.com").href;
try {
const responseText = await this.fetchUrlContent(reportUrl);
let status = 'clean';
//Vous avez déjà signalé ce contenu
if ((responseText.includes("Ce contenu a déjà été signalé")) || (responseText.includes("Vous avez déjà signalé ce contenu"))){
status = 'reported';
} else if (responseText.includes("Ce contenu a déjà été modéré")) {
status = 'administered';
}
if (status !== 'clean') {
ddbCache[messageId] = status;
this.applyDdbHighlight(messageElement, status);
}
} catch (error) {
console.error(`JVC Enhancer: Erreur DDB pour msg ${messageId}`, error);
}
}
sessionStorage.setItem(this.CACHE_KEY_DDB, JSON.stringify(ddbCache));
}
applyDdbHighlight(messageElement, status) {
// Ne supprime que les classes de fond pour éviter les conflits
messageElement.classList.remove('jvc-enhancer-mention', 'jvc-enhancer-op-mention');
if (status === 'reported') {
messageElement.classList.add('jvc-enhancer-ddb-reported');
} else if (status === 'administered') {
messageElement.classList.add('jvc-enhancer-ddb-administered');
}
}
}
new JVCTopicEnhancer();
})();