This repository has been archived on 2024-07-22. You can view files and clone it, but cannot push or open issues or pull requests.
Zaimki/server/cleanupImages.js

212 lines
5.9 KiB
JavaScript

require('../src/dotenv')();
const dbConnection = require('./db');
const awsConfig = require('./aws');
const S3 = require('aws-sdk/clients/s3');
const execute = process.env.EXECUTE === '1';
console.log(execute ? 'WILL REMOVE FILES!' : 'Dry run');
async function cleanup() {
console.log('--- Fetching ids expected to stay ---');
const db = await dbConnection();
const avatars = {}
for (let row of await db.all(`
SELECT avatarSource
FROM users
WHERE avatarSource LIKE 'https://%/images/%'`
)) {
avatars[row.avatarSource.match('https://[^/]+/images/(.*)-(?:thumb|avatar).png')[1]] = true;
}
const flags = {};
for (let row of await db.all(`
SELECT customFlags
FROM profiles
WHERE customFlags != '{}'
`)) {
for (let key of Object.keys(JSON.parse(row.customFlags))) {
flags[key] = true;
}
}
const sources = {};
for (let row of await db.all(`
SELECT images
FROM sources
WHERE images is not null AND images != ''
`)) {
for (let key of row.images.split(',')) {
sources[key] = true;
}
}
const terms = {};
for (let row of await db.all(`
SELECT images
FROM terms
WHERE images is not null AND images != ''
`)) {
for (let key of row.images.split(',')) {
terms[key] = true;
}
}
const cards = {};
for (let row of await db.all(`
SELECT card
FROM profiles
WHERE card is not null AND card != ''
`)) {
cards[row.card.match('https://pronouns-page.s3.eu-west-1.amazonaws.com/card/[^/]+/.+-([^-]+)\.png')[1]] = true;
}
for (let row of await db.all(`
SELECT cardDark
FROM profiles
WHERE cardDark is not null AND cardDark != ''
`)) {
const m = row.cardDark.match('https://pronouns-page.s3.eu-west-1.amazonaws.com/card/[^/]+/.+-([^-]+)-dark\.png');
if (!m) {
console.error(row.cardDark);
continue;
}
cards[m[1]] = true;
}
console.log('Avatars: ' + Object.keys(avatars).length);
console.log('Flags: ' + Object.keys(flags).length);
console.log('Sources: ' + Object.keys(sources).length);
console.log('Terms: ' + Object.keys(terms).length);
console.log('Cards: ' + Object.keys(cards).length);
await db.close();
console.log('--- Cleaning up S3 ---');
const s3 = new S3(awsConfig);
let overall = 0;
let fresh = 0;
let removed = 0;
let removedSize = 0;
const chunkSize = 1000;
let marker = undefined;
while (true) {
console.log('Making a request');
const objects = await s3.listObjects({
Prefix: `images/`,
MaxKeys: chunkSize,
Marker: marker,
}).promise();
const toRemove = [];
const remove = async (object, reason) => {
console.log(`REMOVING: ${object.Key} (${reason})`);
toRemove.push({Key: object.Key});
removed += 1;
removedSize += object.Size;
}
for (let object of objects.Contents) {
overall++;
marker = object.Key;
if (object.LastModified > new Date() - 60*60*1000) {
fresh++;
continue;
}
const [, id, size] = object.Key.match('images/(.*)-(.*).png');
if (avatars[id]) {
if (size !== 'thumb' && size !== 'avatar') {
await remove(object, 'avatar');
}
} else if (flags[id]) {
if (size !== 'flag') {
await remove(object, 'flag');
}
} else if (sources[id]) {
if (size !== 'big' && size !== 'thumb') {
await remove(object, 'source');
}
} else if (terms[id]) {
if (size !== 'flag') {
await remove(object, 'term');
}
} else {
await remove(object, 'not used');
}
}
if (execute && toRemove.length) {
console.log('--- Removal request ---');
await s3.deleteObjects({
Delete: {
Objects: toRemove,
}
}).promise();
}
if (objects.Contents.length < chunkSize) {
break;
}
}
console.log('--- Cards ---');
marker = undefined;
while (true) {
console.log('Making a request');
const objects = await s3.listObjects({
Prefix: `card/`,
MaxKeys: chunkSize,
Marker: marker,
}).promise();
const toRemove = [];
for (let object of objects.Contents) {
overall++;
marker = object.Key;
if (object.LastModified > new Date() - 60*60*1000) {
fresh++;
continue;
}
const id = object.Key.endsWith('-dark.png')
? object.Key.match('card/[^/]+/.+-([^-]+)-dark\.png')[1]
: object.Key.match('card/[^/]+/.+-([^-]+)\.png')[1];
if (!cards[id]) {
console.log(`REMOVING: ${object.Key}`);
toRemove.push({Key: object.Key});
removed += 1;
removedSize += object.Size;
}
}
if (execute && toRemove.length) {
console.log('--- Removal request ---');
await s3.deleteObjects({
Delete: {
Objects: toRemove,
}
}).promise();
}
if (objects.Contents.length < chunkSize) {
break;
}
}
console.log('--- Summary ---');
console.log('Overall: ' + overall);
console.log('Fresh: ' + fresh);
console.log('Removed: ' + removed);
console.log(`Removed size: ${Math.round(removedSize / 1024 / 1024)} MB`);
}
cleanup();