osu! goals: games.osu_goals (maps to pass/FC from the old list) with osu! API v2 metadata (stars NM/DT/HR/HD, BPM, length, AR/OD/CS/HP, combo, objects, tags, community tags, streams from .osu), my best scores and pass/FC via hourly in-app refresh; Goals section on /trackers/games/osu; retired list URL 301s there
All checks were successful
Deploy production / deploy (push) Successful in 1m15s

This commit is contained in:
2026-10-26 00:35:42 +00:00
parent 45841d6f6c
commit 9f8d54d9e3
14 changed files with 41357 additions and 5 deletions

View File

@@ -26,7 +26,8 @@ const RETIRED_LISTS: Record<string, string> = {
'books-to-read': '/trackers/books',
'scientific-papers': '/trackers/books?kind=papers',
'cars-trains-planes-to-spot': '/trackers/spotting',
'movies-shows-to-watch': '/trackers/movies?status=watchlist'
'movies-shows-to-watch': '/trackers/movies?status=watchlist',
'osu-maps-to-pass-fc': '/trackers/games/osu#goals'
};
async function currentList(slug: string) {

View File

@@ -5,11 +5,13 @@ import { gameLibrary, hardwareSensitivities } from '#lib/server/db/schema/index.
import { isOwner, requireOwner } from '#lib/server/owner.js';
import { setGameActive } from '#lib/server/games/active.js';
import { isAutoTracked, loadHistory } from '#lib/server/games/history.js';
import { loadOsuGoals, osuGoalActions } from '#lib/server/osu-goals/load.js';
import type { Actions, PageServerLoad } from './$types';
// One game from games.library, plus its mouse sensitivity (hardware.sensitivities, matched by
// name, short name or alias) when there is one. CS2, PUBG and R6 also get their automatic
// match history (games.matches, filled by the in-app poller).
// match history (games.matches, filled by the in-app poller), and the osu! goals
// (games.osu_goals: maps to pass or FC, with osu! API metadata and my best scores).
// Old single entries, split per title/generation: bo2 became black-ops-2, and the Pokémon
// entry (all generations) now points at the Pokémon journal that covers every game.
const MOVED: Record<string, string> = {
@@ -54,6 +56,7 @@ export const load: PageServerLoad = async (event) => {
owner: isOwner(event),
sensitivity: sensitivity ?? null,
history: isAutoTracked(game.slug) ? await loadHistory(game.slug, isOwner(event)) : null,
osuGoals: game.slug === 'osu' ? await loadOsuGoals() : null,
seo: {
title: `${game.name} · Games`,
description: `${game.name} on Stan Runge’s game tracker${game.status === 'main' ? ': my main game right now' : ''}.`
@@ -70,5 +73,6 @@ export const actions: Actions = {
if (!(await setGameActive(event.params.slug, active)))
return fail(404, { message: 'Unknown game' });
return { active };
}
},
...osuGoalActions
};

View File

@@ -11,6 +11,7 @@
import MapIcon from 'lucide-svelte/icons/map';
import TrackerIcon from '#lib/components/TrackerIcon.svelte';
import MatchHistory from '#lib/game-tracker/MatchHistory.svelte';
import OsuGoals from '#lib/game-tracker/OsuGoals.svelte';
import { gameTrackers } from '#lib/projects.js';
import type { PageProps } from './$types';
@@ -115,6 +116,10 @@
<MatchHistory history={data.history} game={game.slug as 'cs2' | 'pubg' | 'r6'} />
{/if}
{#if data.osuGoals}
<OsuGoals goals={data.osuGoals} owner={data.owner} />
{/if}
{#if game.slug === 'pubg' && data.owner}
<a
href={resolve('/trackers/games/pubg/map')}
@@ -144,7 +149,7 @@
</span>
<ArrowRight size={18} aria-hidden="true" class="ml-4 text-[var(--site-muted)]" />
</a>
{:else if !hasStats && !game.notes && !data.history}
{:else if !hasStats && !game.notes && !data.history && !data.osuGoals}
<p class="empty rounded-xl p-6 text-[var(--site-muted)]">
Nothing tracked for {game.shortName} yet. Stats, ranks and notes show up here once I add them.
</p>