11/* eslint-disable @typescript-eslint/no-explicit-any */
22import { Chess } from 'chess.ts'
3- import { AnalyzedGame , Player , StockfishEvaluation } from 'src/types'
43import { GameTree } from 'src/types/base/tree'
54import { AvailableMoves } from 'src/types/training'
5+ import {
6+ LiveGame ,
7+ Player ,
8+ StockfishEvaluation ,
9+ StreamedGame ,
10+ StreamedMove ,
11+ } from 'src/types'
612
7- // Re-use the readStream utility from analysis.ts
813const readStream = ( processLine : ( data : any ) => void ) => ( response : any ) => {
914 const stream = response . body . getReader ( )
1015 const matcher = / \r ? \n /
@@ -32,15 +37,14 @@ const readStream = (processLine: (data: any) => void) => (response: any) => {
3237 return loop ( )
3338}
3439
35- // Get current Lichess TV game information
3640export const getLichessTVGame = async ( ) => {
3741 const res = await fetch ( 'https://lichess.org/api/tv/channels' )
3842 if ( ! res . ok ) {
3943 throw new Error ( 'Failed to fetch Lichess TV data' )
4044 }
4145 const data = await res . json ( )
4246
43- // Return the best game (highest rated players)
47+ // Return the best rapid game (highest rated players)
4448 const bestChannel = data . rapid
4549 if ( ! bestChannel ?. gameId ) {
4650 throw new Error ( 'No TV game available' )
@@ -53,7 +57,6 @@ export const getLichessTVGame = async () => {
5357 }
5458}
5559
56- // Get basic game information from Lichess API
5760export const getLichessGameInfo = async ( gameId : string ) => {
5861 const res = await fetch ( `https://lichess.org/api/game/${ gameId } ` )
5962 if ( ! res . ok ) {
@@ -62,11 +65,10 @@ export const getLichessGameInfo = async (gameId: string) => {
6265 return res . json ( )
6366}
6467
65- // Stream live moves from a Lichess game
6668export const streamLichessGame = async (
6769 gameId : string ,
68- onGameStart : ( data : any ) => void ,
69- onMove : ( data : any ) => void ,
70+ onGameStart : ( data : StreamedGame ) => void ,
71+ onMove : ( data : StreamedMove ) => void ,
7072 onComplete : ( ) => void ,
7173 abortSignal ?: AbortSignal ,
7274) => {
@@ -79,55 +81,18 @@ export const streamLichessGame = async (
7981 } ,
8082 } )
8183
82- let gameStarted = false
83-
8484 const onMessage = ( message : any ) => {
85- console . log ( 'Raw message received:' , message )
86-
8785 if ( message . id ) {
88- // This is the initial game state with full game info
8986 console . log ( 'Game start message:' , message )
90- onGameStart ( message )
91- gameStarted = true
87+ onGameStart ( message as StreamedGame )
9288 } else if ( message . uci || message . lm ) {
93- // This is a move - handle both formats: {"fen":"...", "uci":"e2e4"} or {"fen":"...", "lm":"e2e4"}
94- // If we haven't received the initial game state yet, trigger game start with a minimal state
95- if ( ! gameStarted ) {
96- console . log (
97- 'First move received without initial game state, creating minimal game' ,
98- )
99- onGameStart ( {
100- id : gameId , // Use the gameId we're streaming
101- players : {
102- white : { user : { name : 'White' } } ,
103- black : { user : { name : 'Black' } } ,
104- } ,
105- fen : message . fen ,
106- } )
107- gameStarted = true
108- }
109-
89+ console . log ( 'Move message:' , message )
11090 onMove ( {
11191 fen : message . fen ,
11292 uci : message . uci || message . lm ,
11393 wc : message . wc ,
11494 bc : message . bc ,
11595 } )
116- } else if ( message . fen && ! message . uci && ! message . lm ) {
117- // This is the initial position - could be the first message for a starting game
118- console . log ( 'Initial position received:' , message )
119- if ( ! gameStarted ) {
120- console . log ( 'Initial position message, creating game' )
121- onGameStart ( {
122- id : gameId ,
123- players : {
124- white : { user : { name : 'White' } } ,
125- black : { user : { name : 'Black' } } ,
126- } ,
127- fen : message . fen ,
128- } )
129- gameStarted = true
130- }
13196 } else {
13297 console . log ( 'Unknown message format:' , message )
13398 }
@@ -155,27 +120,25 @@ export const streamLichessGame = async (
155120 }
156121}
157122
158- // Convert Lichess game data to our AnalyzedGame format for live streaming
159123export const createAnalyzedGameFromLichessStream = (
160124 gameData : any ,
161- ) : AnalyzedGame => {
125+ ) : LiveGame => {
162126 const { players, id } = gameData
163127
164128 const whitePlayer : Player = {
165- name : players ?. white ?. user ?. name || 'White' ,
129+ name : players ?. white ?. user ?. id || 'White' ,
166130 rating : players ?. white ?. rating ,
167131 }
168132
169133 const blackPlayer : Player = {
170- name : players ?. black ?. user ?. name || 'Black' ,
134+ name : players ?. black ?. user ?. id || 'Black' ,
171135 rating : players ?. black ?. rating ,
172136 }
173137
174- // Use the starting position as our tree root - we'll build moves incrementally
175- const startingFen = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'
138+ const startingFen =
139+ gameData . initialFen ||
140+ 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'
176141
177- // Build moves array with just the initial position for now
178- // Moves will be added as they come in via the stream
179142 const gameStates = [
180143 {
181144 board : startingFen ,
@@ -186,35 +149,28 @@ export const createAnalyzedGameFromLichessStream = (
186149 } ,
187150 ]
188151
189- // Create game tree starting from the beginning
190152 const tree = new GameTree ( startingFen )
191153
192154 return {
193155 id : `stream-${ id } ` ,
194156 blackPlayer,
195157 whitePlayer,
158+ gameType : 'stream' ,
159+ type : 'stream' as const ,
196160 moves : gameStates ,
197161 availableMoves : new Array ( gameStates . length ) . fill ( { } ) as AvailableMoves [ ] ,
198- gameType : 'blitz' , // Default to blitz, could be detected from game data
199- termination : {
200- result : '*' , // Live game in progress
201- winner : undefined ,
202- condition : 'Live' ,
203- } ,
204- maiaEvaluations : new Array ( gameStates . length ) . fill ( { } ) ,
205- stockfishEvaluations : new Array ( gameStates . length ) . fill ( undefined ) as (
206- | StockfishEvaluation
207- | undefined
208- ) [ ] ,
162+ termination : undefined ,
163+ maiaEvaluations : [ ] ,
164+ stockfishEvaluations : [ ] ,
165+ loadedFen : gameData . fen ,
166+ loaded : false ,
209167 tree,
210- type : 'stream' as const , // Use stream type for live streams
211- } as AnalyzedGame
168+ } as LiveGame
212169}
213170
214- // Parse a move from the Lichess stream format and update game state
215171export const parseLichessStreamMove = (
216- moveData : any ,
217- currentGame : AnalyzedGame ,
172+ moveData : StreamedMove ,
173+ currentGame : LiveGame ,
218174) => {
219175 const { uci, fen } = moveData
220176
0 commit comments