works on system, lets try on docker

This commit is contained in:
2025-12-13 06:26:39 -05:00
parent 6f416d3912
commit 5c2ed523b9
7 changed files with 1377 additions and 8 deletions

3
.gitignore vendored
View File

@@ -141,4 +141,5 @@ dist
config.json config.json
state.json state.json
cache.json cache.json
docker-compose.yml docker-compose.yml
public/

View File

@@ -0,0 +1,127 @@
const { SlashCommandBuilder } = require('discord.js');
const torn = require('../../torn.js');
const fs = require('fs');
const path = require('path');
// eslint-disable-next-line no-unused-vars
const { createCanvas, registerFont } = require('canvas');
module.exports = {
data: new SlashCommandBuilder()
.setName('updateupgrades')
.setDescription('Generate the faction upgrades PNG'),
async execute(interaction) {
await interaction.deferReply(); // give more time for image generation
const data = await torn.faction.upgrades();
const lines = [];
lines.push("Core Upgrades:");
let armoryNames = [];
for (const upgrade of data.upgrades.core.upgrades) {
if (upgrade.name && String(upgrade.name).toLowerCase().includes('armory')) {
armoryNames.push(upgrade.name.replace(/\s+armory$/i, ''));
} else {
lines.push(` ${upgrade.name} - ${upgrade.ability}`);
}
}
if (armoryNames.length) {
lines.push(` Armory: ${armoryNames.join(', ')}`);
}
lines.push("");
lines.push("Peace Upgrades:");
for (const branch of data.upgrades.peace) {
lines.push(` ${branch.name}`);
for (const upgrade of branch.upgrades) {
lines.push(` ${upgrade.name} - ${upgrade.ability}`);
}
}
lines.push("");
lines.push("War Upgrades:");
for (const branch of data.upgrades.war) {
lines.push(` ${branch.name}`);
for (const upgrade of branch.upgrades) {
lines.push(` ${upgrade.name} - ${upgrade.ability}`);
}
}
// Image rendering settings
const padding = 24;
const maxWidth = 1100;
const fontSize = 18;
const fontFamily = 'Sans';
const lineHeight = Math.round(fontSize * 1.4);
const fontSpec = `${fontSize}px ${fontFamily}`;
// Temporary canvas for measurement
const measureCanvas = createCanvas(10, 10);
const measureCtx = measureCanvas.getContext('2d');
measureCtx.font = fontSpec;
function wrapLine(ctx, text, maxW) {
const words = text.split(' ');
const wrapped = [];
let line = '';
for (const word of words) {
const test = line ? `${line} ${word}` : word;
const w = ctx.measureText(test).width;
if (w > maxW && line) {
wrapped.push(line);
line = word;
} else {
line = test;
}
}
if (line) wrapped.push(line);
return wrapped;
}
let visualLines = [];
let measuredMaxWidth = 0;
const textMaxWidth = maxWidth - padding * 2;
for (const ln of lines) {
if (!ln) {
visualLines.push('');
continue;
}
const wrapped = wrapLine(measureCtx, ln, textMaxWidth);
for (const wln of wrapped) {
visualLines.push(wln);
measuredMaxWidth = Math.max(measuredMaxWidth, Math.ceil(measureCtx.measureText(wln).width));
}
}
const canvasWidth = Math.min(maxWidth, measuredMaxWidth + padding * 2);
const canvasHeight = padding * 2 + visualLines.length * lineHeight;
const canvas = createCanvas(canvasWidth, canvasHeight);
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#0A2472';
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
ctx.font = fontSpec;
ctx.fillStyle = '#ffffff';
ctx.textBaseline = 'top';
let y = padding;
for (const vln of visualLines) {
ctx.fillText(vln, padding, y);
y += lineHeight;
}
const outDir = path.resolve(__dirname, '..', '..', 'public', 'images');
fs.mkdirSync(outDir, { recursive: true });
const outFile = path.join(outDir, 'upgrades.png');
const buffer = canvas.toBuffer('image/png');
fs.writeFileSync(outFile, buffer);
try {
await interaction.editReply({ files: [outFile] });
} catch (err) {
await interaction.editReply('Generated upgrades image but failed to attach it.');
console.debug('Failed to attach image to interaction reply:', err.message || err);
}
},
};

View File

@@ -5,4 +5,6 @@ services:
volumes: volumes:
- ./config.json:/usr/src/bot/config.json - ./config.json:/usr/src/bot/config.json
- ./state.json:/usr/src/bot/state.json - ./state.json:/usr/src/bot/state.json
- ./cache.json:/usr/src/bot/cache.json - ./cache.json:/usr/src/bot/cache.json
ports:
- 3000:3000

View File

@@ -2,6 +2,7 @@ const cron = require('node-cron');
const fs = require('fs'); const fs = require('fs');
const path = require('node:path'); const path = require('node:path');
const torn = require('./torn.js'); const torn = require('./torn.js');
const express = require('express');
let config, state; let config, state;
try { try {
@@ -154,3 +155,38 @@ client.on(Events.MessageCreate, message => {
}); });
} }
}); });
// ensure public folder exists
const publicDir = path.resolve(__dirname, 'public');
fs.mkdirSync(publicDir, { recursive: true });
// load optional config.json (use httpPort) or PORT env var
let cfg = {};
const cfgPath = path.resolve(__dirname, 'config.json');
if (fs.existsSync(cfgPath)) {
// eslint-disable-next-line no-unused-vars
try { cfg = require(cfgPath); } catch (e) { /* ignore */ }
}
const port = process.env.PORT || cfg.httpPort || 3000;
// create simple static server
const app = express();
app.use(express.static(publicDir));
// convenience routes
app.get('/upgrades.png', (req, res) => {
const imgPath = path.join(publicDir, 'images', 'upgrades.png');
if (fs.existsSync(imgPath)) return res.sendFile(imgPath);
res.status(404).send('Not found');
});
app.get('/images', (req, res) => {
const imgDir = path.join(publicDir, 'images');
if (!fs.existsSync(imgDir)) return res.status(404).send('No images');
const files = fs.readdirSync(imgDir).filter(f => /\.(png|jpe?g|gif)$/i.test(f));
res.send(`<pre>${files.join('\n')}</pre>`);
});
app.listen(port, () => {
console.log(`Static server running: http://localhost:${port}/ (serving ${publicDir})`);
});

1211
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -17,7 +17,9 @@
"homepage": "https://github.com/CesiumCs/tornbot#readme", "homepage": "https://github.com/CesiumCs/tornbot#readme",
"description": "", "description": "",
"dependencies": { "dependencies": {
"canvas": "^3.2.0",
"discord.js": "^14.18.0", "discord.js": "^14.18.0",
"express": "^5.2.1",
"fs": "^0.0.1-security", "fs": "^0.0.1-security",
"node-cron": "^3.0.3" "node-cron": "^3.0.3"
}, },

View File

@@ -194,7 +194,7 @@ module.exports.faction = {
async upgrades() { async upgrades() {
const response = await fetch(`https://api.torn.com/v2/faction/upgrades?key=${config.torn}`); const response = await fetch(`https://api.torn.com/v2/faction/upgrades?key=${config.torn}`);
const data = await response.json(); const data = await response.json();
return(data.upgrades); return(data);
}, },
async news(category, from) { async news(category, from) {
const response = await fetch(`https://api.torn.com/v2/faction/news?striptags=false&limit=100&sort=DESC&from=${from}&cat=${category}&key=${config.torn}`) const response = await fetch(`https://api.torn.com/v2/faction/news?striptags=false&limit=100&sort=DESC&from=${from}&cat=${category}&key=${config.torn}`)