[optim] extract cache as component
This commit is contained in:
parent
70795a11fa
commit
2ee5d89e5f
|
@ -6,7 +6,8 @@ import avatar from '../avatar';
|
||||||
import {buildPronoun, parsePronouns} from "../../src/buildPronoun";
|
import {buildPronoun, parsePronouns} from "../../src/buildPronoun";
|
||||||
import {loadTsv} from "../../src/tsv";
|
import {loadTsv} from "../../src/tsv";
|
||||||
import {handleErrorAsync} from "../../src/helpers";
|
import {handleErrorAsync} from "../../src/helpers";
|
||||||
import fs from 'fs';
|
import cache from "../../src/cache";
|
||||||
|
import fs from "fs";
|
||||||
|
|
||||||
const translations = loadSuml('translations');
|
const translations = loadSuml('translations');
|
||||||
|
|
||||||
|
@ -37,82 +38,73 @@ router.get('/banner/:pronounName*.png', handleErrorAsync(async (req, res) => {
|
||||||
|
|
||||||
const pronounName = req.params.pronounName + req.params[0];
|
const pronounName = req.params.pronounName + req.params[0];
|
||||||
|
|
||||||
const cacheDir = `${__dirname}/../../cache/banner`;
|
const result = await cache('banner', `${pronounName}.png`, 24 * 60, async () => {
|
||||||
fs.mkdirSync(cacheDir, { recursive: true });
|
registerFont('static/fonts/quicksand-v21-latin-ext_latin-regular.ttf', {family: 'Quicksand', weight: 'regular'});
|
||||||
const cacheFilename = `${cacheDir}/${pronounName}.png`;
|
registerFont('static/fonts/quicksand-v21-latin-ext_latin-700.ttf', {family: 'Quicksand', weight: 'bold'});
|
||||||
if (fs.existsSync(cacheFilename) && fs.statSync(cacheFilename).mtimeMs >= (new Date() - 24*60*60*1000)) {
|
|
||||||
return res.set('content-type', mime).send(fs.readFileSync(cacheFilename));
|
|
||||||
}
|
|
||||||
|
|
||||||
const saveToCacheAndReturn = (canvas) => {
|
const canvas = createCanvas(width, height)
|
||||||
const buffer = canvas.toBuffer(mime);
|
const context = canvas.getContext('2d')
|
||||||
fs.writeFileSync(cacheFilename, buffer);
|
|
||||||
return res.set('content-type', mime).send(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
registerFont('static/fonts/quicksand-v21-latin-ext_latin-regular.ttf', { family: 'Quicksand', weight: 'regular'});
|
const bg = await loadImage('static/bg.png');
|
||||||
registerFont('static/fonts/quicksand-v21-latin-ext_latin-700.ttf', { family: 'Quicksand', weight: 'bold'});
|
context.drawImage(bg, 0, 0, width, height);
|
||||||
|
|
||||||
const canvas = createCanvas(width, height)
|
const fallback = async _ => {
|
||||||
const context = canvas.getContext('2d')
|
const logo = await loadImage('node_modules/@fortawesome/fontawesome-pro/svgs/light/tags.svg');
|
||||||
|
leftRatio = 5;
|
||||||
const bg = await loadImage('static/bg.png');
|
context.drawImage(logo, width / leftRatio - imageSize / 2, height / 2 - imageSize / 1.25 / 2, imageSize, imageSize / 1.25);
|
||||||
context.drawImage(bg, 0, 0, width, height);
|
context.font = `regular ${translations.title.length < 10 ? 120 : translations.title.length < 14 ? 80 : 72}pt Quicksand`;
|
||||||
|
context.fillText(translations.title, width / leftRatio + imageSize / 1.5, height / 2 + (translations.title.length < 10 ? 48 : translations.title.length < 14 ? 24 : 24));
|
||||||
const fallback = async _ => {
|
|
||||||
const logo = await loadImage('node_modules/@fortawesome/fontawesome-pro/svgs/light/tags.svg');
|
|
||||||
leftRatio = 5;
|
|
||||||
context.drawImage(logo, width / leftRatio - imageSize / 2, height / 2 - imageSize / 1.25 / 2, imageSize, imageSize / 1.25);
|
|
||||||
context.font = `regular ${translations.title.length < 10 ? 120 : translations.title.length < 14 ? 80 : 72}pt Quicksand`;
|
|
||||||
context.fillText(translations.title, width / leftRatio + imageSize / 1.5, height / 2 + (translations.title.length < 10 ? 48 : translations.title.length < 14 ? 24 : 24));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pronounName.startsWith('@')) {
|
|
||||||
const user = await req.db.get(SQL`SELECT id, username, email, avatarSource FROM users WHERE username=${pronounName.substring(1)}`);
|
|
||||||
if (!user) {
|
|
||||||
await fallback();
|
|
||||||
return saveToCacheAndReturn(canvas);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const avatarImage = await loadImage(await avatar(req.db, user));
|
if (pronounName.startsWith('@')) {
|
||||||
|
const user = await req.db.get(SQL`SELECT id, username, email, avatarSource FROM users WHERE username=${pronounName.substring(1)}`);
|
||||||
|
if (!user) {
|
||||||
|
await fallback();
|
||||||
|
return canvas.toBuffer(mime);
|
||||||
|
}
|
||||||
|
|
||||||
drawCircle(context, avatarImage, width / leftRatio - imageSize / 2, height / 2 - imageSize / 2, imageSize);
|
const avatarImage = await loadImage(await avatar(req.db, user));
|
||||||
|
|
||||||
context.font = `regular 48pt Quicksand`
|
drawCircle(context, avatarImage, width / leftRatio - imageSize / 2, height / 2 - imageSize / 2, imageSize);
|
||||||
context.fillText('@' + user.username, width / leftRatio + imageSize, height / 2)
|
|
||||||
|
|
||||||
const logo = await loadImage('static/favicon.svg');
|
context.font = `regular 48pt Quicksand`
|
||||||
|
context.fillText('@' + user.username, width / leftRatio + imageSize, height / 2)
|
||||||
|
|
||||||
context.font = 'regular 24pt Quicksand'
|
const logo = await loadImage('static/favicon.svg');
|
||||||
context.fillStyle = '#C71585';
|
|
||||||
const logoSize = 24 * 1.25;
|
|
||||||
context.drawImage(logo, width / leftRatio + imageSize, height / 2 + logoSize - 4, logoSize, logoSize / 1.25)
|
|
||||||
context.fillText(translations.title, width / leftRatio + imageSize + 36, height / 2 + 48);
|
|
||||||
|
|
||||||
return saveToCacheAndReturn(canvas);
|
context.font = 'regular 24pt Quicksand'
|
||||||
}
|
context.fillStyle = '#C71585';
|
||||||
|
const logoSize = 24 * 1.25;
|
||||||
|
context.drawImage(logo, width / leftRatio + imageSize, height / 2 + logoSize - 4, logoSize, logoSize / 1.25)
|
||||||
|
context.fillText(translations.title, width / leftRatio + imageSize + 36, height / 2 + 48);
|
||||||
|
|
||||||
const pronoun = buildPronoun(
|
return canvas.toBuffer(mime);
|
||||||
parsePronouns(loadTsv(__dirname + '/../../data/pronouns/pronouns.tsv')),
|
}
|
||||||
pronounName,
|
|
||||||
);
|
|
||||||
|
|
||||||
const logo = await loadImage('node_modules/@fortawesome/fontawesome-pro/svgs/light/tags.svg');
|
const pronoun = buildPronoun(
|
||||||
|
parsePronouns(loadTsv(__dirname + '/../../data/pronouns/pronouns.tsv')),
|
||||||
|
pronounName,
|
||||||
|
);
|
||||||
|
|
||||||
if (!pronoun && pronounName !== req.config.pronouns.any) {
|
const logo = await loadImage('node_modules/@fortawesome/fontawesome-pro/svgs/light/tags.svg');
|
||||||
await fallback();
|
|
||||||
return saveToCacheAndReturn(canvas);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.drawImage(logo, width / leftRatio - imageSize / 2, height / 2 - imageSize / 1.25 / 2, imageSize, imageSize / 1.25)
|
if (!pronoun && pronounName !== req.config.pronouns.any) {
|
||||||
context.font = 'regular 48pt Quicksand'
|
await fallback();
|
||||||
context.fillText(translations.pronouns.intro + ':', width / leftRatio + imageSize / 1.5, height / 2 - 36)
|
return canvas.toBuffer(mime);
|
||||||
|
}
|
||||||
|
|
||||||
const pronounNameOptions = pronounName === req.config.pronouns.any ? [req.config.pronouns.any] : pronoun.nameOptions();
|
context.drawImage(logo, width / leftRatio - imageSize / 2, height / 2 - imageSize / 1.25 / 2, imageSize, imageSize / 1.25)
|
||||||
context.font = `bold ${pronounNameOptions.length <= 2 ? '70' : '36'}pt Quicksand`
|
context.font = 'regular 48pt Quicksand'
|
||||||
context.fillText(pronounNameOptions.join('\n'), width / leftRatio + imageSize / 1.5, height / 2 + (pronounNameOptions.length <= 2 ? 72 : 24));
|
context.fillText(translations.pronouns.intro + ':', width / leftRatio + imageSize / 1.5, height / 2 - 36)
|
||||||
|
|
||||||
return saveToCacheAndReturn(canvas);
|
const pronounNameOptions = pronounName === req.config.pronouns.any ? [req.config.pronouns.any] : pronoun.nameOptions();
|
||||||
|
context.font = `bold ${pronounNameOptions.length <= 2 ? '70' : '36'}pt Quicksand`
|
||||||
|
context.fillText(pronounNameOptions.join('\n'), width / leftRatio + imageSize / 1.5, height / 2 + (pronounNameOptions.length <= 2 ? 72 : 24));
|
||||||
|
|
||||||
|
return canvas.toBuffer(mime);
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.set('content-type', mime).send(result);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
import fs from 'fs';
|
||||||
|
|
||||||
|
export default async (dir, filename, maxAgeMinutes, generator) => {
|
||||||
|
const cacheDir = `${__dirname}/../cache/${dir}`
|
||||||
|
fs.mkdirSync(cacheDir, { recursive: true });
|
||||||
|
const cacheFilename = `${cacheDir}/${filename}`;
|
||||||
|
|
||||||
|
if (fs.existsSync(cacheFilename) && fs.statSync(cacheFilename).mtimeMs >= (new Date() - maxAgeMinutes*60*1000)) {
|
||||||
|
return fs.readFileSync(cacheFilename);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await generator();
|
||||||
|
|
||||||
|
fs.writeFileSync(cacheFilename, result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
Reference in New Issue