mirror of
https://gitlab.com/PronounsPage/PronounsPage.git
synced 2025-08-03 11:07:00 -04:00
133 lines
4.1 KiB
TypeScript
133 lines
4.1 KiB
TypeScript
import './setup.ts';
|
||
|
||
import { S3 } from '@aws-sdk/client-s3';
|
||
import * as Sentry from '@sentry/node';
|
||
import Pageres from 'pageres';
|
||
import type { Screenshot } from 'pageres';
|
||
import { ulid } from 'ulid';
|
||
|
||
import { awsConfig, awsParams } from './aws.ts';
|
||
import dbConnection from './db.ts';
|
||
import type { Database } from './db.ts';
|
||
import isHighLoadTime from './overload.js';
|
||
|
||
import jwt from '~/server/jwt.ts';
|
||
import { getLocaleUrls } from '~/src/domain.ts';
|
||
|
||
const s3 = new S3(awsConfig);
|
||
|
||
const urlBases: Record<string, string> = {};
|
||
|
||
for (const [locale, url] of Object.entries(getLocaleUrls(process.env.NUXT_PUBLIC_DOMAIN_BASE))) {
|
||
urlBases[locale] = `${url}/card/@`;
|
||
}
|
||
|
||
const sleep = (ms: number): Promise<void> => new Promise((res) => setTimeout(res, ms));
|
||
|
||
const modes = ['light', 'dark'] as const;
|
||
|
||
const shoot = async (db: Database, mode: 'light' | 'dark'): Promise<void> => {
|
||
const profiles = (await db.all<{ id: string; locale: string; username: string }>(`
|
||
SELECT profiles.id, profiles.locale, users.username
|
||
FROM profiles
|
||
LEFT JOIN users on profiles.userId = users.id
|
||
WHERE profiles.${mode === 'dark' ? 'cardDark' : 'card'} = ''
|
||
ORDER BY RANDOM()
|
||
LIMIT 6
|
||
`)).filter(({ locale }) => !isHighLoadTime(locale));
|
||
|
||
if (profiles.length === 0) {
|
||
console.log('No profiles in the queue');
|
||
return;
|
||
}
|
||
|
||
const results: Record<string, Screenshot> = {};
|
||
|
||
try {
|
||
const pr = new Pageres({
|
||
darkMode: mode === 'dark',
|
||
delay: 3,
|
||
scale: 1.5,
|
||
launchOptions: {
|
||
headless: 'new',
|
||
},
|
||
});
|
||
|
||
for (const { locale, username } of profiles) {
|
||
const token = await jwt.sign(
|
||
locale,
|
||
{
|
||
username: 'example',
|
||
email: 'example@pronouns.page',
|
||
roles: '',
|
||
avatarSource: '',
|
||
bannedReason: null,
|
||
mfa: false,
|
||
authenticated: true,
|
||
},
|
||
'15m',
|
||
process.env.NUXT_PUBLIC_DOMAIN_BASE ?? '',
|
||
);
|
||
|
||
pr.source(`${urlBases[locale] + username}?token=${encodeURIComponent(token)}`, ['1024x300'], {
|
||
filename: `${username}-${locale}`,
|
||
});
|
||
}
|
||
|
||
for (const buffer of await pr.run()) {
|
||
const match = buffer.filename.match(/(.+)-(\w+)\.png/);
|
||
if (!match) {
|
||
console.error('invalid filename', buffer.filename);
|
||
continue;
|
||
}
|
||
const [, username, locale] = match;
|
||
results[`${locale}/${username.replace(/[^A-Za-z0-9.-]/g, '_')}`] = buffer;
|
||
}
|
||
} catch (error) {
|
||
Sentry.captureException(error);
|
||
return;
|
||
}
|
||
|
||
for (const { id, locale, username } of profiles) {
|
||
const cardId = ulid();
|
||
let key = `card/${locale}/${encodeURIComponent(username).replace(/'/g, '_')}-${cardId}.png`;
|
||
if (mode === 'dark') {
|
||
key = mode === 'dark' ? key.replace('.png', '-dark.png') : key;
|
||
}
|
||
|
||
console.log(`Uploading @${username} (${locale}, ${mode}) – ${cardId}`);
|
||
|
||
const buffer = results[`${locale}/${username.replace(/[^A-Za-z0-9.-]/g, '_')}`];
|
||
|
||
if (buffer === undefined) {
|
||
console.error('Cannot find the proper buffer!');
|
||
continue;
|
||
}
|
||
|
||
await s3.putObject({
|
||
Key: key,
|
||
Body: buffer,
|
||
ContentType: 'image/png',
|
||
ACL: 'public-read',
|
||
...awsParams,
|
||
});
|
||
|
||
await db.get(`
|
||
UPDATE profiles
|
||
SET ${mode === 'dark' ? 'cardDark' : 'card'
|
||
}='https://${awsParams.Bucket}.s3.${awsConfig.region}.amazonaws.com/${key}'
|
||
WHERE id='${id}'`);
|
||
}
|
||
};
|
||
|
||
(async (): Promise<void> => {
|
||
const db = await dbConnection();
|
||
while (true) {
|
||
for (const mode of modes) {
|
||
await sleep(3000);
|
||
console.log(`Starting mode: ${mode}`);
|
||
await shoot(db, mode);
|
||
}
|
||
}
|
||
})();
|