spotters: logo coverage script (Wikidata logo/icon, multi-language infobox, website icon fallback), cheaper planes operator queries, refresh adds logos for new orgs
All checks were successful
Deploy production / deploy (push) Successful in 1m9s
All checks were successful
Deploy production / deploy (push) Successful in 1m9s
This commit is contained in:
@@ -306,28 +306,54 @@ async function planes() {
|
||||
for (let depth = 0; id && depth < 6; depth++, id = parent.get(id) ?? null)
|
||||
for (const [cc, n] of m) add(scores, id, cc, n);
|
||||
}
|
||||
// Wikidata operators (P137) and their countries.
|
||||
// Wikidata operators (P137) and their countries, as two cheap queries (the joined
|
||||
// version times out on the public endpoint).
|
||||
const byQid = new Map(types.map((t) => [t.wikidata, t.id]));
|
||||
let ops = 0;
|
||||
let failed = 0;
|
||||
const opsOf = new Map<string, Set<string>>();
|
||||
const fail = (e: unknown) => {
|
||||
failed++;
|
||||
log(`planes: operator chunk failed (${String(e).slice(0, 80)})`);
|
||||
return [];
|
||||
};
|
||||
for (const c of chunks(
|
||||
[...byQid.keys()].filter((q): q is string => !!q),
|
||||
100
|
||||
200
|
||||
)) {
|
||||
// A failing chunk (query timeout) only loses its operator bonus; registrations stay.
|
||||
const res = await sparql<{ item: string; iso: string; n: string }>(`
|
||||
SELECT ?item ?iso (COUNT(DISTINCT ?op) AS ?n) WHERE {
|
||||
VALUES ?item { ${c.map((q) => `wd:${q}`).join(' ')} }
|
||||
?item wdt:P137 ?op . ?op wdt:P17 ?country . ?country wdt:P297 ?iso .
|
||||
} GROUP BY ?item ?iso`).catch((e: unknown) => {
|
||||
failed++;
|
||||
log(`planes: operator chunk failed (${String(e).slice(0, 80)})`);
|
||||
return [];
|
||||
});
|
||||
const res = await sparql<{ item: string; op: string }>(`
|
||||
SELECT ?item ?op WHERE { VALUES ?item { ${c.map((q) => `wd:${q}`).join(' ')} } ?item wdt:P137 ?op . }`).catch(
|
||||
fail
|
||||
);
|
||||
for (const r of res) {
|
||||
const id = byQid.get(r.item.split('/').at(-1)!);
|
||||
if (!id) continue;
|
||||
add(scores, id, r.iso.toLowerCase(), 25 * Math.min(Number(r.n) || 1, 6));
|
||||
const item = r.item.split('/').at(-1)!;
|
||||
const set = opsOf.get(item) ?? new Set<string>();
|
||||
set.add(r.op.split('/').at(-1)!);
|
||||
opsOf.set(item, set);
|
||||
}
|
||||
}
|
||||
const isoOf = new Map<string, Set<string>>();
|
||||
for (const c of chunks([...new Set([...opsOf.values()].flatMap((s) => [...s]))], 300)) {
|
||||
const res = await sparql<{ op: string; iso: string }>(`
|
||||
SELECT ?op ?iso WHERE { VALUES ?op { ${c.map((q) => `wd:${q}`).join(' ')} } ?op wdt:P17 ?country . ?country wdt:P297 ?iso . }`).catch(
|
||||
fail
|
||||
);
|
||||
for (const r of res) {
|
||||
const op = r.op.split('/').at(-1)!;
|
||||
const set = isoOf.get(op) ?? new Set<string>();
|
||||
set.add(r.iso.toLowerCase());
|
||||
isoOf.set(op, set);
|
||||
}
|
||||
}
|
||||
for (const [item, opSet] of opsOf) {
|
||||
const id = byQid.get(item);
|
||||
if (!id) continue;
|
||||
const perCountry = new Map<string, number>();
|
||||
for (const op of opSet)
|
||||
for (const cc of isoOf.get(op) ?? []) perCountry.set(cc, (perCountry.get(cc) ?? 0) + 1);
|
||||
for (const [cc, n] of perCountry) {
|
||||
add(scores, id, cc, 25 * Math.min(n, 6));
|
||||
ops++;
|
||||
}
|
||||
}
|
||||
@@ -355,7 +381,7 @@ async function wildlife() {
|
||||
us: 'United States',
|
||||
gb: 'United Kingdom',
|
||||
cz: 'Czech Republic',
|
||||
tr: 'Turkey',
|
||||
tr: 'Türkiye',
|
||||
kr: 'South Korea'
|
||||
}[cc] ?? dn.of(cc.toUpperCase())!;
|
||||
const found = await inat<{
|
||||
|
||||
Reference in New Issue
Block a user