Skip to content

Commit fe5fad7

Browse files
fix: strip custom PGN result token before backend store
1 parent b698822 commit fe5fad7

1 file changed

Lines changed: 93 additions & 3 deletions

File tree

src/pages/analysis/[...id].tsx

Lines changed: 93 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
MaiaEvaluation,
2121
StockfishEvaluation,
2222
GameNode,
23+
Termination,
2324
} from 'src/types'
2425
import { WindowSizeContext, TreeControllerContext, useTour } from 'src/contexts'
2526
import { Loading } from 'src/components'
@@ -57,13 +58,91 @@ import { MAIA_MODELS } from 'src/constants/common'
5758
import { applyEngineAnalysisData } from 'src/lib/analysis'
5859

5960
const EVAL_BAR_RANGE = 4
61+
const CUSTOM_PGN_RESULT_OVERRIDES_STORAGE_KEY =
62+
'maia_custom_pgn_result_overrides'
63+
const PGN_RESULT_TOKEN_REGEX = /(.*?)(?:\s+)(1-0|0-1|1\/2-1\/2|\*)\s*$/
6064
const DEFAULT_STOCKFISH_EVAL_BAR = {
6165
hasEval: false,
6266
pawns: 0,
6367
displayPawns: 0,
6468
label: '--',
6569
}
6670

71+
const splitTrailingPgnResult = (
72+
pgn: string,
73+
): { pgnWithoutResult: string; result?: string } => {
74+
const match = pgn.match(PGN_RESULT_TOKEN_REGEX)
75+
if (!match) {
76+
return { pgnWithoutResult: pgn }
77+
}
78+
79+
return {
80+
pgnWithoutResult: match[1].trim(),
81+
result: match[2],
82+
}
83+
}
84+
85+
const getCustomPgnResultOverrides = (): Record<string, string> => {
86+
if (typeof window === 'undefined') return {}
87+
88+
try {
89+
const raw = window.localStorage.getItem(
90+
CUSTOM_PGN_RESULT_OVERRIDES_STORAGE_KEY,
91+
)
92+
if (!raw) return {}
93+
const parsed = JSON.parse(raw)
94+
return parsed && typeof parsed === 'object' ? parsed : {}
95+
} catch (error) {
96+
console.warn('Failed to read custom PGN result overrides:', error)
97+
return {}
98+
}
99+
}
100+
101+
const setCustomPgnResultOverride = (gameId: string, result: string): void => {
102+
if (typeof window === 'undefined') return
103+
104+
try {
105+
const overrides = getCustomPgnResultOverrides()
106+
overrides[gameId] = result
107+
window.localStorage.setItem(
108+
CUSTOM_PGN_RESULT_OVERRIDES_STORAGE_KEY,
109+
JSON.stringify(overrides),
110+
)
111+
} catch (error) {
112+
console.warn('Failed to store custom PGN result override:', error)
113+
}
114+
}
115+
116+
const getCustomPgnResultOverride = (gameId: string): string | undefined => {
117+
const override = getCustomPgnResultOverrides()[gameId]
118+
return typeof override === 'string' ? override : undefined
119+
}
120+
121+
const resultTokenToWinner = (
122+
result: string,
123+
): Termination['winner'] | undefined => {
124+
if (result === '1-0') return 'white'
125+
if (result === '0-1') return 'black'
126+
if (result === '1/2-1/2') return 'none'
127+
return undefined
128+
}
129+
130+
const applyCustomResultOverride = (
131+
game: AnalyzedGame,
132+
result?: string,
133+
): AnalyzedGame => {
134+
if (!result || result === '*') return game
135+
136+
return {
137+
...game,
138+
termination: {
139+
...(game.termination || {}),
140+
result,
141+
winner: resultTokenToWinner(result),
142+
},
143+
}
144+
}
145+
67146
const AnalysisPage: NextPage = () => {
68147
const { startTour, tourState } = useTour()
69148

@@ -162,12 +241,16 @@ const AnalysisPage: NextPage = () => {
162241
updateUrl = true,
163242
) => {
164243
const game = await fetchAnalyzedMaiaGame(id, type)
244+
const gameWithOverrides =
245+
type === 'custom'
246+
? applyCustomResultOverride(game, getCustomPgnResultOverride(id))
247+
: game
165248

166249
if (setCurrentMove) setCurrentMove(0)
167250

168-
setAnalyzedGame({ ...game, type })
251+
setAnalyzedGame({ ...gameWithOverrides, type })
169252
setCurrentId([id, type])
170-
await loadGameAnalysisCache({ ...game, type })
253+
await loadGameAnalysisCache({ ...gameWithOverrides, type })
171254

172255
if (updateUrl) {
173256
router.push(`/analysis/${id}/${type}`, undefined, {
@@ -348,12 +431,19 @@ const Analysis: React.FC<Props> = ({
348431
(type: 'fen' | 'pgn', data: string, name?: string) => {
349432
;(async () => {
350433
try {
434+
const pgnPayload =
435+
type === 'pgn' ? splitTrailingPgnResult(data) : undefined
351436
const { game_id } = await storeCustomGame({
352437
name: name,
353-
pgn: type === 'pgn' ? data : undefined,
438+
pgn:
439+
type === 'pgn' ? pgnPayload?.pgnWithoutResult || data : undefined,
354440
fen: type === 'fen' ? data : undefined,
355441
})
356442

443+
if (pgnPayload?.result && pgnPayload.result !== '*') {
444+
setCustomPgnResultOverride(game_id, pgnPayload.result)
445+
}
446+
357447
setShowCustomModal(false)
358448
router.push(`/analysis/${game_id}/custom`)
359449
} catch (error) {

0 commit comments

Comments
 (0)