deckhearth/lib/card-import/discover.js

95 lines
2.6 KiB
JavaScript
Raw Normal View History

import { sql } from '@vercel/postgres';
const EXCLUDED_MTG_SET_TYPES = new Set(['token', 'memorabilia', 'funny', 'treasure_chest']);
/**
* Pure filter: Scryfall set objects not yet present in knownCodes (lowercase set codes).
*/
export function filterMissingMtgSets(scryfallSets, knownCodes, now = new Date()) {
const missing = [];
for (const set of scryfallSets) {
if (!set?.code || set.digital) continue;
if (!set.released_at) continue;
if (new Date(set.released_at) > now) continue;
if (EXCLUDED_MTG_SET_TYPES.has(set.set_type)) continue;
const code = set.code.toLowerCase();
if (knownCodes.has(code)) continue;
missing.push({
code: set.code,
name: set.name,
releasedAt: set.released_at,
});
}
missing.sort((a, b) => b.releasedAt.localeCompare(a.releasedAt));
return missing;
}
/**
* Pure filter: Pokémon TCG set objects not yet present in knownCodes (lowercase set ids).
*/
export function filterMissingPokemonSets(pokemonSets, knownCodes) {
const missing = [];
for (const set of pokemonSets) {
if (!set?.id) continue;
const code = set.id.toLowerCase();
if (knownCodes.has(code)) continue;
missing.push({
id: set.id,
name: set.name,
releasedAt: set.releaseDate || null,
});
}
missing.sort((a, b) => {
const dateA = a.releasedAt || '';
const dateB = b.releasedAt || '';
if (!dateA && !dateB) return 0;
if (!dateA) return 1;
if (!dateB) return -1;
return dateB.localeCompare(dateA);
});
return missing;
}
export async function getKnownMtgSetCodes() {
const { rows } = await sql`
SELECT DISTINCT LOWER(set_code) AS set_code
FROM cards
WHERE game = 'MTG' AND set_code IS NOT NULL
`;
return new Set(rows.map((row) => row.set_code));
}
export async function getKnownPokemonSetCodes() {
const { rows } = await sql`
SELECT DISTINCT LOWER(set_code) AS set_code
FROM cards
WHERE game = 'Pokemon' AND set_code IS NOT NULL
`;
return new Set(rows.map((row) => row.set_code));
}
export async function discoverMissingMtgSets() {
const response = await fetch('https://api.scryfall.com/sets');
if (!response.ok) {
throw new Error(`Scryfall sets API error: ${response.status}`);
}
const data = await response.json();
const knownCodes = await getKnownMtgSetCodes();
return filterMissingMtgSets(data.data || [], knownCodes);
}
export async function discoverMissingPokemonSets() {
const { fetchPokemonSets } = await import('./pokemon-github.js');
const sets = await fetchPokemonSets();
const knownCodes = await getKnownPokemonSetCodes();
return filterMissingPokemonSets(sets, knownCodes);
}