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

@@ -0,0 +1,102 @@
CREATE TABLE "games"."osu_goals" (
"id" serial PRIMARY KEY,
"name" text NOT NULL,
"goal" text,
"mods" text[] DEFAULT '{}'::text[] NOT NULL,
"notes" text,
"sort_order" integer DEFAULT 0 NOT NULL,
"list_item_id" integer,
"match_status" text DEFAULT 'unmatched' NOT NULL,
"match_note" text,
"candidates" jsonb DEFAULT '[]' NOT NULL,
"beatmapset_id" integer,
"beatmap_id" integer,
"mode" text,
"artist" text,
"title" text,
"artist_unicode" text,
"title_unicode" text,
"mapper" text,
"mapper_id" integer,
"version" text,
"diff_mapper_id" integer,
"status" text,
"ranked_at" timestamp with time zone,
"submitted_at" timestamp with time zone,
"source" text,
"genre" text,
"language" text,
"tags" text[] DEFAULT '{}'::text[] NOT NULL,
"user_tags" text[] DEFAULT '{}'::text[] NOT NULL,
"bpm" double precision,
"bpm_min" double precision,
"bpm_max" double precision,
"length_seconds" integer,
"drain_seconds" integer,
"ar" double precision,
"od" double precision,
"cs" double precision,
"hp" double precision,
"max_combo" integer,
"circles" integer,
"sliders" integer,
"spinners" integer,
"stars" double precision,
"stars_dt" double precision,
"stars_hr" double precision,
"stars_hd" double precision,
"stars_hddt" double precision,
"stars_hdhr" double precision,
"attributes" jsonb,
"longest_stream" integer,
"stream_notes" integer,
"play_count" integer,
"pass_count" integer,
"favourite_count" integer,
"map_play_count" integer,
"cover_url" text,
"card_url" text,
"list_url" text,
"preview_url" text,
"focus" text[] DEFAULT '{}'::text[] NOT NULL,
"metadata_at" timestamp with time zone,
"my_play_count" integer,
"best_score_id" bigint,
"best_score" bigint,
"best_accuracy" double precision,
"best_mods" text[] DEFAULT '{}'::text[] NOT NULL,
"best_rank" text,
"best_pp" double precision,
"best_combo" integer,
"best_misses" integer,
"best_fc" boolean,
"best_at" timestamp with time zone,
"passed" boolean DEFAULT false NOT NULL,
"fc" boolean DEFAULT false NOT NULL,
"achieved_at" timestamp with time zone,
"scores" jsonb DEFAULT '[]' NOT NULL,
"scores_at" timestamp with time zone,
"last_error" text,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "osu_goals_goal_check" CHECK ("goal" IS NULL OR "goal" IN ('pass','fc')),
CONSTRAINT "osu_goals_match_check" CHECK ("match_status" IN ('matched','ambiguous','unmatched') AND ("match_status" <> 'matched' OR "beatmap_id" IS NOT NULL)),
CONSTRAINT "osu_goals_name_check" CHECK (length(btrim("name")) > 0)
);
--> statement-breakpoint
CREATE INDEX "osu_goals_beatmap_idx" ON "games"."osu_goals" ("beatmap_id");--> statement-breakpoint
-- Hand-written: grants (same pattern as the other app tables) and the updated_at trigger.
-- Rows come from the retired list lists.osu_maps (imported once, then refreshed by the app).
DO $$
BEGIN
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'personal_app') THEN
GRANT SELECT, INSERT, UPDATE, DELETE ON games.osu_goals TO personal_app;
GRANT USAGE, SELECT ON SEQUENCE games.osu_goals_id_seq TO personal_app;
END IF;
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'personal_ro') THEN
GRANT SELECT ON games.osu_goals TO personal_ro;
END IF;
IF to_regprocedure('meta.touch_updated_at()') IS NOT NULL THEN
CREATE TRIGGER touch_updated_at BEFORE UPDATE ON games.osu_goals FOR EACH ROW EXECUTE FUNCTION meta.touch_updated_at();
END IF;
END $$;

File diff suppressed because it is too large Load Diff