HASH fbe63ca4ea66
DATE 2025-12-13
SUBJECT discord: support seasons
FILES 8 CHANGED
HASH fbe63ca4ea66
DATE 2025-12-13
SUBJECT discord: support seasons
FILES 8 CHANGED
┌─ nix/pkgs/ookstats/src/internal/generator/search.go ───────────────────────┐
│ diff --git a/nix/pkgs/ookstats/src/internal/generator/search.go b/nix/pkgs/ookstat │
│ s/src/internal/generator/search.go │
│ index 04dd0c1..8b931c5 100644 │
│ --- a/nix/pkgs/ookstats/src/internal/generator/search.go │
│ +++ b/nix/pkgs/ookstats/src/internal/generator/search.go │
│ @@ -36,6 +36,7 @@ func GenerateSearchIndex(db *sql.DB, out string, shardSize int) │
│ error { │
│ JOIN player_profiles pp ON p.id = pp.player_id │
│ JOIN realms r ON p.realm_id = r.id │
│ WHERE pp.has_complete_coverage = 1 │
│ + AND pp.season_id = (SELECT MAX(season_number) FROM seasons) │
│ ORDER BY pp.global_ranking ASC, p.name ASC │
│ `) │
│ if err != nil { │
│ @@ -55,6 +56,7 @@ func GenerateSearchIndex(db *sql.DB, out string, shardSize int) │
│ error { │
│ JOIN player_profiles pp ON p.id = pp.player_id │
│ JOIN realms r ON p.realm_id = r.id │
│ WHERE pp.has_complete_coverage = 1 │
│ + AND pp.season_id = (SELECT MAX(season_number) FROM seasons) │
│ `).Scan(&totalPlayers); err != nil { │
│ return err │
│ } │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ .../internal/generator/search.go ───┐
│ diff --git a/nix/pkgs/ookstats/src/internal/ │
│ generator/search.go b/nix/pkgs/ookstats/src/ │
│ internal/generator/search.go │
│ index 04dd0c1..8b931c5 100644 │
│ --- a/nix/pkgs/ookstats/src/internal/generat │
│ or/search.go │
│ +++ b/nix/pkgs/ookstats/src/internal/generat │
│ or/search.go │
│ @@ -36,6 +36,7 @@ func GenerateSearchIndex(d │
│ b *sql.DB, out string, shardSize int) error │
│ { │
│ JOIN player_profiles pp ON p.id = p │
│ p.player_id │
│ JOIN realms r ON p.realm_id = r.id │
│ WHERE pp.has_complete_coverage = 1 │
│ + AND pp.season_id = (SELECT MAX(se │
│ ason_number) FROM seasons) │
│ ORDER BY pp.global_ranking ASC, p.n │
│ ame ASC │
│ `) │
│ if err != nil { │
│ @@ -55,6 +56,7 @@ func GenerateSearchIndex(d │
│ b *sql.DB, out string, shardSize int) error │
│ { │
│ JOIN player_profiles pp ON p.id = pp. │
│ player_id │
│ JOIN realms r ON p.realm_id = r.id │
│ WHERE pp.has_complete_coverage = 1 │
│ + AND pp.season_id = (SELECT MAX(seas │
│ on_number) FROM seasons) │
│ `).Scan(&totalPlayers); err != nil { │
│ return err │
│ } │
└──────────────────────────────────────────────┘
┌─ web/api/discord.ts ───────────────────────────────────────────────────────┐
│ diff --git a/web/api/discord.ts b/web/api/discord.ts │
│ index db6037b..1fb28de 100644 │
│ --- a/web/api/discord.ts │
│ +++ b/web/api/discord.ts │
│ @@ -258,21 +258,24 @@ async function handleButton(interaction: DiscordInteraction) │
│ { │
│ │
│ // handle refresh player profile │
│ if (customId.startsWith("refresh_player:")) { │
│ - const [, region, realm, name] = customId.split(":"); │
│ + const [, region, realm, name, season] = customId.split(":"); │
│ │
│ const { handlePlayerCommand } = await import( │
│ "../src/discord/commands/player.js" │
│ ); │
│ │
│ + const options: any[] = [ │
│ + { name: "name", type: 3, value: name }, // STRING │
│ + { name: "region", type: 3, value: region }, // STRING │
│ + { name: "realm", type: 3, value: realm }, // STRING │
│ + ]; │
│ + if (season) options.push({ name: "season", type: 3, value: season }); // STRI │
│ NG │
│ + │
│ const fakeInteraction: DiscordInteraction = { │
│ ...interaction, │
│ data: { │
│ name: "player", │
│ - options: [ │
│ - { name: "name", type: 3, value: name }, // STRING │
│ - { name: "region", type: 3, value: region }, // STRING │
│ - { name: "realm", type: 3, value: realm }, // STRING │
│ - ], │
│ + options, │
│ }, │
│ }; │
│ │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ web/api/discord.ts ─────────────────┐
│ diff --git a/web/api/discord.ts b/web/api/di │
│ scord.ts │
│ index db6037b..1fb28de 100644 │
│ --- a/web/api/discord.ts │
│ +++ b/web/api/discord.ts │
│ @@ -258,21 +258,24 @@ async function handleB │
│ utton(interaction: DiscordInteraction) { │
│ │
│ // handle refresh player profile │
│ if (customId.startsWith("refresh_player:" │
│ )) { │
│ - const [, region, realm, name] = customI │
│ d.split(":"); │
│ + const [, region, realm, name, season] = │
│ customId.split(":"); │
│ │
│ const { handlePlayerCommand } = await i │
│ mport( │
│ "../src/discord/commands/player.js" │
│ ); │
│ │
│ + const options: any[] = [ │
│ + { name: "name", type: 3, value: name │
│ }, // STRING │
│ + { name: "region", type: 3, value: reg │
│ ion }, // STRING │
│ + { name: "realm", type: 3, value: real │
│ m }, // STRING │
│ + ]; │
│ + if (season) options.push({ name: "seaso │
│ n", type: 3, value: season }); // STRING │
│ + │
│ const fakeInteraction: DiscordInteracti │
│ on = { │
│ ...interaction, │
│ data: { │
│ name: "player", │
│ - options: [ │
│ - { name: "name", type: 3, value: n │
│ ame }, // STRING │
│ - { name: "region", type: 3, value: │
│ region }, // STRING │
│ - { name: "realm", type: 3, value: │
│ realm }, // STRING │
│ - ], │
│ + options, │
│ }, │
│ }; │
│ │
└──────────────────────────────────────────────┘
┌─ web/src/discord/commands/player.ts ───────────────────────────────────────┐
│ diff --git a/web/src/discord/commands/player.ts b/web/src/discord/commands/player. │
│ ts │
│ index 2bb16f3..1e3e43e 100644 │
│ --- a/web/src/discord/commands/player.ts │
│ +++ b/web/src/discord/commands/player.ts │
│ @@ -6,7 +6,7 @@ import type { │
│ PlayerCommandOptions, │
│ } from "../types.js"; │
│ import { fetchPlayerProfile } from "../../lib/api.js"; │
│ -import { API_BASE_URL } from "../constants.js"; │
│ +import { API_BASE_URL, DEFAULT_SEASON_ID } from "../constants.js"; │
│ import { │
│ createPlayerProfileEmbed, │
│ createViewProfileButton, │
│ @@ -43,6 +43,7 @@ export async function handlePlayerCommand( │
│ const name = options.name.trim(); │
│ const region = options.region.toLowerCase(); │
│ const realm = options.realm.toLowerCase(); │
│ + const season = options.season || DEFAULT_SEASON_ID; │
│ │
│ // validate region │
│ if (!["us", "eu", "kr", "tw"].includes(region)) { │
│ @@ -64,8 +65,8 @@ export async function handlePlayerCommand( │
│ } │
│ │
│ // create embed and button │
│ - const embed = createPlayerProfileEmbed(profile); │
│ - const buttons = createViewProfileButton(name, realm, region); │
│ + const embed = createPlayerProfileEmbed(profile, season); │
│ + const buttons = createViewProfileButton(name, realm, region, season); │
│ │
│ return { │
│ embeds: [embed], │
│ @@ -101,6 +102,7 @@ function parsePlayerOptions( │
│ name: getOptionValue(options, "name") as string, │
│ region: getOptionValue(options, "region") as "us" | "eu" | "kr" | "tw", │
│ realm: getOptionValue(options, "realm") as string, │
│ + season: getOptionValue(options, "season") as string | undefined, │
│ }; │
│ } │
│ │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ ...rc/discord/commands/player.ts ───┐
│ diff --git a/web/src/discord/commands/player │
│ .ts b/web/src/discord/commands/player.ts │
│ index 2bb16f3..1e3e43e 100644 │
│ --- a/web/src/discord/commands/player.ts │
│ +++ b/web/src/discord/commands/player.ts │
│ @@ -6,7 +6,7 @@ import type { │
│ PlayerCommandOptions, │
│ } from "../types.js"; │
│ import { fetchPlayerProfile } from "../../l │
│ ib/api.js"; │
│ -import { API_BASE_URL } from "../constants. │
│ js"; │
│ +import { API_BASE_URL, DEFAULT_SEASON_ID } │
│ from "../constants.js"; │
│ import { │
│ createPlayerProfileEmbed, │
│ createViewProfileButton, │
│ @@ -43,6 +43,7 @@ export async function hand │
│ lePlayerCommand( │
│ const name = options.name.trim(); │
│ const region = options.region.toLowerCase │
│ (); │
│ const realm = options.realm.toLowerCase() │
│ ; │
│ + const season = options.season || DEFAULT_ │
│ SEASON_ID; │
│ │
│ // validate region │
│ if (!["us", "eu", "kr", "tw"].includes(re │
│ gion)) { │
│ @@ -64,8 +65,8 @@ export async function hand │
│ lePlayerCommand( │
│ } │
│ │
│ // create embed and button │
│ - const embed = createPlayerProfileEmbed( │
│ profile); │
│ - const buttons = createViewProfileButton │
│ (name, realm, region); │
│ + const embed = createPlayerProfileEmbed( │
│ profile, season); │
│ + const buttons = createViewProfileButton │
│ (name, realm, region, season); │
│ │
│ return { │
│ embeds: [embed], │
│ @@ -101,6 +102,7 @@ function parsePlayerOpti │
│ ons( │
│ name: getOptionValue(options, "name") a │
│ s string, │
│ region: getOptionValue(options, "region │
│ ") as "us" | "eu" | "kr" | "tw", │
│ realm: getOptionValue(options, "realm") │
│ as string, │
│ + season: getOptionValue(options, "season │
│ ") as string | undefined, │
│ }; │
│ } │
│ │
└──────────────────────────────────────────────┘
┌─ web/src/discord/constants.ts ─────────────────────────────────────────────┐
│ diff --git a/web/src/discord/constants.ts b/web/src/discord/constants.ts │
│ index 60a9e7c..66944ad 100644 │
│ --- a/web/src/discord/constants.ts │
│ +++ b/web/src/discord/constants.ts │
│ @@ -137,4 +137,4 @@ export const CACHE = { │
│ } as const; │
│ │
│ // default season (current) │
│ -export const DEFAULT_SEASON_ID = "1"; │
│ +export const DEFAULT_SEASON_ID = "2"; │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ web/src/discord/constants.ts ───────┐
│ diff --git a/web/src/discord/constants.ts b/ │
│ web/src/discord/constants.ts │
│ index 60a9e7c..66944ad 100644 │
│ --- a/web/src/discord/constants.ts │
│ +++ b/web/src/discord/constants.ts │
│ @@ -137,4 +137,4 @@ export const CACHE = { │
│ } as const; │
│ │
│ // default season (current) │
│ -export const DEFAULT_SEASON_ID = "1"; │
│ +export const DEFAULT_SEASON_ID = "2"; │
└──────────────────────────────────────────────┘
┌─ web/src/discord/embeds/player-profile.ts ─────────────────────────────────┐
│ diff --git a/web/src/discord/embeds/player-profile.ts b/web/src/discord/embeds/pla │
│ yer-profile.ts │
│ index 0e9536e..cf426d1 100644 │
│ --- a/web/src/discord/embeds/player-profile.ts │
│ +++ b/web/src/discord/embeds/player-profile.ts │
│ @@ -23,14 +23,29 @@ const BRACKET_PERCENTILES: Record<string, string> = { │
│ }; │
│ │
│ // creates a player profile embed │
│ -export function createPlayerProfileEmbed(profile: PlayerProfileData): Embed { │
│ +export function createPlayerProfileEmbed( │
│ + profile: PlayerProfileData, │
│ + season: string = "2", │
│ +): Embed { │
│ const player = profile.player; │
│ if (!player) { │
│ throw new Error("Player data not found"); │
│ } │
│ │
│ - // get season 1 data (current season) │
│ - const seasonData = player.seasons?.["1"]; │
│ + // get specified season data, fallback to latest season if requested season doe │
│ sn't exist │
│ + let seasonData = player.seasons?.[season]; │
│ + let actualSeason = season; │
│ + │
│ + if (!seasonData && player.seasons) { │
│ + // find the highest season number available │
│ + const availableSeasons = Object.keys(player.seasons) │
│ + .map(Number) │
│ + .sort((a, b) => b - a); │
│ + if (availableSeasons.length > 0) { │
│ + actualSeason = String(availableSeasons[0]); │
│ + seasonData = player.seasons[actualSeason]; │
│ + } │
│ + } │
│ │
│ // determine ranking bracket │
│ const bracket = seasonData?.global_ranking_bracket || "common"; │
│ @@ -134,13 +149,19 @@ export function createPlayerProfileEmbed(profile: PlayerProf │
│ ileData): Embed { │
│ .replace(/\s+/g, "_") as keyof typeof CLASS_COLORS; │
│ const color = CLASS_COLORS[classKey] || 0x5865f2; // fallback to discord blurpl │
│ e │
│ │
│ + // add footer with season info │
│ + const seasonNote = │
│ + actualSeason !== season │
│ + ? ` - Showing Season ${actualSeason} (Season ${season} data not available)` │
│ + : ` - Season ${actualSeason}`; │
│ + │
│ return { │
│ title, │
│ description, │
│ fields, │
│ color, │
│ footer: { │
│ - text: "wowsimstats.com", │
│ + text: `wowsimstats.com${seasonNote}`, │
│ }, │
│ timestamp: new Date().toISOString(), │
│ }; │
│ @@ -151,8 +172,9 @@ export function createViewProfileButton( │
│ name: string, │
│ realm: string, │
│ region: string, │
│ + season: string = "2", │
│ ): MessageComponent[] { │
│ - const profileUrl = `${API_BASE_URL}/player/${region}/${realm}/${name}`; │
│ + const profileUrl = `${API_BASE_URL}/player/${region}/${realm}/${name}?season=${ │
│ season}`; │
│ const armoryUrl = `https://classic-armory.org/character/${region}/mop/${realm}/ │
│ ${name}`; │
│ │
│ return [ │
│ @@ -163,7 +185,7 @@ export function createViewProfileButton( │
│ type: ComponentType.BUTTON, │
│ style: ButtonStyle.PRIMARY, │
│ label: "? Refresh", │
│ - custom_id: `refresh_player:${region}:${realm}:${name}`, │
│ + custom_id: `refresh_player:${region}:${realm}:${name}:${season}`, │
│ }, │
│ { │
│ type: ComponentType.BUTTON, │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ ...cord/embeds/player-profile.ts ───┐
│ diff --git a/web/src/discord/embeds/player-p │
│ rofile.ts b/web/src/discord/embeds/player-pr │
│ ofile.ts │
│ index 0e9536e..cf426d1 100644 │
│ --- a/web/src/discord/embeds/player-profile. │
│ ts │
│ +++ b/web/src/discord/embeds/player-profile. │
│ ts │
│ @@ -23,14 +23,29 @@ const BRACKET_PERCENTILE │
│ S: Record<string, string> = { │
│ }; │
│ │
│ // creates a player profile embed │
│ -export function createPlayerProfileEmbed(pr │
│ ofile: PlayerProfileData): Embed { │
│ +export function createPlayerProfileEmbed( │
│ + profile: PlayerProfileData, │
│ + season: string = "2", │
│ +): Embed { │
│ const player = profile.player; │
│ if (!player) { │
│ throw new Error("Player data not found" │
│ ); │
│ } │
│ │
│ - // get season 1 data (current season) │
│ - const seasonData = player.seasons?.["1"]; │
│ + // get specified season data, fallback to │
│ latest season if requested season doesn't e │
│ xist │
│ + let seasonData = player.seasons?.[season] │
│ ; │
│ + let actualSeason = season; │
│ + │
│ + if (!seasonData && player.seasons) { │
│ + // find the highest season number avail │
│ able │
│ + const availableSeasons = Object.keys(pl │
│ ayer.seasons) │
│ + .map(Number) │
│ + .sort((a, b) => b - a); │
│ + if (availableSeasons.length > 0) { │
│ + actualSeason = String(availableSeason │
│ s[0]); │
│ + seasonData = player.seasons[actualSea │
│ son]; │
│ + } │
│ + } │
│ │
│ // determine ranking bracket │
│ const bracket = seasonData?.global_rankin │
│ g_bracket || "common"; │
│ @@ -134,13 +149,19 @@ export function create │
│ PlayerProfileEmbed(profile: PlayerProfileDat │
│ a): Embed { │
│ .replace(/\s+/g, "_") as keyof typeof C │
│ LASS_COLORS; │
│ const color = CLASS_COLORS[classKey] || 0 │
│ x5865f2; // fallback to discord blurple │
│ │
│ + // add footer with season info │
│ + const seasonNote = │
│ + actualSeason !== season │
│ + ? ` - Showing Season ${actualSeason} │
│ (Season ${season} data not available)` │
│ + : ` - Season ${actualSeason}`; │
│ + │
│ return { │
│ title, │
│ description, │
│ fields, │
│ color, │
│ footer: { │
│ - text: "wowsimstats.com", │
│ + text: `wowsimstats.com${seasonNote}`, │
│ }, │
│ timestamp: new Date().toISOString(), │
│ }; │
│ @@ -151,8 +172,9 @@ export function createVi │
│ ewProfileButton( │
│ name: string, │
│ realm: string, │
│ region: string, │
│ + season: string = "2", │
│ ): MessageComponent[] { │
│ - const profileUrl = `${API_BASE_URL}/playe │
│ r/${region}/${realm}/${name}`; │
│ + const profileUrl = `${API_BASE_URL}/playe │
│ r/${region}/${realm}/${name}?season=${season │
│ }`; │
│ const armoryUrl = `https://classic-armory │
│ .org/character/${region}/mop/${realm}/${name │
│ }`; │
│ │
│ return [ │
│ @@ -163,7 +185,7 @@ export function createVi │
│ ewProfileButton( │
│ type: ComponentType.BUTTON, │
│ style: ButtonStyle.PRIMARY, │
│ label: "? Refresh", │
│ - custom_id: `refresh_player:${regi │
│ on}:${realm}:${name}`, │
│ + custom_id: `refresh_player:${regi │
│ on}:${realm}:${name}:${season}`, │
│ }, │
│ { │
│ type: ComponentType.BUTTON, │
└──────────────────────────────────────────────┘
┌─ web/src/discord/indexes/cache.ts ─────────────────────────────────────────┐
│ diff --git a/web/src/discord/indexes/cache.ts b/web/src/discord/indexes/cache.ts │
│ index 19a12b9..4b0594d 100644 │
│ --- a/web/src/discord/indexes/cache.ts │
│ +++ b/web/src/discord/indexes/cache.ts │
│ @@ -97,7 +97,7 @@ async function loadDungeons(): Promise<CachedDungeon[]> { │
│ } │
│ │
│ try { │
│ - const url = `${API_BASE_URL}/api/leaderboard/season/1/global/index.json`; │
│ + const url = `${API_BASE_URL}/api/leaderboard/season/2/global/index.json`; │
│ const response = await fetch(url); │
│ if (!response.ok) │
│ throw new Error(`Failed to fetch dungeons: ${response.statusText}`); │
│ @@ -124,7 +124,7 @@ async function loadClasses(): Promise<CachedClass[]> { │
│ } │
│ │
│ try { │
│ - const url = `${API_BASE_URL}/api/leaderboard/season/1/players/class/index.jso │
│ n`; │
│ + const url = `${API_BASE_URL}/api/leaderboard/season/2/players/class/index.jso │
│ n`; │
│ const response = await fetch(url); │
│ if (!response.ok) │
│ throw new Error(`Failed to fetch classes: ${response.statusText}`); │
│ @@ -151,8 +151,8 @@ async function loadPlayers(): Promise<CachedPlayer[]> { │
│ } │
│ │
│ try { │
│ - // load both shards │
│ - const shards = ["000", "001"]; │
│ + // load all shards (000, 001, 002, ...) │
│ + const shards = ["000", "001", "002"]; │
│ const allPlayers: CachedPlayer[] = []; │
│ │
│ for (const shard of shards) { │
│ @@ -196,7 +196,7 @@ async function loadRealms( │
│ } │
│ │
│ try { │
│ - const url = `${API_BASE_URL}/api/leaderboard/season/1/${region}/index.json`; │
│ + const url = `${API_BASE_URL}/api/leaderboard/season/2/${region}/index.json`; │
│ const response = await fetch(url); │
│ if (!response.ok) │
│ throw new Error( │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ web/src/discord/indexes/cache.ts ───┐
│ diff --git a/web/src/discord/indexes/cache.t │
│ s b/web/src/discord/indexes/cache.ts │
│ index 19a12b9..4b0594d 100644 │
│ --- a/web/src/discord/indexes/cache.ts │
│ +++ b/web/src/discord/indexes/cache.ts │
│ @@ -97,7 +97,7 @@ async function loadDungeon │
│ s(): Promise<CachedDungeon[]> { │
│ } │
│ │
│ try { │
│ - const url = `${API_BASE_URL}/api/leader │
│ board/season/1/global/index.json`; │
│ + const url = `${API_BASE_URL}/api/leader │
│ board/season/2/global/index.json`; │
│ const response = await fetch(url); │
│ if (!response.ok) │
│ throw new Error(`Failed to fetch dung │
│ eons: ${response.statusText}`); │
│ @@ -124,7 +124,7 @@ async function loadClass │
│ es(): Promise<CachedClass[]> { │
│ } │
│ │
│ try { │
│ - const url = `${API_BASE_URL}/api/leader │
│ board/season/1/players/class/index.json`; │
│ + const url = `${API_BASE_URL}/api/leader │
│ board/season/2/players/class/index.json`; │
│ const response = await fetch(url); │
│ if (!response.ok) │
│ throw new Error(`Failed to fetch clas │
│ ses: ${response.statusText}`); │
│ @@ -151,8 +151,8 @@ async function loadPlaye │
│ rs(): Promise<CachedPlayer[]> { │
│ } │
│ │
│ try { │
│ - // load both shards │
│ - const shards = ["000", "001"]; │
│ + // load all shards (000, 001, 002, ...) │
│ + const shards = ["000", "001", "002"]; │
│ const allPlayers: CachedPlayer[] = []; │
│ │
│ for (const shard of shards) { │
│ @@ -196,7 +196,7 @@ async function loadRealm │
│ s( │
│ } │
│ │
│ try { │
│ - const url = `${API_BASE_URL}/api/leader │
│ board/season/1/${region}/index.json`; │
│ + const url = `${API_BASE_URL}/api/leader │
│ board/season/2/${region}/index.json`; │
│ const response = await fetch(url); │
│ if (!response.ok) │
│ throw new Error( │
└──────────────────────────────────────────────┘
┌─ web/src/discord/types.ts ─────────────────────────────────────────────────┐
│ diff --git a/web/src/discord/types.ts b/web/src/discord/types.ts │
│ index 4d1a214..dc19672 100644 │
│ --- a/web/src/discord/types.ts │
│ +++ b/web/src/discord/types.ts │
│ @@ -200,6 +200,7 @@ export interface PlayerCommandOptions { │
│ name: string; │
│ region: "us" | "eu" | "kr" | "tw"; │
│ realm: string; │
│ + season?: string; │
│ } │
│ │
│ export interface PaginationData { │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ web/src/discord/types.ts ───────────┐
│ diff --git a/web/src/discord/types.ts b/web/ │
│ src/discord/types.ts │
│ index 4d1a214..dc19672 100644 │
│ --- a/web/src/discord/types.ts │
│ +++ b/web/src/discord/types.ts │
│ @@ -200,6 +200,7 @@ export interface PlayerC │
│ ommandOptions { │
│ name: string; │
│ region: "us" | "eu" | "kr" | "tw"; │
│ realm: string; │
│ + season?: string; │
│ } │
│ │
│ export interface PaginationData { │
└──────────────────────────────────────────────┘
┌─ web/src/scripts/deploy-commands.ts ───────────────────────────────────────┐
│ diff --git a/web/src/scripts/deploy-commands.ts b/web/src/scripts/deploy-commands. │
│ ts │
│ index 274fdfc..24e4506 100644 │
│ --- a/web/src/scripts/deploy-commands.ts │
│ +++ b/web/src/scripts/deploy-commands.ts │
│ @@ -43,6 +43,16 @@ const commands = [ │
│ .setDescription("Realm") │
│ .setRequired(true) │
│ .setAutocomplete(true), │
│ + ) │
│ + .addStringOption((option) => │
│ + option │
│ + .setName("season") │
│ + .setDescription("Season (default: current season)") │
│ + .setRequired(false) │
│ + .addChoices( │
│ + { name: "Season 1", value: "1" }, │
│ + { name: "Season 2", value: "2" }, │
│ + ), │
│ ), │
│ │
│ // /leaderboard command │
│ @@ -102,7 +112,11 @@ const commands = [ │
│ option │
│ .setName("season") │
│ .setDescription("Season (default: current season)") │
│ - .setRequired(false), │
│ + .setRequired(false) │
│ + .addChoices( │
│ + { name: "Season 1", value: "1" }, │
│ + { name: "Season 2", value: "2" }, │
│ + ), │
│ ), │
│ ) │
│ .addSubcommand((subcommand) => │
│ @@ -160,7 +174,11 @@ const commands = [ │
│ option │
│ .setName("season") │
│ .setDescription("Season (default: current season)") │
│ - .setRequired(false), │
│ + .setRequired(false) │
│ + .addChoices( │
│ + { name: "Season 1", value: "1" }, │
│ + { name: "Season 2", value: "2" }, │
│ + ), │
│ ), │
│ ), │
│ ].map((command) => command.toJSON()); │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ ...rc/scripts/deploy-commands.ts ───┐
│ diff --git a/web/src/scripts/deploy-commands │
│ .ts b/web/src/scripts/deploy-commands.ts │
│ index 274fdfc..24e4506 100644 │
│ --- a/web/src/scripts/deploy-commands.ts │
│ +++ b/web/src/scripts/deploy-commands.ts │
│ @@ -43,6 +43,16 @@ const commands = [ │
│ .setDescription("Realm") │
│ .setRequired(true) │
│ .setAutocomplete(true), │
│ + ) │
│ + .addStringOption((option) => │
│ + option │
│ + .setName("season") │
│ + .setDescription("Season (default: c │
│ urrent season)") │
│ + .setRequired(false) │
│ + .addChoices( │
│ + { name: "Season 1", value: "1" }, │
│ + { name: "Season 2", value: "2" }, │
│ + ), │
│ ), │
│ │
│ // /leaderboard command │
│ @@ -102,7 +112,11 @@ const commands = [ │
│ option │
│ .setName("season") │
│ .setDescription("Season (defaul │
│ t: current season)") │
│ - .setRequired(false), │
│ + .setRequired(false) │
│ + .addChoices( │
│ + { name: "Season 1", value: "1 │
│ " }, │
│ + { name: "Season 2", value: "2 │
│ " }, │
│ + ), │
│ ), │
│ ) │
│ .addSubcommand((subcommand) => │
│ @@ -160,7 +174,11 @@ const commands = [ │
│ option │
│ .setName("season") │
│ .setDescription("Season (defaul │
│ t: current season)") │
│ - .setRequired(false), │
│ + .setRequired(false) │
│ + .addChoices( │
│ + { name: "Season 1", value: "1 │
│ " }, │
│ + { name: "Season 2", value: "2 │
│ " }, │
│ + ), │
│ ), │
│ ), │
│ ].map((command) => command.toJSON()); │
└──────────────────────────────────────────────┘
[ BACK TO LOG ]
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET