diff --git a/.vscode/settings.json b/.vscode/settings.json index de2d6290e..f17372342 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,6 +13,7 @@ "playerachievements", "playerinfo", "Resvg", + "roboto", "searchclans", "searchplayers", "searchtanks", diff --git a/package.json b/package.json index feb01e488..ee84e10c7 100644 --- a/package.json +++ b/package.json @@ -5,11 +5,14 @@ "main": "src/index.ts", "type": "module", "scripts": { - "dev:bot": "yarn build:bot --dev && yarn start --dev", - "start": "node --enable-source-maps --trace-warnings dist/bot.cjs", - "zip": "zip -r dist.zip dist", - "build:bot": "node scripts/build --bot", + "build:bot": "node scripts/build --build=bot", + "build:server": "node scripts/build --build=server", "build": "yarn lint && yarn build:bot", + "dev:bot": "yarn build:bot --dev && yarn start:bot --dev", + "dev:server": "yarn build:server --dev && yarn start:server --dev", + "start:bot": "node --enable-source-maps --trace-warnings dist/bot.cjs", + "start:server": "node --enable-source-maps --trace-warnings dist/server.cjs", + "zip": "zip -r dist.zip dist", "lint": "tsc" }, "license": "MIT", diff --git a/scripts/build.js b/scripts/build.js index 575ad8c1b..d2161ac2e 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -27,7 +27,20 @@ const commonOptions = { }; console.log('Building...'); -build({ - entryPoints: ['src/bot.ts'], - outfile: 'dist/bot.cjs', -}); +if (buildBot) { + build({ + ...commonOptions, + + entryPoints: ['src/bot.ts'], + outfile: 'dist/bot.cjs', + }); +} + +if (buildServer) { + build({ + ...commonOptions, + + entryPoints: ['src/server.ts'], + outfile: 'dist/server.cjs', + }); +} diff --git a/src/core/ui/jsxToSvg.ts b/src/core/ui/jsxToSvg.ts new file mode 100644 index 000000000..5c6aa1290 --- /dev/null +++ b/src/core/ui/jsxToSvg.ts @@ -0,0 +1,42 @@ +import { readFile } from 'fs'; +import { join } from 'path'; +import satori from 'satori'; +import robotoBlackFile from '../../assets/fonts/Roboto-Black.ttf'; +import robotoBoldFile from '../../assets/fonts/Roboto-Bold.ttf'; +import robotoFile from '../../assets/fonts/Roboto.ttf'; + +const FONT_NAME = 'Roboto'; +const FONT_FILES = [robotoFile, robotoBoldFile, robotoBlackFile]; + +let roboto: Buffer; +let robotoBold: Buffer; +let robotoBlack: Buffer; + +console.log('Importing fonts...'); +Promise.all( + FONT_FILES.map( + (file) => + new Promise((resolve, reject) => { + const path = join(__dirname, file); + + readFile(path, (error, data) => { + if (error) reject(error); + resolve(data); + }); + }), + ), +).then((data) => { + [roboto, robotoBold, robotoBlack] = data; + console.log('Fonts imported'); +}); + +export default async function jsxToSvg(jsx: JSX.Element) { + return await satori(jsx, { + width: 640, + fonts: [ + { data: roboto, name: FONT_NAME, weight: 400 }, + { data: robotoBold, name: FONT_NAME, weight: 700 }, + { data: robotoBlack, name: FONT_NAME, weight: 900 }, + ], + }); +} diff --git a/src/core/ui/render.tsx b/src/core/ui/render.tsx index 19ba744b1..ae00848bc 100644 --- a/src/core/ui/render.tsx +++ b/src/core/ui/render.tsx @@ -1,48 +1,9 @@ -import { Resvg } from '@resvg/resvg-js'; -import { readFile } from 'fs'; -import { join } from 'path'; -import { ReactNode } from 'react'; -import satori from 'satori'; -import robotoBlackFile from '../../assets/fonts/Roboto-Black.ttf'; -import robotoBoldFile from '../../assets/fonts/Roboto-Bold.ttf'; -import robotoFile from '../../assets/fonts/Roboto.ttf'; +import jsxToSvg from './jsxToSvg.js'; +import svgToPng from './svgToPng.js'; -const FONT_NAME = 'Roboto'; -const FONT_FILES = [robotoFile, robotoBoldFile, robotoBlackFile]; - -let roboto: Buffer; -let robotoBold: Buffer; -let robotoBlack: Buffer; - -console.log('Importing fonts...'); -Promise.all( - FONT_FILES.map( - (file) => - new Promise((resolve, reject) => { - const path = join(__dirname, file); - - readFile(path, (error, data) => { - if (error) reject(error); - resolve(data); - }); - }), - ), -).then((data) => { - [roboto, robotoBold, robotoBlack] = data; - console.log('Fonts imported'); -}); - -export default async function render(element: ReactNode) { - const svg = await satori(element, { - width: 640, - fonts: [ - { data: roboto, name: FONT_NAME, weight: 400 }, - { data: robotoBold, name: FONT_NAME, weight: 700 }, - { data: robotoBlack, name: FONT_NAME, weight: 900 }, - ], - }); - - const png = new Resvg(svg).render().asPng(); +export default async function render(jsx: JSX.Element) { + const svg = await jsxToSvg(jsx); + const png = svgToPng(svg); return png; } diff --git a/src/core/ui/svgToPng.ts b/src/core/ui/svgToPng.ts new file mode 100644 index 000000000..3a221097d --- /dev/null +++ b/src/core/ui/svgToPng.ts @@ -0,0 +1,5 @@ +import { Resvg } from "@resvg/resvg-js"; + +export default function svgToPng(svg: string) { + return new Resvg(svg).render().asPng() +} \ No newline at end of file diff --git a/src/server.ts b/src/server.ts index f442940f6..857cc4937 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,7 +1,18 @@ import express from 'express'; +import jsxToSvg from './core/ui/jsxToSvg.js'; +import today from './renderers/today.js'; const app = express(); -app.get('/', (req, res) => { - res.send('Hello World!'); +app.get('/', async (req, res) => { + const jsx = await today({ server: 'com', id: 1028700193 }); + const svg = await jsxToSvg(jsx); + + res.writeHead(200, { + 'Content-Type': 'image/svg+xml', + 'Content-Length': svg.length, + }); + res.end(svg); }); + +app.listen(process.env.PORT || 3000);