move one-offs to subfolder; add better note about hroth/viera script

This commit is contained in:
ewin 2025-08-12 18:42:12 -04:00
parent dc1c1514a6
commit c0ae1f240f
Signed by: erin
SSH key fingerprint: SHA256:swjoHhREbZPbWe+gyJNi24d4NAxJSyUIm3fpZj4z3wc
2 changed files with 12 additions and 10 deletions

View file

@ -0,0 +1,136 @@
#!/usr/bin/env node
// Renames A-class Stellar Missions to replace A-1, A-2, A-3 difficulty
// indicators with the new empty/EX/EX+ naming used in patch 7.3.
// https://na.finalfantasyxiv.com/lodestone/topics/detail/907c6d2aa020c0e4458ed1477668521fb4a117ec#:~:text=The%20notation,adjusted%2E
import {getMediawikiClient} from '../../lib/config.js';
import {diff} from '../../lib/util/diff.js';
import {readExistingParameter, setExistingParameter} from '../../lib/util/template-parameters.js';
const mw = await getMediawikiClient();
const missions = await mw.listCategoryPages('Category:Stellar Missions', [0], 1000);
const updateMissionTitle = title => title
// "A-1: Aetherochemical Samples I" -> "Aetherochemical Samples I"
.replace(/^A-1: /, '')
// "A-2: Aetherochemical Samples II" -> "EX: Aetherochemical Samples II"
.replace(/^A-2/, 'EX')
// "A-3: Aetherochemical Samples III" -> "EX+: Aetherochemical Samples III"
.replace(/^A-3/, 'EX+');
// Move all the mission pages we need to move
console.log('Moving pages');
await Promise.allSettled(missions.map(async ({title}) => {
// Rename this mission page if necessary
let newTitle = updateMissionTitle(title);
if (title === newTitle) return; // not an A-class mission, nothing to change
try {
await mw.movePage(title, newTitle, {
reason: 'A-rank stellar mission difficulties were renamed in patch 7.3',
redirect: true,
moveTalk: true,
moveSubpages: true,
});
console.log(title, '->', newTitle);
} catch (error) {
if (error.message.includes('[articleexists]')) {
try {
await mw.movePage(title, newTitle + ' (Stellar Mission)', {
reason: 'A-rank stellar mission difficulties were renamed in patch 7.3',
redirect: true,
moveTalk: true,
moveSubpages: true,
});
} catch (err2) {
console.error('Failed to move', title, 'to', newTitle + '(Stellar Mission)', ':', err2);
}
} else {
console.error('Failed to move', title, 'to', newTitle, ':', error);
}
}
}));
console.log('Done renaming');
// Fetch the category listing again now that a bunch of titles have changed
const movedMissions = await mw.listCategoryPages('Category:Stellar Missions', [0], 1000);
// Fix `previous`/`next` infobox parameters for sequential missions and use
// `rank = A` consistently for all A-class missions
for (const {title} of movedMissions) {
let pageContent = await mw.readPage(title);
const originalPageContent = pageContent;
for (const parameter of ['previous', 'next']) {
const oldValue = readExistingParameter(pageContent, parameter);
const newValue = updateMissionTitle(oldValue);
if (oldValue === newValue) continue; // mission title didn't change
// Update the value on the page
let updatedPageContent = setExistingParameter(pageContent, parameter, newValue);
if (updatedPageContent == null) {
// something very weird has happened, this shouldn't be able to fail
// if we already got the value of the parameter earlier
console.error('weird shit happened with', title);
continue;
}
pageContent = updatedPageContent;
}
if (readExistingParameter(pageContent, 'rank').match(/A-[123]/)) {
pageContent = setExistingParameter(pageContent, 'rank', 'A');
}
console.log('Diff for', title);
diff(originalPageContent, pageContent);
try {
if (originalPageContent === pageContent) {
console.log('No changes');
} else {
await mw.editPage(title, pageContent, 'Update links to mission(s) renamed in 7.3');
console.log('Written.');
}
} catch (error) {
console.error('Error writing page:', error);
console.error('writes should not fail, this seems bad, dying now');
process.exit(1);
}
};
// Also update mission names for all CE item recipes
const items = await mw.listCategoryPages('Category:Cosmic Exploration Items', [0], 10000);
for (const {title} of items) {
let pageContent = await mw.readPage(title);
const originalPageContent = pageContent;
const infoboxes = pageContent.split('{{Recipe');
infoboxes.forEach((infobox, i) => {
if (i === 0) return; // ignore stuff before first recipe infobox
// console.log(infobox);
const mission = readExistingParameter(infobox, 'mission');
const updatedMission = updateMissionTitle(mission);
infoboxes[i] = setExistingParameter(infobox, 'mission', updatedMission);
});
pageContent = infoboxes.join('{{Recipe');
console.log('Diff for', title);
diff(originalPageContent, pageContent);
try {
if (originalPageContent === pageContent) {
console.log('No changes');
} else {
await mw.editPage(title, pageContent, 'Update links to mission(s) renamed in 7.3');
console.log('Written.');
}
} catch (error) {
console.error('Error writing page:', error);
console.error('writes should not fail, this seems bad, dying now');
process.exit(1);
}
}
console.log('Done with content updates');

