Skip to content

Instantly share code, notes, and snippets.

@hzoo
Created February 14, 2026 17:47
Show Gist options
  • Select an option

  • Save hzoo/af29e0b4b20c2345c68475a8340a0b56 to your computer and use it in GitHub Desktop.

Select an option

Save hzoo/af29e0b4b20c2345c68475a8340a0b56 to your computer and use it in GitHub Desktop.
Archived agent-sounds preset fetch scripts (SC2, Nintendo, OG packs) from commit 9d7ebd9
#!/usr/bin/env bun
import { existsSync } from "node:fs";
import { copyFile, mkdir, unlink, writeFile } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const BASE = "https://downloads.khinsider.com";
const UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36";
const DELAY_MS = 1000;
const ALBUMS: Record<string, [string, number]> = {
switch: ["nintendo-switch-sound-effects", 5],
gamecube: ["nintendo-gamecube-system-soundtrack-gc-gamerip-2001", 10],
gba: ["gameboy-advance-system-music", 5],
ds: ["nintendo-ds-system-music", 15],
wii: ["wii-system-soundtrack", 15],
};
const SKIP_TRACKS = new Set(["ds::Signal Search"]);
const HOOK_MAP: Record<string, string[]> = {
"switch::Turn On": ["session-start"],
"switch::Klick": ["prompt-submit"],
"switch::Select": ["prompt-submit"],
"switch::This One": ["prompt-submit"],
"switch::Tick": ["prompt-submit"],
"switch::Turn Off": ["session-end"],
"switch::Standby": ["stop"],
"switch::Loading": ["pre-compact"],
"switch::Eshop Intro": ["subagent-start"],
"switch::Dada 0": ["subagent-start"],
"switch::Dada 1": ["subagent-start"],
"switch::Dada 2": ["subagent-start"],
"switch::Dada 3": ["subagent-start"],
"switch::Bing": ["task-completed"],
"switch::Dodo": ["subagent-stop"],
"switch::Jig 0": ["task-completed"],
"switch::Jig 1": ["task-completed"],
"switch::Error": ["tool-failure"],
"switch::News": ["notification"],
"switch::Home": ["notification"],
"switch::Album": ["notification"],
"switch::Icons": ["notification"],
"switch::Nock": ["permission-request"],
"switch::Enter & Back": ["permission-request"],
"switch::Popup + Run Title": ["permission-request"],
"switch::Controller": ["subagent-stop"],
"switch::Settings": ["pre-compact"],
"switch::User": ["notification"],
"switch::Border": ["stop"],
"switch::Eshop": ["subagent-stop"],
"gamecube::Startup Sound (Standard)": ["session-start"],
"gamecube::Startup Sound (Whimsical)": ["task-completed"],
"gamecube::Startup Sound (Kabuki)": ["notification"],
"gba::Game Boy Advance BIOS": ["session-start", "task-completed"],
"gba::Game Boy BIOS": ["notification", "subagent-stop"],
"gba::Gameboy Advance Link Cable": ["subagent-start"],
"ds::Start up": ["session-start"],
"ds::Start Up on your birthday": ["task-completed"],
"ds::PictoChat Enter": ["subagent-start"],
"ds::PictoChat Birthday Enter": ["notification"],
"ds::Alarm": ["tool-failure"],
"wii::Wii Menu Startup": ["session-start"],
"wii::No Disc Inserted Banner": ["tool-failure"],
"wii::Mii Channel Banner": ["notification"],
"wii::Virtual Console Banner": ["task-completed"],
"wii::SD Card Software Banner": ["pre-compact"],
"wii::GameCube Disc Banner": ["subagent-stop"],
"wii::Wii System v1.0 Channel Banner": ["subagent-start"],
"wii::Wii Fit Channel Banner": ["permission-request"],
"wii::Wii Fit Body Check Channel Banner": ["permission-request"],
"wii::Mario Kart Channel Banner": ["subagent-start"],
"wii::Wii + Internet Channel Banner": ["subagent-start"],
"wii::Skyward Sword Save Data Update Channel Banner": ["notification"],
"wii::Wii U Transfer Tool Channel Banner": ["notification"],
"wii::Wii U Transfer Tool - Transfer Completed": ["task-completed"],
};
const CURATED: Record<string, [string, string]> = {
"session-start": ["gamecube", "Startup Sound (Standard)"],
"prompt-submit": ["switch", "Klick"],
stop: ["switch", "Turn Off"],
"pre-compact": ["switch", "Loading"],
"subagent-start": ["switch", "Eshop Intro"],
"subagent-stop": ["gba", "Game Boy Advance BIOS"],
"tool-failure": ["switch", "Error"],
notification: ["switch", "News"],
"task-completed": ["switch", "Bing"],
"permission-request": ["switch", "Nock"],
"session-end": ["wii", "Wii Menu Startup"],
};
type Track = { name: string; url: string; duration: number };
function escapeRegExp(text: string): string {
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
function decodeHtmlEntities(text: string): string {
const named: Record<string, string> = {
amp: "&",
lt: "<",
gt: ">",
quot: "\"",
apos: "'",
nbsp: " ",
};
return text.replace(/&(#x?[0-9a-fA-F]+|[a-zA-Z]+);/g, (match, token: string) => {
if (token.startsWith("#x") || token.startsWith("#X")) {
const code = Number.parseInt(token.slice(2), 16);
return Number.isFinite(code) ? String.fromCodePoint(code) : match;
}
if (token.startsWith("#")) {
const code = Number.parseInt(token.slice(1), 10);
return Number.isFinite(code) ? String.fromCodePoint(code) : match;
}
return named[token] ?? match;
});
}
function usage(exitCode = 0): never {
console.log("Usage: bun run tools/fetch-nintendo-sounds.ts [--dry-run] [--console switch|gamecube|gba|ds|wii|all]");
process.exit(exitCode);
}
function key(consoleName: string, trackName: string) {
return `${consoleName}::${trackName}`;
}
function parseArgs(argv: string[]) {
const consoles = Object.keys(ALBUMS);
let dryRun = false;
let consoleName: string | "all" = "all";
for (let i = 0; i < argv.length; i += 1) {
const arg = argv[i];
if (arg === "--help" || arg === "-h") usage(0);
if (arg === "--dry-run") {
dryRun = true;
continue;
}
if (arg === "--console") {
const value = argv[i + 1];
if (!value) usage(1);
if (value === "all" || consoles.includes(value)) {
consoleName = value;
i += 1;
continue;
}
console.error(`unknown console: ${value}`);
usage(1);
}
console.error(`unknown arg: ${arg}`);
usage(1);
}
return { dryRun, consoles: consoleName === "all" ? consoles : [consoleName] };
}
function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function fetchText(url: string): Promise<string> {
const resp = await fetch(url, { headers: { "User-Agent": UA } });
if (!resp.ok) throw new Error(`HTTP ${resp.status} ${resp.statusText}`);
return await resp.text();
}
async function downloadBinary(url: string, dest: string) {
const resp = await fetch(url, { headers: { "User-Agent": UA, Referer: BASE } });
if (!resp.ok) throw new Error(`HTTP ${resp.status} ${resp.statusText}`);
const bytes = new Uint8Array(await resp.arrayBuffer());
await writeFile(dest, bytes);
return bytes.byteLength;
}
function parseAlbum(html: string, slug: string): Track[] {
const tracks: Track[] = [];
const seen = new Set<string>();
const linkRe = new RegExp(`<a\\s+href="(/game-soundtracks/album/${escapeRegExp(slug)}/[^"]+)"[^>]*>\\s*([^<]+?)\\s*</a>`);
const durationRe = /(\d+):(\d{2})/;
const rows = html.match(/<tr[^>]*>(.*?)<\/tr>/gs) ?? [];
for (const row of rows) {
const linkMatch = row.match(linkRe);
if (!linkMatch) continue;
const urlPath = linkMatch[1];
const name = decodeHtmlEntities(linkMatch[2].trim());
if (["MP3", "FLAC", "OGG"].includes(name.toUpperCase())) continue;
if (seen.has(name)) continue;
seen.add(name);
const d = row.match(durationRe);
const duration = d ? Number(d[1]) * 60 + Number(d[2]) : 999;
tracks.push({ name, url: `${BASE}${urlPath}`, duration });
}
return tracks;
}
function parseDownloadUrl(html: string): string | null {
const audio = html.match(/<audio[^>]*>\s*<source\s+src="([^"]+)"/);
if (audio?.[1]) return audio[1];
for (const pattern of [
/href="(https?:\/\/[^"\s]*(?:vgmsite|vgmtreasurechest)[^"\s]*\.mp3[^"\s]*)"/,
/href="(https?:\/\/[^"\s]*\.mp3)"/,
]) {
const match = html.match(pattern);
if (match?.[1]) return match[1];
}
return null;
}
function safeFilename(name: string): string {
return `${name.replace(/[^\w\s-]/g, "").trim().replace(/\s+/g, "-").toLowerCase()}.mp3`;
}
async function main() {
const { dryRun, consoles } = parseArgs(process.argv.slice(2));
if (dryRun) console.log(" --dry-run: no files will be written");
const downloaded: Record<string, Record<string, string>> = {};
for (const consoleName of consoles) {
const [slug, maxDuration] = ALBUMS[consoleName];
const presetDir = path.join(ROOT, "presets", `nintendo-${consoleName}`);
if (!dryRun) await mkdir(presetDir, { recursive: true });
console.log(`\n [${consoleName.toUpperCase()}]`);
console.log(` album: ${slug}`);
let html: string;
try {
html = await fetchText(`${BASE}/game-soundtracks/album/${slug}`);
} catch (error) {
console.log(` FAILED to fetch album page: ${String(error)}`);
continue;
}
const tracks = parseAlbum(html, slug);
console.log(` ${tracks.length} tracks found`);
const kept: Track[] = [];
for (const track of tracks) {
if (SKIP_TRACKS.has(key(consoleName, track.name))) {
console.log(` skip: ${track.name} (excluded)`);
continue;
}
if (track.duration > maxDuration) {
console.log(` skip: ${track.name} (${track.duration}s > ${maxDuration}s)`);
continue;
}
kept.push(track);
console.log(` keep: ${track.name} (${track.duration}s)`);
}
if (dryRun) {
console.log(" --dry-run, preview only");
downloaded[consoleName] = downloaded[consoleName] ?? {};
for (const track of kept) {
downloaded[consoleName][track.name] = safeFilename(track.name);
}
continue;
}
let failed = 0;
for (const track of kept) {
const filename = safeFilename(track.name);
const dest = path.join(presetDir, filename);
downloaded[consoleName] = downloaded[consoleName] ?? {};
if (existsSync(dest)) {
console.log(` exists: ${filename}`);
downloaded[consoleName][track.name] = filename;
continue;
}
process.stdout.write(` ${track.name}... `);
await sleep(DELAY_MS);
try {
const trackHtml = await fetchText(track.url);
const dlUrl = parseDownloadUrl(trackHtml);
if (!dlUrl) {
console.log("FAILED (no download URL in page)");
failed += 1;
continue;
}
await sleep(DELAY_MS);
const size = await downloadBinary(dlUrl, dest);
downloaded[consoleName][track.name] = filename;
console.log(`OK (${Math.floor(size / 1024)}KB)`);
} catch (error) {
console.log(`FAILED: ${String(error)}`);
failed += 1;
if (existsSync(dest)) await unlink(dest);
}
}
if (failed > 0) {
console.log(` ${failed} downloads failed`);
}
const preset: { name: string; sounds: Record<string, Array<{ file: string; unit: string; quote: string }>> } = {
name: `Nintendo ${consoleName.toUpperCase()}`,
sounds: {},
};
for (const [trackName, filename] of Object.entries(downloaded[consoleName] ?? {})) {
const hooks = HOOK_MAP[key(consoleName, trackName)] ?? [];
for (const hook of hooks) {
(preset.sounds[hook] ||= []).push({
file: filename,
unit: consoleName,
quote: trackName,
});
}
}
const manifest = path.join(presetDir, "preset.json");
await writeFile(manifest, `${JSON.stringify(preset, null, 2)}\n`, "utf8");
console.log(` wrote ${manifest}`);
}
if (dryRun) {
console.log("\n [CURATED PREVIEW]");
for (const [hook, [consoleName, trackName]] of Object.entries(CURATED)) {
const filename = downloaded[consoleName]?.[trackName];
if (!filename) {
console.log(` missing: ${consoleName}/${trackName} -> ${hook}`);
} else {
console.log(` ${hook}: ${consoleName}/${trackName} (${filename})`);
}
}
return;
}
console.log("\n [CURATED]");
const curatedDir = path.join(ROOT, "presets", "nintendo");
await mkdir(curatedDir, { recursive: true });
const preset: { name: string; sounds: Record<string, Array<{ file: string; unit: string; quote: string }>> } = {
name: "Nintendo",
sounds: {},
};
for (const [hook, [consoleName, trackName]] of Object.entries(CURATED)) {
const filename = downloaded[consoleName]?.[trackName];
if (!filename) {
console.log(` missing: ${consoleName}/${trackName}${hook}`);
continue;
}
const src = path.join(ROOT, "presets", `nintendo-${consoleName}`, filename);
const dstName = `${consoleName}-${filename}`;
const dst = path.join(curatedDir, dstName);
if (existsSync(src) && !existsSync(dst)) {
await copyFile(src, dst);
}
preset.sounds[hook] = [{
file: dstName,
unit: consoleName,
quote: trackName,
}];
console.log(` ${hook}: ${consoleName}/${trackName}`);
}
const manifest = path.join(curatedDir, "preset.json");
await writeFile(manifest, `${JSON.stringify(preset, null, 2)}\n`, "utf8");
console.log(` wrote ${manifest}`);
console.log("\n activate with: agent-sounds use nintendo");
}
main().catch((error) => {
console.error(error);
process.exit(1);
});
#!/usr/bin/env bun
import { existsSync } from "node:fs";
import { mkdir, unlink, writeFile } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const RAW = "https://raw.githubusercontent.com/PeonPing/og-packs/main";
const PACKS = ["glados", "ocarina_of_time"] as const;
const CATEGORY_MAP: Record<string, string[]> = {
"session.start": ["session-start"],
"task.acknowledge": ["prompt-submit"],
"task.complete": ["stop", "task-completed"],
"task.error": ["tool-failure"],
"input.required": ["permission-request"],
"resource.limit": ["pre-compact"],
};
type Pack = (typeof PACKS)[number];
type OpenPeonSound = {
file: string;
label?: string;
};
type OpenPeonCategory = {
sounds?: OpenPeonSound[];
};
type OpenPeonManifest = {
display_name?: string;
categories?: Record<string, OpenPeonCategory>;
};
function usage(exitCode = 0): never {
console.log("Usage: bun run tools/fetch-og-packs.ts [--dry-run] [--pack glados|ocarina_of_time|all]");
process.exit(exitCode);
}
function parseArgs(argv: string[]) {
let dryRun = false;
let pack: Pack | "all" = "all";
for (let i = 0; i < argv.length; i += 1) {
const arg = argv[i];
if (arg === "--help" || arg === "-h") usage(0);
if (arg === "--dry-run") {
dryRun = true;
continue;
}
if (arg === "--pack") {
const value = argv[i + 1];
if (!value) usage(1);
if (value === "all" || PACKS.includes(value as Pack)) {
pack = value as Pack | "all";
i += 1;
continue;
}
console.error(`unknown pack: ${value}`);
usage(1);
}
console.error(`unknown arg: ${arg}`);
usage(1);
}
return { dryRun, packs: pack === "all" ? [...PACKS] : [pack] };
}
async function fetchJson<T>(url: string): Promise<T> {
const resp = await fetch(url);
if (!resp.ok) throw new Error(`HTTP ${resp.status} ${resp.statusText}`);
return (await resp.json()) as T;
}
async function download(url: string, dest: string): Promise<number> {
const resp = await fetch(url);
if (!resp.ok) throw new Error(`HTTP ${resp.status} ${resp.statusText}`);
const bytes = new Uint8Array(await resp.arrayBuffer());
await writeFile(dest, bytes);
return bytes.byteLength;
}
async function main() {
const { dryRun, packs } = parseArgs(process.argv.slice(2));
if (dryRun) {
console.log(" --dry-run: no files will be written");
}
for (const pack of packs) {
console.log(`\n [${pack}]`);
const manifestUrl = `${RAW}/${pack}/openpeon.json`;
const meta = await fetchJson<OpenPeonManifest>(manifestUrl);
const display = meta.display_name ?? pack;
console.log(` ${display}`);
const presetDir = path.join(ROOT, "presets", pack, "sounds");
if (!dryRun) {
await mkdir(presetDir, { recursive: true });
}
const preset: { name: string; sounds: Record<string, Array<{ file: string; unit: string; quote: string }>> } = {
name: display,
sounds: {},
};
for (const [category, categoryData] of Object.entries(meta.categories ?? {})) {
const events = CATEGORY_MAP[category];
if (!events) {
console.log(` skip category: ${category}`);
continue;
}
for (const sound of categoryData.sounds ?? []) {
const srcFile = sound.file;
const filename = srcFile.split("/").pop() ?? srcFile;
const label = sound.label ?? filename;
const dest = path.join(presetDir, filename);
if (!existsSync(dest) && !dryRun) {
const dlUrl = `${RAW}/${pack}/${srcFile}`;
process.stdout.write(` ${filename}... `);
try {
const size = await download(dlUrl, dest);
console.log(`OK (${Math.floor(size / 1024)}KB)`);
} catch (error) {
console.log(`FAILED: ${String(error)}`);
if (existsSync(dest)) {
await unlink(dest);
}
continue;
}
} else {
console.log(` ${dryRun ? "[dry] " : ""}${filename}`);
}
for (const event of events) {
(preset.sounds[event] ||= []).push({
file: `sounds/${filename}`,
unit: pack,
quote: label,
});
}
}
}
if (dryRun) {
const total = Object.values(preset.sounds).reduce((acc, entries) => acc + entries.length, 0);
console.log(` would map ${total} sounds into ${Object.keys(preset.sounds).length} events`);
continue;
}
const manifestPath = path.join(ROOT, "presets", pack, "preset.json");
await writeFile(manifestPath, `${JSON.stringify(preset, null, 2)}\n`, "utf8");
console.log(` wrote ${manifestPath}`);
}
console.log(`\n activate with: agent-sounds use ${packs[0]}`);
}
main().catch((error) => {
console.error(error);
process.exit(1);
});
#!/usr/bin/env bun
import { existsSync } from "node:fs";
import { mkdir, unlink, writeFile } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const PRESET_DIR = path.join(ROOT, "presets", "starcraft2-full");
const UNITS: Record<string, string[]> = {
protoss: [
"Adept", "Archon", "Carrier", "Colossus", "DarkTemplar",
"Disruptor", "HighTemplar", "Immortal", "Mothership",
"Observer", "Oracle", "Phoenix", "Probe", "Sentry",
"Stalker", "Tempest", "VoidRay", "WarpPrism", "Zealot",
"Arbiter", "Dragoon",
],
terran: [
"SCV", "Marine", "Marauder", "Reaper", "Hellion",
"SiegeTank", "Cyclone", "WidowMine", "Thor", "Viking",
"Medivac", "Banshee", "Raven", "Battlecruiser", "Ghost",
],
zerg: [
"Drone", "Baneling", "Hydralisk", "Mutalisk", "Corruptor",
"BroodLord", "Infestor", "Lurker",
],
};
const ACTION_HOOKS: Record<string, string[]> = {
Ready: ["session-start", "subagent-start", "task-completed"],
What: ["notification", "permission-request"],
Yes: ["prompt-submit", "subagent-stop"],
Attack: ["stop"],
Help: ["tool-failure", "pre-compact"],
Death: ["session-end"],
};
const API = "https://starcraft.fandom.com/api.php";
type WikiImage = { name: string; url: string };
type AllImagesResponse = {
query: { allimages: WikiImage[] };
continue?: { aicontinue?: string };
};
type SoundEntry = {
unit: string;
race: string;
wiki_name: string;
url: string;
};
function usage(exitCode = 0): never {
console.log("Usage: bun run tools/fetch-sc2-sounds.ts [--dry-run] [--race protoss|terran|zerg|all]");
process.exit(exitCode);
}
function parseArgs(argv: string[]) {
const races = Object.keys(UNITS);
let dryRun = false;
let race: string | "all" = "all";
for (let i = 0; i < argv.length; i += 1) {
const arg = argv[i];
if (arg === "--help" || arg === "-h") usage(0);
if (arg === "--dry-run") {
dryRun = true;
continue;
}
if (arg === "--race") {
const value = argv[i + 1];
if (!value) usage(1);
if (value === "all" || races.includes(value)) {
race = value;
i += 1;
continue;
}
console.error(`unknown race: ${value}`);
usage(1);
}
console.error(`unknown arg: ${arg}`);
usage(1);
}
return { dryRun, races: race === "all" ? races : [race] };
}
async function fetchJson<T>(url: string): Promise<T> {
const resp = await fetch(url, { headers: { "User-Agent": "Mozilla/5.0" } });
if (!resp.ok) throw new Error(`HTTP ${resp.status} ${resp.statusText}`);
return (await resp.json()) as T;
}
async function apiListOgg(unit: string): Promise<WikiImage[]> {
const files: WikiImage[] = [];
const params = new URLSearchParams({
action: "query",
list: "allimages",
aiprefix: `${unit}_`,
ailimit: "500",
format: "json",
});
while (true) {
const url = `${API}?${params.toString()}`;
const data = await fetchJson<AllImagesResponse>(url);
for (const img of data.query.allimages) {
if (img.name.endsWith(".ogg")) files.push(img);
}
const next = data.continue?.aicontinue;
if (!next) break;
params.set("aicontinue", next);
}
return files;
}
function parseAction(filename: string): string | null {
const stem = filename.replace(/\.[^.]+$/, "");
const parts = stem.split("_", 2);
if (parts.length < 2) return null;
const action = parts[1].replace(/[0-9]+$/, "");
return ACTION_HOOKS[action] ? action : null;
}
async function download(url: string, dest: string) {
const resp = await fetch(url, { headers: { "User-Agent": "Mozilla/5.0" } });
if (!resp.ok) throw new Error(`HTTP ${resp.status} ${resp.statusText}`);
const bytes = new Uint8Array(await resp.arrayBuffer());
await writeFile(dest, bytes);
}
async function main() {
const { dryRun, races } = parseArgs(process.argv.slice(2));
if (!dryRun) {
await mkdir(PRESET_DIR, { recursive: true });
}
const byAction: Record<string, SoundEntry[]> = {};
let total = 0;
for (const race of races) {
console.log(`\n [${race.toUpperCase()}]`);
for (const unit of UNITS[race]) {
process.stdout.write(` ${unit}... `);
const files = await apiListOgg(unit);
const oggs = files
.map((file) => ({ file, action: parseAction(file.name) }))
.filter((entry): entry is { file: WikiImage; action: string } => Boolean(entry.action));
console.log(`${oggs.length} sounds`);
for (const { file, action } of oggs) {
(byAction[action] ||= []).push({
unit,
race,
wiki_name: file.name,
url: file.url,
});
total += 1;
}
}
}
console.log(`\n total: ${total} sounds across ${Object.keys(byAction).length} actions`);
for (const action of Object.keys(byAction).sort()) {
const sounds = byAction[action] ?? [];
const hooks = ACTION_HOOKS[action] ?? [];
const counts: Record<string, number> = {};
for (const sound of sounds) {
counts[sound.race] = (counts[sound.race] ?? 0) + 1;
}
const breakdown = Object.keys(counts)
.sort()
.map((race) => `${race}:${counts[race]}`)
.join(", ");
console.log(` ${action}: ${sounds.length} (${breakdown}) → ${hooks.join(", ")}`);
}
if (dryRun) {
console.log("\n --dry-run, stopping here");
return;
}
console.log(`\n downloading to ${PRESET_DIR}...`);
let failed = 0;
for (const sounds of Object.values(byAction)) {
for (const entry of sounds) {
const dest = path.join(PRESET_DIR, entry.wiki_name);
if (existsSync(dest)) continue;
console.log(` ${entry.wiki_name}`);
try {
await download(entry.url, dest);
} catch (error) {
console.log(` FAILED: ${String(error)}`);
failed += 1;
if (existsSync(dest)) await unlink(dest);
}
}
}
const preset: {
name: string;
sounds: Record<string, Array<{ file: string; unit: string; race: string; quote: string }>>;
} = {
name: "StarCraft 2 (Full)",
sounds: {},
};
for (const [action, hooks] of Object.entries(ACTION_HOOKS)) {
const sounds = byAction[action] ?? [];
for (const hook of hooks) {
const entries = sounds
.filter((sound) => existsSync(path.join(PRESET_DIR, sound.wiki_name)))
.map((sound) => ({
file: sound.wiki_name,
unit: sound.unit,
race: sound.race,
quote: `${sound.unit} ${action}`,
}));
if (entries.length > 0) {
preset.sounds[hook] = entries;
}
}
}
const manifest = path.join(PRESET_DIR, "preset.json");
await writeFile(manifest, `${JSON.stringify(preset, null, 2)}\n`, "utf8");
console.log(`\n wrote ${manifest}`);
if (failed > 0) console.log(` ${failed} downloads failed`);
console.log(" activate with: agent-sounds use starcraft2-full");
}
main().catch((error) => {
console.error(error);
process.exit(1);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment