This commit is contained in:
Louis Mazin 2026-04-16 01:13:27 +02:00
parent 89f1b3406c
commit 143102d7ef

View File

@ -1,4 +1,6 @@
const { EmbedBuilder, ActionRowBuilder, StringSelectMenuBuilder } = require('discord.js'); const { EmbedBuilder, ActionRowBuilder, StringSelectMenuBuilder } = require('discord.js');
const fs = require('node:fs');
const path = require('node:path');
const PINBOARD_SELECT_CUSTOM_ID = 'pinboard-image-select'; const PINBOARD_SELECT_CUSTOM_ID = 'pinboard-image-select';
const selectedImageIndexByMessage = new Map(); const selectedImageIndexByMessage = new Map();
@ -18,12 +20,72 @@ const toCacheBustedUrl = (url) => {
return `${url}${separator}cb=${getCacheBustValue()}`; return `${url}${separator}cb=${getCacheBustValue()}`;
}; };
const parsePinboardImageUrls = () => { const readPinboardRawFromEnvFile = () => {
const raw = process.env.PINBOARD_IMAGE_URLS || ''; try {
return raw const envPath = path.join(process.cwd(), '.env');
if (!fs.existsSync(envPath)) {
return '';
}
const content = fs.readFileSync(envPath, 'utf8');
const marker = 'PINBOARD_IMAGE_URLS=';
const start = content.indexOf(marker);
if (start === -1) {
return '';
}
const afterMarkerIndex = start + marker.length;
const rest = content.slice(afterMarkerIndex);
const nextVarMatch = rest.match(/\n[A-Z0-9_]+=/);
const end = nextVarMatch ? afterMarkerIndex + nextVarMatch.index : content.length;
return content.slice(afterMarkerIndex, end).trim();
} catch (error) {
return '';
}
};
const parsePinboardImageItems = () => {
let raw = process.env.PINBOARD_IMAGE_URLS || '';
// Support multiline object-like config when dotenv only captures the first line.
if (!raw || raw.trim() === '{') {
raw = readPinboardRawFromEnvFile();
}
if (!raw) {
return [];
}
const items = [];
const pairRegex = /name\s*:\s*([^,\n]+?)\s*,\s*url\s*:\s*(https?:\/\/[^\s,}\]]+)/gim;
let match = pairRegex.exec(raw);
while (match) {
const name = match[1].trim().replace(/^['"]|['"]$/g, '');
const url = match[2].trim().replace(/^['"]|['"]$/g, '');
if (name && /^https?:\/\//i.test(url)) {
items.push({ name, url });
}
match = pairRegex.exec(raw);
}
if (items.length > 0) {
return items;
}
// Fallback legacy: comma-separated URLs only
const urls = raw
.split(',') .split(',')
.map(url => url.trim()) .map(url => url.trim())
.filter(url => /^https?:\/\//i.test(url)); .filter(url => /^https?:\/\//i.test(url));
return urls.map((url, index) => ({
name: `Image ${index + 1}`,
url
}));
}; };
const clampIndex = (index, length) => { const clampIndex = (index, length) => {
@ -33,18 +95,19 @@ const clampIndex = (index, length) => {
return index; return index;
}; };
const buildSelectedImageEmbed = (url, index, total) => ( const buildSelectedImageEmbed = (item, index, total) => (
new EmbedBuilder() new EmbedBuilder()
.setColor('#f59e0b') .setColor('#f59e0b')
.setTitle(`Image selectionnee (${index + 1}/${total})`) .setTitle(item.name)
.setImage(toCacheBustedUrl(url)) .setDescription(`Image ${index + 1}/${total}`)
.setImage(toCacheBustedUrl(item.url))
); );
const buildImageSelectorRow = (urls, selectedIndex) => { const buildImageSelectorRow = (items, selectedIndex) => {
const options = urls.slice(0, 25).map((url, index) => ({ const options = items.slice(0, 25).map((item, index) => ({
label: `Image ${index + 1}`, label: item.name.length > 100 ? `${item.name.slice(0, 97)}...` : item.name,
value: String(index), value: String(index),
description: url.length > 95 ? `${url.slice(0, 92)}...` : url, description: item.url.length > 95 ? `${item.url.slice(0, 92)}...` : item.url,
default: index === selectedIndex default: index === selectedIndex
})); }));
@ -100,17 +163,17 @@ const buildPanelEmbed = (status) => {
const buildPanelPayload = (status, messageId) => { const buildPanelPayload = (status, messageId) => {
const panelEmbed = buildPanelEmbed(status); const panelEmbed = buildPanelEmbed(status);
const pinboardUrls = parsePinboardImageUrls(); const pinboardItems = parsePinboardImageItems().slice(0, 25);
if (pinboardUrls.length === 0) { if (pinboardItems.length === 0) {
return { content: '', embeds: [panelEmbed], components: [] }; return { content: '', embeds: [panelEmbed], components: [] };
} }
const currentIndex = clampIndex(selectedImageIndexByMessage.get(messageId) ?? 0, pinboardUrls.length); const currentIndex = clampIndex(selectedImageIndexByMessage.get(messageId) ?? 0, pinboardItems.length);
selectedImageIndexByMessage.set(messageId, currentIndex); selectedImageIndexByMessage.set(messageId, currentIndex);
const selectedImageEmbed = buildSelectedImageEmbed(pinboardUrls[currentIndex], currentIndex, pinboardUrls.length); const selectedImageEmbed = buildSelectedImageEmbed(pinboardItems[currentIndex], currentIndex, pinboardItems.length);
const selectorRow = buildImageSelectorRow(pinboardUrls, currentIndex); const selectorRow = buildImageSelectorRow(pinboardItems, currentIndex);
return { return {
content: '', content: '',
@ -173,15 +236,15 @@ const handlePinboardSelection = async (interaction) => {
} }
try { try {
const pinboardUrls = parsePinboardImageUrls(); const pinboardItems = parsePinboardImageItems().slice(0, 25);
if (pinboardUrls.length === 0) { if (pinboardItems.length === 0) {
await interaction.reply({ content: 'Aucune image configuree dans PINBOARD_IMAGE_URLS.', ephemeral: true }); await interaction.reply({ content: 'Aucune image configuree dans PINBOARD_IMAGE_URLS.', ephemeral: true });
return true; return true;
} }
const selectedRaw = Number.parseInt(interaction.values?.[0] || '0', 10); const selectedRaw = Number.parseInt(interaction.values?.[0] || '0', 10);
const selectedIndex = clampIndex(selectedRaw, pinboardUrls.length); const selectedIndex = clampIndex(selectedRaw, pinboardItems.length);
selectedImageIndexByMessage.set(interaction.message.id, selectedIndex); selectedImageIndexByMessage.set(interaction.message.id, selectedIndex);
const status = await getMinecraftStatus(); const status = await getMinecraftStatus();