Files
deepl-christina/cleanup-glossaries.js
christinatrs 92f44a2916 first commit
2026-07-31 11:25:43 +02:00

104 lines
3.7 KiB
JavaScript

/**
* One-off maintenance script: lists every glossary that currently exists on
* your DeepL account and compares it against the glossaries this app
* actually tracks in domains.json. Run this on the machine where server.js
* runs (it needs the same DEEPL_API_KEY and network access to DeepL).
*
* Why you might need this: DeepL accounts have a cap on total glossary
* count. If you ever hit a "Too many glossaries" (456) error when saving
* terms, it means glossaries exist on your DeepL account that this app
* isn't tracking anymore (e.g. left over from earlier testing/debugging, or
* from a save that got interrupted). This script finds and removes those
* orphans so you have room to save again.
*
* Usage:
* node cleanup-glossaries.js # dry run - lists orphans only
* node cleanup-glossaries.js --delete # actually deletes the orphans
*/
const fs = require('fs');
const path = require('path');
function loadEnv() {
const envPath = path.join(__dirname, '.env');
if (!fs.existsSync(envPath)) return;
for (const line of fs.readFileSync(envPath, 'utf8').split('\n')) {
const m = line.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*)\s*$/i);
if (m && !process.env[m[1]]) process.env[m[1]] = m[2].replace(/^["']|["']$/g, '');
}
}
loadEnv();
const DEEPL_API_KEY = process.env.DEEPL_API_KEY;
if (!DEEPL_API_KEY) {
console.error('DEEPL_API_KEY not found (checked .env and environment).');
process.exit(1);
}
const base = DEEPL_API_KEY.endsWith(':fx') ? 'https://api-free.deepl.com' : 'https://api.deepl.com';
function loadDomainsJson() {
const p = path.join(__dirname, 'domains.json');
if (!fs.existsSync(p)) return {};
try {
return JSON.parse(fs.readFileSync(p, 'utf8'));
} catch {
return {};
}
}
async function main() {
const domains = loadDomainsJson();
const trackedIds = new Set();
for (const d of Object.values(domains)) {
if (!d || !d.glossaries) continue;
for (const g of Object.values(d.glossaries)) {
if (g && g.id) trackedIds.add(g.id);
}
}
const resp = await fetch(`${base}/v2/glossaries`, {
headers: { Authorization: `DeepL-Auth-Key ${DEEPL_API_KEY}` },
});
if (!resp.ok) {
console.error(`Failed to list glossaries: ${resp.status} ${await resp.text()}`);
process.exit(1);
}
const { glossaries } = await resp.json();
console.log(`Found ${glossaries.length} glossary/glossaries on the DeepL account. This app tracks ${trackedIds.size} of them in domains.json.\n`);
const orphans = glossaries.filter((g) => !trackedIds.has(g.glossary_id));
if (orphans.length === 0) {
console.log('No orphaned glossaries found. Nothing to clean up.');
console.log('(If you are still getting "Too many glossaries", the account limit may just need to be raised with DeepL, or every glossary on the account is legitimately in use.)');
return;
}
console.log(`Orphaned glossaries (exist on DeepL, not referenced by domains.json):\n`);
for (const g of orphans) {
console.log(` - ${g.glossary_id} "${g.name}" ${g.source_lang}->${g.target_lang} (${g.entry_count} entries, created ${g.creation_time})`);
}
const shouldDelete = process.argv.includes('--delete');
if (!shouldDelete) {
console.log(`\nDry run only - nothing was deleted. Re-run with --delete to remove the ${orphans.length} orphan(s) above.`);
return;
}
console.log('\nDeleting orphans...');
for (const g of orphans) {
const delResp = await fetch(`${base}/v2/glossaries/${g.glossary_id}`, {
method: 'DELETE',
headers: { Authorization: `DeepL-Auth-Key ${DEEPL_API_KEY}` },
});
console.log(` - ${g.glossary_id}: ${delResp.ok ? 'deleted' : `failed (${delResp.status})`}`);
}
console.log('Done.');
}
main().catch((e) => {
console.error(e);
process.exit(1);
});