first commit

This commit is contained in:
nix
2026-05-16 11:10:19 +02:00
commit 509c9b3737
172 changed files with 14496 additions and 0 deletions
+38
View File
@@ -0,0 +1,38 @@
const audios = [
"/data/media/mp3/win7.start.mp3",
"/data/media/mp3/win10.usb.mp3",
"/data/media/mp3/winxp.shut.mp3",
"/data/media/mp3/win10.error.mp3"
];
// Calculer l'index basé sur le jour actuel
const audioIndex = Math.floor(Date.now() / (1000 * 60 * 60 * 24)) % audios.length;
window.addEventListener('load', () => {
const audio = document.getElementById("monSon");
if (!audio) {
console.error("Element audio non trouvé");
return;
}
audio.src = audios[audioIndex];
audio.volume = 1.0;
console.log("En attente d'un clic pour jouer:", audios[audioIndex]);
// Jouer le son au premier clic
const playAudio = () => {
console.log("Clic détecté - lecture du son");
audio.play().catch((error) => {
console.log("Erreur de lecture:", error);
});
document.removeEventListener("click", playAudio);
document.removeEventListener("keydown", playAudio);
document.removeEventListener("touchstart", playAudio);
};
document.addEventListener("click", playAudio);
document.addEventListener("keydown", playAudio);
document.addEventListener("touchstart", playAudio);
});
Executable
+70
View File
@@ -0,0 +1,70 @@
// ============================================
// bg.js - Optimized with WebM support
// ============================================
(function() {
'use strict';
const bgs = [
"/data/fond/moon_1080p.webm", // Changed to WebM
"/data/fond/astro.webp", // Changed to WebP
"/data/fond/Pino.png",
];
const bgIndex = Math.floor(Date.now() / (1000 * 60 * 60 * 24)) % bgs.length;
let visibilityHandler = null;
document.addEventListener("DOMContentLoaded", () => {
const src = bgs[bgIndex];
const video = document.getElementById("bg-video");
const img = document.getElementById("bg-image");
if (!video || !img) return;
const isVideo = /\.(mp4|webm|ogg)$/i.test(src);
const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
// Reduced motion → force image with WebP fallback
if (prefersReducedMotion && isVideo) {
const fallback = src.replace(/\.(mp4|webm|ogg)$/i, ".webp");
img.src = fallback;
img.style.display = "block";
video.style.display = "none";
return;
}
if (isVideo) {
video.src = src;
video.style.display = "block";
img.style.display = "none";
// Visibility handler for pause/play
visibilityHandler = function() {
if (document.hidden) {
video.pause();
} else {
video.play().catch(e => console.log('Video play prevented:', e));
}
};
document.addEventListener('visibilitychange', visibilityHandler);
// Cleanup on page unload
window.addEventListener('beforeunload', () => {
if (visibilityHandler) {
document.removeEventListener('visibilitychange', visibilityHandler);
}
video.pause();
video.src = '';
});
video.load();
} else {
img.src = src;
img.style.display = "block";
video.style.display = "none";
video.pause();
video.src = '';
}
});
})();
+18
View File
@@ -0,0 +1,18 @@
document.addEventListener("DOMContentLoaded", () => {
const motdMessage = window.motds[window.motdIndex];
const targetMessage = "Linux c'est mieux que tout, si quelqu'un pointe les problèmes de compatibilité, c'est la faute des devs des logiciels.";
if (motdMessage === targetMessage) {
// Create a div with an ID
const linkTarget = document.createElement("div");
linkTarget.id = "linux-motd";
linkTarget.textContent = "Special MOTD section!";
document.getElementById("links-container").appendChild(linkTarget);
// Create an anchor linking to it
const anchor = document.createElement("a");
anchor.href = "#linux-motd";
anchor.textContent = "Go to special MOTD";
document.getElementById("links-container").appendChild(anchor);
}
});
+20
View File
@@ -0,0 +1,20 @@
// ============================================
// captcha.js - Optimized
// ============================================
(function() {
'use strict';
const captchas = [
"secret/captcha2.html",
"secret/captcha.html",
];
const captchaIndex = Math.floor(Date.now() / (1000 * 60 * 60 * 24)) % captchas.length;
document.addEventListener("DOMContentLoaded", () => {
const captchaLink = document.getElementById("captchas");
if (captchaLink) {
captchaLink.href = captchas[captchaIndex];
}
});
})();
+41
View File
@@ -0,0 +1,41 @@
window.addEventListener('load', () => {
const cookieBtn = document.createElement('button');
cookieBtn.textContent = 'Accept Cookies 🍪';
cookieBtn.className = 'cookie-btn';
cookieBtn.style.position = 'fixed';
cookieBtn.style.bottom = '20px';
cookieBtn.style.right = '20px';
cookieBtn.style.zIndex = '9999';
document.body.appendChild(cookieBtn);
cookieBtn.addEventListener('click', () => {
for (let i = 0; i < 100; i++) createCookie();
});
function createCookie() {
const cookie = document.createElement('div');
cookie.textContent = '🍪';
Object.assign(cookie.style, {
position: 'fixed',
fontSize: `${Math.random() * 30 + 20}px`,
left: `${Math.random() * window.innerWidth}px`,
top: `-${Math.random() * 50}px`,
zIndex: '9999',
pointerEvents: 'none',
transition: 'transform 5s linear, opacity 5s linear'
});
document.body.appendChild(cookie);
setTimeout(() => {
cookie.style.transform =
`translateY(${window.innerHeight + 50}px) rotate(${Math.random() * 360}deg)`;
cookie.style.opacity = '0';
}, 50);
setTimeout(() => cookie.remove(), 5500);
}
});
+388
View File
@@ -0,0 +1,388 @@
/**
* Sparklines & Easter Egg - Nixiews Dashboard
* Ajoute des mini-graphiques dans les stat-cards existantes
* + easter egg clavier dans le loader
* + lecture du fichier server.status (remplace news.json)
*/
(function () {
'use strict';
// =========================================================
// CONFIG
// =========================================================
const MAX_POINTS = 20;
const CANVAS_H = 36;
const COLOR_OK = '#50fa7b';
const COLOR_WARN = '#ffb86c';
const COLOR_DANGER = '#ff5555';
const COLOR_LINE = 'rgba(98,114,164,0.35)';
const COLOR_FILL_OK = 'rgba(80,250,123,0.12)';
const TRACKED = [
{
id: 'cpu',
max: 100,
warn: 50,
danger: 80,
parse: v => parseFloat(v),
},
{
id: 'ram',
max: null,
maxId: 'ram-subtitle',
warn: 60,
danger: 80,
parse: (v, sub) => {
const m = sub && sub.match(/\((\d+\.?\d*)%\)/);
return m ? parseFloat(m[1]) : null;
},
},
{
id: 'load',
max: 8,
warn: 50,
danger: 80,
parse: v => Math.min((parseFloat(v) / 8) * 100, 100),
},
];
const history = {};
TRACKED.forEach(t => { history[t.id] = []; });
// =========================================================
// CANVAS / SPARKLINES
// =========================================================
function injectCanvas(statCard) {
if (statCard.querySelector('.spark-canvas')) return;
const canvas = document.createElement('canvas');
canvas.className = 'spark-canvas';
canvas.width = statCard.offsetWidth || 150;
canvas.height = CANVAS_H;
canvas.style.cssText = `
display: block;
width: 100%;
height: ${CANVAS_H}px;
margin-top: 0.5rem;
border-radius: 6px;
opacity: 0.85;
`;
statCard.appendChild(canvas);
return canvas;
}
function drawSparkline(canvas, data, warn, danger) {
if (!canvas || data.length < 2) return;
const ctx = canvas.getContext('2d');
const W = canvas.offsetWidth || canvas.width;
const H = canvas.height;
canvas.width = W;
ctx.clearRect(0, 0, W, H);
const range = 100;
const stepX = W / (MAX_POINTS - 1);
const xOf = i => i * stepX;
const yOf = v => H - ((v / range) * (H - 4)) - 2;
const last = data[data.length - 1];
const color = last > danger ? COLOR_DANGER : last > warn ? COLOR_WARN : COLOR_OK;
ctx.beginPath();
ctx.moveTo(xOf(0), H);
data.forEach((v, i) => ctx.lineTo(xOf(i), yOf(v)));
ctx.lineTo(xOf(data.length - 1), H);
ctx.closePath();
ctx.fillStyle = last > danger
? 'rgba(255,85,85,0.10)'
: last > warn
? 'rgba(255,184,108,0.10)'
: COLOR_FILL_OK;
ctx.fill();
ctx.beginPath();
data.forEach((v, i) => {
i === 0 ? ctx.moveTo(xOf(i), yOf(v)) : ctx.lineTo(xOf(i), yOf(v));
});
ctx.strokeStyle = color;
ctx.lineWidth = 2;
ctx.lineJoin = 'round';
ctx.stroke();
const lx = xOf(data.length - 1);
const ly = yOf(last);
ctx.beginPath();
ctx.arc(lx, ly, 3, 0, Math.PI * 2);
ctx.fillStyle = color;
ctx.fill();
[50, 80].forEach(pct => {
const gy = yOf(pct);
ctx.beginPath();
ctx.moveTo(0, gy);
ctx.lineTo(W, gy);
ctx.strokeStyle = COLOR_LINE;
ctx.lineWidth = 0.8;
ctx.setLineDash([3, 4]);
ctx.stroke();
ctx.setLineDash([]);
});
}
function sample() {
TRACKED.forEach(t => {
const el = document.getElementById(t.id);
const subEl = document.getElementById(t.id + '-subtitle');
if (!el) return;
const raw = el.textContent.trim();
const sub = subEl ? subEl.textContent.trim() : '';
const val = t.parse(raw, sub);
if (val === null || isNaN(val)) return;
history[t.id].push(val);
if (history[t.id].length > MAX_POINTS) history[t.id].shift();
const card = el.closest('.stat-card');
if (!card) return;
let canvas = card.querySelector('.spark-canvas');
if (!canvas) canvas = injectCanvas(card);
if (!canvas) return;
drawSparkline(canvas, history[t.id], t.warn, t.danger);
});
}
function watchStats() {
const section = document.querySelector('.stats-section');
if (!section) return;
const obs = new MutationObserver(() => sample());
obs.observe(section, { subtree: true, characterData: true, childList: true });
setTimeout(sample, 6000);
}
// =========================================================
// EASTER EGG
// =========================================================
const EASTER_COMMANDS = {
'sudo': '⚠ [sudo] password for nixiews: \n💀 sudo: permission refusée. T\'es pas root ici.',
'rm -rf /': '💀 SIGTERM — Au revoir cruel monde... \n ... nan je déconne, j\'ai pas les droits.',
'rm -rf': '💀 Haha non. Pas sur mon serveur.',
'emerge': '🟢 emerge: Calcul du dépôt world...\n ETA: 3 jours, 14 heures, 7 minutes.\n (C\'est Gentoo, t\'avais qu\'à pas.)',
'nixos-rebuild': '❓ nixos-rebuild: command not found\n Ici c\'est Gentoo/Debian. Le pseudo c\'est juste un pseudo.',
'pacman': '🔴 erreur: pacman not found. Ici c\'est Gentoo/Debian.',
'apt': '🟡 apt: command not found (on Gentoo side)\n Essaie emerge plutôt.',
'reboot': '♻ Reboot programmé dans... nan, j\'ai changé d\'avis.',
'uname': '🐧 Linux nicoleta 6.x.x-gentoo #1 SMP PREEMPT_DYNAMIC\n x86_64 GNU/Linux',
'htop': '📊 htop: trop stylé pour être lancé dans un easter egg.',
'ls': '📁 . .. index.html data/ secret/ binpkg/ fun/ minecraft/',
'cat /etc/passwd': '😏 root:x:0:0::/root:/bin/bash\n nixiews:x:1000:1000::/home/nixiews:/bin/zsh\n claude:x:9999:9999:meilleur ami:/dev/null:/bin/sh',
'help': '📖 Commandes disponibles:\n sudo, rm -rf /, emerge, nixos-rebuild, pacman, apt,\n reboot, uname, htop, ls, cat /etc/passwd, help\n (Nixiews = pseudo, pas une distro 🙃)',
};
let typedBuffer = '';
let eggTimeout = null;
function resetBuffer() { typedBuffer = ''; }
function checkEasterEgg(key) {
const loader = document.getElementById('loader');
if (!loader || loader.style.display === 'none' || loader.style.opacity === '0') return;
typedBuffer += key.toLowerCase();
if (typedBuffer.length > 30) typedBuffer = typedBuffer.slice(-30);
clearTimeout(eggTimeout);
eggTimeout = setTimeout(resetBuffer, 2500);
for (const [cmd, response] of Object.entries(EASTER_COMMANDS)) {
if (typedBuffer.endsWith(cmd)) {
triggerEgg(cmd, response);
typedBuffer = '';
break;
}
}
}
function triggerEgg(cmd, response) {
const logs = document.querySelector('#loader .logs');
if (!logs) return;
const cmdLine = document.createElement('div');
cmdLine.style.cssText = `
color: #8be9fd;
font-family: 'Courier New', monospace;
font-size: 0.85rem;
margin-top: 0.3rem;
animation: fadeIn 0.2s ease;
`;
cmdLine.innerHTML = `<span style="color:#50fa7b">nixiews@nicoleta</span><span style="color:#f8f8f2">:</span><span style="color:#bd93f9">~</span><span style="color:#f8f8f2">$</span> ${cmd}`;
logs.appendChild(cmdLine);
setTimeout(() => {
const responseLine = document.createElement('div');
responseLine.style.cssText = `
color: #f1fa8c;
font-family: 'Courier New', monospace;
font-size: 0.82rem;
white-space: pre-wrap;
margin-bottom: 0.3rem;
animation: fadeIn 0.3s ease;
`;
responseLine.textContent = response;
logs.appendChild(responseLine);
logs.scrollTop = logs.scrollHeight;
}, 300);
logs.scrollTop = logs.scrollHeight;
}
// =========================================================
// SERVER STATUS — lecture directe du .status
// =========================================================
const STATUS_ENDPOINT = '/data/server.status';
function parseStatusFile(text) {
const result = { status: '', couleur: '#bd93f9', date: '', message: '', motds: [] };
const lines = text.split('\n');
for (const line of lines) {
const m = line.match(/^\[(\w+)\]\s*(.*)$/);
if (!m) continue;
const [, key, val] = m;
if (key === 'motd') {
result.motds.push(val.trim());
} else {
result[key] = val.trim();
}
}
return result;
}
function buildStatusCard(data) {
const motdsHtml = data.motds.map(m =>
`<div class="status-motd">💬 ${m}</div>`
).join('');
return `
<div class="status-header">
<span class="status-badge" style="color:${data.couleur};border-color:${data.couleur}20;background:${data.couleur}15">
${data.status}
</span>
${data.date ? `<span class="status-date">${data.date}</span>` : ''}
</div>
${data.message ? `<p class="status-message">${data.message}</p>` : ''}
${motdsHtml ? `<div class="status-motds">${motdsHtml}</div>` : ''}
`;
}
function injectStatusSection() {
const mainContent = document.querySelector('.main-content');
const otherSection = document.querySelector('.other-section');
if (!mainContent) return null;
const section = document.createElement('div');
section.className = 'news-section';
section.innerHTML = `
<h2>Infos du jour</h2>
<div class="news-card">
<div class="news-loading">
<div class="mc-loading-dot"></div>
<div class="mc-loading-dot"></div>
<div class="mc-loading-dot"></div>
</div>
</div>`;
if (otherSection) {
mainContent.insertBefore(section, otherSection);
} else {
mainContent.appendChild(section);
}
const style = document.createElement('style');
style.textContent = `
.news-section h2 { color: #bd93f9; font-size: 1.5rem; margin-bottom: 1rem; }
.news-card {
background-color: rgba(68,71,90,0.95);
border-radius: 12px;
padding: 1.4rem 1.6rem;
border-left: 3px solid #bd93f9;
transition: box-shadow 0.2s ease;
}
.news-card:hover { box-shadow: 0 8px 20px rgba(0,0,0,0.4); }
.status-header { display: flex; align-items: center; gap: 1rem; margin-bottom: 0.8rem; }
.status-badge {
font-size: 0.82rem;
font-weight: 700;
padding: 0.2rem 0.7rem;
border-radius: 20px;
border: 1px solid;
white-space: nowrap;
}
.status-date { font-size: 0.78rem; color: #6272a4; font-family: 'Courier New', monospace; margin-left: auto; }
.status-message { color: #f8f8f2; font-size: 0.95rem; margin-bottom: 0.9rem; line-height: 1.5; }
.status-motds { display: flex; flex-direction: column; gap: 0.4rem; }
.status-motd {
font-size: 0.85rem;
color: #6272a4;
padding: 0.3rem 0.6rem;
background: rgba(40,42,54,0.6);
border-radius: 6px;
font-family: 'Courier New', monospace;
}
.news-loading { display: flex; align-items: center; justify-content: center; gap: 0.4rem; padding: 0.6rem 0; }
.status-error { color: #ff5555; font-size: 0.85rem; font-family: 'Courier New', monospace; }
`;
document.head.appendChild(style);
return section.querySelector('.news-card');
}
async function fetchStatus(card) {
try {
const res = await fetch(STATUS_ENDPOINT, { cache: 'no-cache' });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const text = await res.text();
card.innerHTML = buildStatusCard(parseStatusFile(text));
} catch (e) {
card.innerHTML = `<span class="status-error">⚠ Impossible de charger server.status (${e.message})</span>`;
}
}
function initStatus() {
const card = injectStatusSection();
if (card) fetchStatus(card);
}
// =========================================================
// INIT
// =========================================================
function init() {
document.addEventListener('keypress', e => {
if (e.key && e.key.length === 1) checkEasterEgg(e.key);
});
document.addEventListener('keydown', e => {
if (e.key === 'Enter') checkEasterEgg(' ');
});
if (document.querySelector('.stats-section')) {
watchStats();
} else {
document.addEventListener('DOMContentLoaded', watchStats);
}
initStatus();
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();
Executable
+19
View File
@@ -0,0 +1,19 @@
// script normal
// change d'image tout les jours
const images = [
"autre/Image1.html",
"autre/Image2.html",
"autre/Image3.html",
"autre/Image4.html",
"autre/Image5.html",
"autre/Image6.html",
"autre/Image7.html",
"autre/Image8.html",
"autre/Image9.html",
]
const imageIndex = Math.floor(Date.now() / (1000 * 60 * 60 * 24)) % images.length
document.addEventListener("DOMContentLoaded", () => {
document.getElementById("image").href = images[imageIndex]
})
+315
View File
@@ -0,0 +1,315 @@
/* =========================
CONFIG
========================= */
const MIN_TIME = 10000;
const startTime = performance.now();
/* =========================
HELPERS
========================= */
function getTimeStamp() {
return new Date().toLocaleTimeString("fr-FR", {
hour: "2-digit",
minute: "2-digit",
second: "2-digit"
});
}
/* =========================
SEQUENTIAL TEXT + FROZEN TIME
========================= */
const steps = document.querySelectorAll(".step");
steps.forEach((el, i) => {
setTimeout(() => {
const timeEl = el.querySelector(".time");
if (timeEl) timeEl.textContent = getTimeStamp();
el.classList.add("visible");
}, i * 600);
});
/* =========================
RANDOM GRID / PIXEL ART
========================= */
const grid = document.getElementById("grid");
let gridSquares = []; // Track for cleanup
let pixelIntervals = []; // Track pixel intervals for cleanup
if (grid) {
const squareCount = Math.floor(Math.random() * 6) + 8;
const occupiedCells = new Set(); // Track occupied grid positions
for (let i = 0; i < squareCount; i++) {
const square = document.createElement("div");
square.className = "square";
// Find an unoccupied position
let col, row, posKey;
let attempts = 0;
do {
col = Math.floor(Math.random() * 5) + 1;
row = Math.floor(Math.random() * 4) + 1;
posKey = `${col}-${row}`;
attempts++;
} while (occupiedCells.has(posKey) && attempts < 50);
// Mark position as occupied
occupiedCells.add(posKey);
square.style.gridColumn = col;
square.style.gridRow = row;
// Make squares visible immediately without animation
square.style.opacity = "1";
square.style.transform = "none";
// Draw pixels on hover (can be triggered multiple times)
const drawHandler = () => {
const canvas = square.querySelector("canvas");
if (!canvas || !square.hasPixels) {
drawPixels(square);
if (!square.pixelInterval) {
startPixelCycle(square); // Start the 5-second cycle for this square
}
}
};
square.addEventListener("pointerenter", drawHandler);
gridSquares.push(square);
grid.appendChild(square);
}
}
function drawPixels(el) {
const existingCanvas = el.querySelector("canvas");
if (existingCanvas) {
existingCanvas.remove();
}
const canvas = document.createElement("canvas");
canvas.width = el.clientWidth;
canvas.height = el.clientHeight;
canvas.style.position = "absolute";
canvas.style.top = "0";
canvas.style.left = "0";
el.appendChild(canvas);
const ctx = canvas.getContext("2d");
const colors = ["#ff4fd8", "#9333ea", "#ef4444"];
const px = 6;
// Fill background
ctx.fillStyle = "#0a0a0c";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Collect all pixel positions that will be drawn
const pixels = [];
for (let x = 0; x < canvas.width; x += px) {
for (let y = 0; y < canvas.height; y += px) {
if (Math.random() > 0.6) {
pixels.push({
x: x,
y: y,
color: colors[Math.floor(Math.random() * colors.length)]
});
}
}
}
// Mark that this square has pixels
el.hasPixels = true;
// Create an offscreen canvas to draw all pixels at once
const offscreenCanvas = document.createElement("canvas");
offscreenCanvas.width = canvas.width;
offscreenCanvas.height = canvas.height;
const offscreenCtx = offscreenCanvas.getContext("2d");
// Draw all pixels on offscreen canvas
offscreenCtx.fillStyle = "#0a0a0c";
offscreenCtx.fillRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
pixels.forEach(pixel => {
offscreenCtx.fillStyle = pixel.color;
offscreenCtx.fillRect(pixel.x, pixel.y, px, px);
});
// Animate the entire pixel pattern sliding in from left
const duration = 400; // ms for animation
const startTime = performance.now();
const startX = -canvas.width; // Start completely off-screen to the left
const endX = 0;
function animate(currentTime) {
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / duration, 1);
// Clear canvas
ctx.fillStyle = "#0a0a0c";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Calculate current X position
const currentX = startX + (endX - startX) * progress;
// Draw the entire offscreen canvas at the current position
ctx.drawImage(offscreenCanvas, currentX, 0);
if (progress < 1) {
requestAnimationFrame(animate);
}
}
requestAnimationFrame(animate);
}
function clearPixels(el) {
const canvas = el.querySelector("canvas");
if (!canvas) return;
const ctx = canvas.getContext("2d");
// Create an offscreen canvas with current pixel state
const offscreenCanvas = document.createElement("canvas");
offscreenCanvas.width = canvas.width;
offscreenCanvas.height = canvas.height;
const offscreenCtx = offscreenCanvas.getContext("2d");
// Copy current canvas to offscreen
offscreenCtx.drawImage(canvas, 0, 0);
// Animate the entire pixel pattern sliding out to the right
const duration = 400; // ms for animation
const startTime = performance.now();
const startX = 0;
const endX = canvas.width; // Slide completely off-screen to the right
function animate(currentTime) {
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / duration, 1);
// Clear canvas
ctx.fillStyle = "#0a0a0c";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Calculate current X position
const currentX = startX + (endX - startX) * progress;
// Draw the entire offscreen canvas at the current position
ctx.drawImage(offscreenCanvas, currentX, 0);
if (progress < 1) {
requestAnimationFrame(animate);
} else {
// Final clear
ctx.fillStyle = "#0a0a0c";
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
}
requestAnimationFrame(animate);
}
function startPixelCycle(square) {
const interval = setInterval(() => {
clearPixels(square);
square.hasPixels = false; // Mark that pixels are cleared
}, 5000);
pixelIntervals.push(interval);
// Store interval on the element for later cleanup
square.pixelInterval = interval;
}
/* =========================
LOADER CLEANUP
========================= */
function cleanupLoader() {
// Clear all intervals
pixelIntervals.forEach(interval => clearInterval(interval));
pixelIntervals = [];
// Remove grid squares
gridSquares.forEach(sq => sq.remove());
gridSquares = [];
// Remove loader
const loader = document.getElementById("loader");
if (loader) {
loader.style.opacity = "0";
loader.style.pointerEvents = "none";
setTimeout(() => {
loader.remove();
}, 800);
}
}
/* =========================
LOADER HANDOFF
========================= */
function hideLoader() {
const elapsed = performance.now() - startTime;
const remaining = Math.max(0, MIN_TIME - elapsed);
setTimeout(() => {
document.body.classList.remove("loading");
cleanupLoader(); // Clean up properly
}, remaining);
}
window.addEventListener("load", hideLoader);
/* =========================
LOADING BAR - OPTIMIZED
========================= */
const loadingBar = document.getElementById('loading-bar');
let currentLoadingInterval = null;
function showLoadingBar() {
// Clear any existing interval first
if (currentLoadingInterval) {
clearInterval(currentLoadingInterval);
}
loadingBar.style.width = '0%';
loadingBar.style.display = 'block';
setTimeout(() => loadingBar.style.width = '30%', 50);
let progress = 30;
currentLoadingInterval = setInterval(() => {
progress += Math.random() * 20;
if (progress < 90) {
loadingBar.style.width = progress + '%';
} else {
clearInterval(currentLoadingInterval);
currentLoadingInterval = null;
}
}, 300);
return currentLoadingInterval;
}
function completeLoadingBar(interval) {
if (interval) {
clearInterval(interval);
if (interval === currentLoadingInterval) {
currentLoadingInterval = null;
}
}
loadingBar.style.width = '100%';
setTimeout(() => {
loadingBar.style.width = '0%';
}, 400);
}
// Initial page load
let pageLoadInterval;
if (document.readyState === 'loading') {
pageLoadInterval = showLoadingBar();
}
window.addEventListener('load', () => {
completeLoadingBar(pageLoadInterval);
});
+282
View File
@@ -0,0 +1,282 @@
/**
* Minecraft Server Status - Sidebar Widget
* Source : API Crafty Controller (proxy PHP crafty-stats.php)
*/
(function () {
'use strict';
const API = '/data/api/crafty-stats.php';
const MODS_API = '/data/api/mods-mc.php';
const INTERVAL = 30000; // 30s
const SERVERS = [
{ key: 'mc1', cardId: 'mc-card-0' },
{ key: 'mc2', cardId: 'mc-card-1' },
];
let timer = null;
let modsData = null; // cache des mods, chargé une seule fois
// ── Mods ────────────────────────────────────────────────────────────────
const modsStyle = document.createElement('style');
modsStyle.textContent = `
.mc-mods-section {
margin-top: 0.5rem;
border-top: 1px solid rgba(98, 114, 164, 0.3);
padding-top: 0.5rem;
}
.mc-mods-toggle {
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
padding: 0.25rem 0;
user-select: none;
}
.mc-mods-toggle-label {
font-size: 0.72rem;
font-weight: 700;
color: #6272a4;
text-transform: uppercase;
letter-spacing: 0.07em;
}
.mc-mods-toggle-meta {
display: flex;
align-items: center;
gap: 0.4rem;
font-size: 0.68rem;
color: #6272a4;
}
.mc-mods-arrow {
font-size: 0.6rem;
color: #6272a4;
transition: transform 0.2s;
display: inline-block;
}
.mc-mods-arrow.open { transform: rotate(90deg); }
.mc-mods-pills {
display: none;
flex-wrap: wrap;
gap: 0.3rem;
padding-top: 0.45rem;
}
.mc-mods-pills.open { display: flex; }
.mc-mod-pill {
background: rgba(98, 114, 164, 0.25);
color: #f8f8f2;
font-size: 0.65rem;
padding: 2px 7px;
border-radius: 20px;
border: 1px solid rgba(98, 114, 164, 0.35);
white-space: nowrap;
cursor: default;
}
.mc-mod-pill:hover {
background: rgba(189, 147, 249, 0.2);
border-color: rgba(189, 147, 249, 0.5);
color: #bd93f9;
}
.mc-mods-error {
font-size: 0.7rem;
color: #ff5555;
padding-top: 0.3rem;
font-style: italic;
}
`;
document.head.appendChild(modsStyle);
async function fetchMods() {
try {
const res = await fetch(MODS_API, { cache: 'no-cache' });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
modsData = await res.json();
} catch (e) {
console.warn('[mods-mc] Erreur fetch :', e);
}
}
function appendMods(card, srv) {
if (!modsData) return;
// trouve l'entrée correspondant au nom du serveur Crafty
const entry = modsData.find(m => m.label === srv?.name) ?? modsData[SERVERS.findIndex(s => s.cardId === card.id)];
if (!entry) return;
const section = document.createElement('div');
section.className = 'mc-mods-section';
if (entry.error) {
const err = document.createElement('div');
err.className = 'mc-mods-error';
err.textContent = entry.error;
section.appendChild(err);
card.appendChild(section);
return;
}
const count = entry.mods.length;
const toggle = document.createElement('div');
toggle.className = 'mc-mods-toggle';
toggle.innerHTML = `
<span class="mc-mods-toggle-label">Mods</span>
<span class="mc-mods-toggle-meta">
<span>${count} mod${count !== 1 ? 's' : ''}</span>
<span class="mc-mods-arrow">&#9656;</span>
</span>
`;
const pills = document.createElement('div');
pills.className = 'mc-mods-pills';
entry.mods.forEach(mod => {
const pill = document.createElement('span');
pill.className = 'mc-mod-pill';
pill.title = mod.file;
pill.textContent = mod.name;
pills.appendChild(pill);
});
toggle.addEventListener('click', () => {
pills.classList.toggle('open');
toggle.querySelector('.mc-mods-arrow').classList.toggle('open');
});
section.appendChild(toggle);
section.appendChild(pills);
card.appendChild(section);
}
// ── Status ───────────────────────────────────────────────────────────────
async function fetchAll() {
let data;
try {
const res = await fetch(API, { cache: 'no-cache' });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
data = await res.json();
} catch (e) {
console.error('crafty-stats error:', e);
return;
}
if (!data.success) return;
SERVERS.forEach(({ key, cardId }) => {
const card = document.getElementById(cardId);
if (!card) return;
renderCard(card, data.servers?.[key]);
});
updateStatCards(data.servers);
}
function renderCard(card, srv) {
if (!srv) {
card.innerHTML = `
<div class="mc-header">
<span class="mc-name">Serveur inconnu</span>
<span class="mc-badge mc-offline">&#9679; Hors ligne</span>
</div>`;
appendMods(card, srv);
return;
}
const online = srv.running;
const players = online ? `${srv.players} / ${srv.max_players}` : '— / —';
let ramHtml = '';
if (online && srv.ram_used !== null) {
const usedStr = ramFmt(srv.ram_used);
const allocStr = srv.ram_alloc ? ramFmt(srv.ram_alloc) : '?';
const pct = srv.ram_alloc > 0 ? Math.round((srv.ram_used / srv.ram_alloc) * 100) : 0;
const color = pct > 90 ? '#ff5555' : pct > 70 ? '#ffb86c' : '#50fa7b';
ramHtml = `
<span class="mc-ram" style="color:${color}">
<svg width="10" height="10" viewBox="0 0 24 24" fill="currentColor" style="color:#bd93f9;flex-shrink:0">
<path d="M4 6h16v2H4zm0 5h16v2H4zm0 5h16v2H4z"/>
</svg>
${usedStr}<span style="color:#6272a4;font-weight:400"> / ${allocStr}</span>
</span>`;
}
const cpuHtml = (online && srv.cpu !== null)
? `<span class="mc-version">${srv.cpu}% CPU</span>`
: '';
card.innerHTML = `
<div class="mc-header">
<span class="mc-name">${esc(srv.name)}</span>
<span class="mc-badge ${online ? 'mc-online' : 'mc-offline'}">${online ? '&#9679; En ligne' : '&#9679; Hors ligne'}</span>
</div>
<div class="mc-address">${esc('nix.roulaise.net')}:${srv.port}</div>
<div class="mc-info">
<span class="mc-players">
<svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor">
<path d="M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z"/>
</svg>
${players} joueurs
</span>
${ramHtml}
${cpuHtml}
</div>`;
appendMods(card, srv);
}
function updateStatCards(servers) {
['mc1', 'mc2'].forEach((key, i) => {
const n = i + 1;
const el = document.getElementById(`mc${n}-ram`);
const sub = document.getElementById(`mc${n}-ram-subtitle`);
if (!el) return;
const srv = servers?.[key];
if (!srv || !srv.running) {
el.textContent = 'Éteint';
if (sub) sub.textContent = '—';
el.style.color = '#6272a4';
return;
}
if (srv.ram_used !== null) {
const pct = srv.ram_alloc > 0 ? Math.round((srv.ram_used / srv.ram_alloc) * 100) : 0;
el.textContent = ramFmt(srv.ram_used);
if (sub) sub.textContent = `alloué: ${srv.ram_alloc ? ramFmt(srv.ram_alloc) : '?'} (${pct}%)`;
el.style.color = pct > 90 ? '#ff5555' : pct > 70 ? '#ffb86c' : '#50fa7b';
} else {
el.textContent = '...';
if (sub) sub.textContent = '—';
}
});
}
function ramFmt(mio) {
return mio >= 1024 ? (mio / 1024).toFixed(1) + ' Gio' : mio + ' Mio';
}
function esc(s) {
return String(s)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;');
}
function start() { timer = setInterval(fetchAll, INTERVAL); }
function stop() { clearInterval(timer); timer = null; }
async function init() {
if (!document.getElementById('mc-card-0')) return;
await fetchMods(); // charge les mods une seule fois au démarrage
fetchAll();
start();
window.addEventListener('beforeunload', stop);
document.addEventListener('visibilitychange', () =>
document.hidden ? stop() : (fetchAll(), start())
);
}
document.readyState === 'loading'
? document.addEventListener('DOMContentLoaded', init)
: init();
})();
+128
View File
@@ -0,0 +1,128 @@
(function () {
const API_URL = '/data/api/mods-mc.php';
// Injecte le CSS dans <head>
const style = document.createElement('style');
style.textContent = `
.mc-mods-section {
margin-top: 0.5rem;
border-top: 1px solid rgba(98, 114, 164, 0.3);
padding-top: 0.5rem;
}
.mc-mods-toggle {
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
padding: 0.25rem 0;
user-select: none;
}
.mc-mods-toggle-label {
font-size: 0.72rem;
font-weight: 700;
color: #6272a4;
text-transform: uppercase;
letter-spacing: 0.07em;
}
.mc-mods-toggle-meta {
display: flex;
align-items: center;
gap: 0.4rem;
font-size: 0.68rem;
color: #6272a4;
}
.mc-mods-arrow {
font-size: 0.6rem;
color: #6272a4;
transition: transform 0.2s;
display: inline-block;
}
.mc-mods-arrow.open { transform: rotate(90deg); }
.mc-mods-pills {
display: none;
flex-wrap: wrap;
gap: 0.3rem;
padding-top: 0.45rem;
}
.mc-mods-pills.open { display: flex; }
.mc-mod-pill {
background: rgba(98, 114, 164, 0.25);
color: #f8f8f2;
font-size: 0.65rem;
padding: 2px 7px;
border-radius: 20px;
border: 1px solid rgba(98, 114, 164, 0.35);
white-space: nowrap;
cursor: default;
}
.mc-mod-pill:hover {
background: rgba(189, 147, 249, 0.2);
border-color: rgba(189, 147, 249, 0.5);
color: #bd93f9;
}
.mc-mods-error {
font-size: 0.7rem;
color: #ff5555;
padding-top: 0.3rem;
font-style: italic;
}
`;
document.head.appendChild(style);
function buildModsBlock(srv, cardEl) {
const section = document.createElement('div');
section.className = 'mc-mods-section';
if (srv.error) {
const err = document.createElement('div');
err.className = 'mc-mods-error';
err.textContent = srv.error;
section.appendChild(err);
cardEl.appendChild(section);
return;
}
const count = srv.mods.length;
const toggle = document.createElement('div');
toggle.className = 'mc-mods-toggle';
toggle.innerHTML = `
<span class="mc-mods-toggle-label">Mods</span>
<span class="mc-mods-toggle-meta">
<span>${count} mod${count !== 1 ? 's' : ''}</span>
<span class="mc-mods-arrow">&#9656;</span>
</span>
`;
const pills = document.createElement('div');
pills.className = 'mc-mods-pills';
srv.mods.forEach(mod => {
const pill = document.createElement('span');
pill.className = 'mc-mod-pill';
pill.title = mod.file;
pill.textContent = mod.name;
pills.appendChild(pill);
});
toggle.addEventListener('click', () => {
const arrow = toggle.querySelector('.mc-mods-arrow');
pills.classList.toggle('open');
arrow.classList.toggle('open');
});
section.appendChild(toggle);
section.appendChild(pills);
cardEl.appendChild(section);
}
fetch(API_URL)
.then(r => r.json())
.then(data => {
data.forEach((srv, i) => {
const card = document.getElementById('mc-card-' + i);
if (card) buildModsBlock(srv, card);
});
})
.catch(err => {
console.warn('[mods-mc] Erreur fetch :', err);
});
})();
+41
View File
@@ -0,0 +1,41 @@
// ============================================
// motd.js - Optimized
// ============================================
(function() {
'use strict';
const motds = [
"Gloire à Titebouille!",
"On dit chocolatine ici!",
"C'est un MOTD ça?",
"Je vais vous ciscoter!",
"Belgian gooner femboy ahhh",
"Miku cosplay UwU",
"Nothing to see",
"If it's stupid but works, then it's not stupid",
"Wait, you're playing Unturned?!",
"Revert to Aquaba!",
"Cherche GOTHIQUES svp :(",
"Vous m'ouvrez Packet Tracer.",
"Gooner Land",
"QT va te faire foutre",
"J'aime l'informatique vu que je suis obligé",
"Allo à l'huile",
"On à cours dans le local technique",
"Je suis pas con, je suis autiste",
"Toni aime bien penser que son café est italien.",
"C'est une violation de la loi Sherman",
"Le kernel cisco packet ryzen dragon s24+ c'est pour quand ?",
"Hacheur - HkmGZ",
"Met un PEKKA! Nan, CT3000+L!",
];
const motdIndex = Math.floor(Date.now() / (1000 * 60 * 60 * 24)) % motds.length;
document.addEventListener("DOMContentLoaded", () => {
const motdElement = document.getElementById("motd");
if (motdElement) {
motdElement.textContent = motds[motdIndex];
}
});
})();
+1
View File
@@ -0,0 +1 @@
console.log('Bienvenue sur le site le plus inutile du monde!');
Executable
+30
View File
@@ -0,0 +1,30 @@
// ============================================
// ri.js - Optimized (keeping GIFs as GIF)
// ============================================
(function() {
'use strict';
const ris = [
"data/media/linux-tux.gif", // Optimized GIF
"data/media/Titebouille.gif", // Optimized GIF
"data/media/gurl1.gif", // Optimized GIF
"data/media/gurl2.gif", // Optimized GIF
"data/media/gurl3.gif", // Optimized GIF
"data/media/Dance1.gif", // Optimized GIF
"data/media/Duck2.webp", // WebP (was PNG)
"data/media/Honk.gif", // Optimized GIF
"data/media/petpet.gif", // Optimized GIF
"data/media/Ereaser.jpg",
];
const riIndex = Math.floor(Date.now() / (1000 * 60 * 60 * 24)) % ris.length;
document.addEventListener("DOMContentLoaded", () => {
const riElement = document.getElementById("ris");
if (riElement) {
// Set loading attribute for better performance
riElement.loading = "lazy";
riElement.src = ris[riIndex];
}
});
})();
+166
View File
@@ -0,0 +1,166 @@
/**
* System Stats Loader — inclut MDADM
*/
(function() {
'use strict';
const API_STATS = '/data/api/system-stats.php';
const API_MDADM = '/data/api/mdadm-status.php';
const INTERVAL = 5000;
let timer = null;
let updating = false;
let loadedOnce = false;
const el = {
uptime: document.getElementById('uptime'),
cpu: document.getElementById('cpu'),
ram: document.getElementById('ram'),
ramSub: document.getElementById('ram-subtitle'),
diskRoot: document.getElementById('disk-root'),
diskRootSub: document.getElementById('disk-root-subtitle'),
diskVar: document.getElementById('disk-var'),
diskVarSub: document.getElementById('disk-var-subtitle'),
diskSrv: document.getElementById('disk-srv'),
diskSrvSub: document.getElementById('disk-srv-subtitle'),
load: document.getElementById('load'),
processes: document.getElementById('processes'),
mdadmCard: document.getElementById('mdadm-card'),
mdadmStatus: document.getElementById('mdadm-status'),
mdadmSub: document.getElementById('mdadm-subtitle'),
};
function set(element, value) {
if (!element || value === undefined) return;
const v = String(value);
if (element.textContent !== v) element.textContent = v;
}
function color(element, percent, warn, danger) {
if (!element) return;
const c = percent > danger ? '#ff5555' : percent > warn ? '#ffb86c' : '#50fa7b';
if (element.style.color !== c) element.style.color = c;
}
async function fetchStats() {
if (updating) return;
updating = true;
try {
const r = await fetch(API_STATS, { cache: 'no-cache' });
if (!r.ok) throw new Error(`HTTP ${r.status}`);
const { success, data } = await r.json();
if (success && data) renderStats(data);
else if (loadedOnce) showError();
} catch(e) {
console.error('system-stats:', e);
if (loadedOnce) showError();
} finally {
updating = false;
}
}
function renderStats(s) {
loadedOnce = true;
set(el.uptime, s.uptime);
if (s.cpu_usage !== undefined) {
set(el.cpu, s.cpu_usage + '%');
color(el.cpu, s.cpu_usage, 50, 80);
}
if (s.ram_used !== undefined) {
set(el.ram, s.ram_used + ' Gio');
set(el.ramSub, `sur ${s.ram_total} Gio (${s.ram_percent}%)`);
color(el.ram, s.ram_percent, 60, 80);
}
if (s.disk_root_free !== undefined) {
set(el.diskRoot, s.disk_root_free + ' Gio');
set(el.diskRootSub, `sur ${s.disk_root_total} Gio (${s.disk_root_percent}% utilisé)`);
color(el.diskRoot, s.disk_root_percent, 70, 90);
}
if (s.disk_var_free !== undefined) {
set(el.diskVar, s.disk_var_free + ' Gio');
set(el.diskVarSub, `sur ${s.disk_var_total} Gio (${s.disk_var_percent}% utilisé)`);
color(el.diskVar, s.disk_var_percent, 70, 90);
}
if (s.disk_srv_free !== undefined) {
set(el.diskSrv, s.disk_srv_free + ' Gio');
set(el.diskSrvSub, `sur ${s.disk_srv_total} Gio (${s.disk_srv_percent}% utilisé)`);
color(el.diskSrv, s.disk_srv_percent, 70, 90);
}
if (s.load_1 !== undefined) {
set(el.load, s.load_1);
color(el.load, (s.load_1 / 4) * 100, 50, 80);
}
set(el.processes, s.processes);
}
async function fetchMdadm() {
try {
const r = await fetch(API_MDADM, { cache: 'no-cache' });
if (!r.ok) throw new Error(`HTTP ${r.status}`);
const d = await r.json();
if (d.healthy) {
set(el.mdadmStatus, '✓ Sain');
if (el.mdadmStatus) el.mdadmStatus.style.color = '#50fa7b';
set(el.mdadmSub, d.arrays.map(a => `${a.name} [${a.bitmap}]`).join(' · '));
if (el.mdadmCard) el.mdadmCard.style.borderTop = '';
} else {
set(el.mdadmStatus, '⚠ Dégradé');
if (el.mdadmStatus) el.mdadmStatus.style.color = '#ff5555';
set(el.mdadmSub, d.arrays
.filter(a => a.health !== 'ok')
.map(a => `${a.name}: ${a.detail || a.health}`)
.join(' · '));
if (el.mdadmCard) el.mdadmCard.style.borderTop = '2px solid #ff5555';
}
} catch(e) {
set(el.mdadmStatus, '?');
if (el.mdadmStatus) el.mdadmStatus.style.color = '#ffb86c';
set(el.mdadmSub, 'erreur fetch');
}
}
function showError() {
['uptime','cpu','ram','diskRoot','diskVar','diskSrv','load','processes'].forEach(k => {
if (el[k]) { el[k].textContent = 'Erreur'; el[k].style.color = '#ff5555'; }
});
}
async function refresh() {
await fetchStats();
await fetchMdadm();
}
function stop() {
if (timer) { clearInterval(timer); timer = null; }
}
function start() {
stop();
timer = setInterval(refresh, INTERVAL);
}
function init() {
if (!document.querySelector('.stats-section')) return;
refresh();
start();
window.addEventListener('beforeunload', stop);
document.addEventListener('visibilitychange', () => {
if (document.hidden) stop();
else { refresh(); start(); }
});
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
else init();
})();