View file

@ -0,0 +1,71 @@
#!/usr/bin/env node
// Adds infobox parameters for Viera and Hrothgar hat compatibility based on
// data compiled by Crye. Expects there to be a `hats.csv` file in the repo root
// which is an export of the "HEAD" sheet of this Google Sheets document:
// https://docs.google.com/spreadsheets/d/13s_qxWThsensslulLfAxN0-hzQZVCqS9fKaImlLXbVU/edit?gid=38787585#gid=38787585
import {readFileSync} from 'node:fs';
import {join} from 'node:path';
import {getMediawikiClient} from '../../lib/config.js';
import {diff} from '../../lib/util/diff.js';
import {addParameterAtBottom, setExistingParameter} from '../../lib/util/template-parameters.js';
const mw = await getMediawikiClient();
// parse CSV, naively assume there are no quotes or backslashes (because i checked)
const data = readFileSync(join(import.meta.dirname, '../../hats.csv'), 'utf-8').split(/\r?\n/g).map(line => line && line.split(','));
console.log(data.slice(0, 1));
const headers = data.splice(0, 1)[0];
const COL_ITEM = headers.findIndex(field => field.toLowerCase() === 'item');
const COL_VIERA = headers.findIndex(field => field.toLowerCase().includes('viera'));
const COL_HROTH = headers.findIndex(field => field.toLowerCase().includes('hrothgar'));
console.log('Processing', data.length, 'items');
for (const line of data) {
const item = line[COL_ITEM];
const params = {
'display-on-viera': line[COL_VIERA].toLowerCase() === 'yes' ? 'y' : 'n',
'display-on-hrothgar': line[COL_HROTH].toLowerCase() === 'yes' ? 'y' : 'n',
}
console.log(item, params);
// read and apply updates
const pageContent = await mw.readPage(item);
let newPageContent = pageContent;
try {
for (const [paramName, paramValue] of Object.entries(params)) {
newPageContent = setExistingParameter(newPageContent, paramName, paramValue)
?? addParameterAtBottom(newPageContent, paramName, paramValue);
if (!newPageContent) {
console.log(pageContent);
throw new Error('adding parameter to the page failed');
}
}
} catch (error) {
console.error(error);
console.log('skipping this item');
continue;
}
if (newPageContent === pageContent) {
// no changes
console.log('No changes, skipping');
continue;
}
diff(pageContent, newPageContent);
// write
try {
await mw.editPage(item, newPageContent, 'Add Hrothgar/Viera headwear data');
} catch (error) {
console.error('Failed to write:', error);
process.exit(1);
}
console.log('Written.');
}
console.log('done!');