planes: stricter photo matching, skip company articles, payload-not-pax
All checks were successful
Deploy production / deploy (push) Successful in 1m8s

This commit is contained in:
2026-10-24 20:26:13 +00:00
parent 6696bc7162
commit eccae362ec

View File

@@ -70,7 +70,7 @@ type Photo = {
// ---------------------------------------------------------------- commons
const BAD_FILE =
/\.(svg|gif|tiff?|pdf|djvu|webm|ogv|stl)$|logo|emblem|badge|insignia|roundel|patch\b|wordmark|map\b|karte|locator|diagram|chart|graph|schema|schematic|drawing|sketch|blueprint|patent|3[- ]?view|three[- ]view|icon|flag|coat of arms|wappen|signature|symbol|cutaway|silhouette|commons-|wiki|stub|poster|advert|brochure|stamp|timeline|cockpit|flight deck|instrument|panel|cabin|interior|seats?\b|galley|lavatory|engine\b|nacelle|propeller\b|landing gear|undercarriage|wheel|tyre|tire\b|crash|wreck|accident|debris|incident|fire\b|burnt|scrap|graveyard|boneyard|\btoys?\b|scale model|model aircraft|lego|diecast|plastic model|kit\b|simulator|mock-?up|ticket|menu|uniform|crew\b|pilot\b|portrait|ceremony|memorial|grave|plaque|statue|stamp/i;
/\.(svg|gif|tiff?|pdf|djvu|webm|ogv|stl)$|logo|emblem|badge|insignia|roundel|patch\b|wordmark|map\b|karte|locator|diagram|chart|graph|schema|schematic|drawing|sketch|blueprint|patent|3[- ]?view|three[- ]view|icon|flag|coat of arms|wappen|signature|symbol|cutaway|silhouette|commons-|wiki|stub|poster|advert|brochure|stamp|timeline|cockpit|flight deck|instrument|panel|cabin|interior|seats?\b|galley|lavatory|engine\b|nacelle|propeller\b|landing gear|undercarriage|wheel|tyre|\btire\b|crash|wreck|accident|debris|incident|\bfire\b|burnt|scrap|graveyard|boneyard|\btoys?\b|scale model|model aircraft|lego|diecast|plastic model|kit\b|simulator|mock-?up|ticket|menu|uniform|crew\b|pilot\b|portrait|ceremony|memorial|grave|plaque|statue|stamp|\bvs\b|versus|deliveries|render|cgi\b|\btug\b|tow cart|comparison|3 ?-?seiten|zeichnung|fahrwerk|atterrissage|tail ?gear|tail ?bumper|wn.trze|innenraum|first class|business class|radar\b/i;
const infoCache = new Map<string, ImageInfo | null>();
async function imageInfo(files: string[], width = THUMB) {
@@ -210,7 +210,12 @@ const GENERIC = new Set(
);
const esc = (s: string) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
type Rule = { test: (f: string) => boolean; designators: string[]; required: string[] };
type Rule = {
test: (f: string) => boolean;
loose: (f: string) => boolean;
designators: string[];
required: string[];
};
/** Name-based tests for one type: designators like AH64 / A320 / 737 (with maker) and rare words. */
function ruleFor(t: Target, wordUse: Map<string, number>): Rule {
const makerWords = tokens(t.maker).filter((w) => w.length >= 3 && !GENERIC.has(w));
@@ -238,9 +243,12 @@ function ruleFor(t: Target, wordUse: Map<string, number>): Rule {
else if (makerWords.length)
tests.push(new RegExp(`(?=.* (?:${makerWords.map(esc).join('|')}) ).* ${esc(w)} `));
}
// Inside the type's own article or category, a telling name word alone is enough ("Spitfire").
const looseRe = words.length ? new RegExp(words.map((w) => ` ${esc(w)} `).join('|')) : null;
return {
designators,
required,
loose: (f) => !!looseRe && looseRe.test(norm(f)),
test: (f) => {
const F = norm(f);
return (
@@ -306,7 +314,11 @@ async function photosFor(targets: Target[], all: Target[]) {
o.required.some((r) => !rule.required.includes(r)) ||
o.designators.some((d) => !rule.designators.includes(d))
);
const ok = (f: string) => !BAD_FILE.test(f) && rule.test(f) && !siblings.some((s) => s.test(f));
const ok = (f: string) =>
!BAD_FILE.test(f) &&
!/\.png$/i.test(f) &&
(rule.test(f) || rule.loose(f)) &&
!siblings.some((s) => s.test(f));
const own = wd.own.get(t.wikidata);
const picks: { file: string; kind: Photo['kind']; caption: string | null }[] = [];
if (own?.image && !/\.(svg|gif)$/i.test(own.image))