slowlydev / f1-dash

A real-time F1 dashboard
https://f1-dash.com
GNU General Public License v3.0
510 stars 51 forks source link

[Feature] Replay race from archive #37

Open slowlydev opened 10 months ago

slowlydev commented 10 months ago

Add a future where a user can click on a session from the archive and get a replay of the timing of that session. Media controls for the replay would also be great. With that I mean following things:

Here is some useful links: f1 livetiming api, all categories and their replay data

devtronaut commented 4 months ago

Hello there :)

Nice project, first of all! Very cool to see the exceptional effort going into this <3

As far as I can tell from the docker-compose file in the project root, you're already using timescale on top of postgres. So the infra for the feature appears to be there already.

Could you elaborate quickly on how the states (previously odctrl.rs / rdctrl.rs as per the live-backend readme) are handled / updated now? Feel free to point me to the correct file, if I just wasn't looking for it in the right place ;)

slowlydev commented 4 months ago

Hello there :)

Hi 👋🏻

Nice project, first of all! Very cool to see the exceptional effort going into this <3

Thank you I appreciate it 🙏🏻

Could you elaborate quickly on how the states (previously odctrl.rs / rdctrl.rs as per the live-backend readme) are handled / updated now? Feel free to point me to the correct file, if I just wasn't looking for it in the right place ;)

Ah yes, good reminder for me to update the readme again as I decided to use Axum now and do some things differently than before.

The current version of the backend is simpler and has less moving components now. rdctrl is now mostly in the client and server::live. They communicate via a broadcast::channel in main which gets passed to the server where we spin up Axum. Also Live updates are now using SSE instead of WebSockets.

Because of the transition to SSE and Axum interaction with old data (odctrl) is now over regular GET HTTP requests of which the routes can be found in server and the logic of the endpoints in the respective sub modules of server

I have already implemented an endpoint to get the snapshots of the state through time it can be found here server::recap I am unsure if this is the correct approach, as I feel like maybe we can leverage timescale more than the current implementation.

As the keeper which is running on separate thread is just storing the full state every second.

This specific issue would require more new code and maybe could even be done by the frontend alone.

devtronaut commented 4 months ago

Thanks for the detailed explanation. :)

Yeah, I think the update frequency should be higher than once every second, in order for the whole thing to feel "fluent". What's the update frequency on the live data?

I guess that's what you mean by "leverage timescale more"?

slowlydev commented 3 months ago

You're welcome!

Hm okay, yeah maybe less than one second would be better and make it more fluent when using the timeline during a session. Im not sure if there is a "update frequency" or at least I haven't looked for it, but I know that car data and positional data updates more frequent and in batches. The other updates sometimes also get batched, but that does not have to be.

By levering timescale I mean use its features more other than just using the retention policy I guess . Currently I just write into it and read history with queries, I think these history queries for graphs of gap, and lap time could be improved on.

Also I am not really planning to use the timescale database for this specific issue, as f1 gives us the data already after a race/session in a few hours. The link I added in the issue includes all the paths for the files for all the "categories" of data, like timingData, raceControlMessages and more.

https://livetiming.formula1.com/static/2023/2023-11-05_São_Paulo_Grand_Prix/2023-11-05_Race/Index.json

For example here's the jsonStream for all race control messages https://livetiming.formula1.com/static/2023/2023-11-05_São_Paulo_Grand_Prix/2023-11-05_Race/RaceControlMessages.jsonStream

I think this approach might be better because we could maybe do it without big backend involvement and keeping all that data ourselves just does not make a lot of sense if they keep it as well In a well structured and accessible manner.

SpatzlHD commented 3 months ago

You are right is you can pretty much access all the data from the client is there any need for the involvment of the backend server or could we run into issues by the requests beeing blocked when coming from the client?

SpatzlHD commented 3 months ago

Also it should be possible to reuse the components you already built right? I could throw together a proof of concept but my design skills are really shit so that part I am not capable of achieving anything near what you have done. So let me know what you think if you don't want me to do that or someone else is already working on it please let me know I don't have to do this

slowlydev commented 3 months ago

Hey there @SpatzlHD, I think client should be possible im not sure if maybe CORS could be an issue but we just would need to try, else we proxy through one of the backends. Maybe the api one (api-backend folder) as its more "static json data" and we could either store or cache it and do fancy analytics (post race, not live) with it.

Components and most of the dashboard could and should be reused. There's also already some components for replay, like play pause or a "playback progress timeline thingy". The "only" thing that needs to be adjusted is instead of a web socket with partial updates use the jsonStreams.

I could come up with an UI later to select the races and so on. (for the browsing maybe some endpoints at api-backend would be good)

I am currently not working on past race/session replays, maybe @devtronaut is but I am not sure if he's working on this issue or on a feature where you could replay a running race with the database. (no GitHub issue for that yet)

From my side feel free to do a POC If you want to. And if it works well we can go from there :)

devtronaut commented 3 months ago

Not working on anything for f1-dash atm. @SpatzlHD feel free to take it :)

SpatzlHD commented 3 months ago

I would love to work on this! I am a bit busy the next days but I am going to start with this on the weekend! I am going to try this on the client first without the backend but maybe we need to proxy it like you already said but I would have to test that.

SpatzlHD commented 3 months ago

Also because you are using nextjs could we not just use something like a server action to fetch the data without getting blocked by cors? I never tried that but shouldn't that work without having to proxy the request through the backend api?

slowlydev commented 3 months ago

Also because you are using nextjs could we not just use something like a server action to fetch the data without getting blocked by cors?

Yes we are using next.js, I also have not yet worked with server actions. But it might work yes. The only concern I have is that server actions would eat up Vercel usage (already at the limits or over), as f1-dash frontend is still hosted there. But I am looking into options of moving out of Vercel.

SpatzlHD commented 3 months ago

first thing i noticed: we need to proxy the request as we are getting blocked by cors second thing: can someone help me figure out what exactly the time present before the json data is representing i cant figure out what excactly is specified there 🤔 My guess would be it is the time elapsed since the start of the broadcast or something and to get the time in the race i would need to calculate the difference to the timestap at which the SessionStatus is updated to started. But please correct me if i am wrong or you have another idea

PitLaneTimeCollection.jsonStream:

01:08:41.453{"PitTimes":{"20":{"RacingNumber":"20","Duration":"30.4","Lap":"7"}}}
01:09:10.702{"PitTimes":{"_deleted":["20"]}}
01:16:42.724{"PitTimes":{"27":{"RacingNumber":"27","Duration":"24.2","Lap":"12"}}}
01:17:10.650{"PitTimes":{"_deleted":["27"]}}
01:34:53.280{"PitTimes":{"24":{"RacingNumber":"24","Duration":"25.5","Lap":"24"}}}
01:35:01.219{"PitTimes":{"1":{"RacingNumber":"1","Duration":"24.3","Lap":"25"}}}
01:35:01.574{"PitTimes":{"63":{"RacingNumber":"63","Duration":"24.0","Lap":"25"}}}
01:35:02.592{"PitTimes":{"81":{"RacingNumber":"81","Duration":"23.9","Lap":"25"}}}
01:35:22.349{"PitTimes":{"44":{"RacingNumber":"44","Duration":"23.7","Lap":"25"}}}
01:35:23.621{"PitTimes":{"14":{"RacingNumber":"14","Duration":"25.7","Lap":"25"}}}
01:35:27.271{"PitTimes":{"_deleted":["24"]}}
01:35:32.675{"PitTimes":{"_deleted":["1"]}}
01:35:35.841{"PitTimes":{"_deleted":["63"]}}
01:35:37.088{"PitTimes":{"_deleted":["81"]}}
01:35:56.442{"PitTimes":{"18":{"RacingNumber":"18","Duration":"24.2","Lap":"25"}}}
01:35:59.819{"PitTimes":{"_deleted":["44"]}}
01:36:02.433{"PitTimes":{"_deleted":["14"]}}
01:36:04.383{"PitTimes":{"23":{"RacingNumber":"23","Duration":"24.7","Lap":"25"}}}
01:36:07.548{"PitTimes":{"16":{"RacingNumber":"16","Duration":"24.0","Lap":"25"}}}
01:36:14.473{"PitTimes":{"55":{"RacingNumber":"55","Duration":"27.6","Lap":"25"}}}
01:36:15.341{"PitTimes":{"20":{"RacingNumber":"20","Duration":"26.7","Lap":"25"}}}
01:36:16.297{"PitTimes":{"10":{"RacingNumber":"10","Duration":"24.9","Lap":"25"}}}
01:36:28.034{"PitTimes":{"11":{"RacingNumber":"11","Duration":"33.7","Lap":"25"}}}
01:36:30.492{"PitTimes":{"_deleted":["18"]}}
01:36:31.177{"PitTimes":{"27":{"RacingNumber":"27","Duration":"24.6","Lap":"25"}}}
01:36:39.181{"PitTimes":{"_deleted":["23"]}}
01:36:40.885{"PitTimes":{"_deleted":["16"]}}
01:36:46.899{"PitTimes":{"_deleted":["55"]}}
01:36:48.793{"PitTimes":{"_deleted":["20"]}}
01:36:49.711{"PitTimes":{"_deleted":["10"]}}
01:36:52.693{"PitTimes":{"4":{"RacingNumber":"4","Duration":"23.4","Lap":"26"}}}
01:36:56.734{"PitTimes":{"_deleted":["11"]}}
01:37:04.818{"PitTimes":{"_deleted":["27"]}}
01:37:29.300{"PitTimes":{"_deleted":["4"]}}
01:37:52.335{"PitTimes":{"3":{"RacingNumber":"3","Duration":"30.2","Lap":"26"}}}
01:38:23.602{"PitTimes":{"_deleted":["3"]}}
01:42:03.433{"PitTimes":{"16":{"RacingNumber":"16","Duration":"47.1","Lap":"28"}}}
01:42:33.799{"PitTimes":{"_deleted":["16"]}}
01:47:41.549{"PitTimes":{"16":{"RacingNumber":"16","Duration":"24.6","Lap":"31"}}}
01:48:09.289{"PitTimes":{"_deleted":["16"]}}
02:00:05.161{"PitTimes":{"10":{"RacingNumber":"10","Duration":"24.4","Lap":"40"}}}
02:00:37.636{"PitTimes":{"_deleted":["10"]}}
02:01:33.992{"PitTimes":{"20":{"RacingNumber":"20","Duration":"24.8","Lap":"41"}}}
02:02:05.986{"PitTimes":{"_deleted":["20"]}}
02:02:55.251{"PitTimes":{"77":{"RacingNumber":"77","Duration":"24.9","Lap":"42"}}}
02:03:27.006{"PitTimes":{"_deleted":["77"]}}
02:03:56.051{"PitTimes":{"44":{"RacingNumber":"44","Duration":"24.2","Lap":"43"}}}
02:04:19.287{"PitTimes":{"3":{"RacingNumber":"3","Duration":"23.8","Lap":"43"}}}
02:04:21.445{"PitTimes":{"55":{"RacingNumber":"55","Duration":"24.1","Lap":"43"}}}
02:04:22.184{"PitTimes":{"11":{"RacingNumber":"11","Duration":"24.4","Lap":"43"}}}
02:04:26.993{"PitTimes":{"_deleted":["44"]}}
02:04:50.641{"PitTimes":{"_deleted":["3"]}}
02:04:52.811{"PitTimes":{"_deleted":["55"]}}
02:04:53.492{"PitTimes":{"_deleted":["11"]}}
02:05:18.433{"PitTimes":{"81":{"RacingNumber":"81","Duration":"23.4","Lap":"44"}}}
02:05:32.917{"PitTimes":{"14":{"RacingNumber":"14","Duration":"24.3","Lap":"44"}}}
02:05:37.075{"PitTimes":{"22":{"RacingNumber":"22","Duration":"25.5","Lap":"44"}}}
02:05:40.089{"PitTimes":{"18":{"RacingNumber":"18","Duration":"25.0","Lap":"44"}}}
02:05:41.649{"PitTimes":{"31":{"RacingNumber":"31","Duration":"24.4","Lap":"44"}}}
02:05:44.180{"PitTimes":{"23":{"RacingNumber":"23","Duration":"24.8","Lap":"44"}}}
02:05:48.474{"PitTimes":{"_deleted":["81"]}}
02:05:52.952{"PitTimes":{"27":{"RacingNumber":"27","Duration":"24.7","Lap":"44"}}}
02:06:03.182{"PitTimes":{"_deleted":["14"]}}
02:06:07.706{"PitTimes":{"_deleted":["22"]}}
02:06:10.608{"PitTimes":{"_deleted":["18"]}}
02:06:12.495{"PitTimes":{"_deleted":["31"]}}
02:06:14.490{"PitTimes":{"_deleted":["23"]}}
02:06:22.534{"PitTimes":{"_deleted":["27"]}}
02:06:38.210{"PitTimes":{"1":{"RacingNumber":"1","Duration":"24.2","Lap":"45"}}}
02:06:42.270{"PitTimes":{"63":{"RacingNumber":"63","Duration":"25.4","Lap":"45"}}}
02:06:44.304{"PitTimes":{"24":{"RacingNumber":"24","Duration":"65.5","Lap":"44"}}}
02:07:07.589{"PitTimes":{"_deleted":["1"]}}
02:07:11.813{"PitTimes":{"_deleted":["63"]}}
02:07:21.892{"PitTimes":{"_deleted":["24"]}}
02:09:28.017{"PitTimes":{"4":{"RacingNumber":"4","Duration":"23.9","Lap":"47"}}}
02:09:57.171{"PitTimes":{"_deleted":["4"]}}
02:19:15.929{"PitTimes":{"24":{"RacingNumber":"24","Duration":"28.3","Lap":"52"}}}
02:19:32.561{"PitTimes":{"63":{"RacingNumber":"63","Duration":"28.1","Lap":"54"}}}
02:19:38.620{"PitTimes":{"44":{"RacingNumber":"44","Duration":"28.8","Lap":"54"}}}
02:19:47.966{"PitTimes":{"_deleted":["24"]}}
02:20:04.020{"PitTimes":{"_deleted":["63"]}}
02:20:12.037{"PitTimes":{"_deleted":["44"]}}
02:20:36.886{"PitTimes":{"20":{"RacingNumber":"20","Duration":"26.8","Lap":"54"}}}
02:21:07.911{"PitTimes":{"_deleted":["20"]}}

SessionData.jsonStream:

00:00:00.000{"Series":[],"StatusSeries":[{"Utc":"2024-06-09T16:57:28.055Z","TrackStatus":"AllClear"}]}
00:01:57.540{"Series":{"0":{"Utc":"2024-06-09T17:08:13.154Z","Lap":1}}}
00:56:55.990{"StatusSeries":{"1":{"Utc":"2024-06-09T18:03:11.604Z","SessionStatus":"Started"}}}
00:57:20.650{"StatusSeries":{"2":{"Utc":"2024-06-09T18:03:36.264Z","TrackStatus":"Yellow"}}}
00:57:22.651{"StatusSeries":{"3":{"Utc":"2024-06-09T18:03:38.265Z","TrackStatus":"AllClear"}}}
00:58:39.947{"Series":{"1":{"Utc":"2024-06-09T18:04:55.561Z","Lap":2}}}
01:00:16.544{"Series":{"2":{"Utc":"2024-06-09T18:06:32.158Z","Lap":3}}}
01:01:52.966{"Series":{"3":{"Utc":"2024-06-09T18:08:08.58Z","Lap":4}}}
01:03:27.525{"Series":{"4":{"Utc":"2024-06-09T18:09:43.139Z","Lap":5}}}
01:05:01.640{"Series":{"5":{"Utc":"2024-06-09T18:11:17.254Z","Lap":6}}}
01:06:10.057{"StatusSeries":{"4":{"Utc":"2024-06-09T18:12:25.671Z","TrackStatus":"Yellow"}}}
01:06:31.270{"StatusSeries":{"5":{"Utc":"2024-06-09T18:12:46.884Z","TrackStatus":"AllClear"}}}
01:06:34.551{"Series":{"6":{"Utc":"2024-06-09T18:12:50.165Z","Lap":7}}}
01:08:05.499{"Series":{"7":{"Utc":"2024-06-09T18:14:21.113Z","Lap":8}}}
01:09:36.948{"Series":{"8":{"Utc":"2024-06-09T18:15:52.562Z","Lap":9}}}
01:11:07.354{"Series":{"9":{"Utc":"2024-06-09T18:17:22.968Z","Lap":10}}}
01:12:37.132{"Series":{"10":{"Utc":"2024-06-09T18:18:52.746Z","Lap":11}}}
01:14:06.832{"Series":{"11":{"Utc":"2024-06-09T18:20:22.446Z","Lap":12}}}
01:15:36.374{"Series":{"12":{"Utc":"2024-06-09T18:21:51.988Z","Lap":13}}}
01:17:04.894{"Series":{"13":{"Utc":"2024-06-09T18:23:20.508Z","Lap":14}}}
01:18:33.850{"Series":{"14":{"Utc":"2024-06-09T18:24:49.464Z","Lap":15}}}
01:20:02.394{"Series":{"15":{"Utc":"2024-06-09T18:26:18.008Z","Lap":16}}}
01:21:29.875{"Series":{"16":{"Utc":"2024-06-09T18:27:45.489Z","Lap":17}}}
01:22:57.490{"Series":{"17":{"Utc":"2024-06-09T18:29:13.104Z","Lap":18}}}
01:24:24.834{"Series":{"18":{"Utc":"2024-06-09T18:30:40.448Z","Lap":19}}}
01:25:51.370{"Series":{"19":{"Utc":"2024-06-09T18:32:06.984Z","Lap":20}}}
01:27:17.422{"Series":{"20":{"Utc":"2024-06-09T18:33:33.036Z","Lap":21}}}
01:28:43.573{"Series":{"21":{"Utc":"2024-06-09T18:34:59.187Z","Lap":22}}}
01:30:08.025{"Series":{"22":{"Utc":"2024-06-09T18:36:23.639Z","Lap":23}}}
01:31:33.253{"Series":{"23":{"Utc":"2024-06-09T18:37:48.867Z","Lap":24}}}
01:32:57.978{"Series":{"24":{"Utc":"2024-06-09T18:39:13.592Z","Lap":25}}}
01:33:25.859{"StatusSeries":{"6":{"Utc":"2024-06-09T18:39:41.473Z","TrackStatus":"Yellow"}}}
01:34:10.738{"StatusSeries":{"7":{"Utc":"2024-06-09T18:40:26.352Z","TrackStatus":"SCDeployed"}}}
01:34:29.367{"Series":{"25":{"Utc":"2024-06-09T18:40:44.981Z","Lap":26}}}
01:36:49.450{"Series":{"26":{"Utc":"2024-06-09T18:43:05.064Z","Lap":27}}}
01:38:59.547{"Series":{"27":{"Utc":"2024-06-09T18:45:15.161Z","Lap":28}}}
01:41:07.883{"Series":{"28":{"Utc":"2024-06-09T18:47:23.497Z","Lap":29}}}
01:42:49.656{"StatusSeries":{"8":{"Utc":"2024-06-09T18:49:05.27Z","TrackStatus":"AllClear"}}}
01:42:55.930{"StatusSeries":{"9":{"Utc":"2024-06-09T18:49:11.544Z","TrackStatus":"Yellow"}}}
01:43:05.286{"StatusSeries":{"10":{"Utc":"2024-06-09T18:49:20.9Z","TrackStatus":"AllClear"}}}
01:43:21.836{"Series":{"29":{"Utc":"2024-06-09T18:49:37.45Z","Lap":30}}}
01:44:48.015{"Series":{"30":{"Utc":"2024-06-09T18:51:03.629Z","Lap":31}}}
01:46:17.210{"Series":{"31":{"Utc":"2024-06-09T18:52:32.824Z","Lap":32}}}
01:47:47.962{"Series":{"32":{"Utc":"2024-06-09T18:54:03.576Z","Lap":33}}}
01:49:17.469{"Series":{"33":{"Utc":"2024-06-09T18:55:33.083Z","Lap":34}}}
01:50:45.214{"Series":{"34":{"Utc":"2024-06-09T18:57:00.828Z","Lap":35}}}
01:52:12.022{"Series":{"35":{"Utc":"2024-06-09T18:58:27.636Z","Lap":36}}}
01:53:38.319{"Series":{"36":{"Utc":"2024-06-09T18:59:53.933Z","Lap":37}}}
01:55:04.087{"Series":{"37":{"Utc":"2024-06-09T19:01:19.701Z","Lap":38}}}
01:56:29.435{"Series":{"38":{"Utc":"2024-06-09T19:02:45.049Z","Lap":39}}}
01:57:54.314{"Series":{"39":{"Utc":"2024-06-09T19:04:09.928Z","Lap":40}}}
01:59:19.014{"Series":{"40":{"Utc":"2024-06-09T19:05:34.628Z","Lap":41}}}
02:00:22.031{"StatusSeries":{"11":{"Utc":"2024-06-09T19:06:37.645Z","TrackStatus":"Yellow"}}}
02:00:25.533{"StatusSeries":{"12":{"Utc":"2024-06-09T19:06:41.147Z","TrackStatus":"AllClear"}}}
02:00:43.145{"Series":{"41":{"Utc":"2024-06-09T19:06:58.759Z","Lap":42}}}
02:02:07.215{"Series":{"42":{"Utc":"2024-06-09T19:08:22.829Z","Lap":43}}}
02:03:31.610{"Series":{"43":{"Utc":"2024-06-09T19:09:47.224Z","Lap":44}}}
02:04:55.890{"Series":{"44":{"Utc":"2024-06-09T19:11:11.504Z","Lap":45}}}
02:06:23.314{"Series":{"45":{"Utc":"2024-06-09T19:12:38.928Z","Lap":46}}}
02:07:46.571{"Series":{"46":{"Utc":"2024-06-09T19:14:02.185Z","Lap":47}}}
02:09:26.369{"Series":{"47":{"Utc":"2024-06-09T19:15:41.983Z","Lap":48}}}
02:10:50.723{"Series":{"48":{"Utc":"2024-06-09T19:17:06.337Z","Lap":49}}}
02:11:28.851{"StatusSeries":{"13":{"Utc":"2024-06-09T19:17:44.465Z","TrackStatus":"Yellow"}}}
02:11:32.364{"StatusSeries":{"14":{"Utc":"2024-06-09T19:17:47.978Z","TrackStatus":"AllClear"}}}
02:12:10.186{"Series":{"49":{"Utc":"2024-06-09T19:18:25.8Z","Lap":50}}}
02:13:28.736{"Series":{"50":{"Utc":"2024-06-09T19:19:44.35Z","Lap":51}}}
02:14:46.853{"Series":{"51":{"Utc":"2024-06-09T19:21:02.467Z","Lap":52}}}
02:15:55.916{"StatusSeries":{"15":{"Utc":"2024-06-09T19:22:11.53Z","TrackStatus":"Yellow"}}}
02:16:02.555{"StatusSeries":{"16":{"Utc":"2024-06-09T19:22:18.169Z","TrackStatus":"AllClear"}}}
02:16:04.770{"Series":{"52":{"Utc":"2024-06-09T19:22:20.384Z","Lap":53}}}
02:17:14.224{"StatusSeries":{"17":{"Utc":"2024-06-09T19:23:29.838Z","TrackStatus":"Yellow"}}}
02:17:21.984{"Series":{"53":{"Utc":"2024-06-09T19:23:37.598Z","Lap":54}}}
02:17:43.757{"StatusSeries":{"18":{"Utc":"2024-06-09T19:23:59.371Z","TrackStatus":"SCDeployed"}}}
02:19:01.881{"Series":{"54":{"Utc":"2024-06-09T19:25:17.495Z","Lap":55}}}
02:21:12.648{"Series":{"55":{"Utc":"2024-06-09T19:27:28.262Z","Lap":56}}}
02:23:16.695{"Series":{"56":{"Utc":"2024-06-09T19:29:32.309Z","Lap":57}}}
02:25:13.281{"Series":{"57":{"Utc":"2024-06-09T19:31:28.895Z","Lap":58}}}
02:26:50.454{"StatusSeries":{"19":{"Utc":"2024-06-09T19:33:06.068Z","TrackStatus":"AllClear"}}}
02:27:28.903{"Series":{"58":{"Utc":"2024-06-09T19:33:44.517Z","Lap":59}}}
02:28:47.286{"Series":{"59":{"Utc":"2024-06-09T19:35:02.9Z","Lap":60}}}
02:30:04.707{"Series":{"60":{"Utc":"2024-06-09T19:36:20.321Z","Lap":61}}}
02:31:21.366{"Series":{"61":{"Utc":"2024-06-09T19:37:36.98Z","Lap":62}}}
02:32:37.657{"Series":{"62":{"Utc":"2024-06-09T19:38:53.271Z","Lap":63}}}
02:33:53.625{"Series":{"63":{"Utc":"2024-06-09T19:40:09.239Z","Lap":64}}}
02:35:09.450{"Series":{"64":{"Utc":"2024-06-09T19:41:25.064Z","Lap":65}}}
02:36:25.353{"Series":{"65":{"Utc":"2024-06-09T19:42:40.967Z","Lap":66}}}
02:37:30.750{"StatusSeries":{"20":{"Utc":"2024-06-09T19:43:46.364Z","TrackStatus":"Yellow"}}}
02:37:41.170{"Series":{"66":{"Utc":"2024-06-09T19:43:56.784Z","Lap":67}}}
02:37:54.956{"StatusSeries":{"21":{"Utc":"2024-06-09T19:44:10.57Z","TrackStatus":"AllClear"}}}
02:38:56.926{"Series":{"67":{"Utc":"2024-06-09T19:45:12.54Z","Lap":68}}}
02:40:12.677{"Series":{"68":{"Utc":"2024-06-09T19:46:28.291Z","Lap":69}}}
02:41:28.640{"Series":{"69":{"Utc":"2024-06-09T19:47:44.254Z","Lap":70}}}
02:42:44.147{"StatusSeries":{"22":{"Utc":"2024-06-09T19:48:59.761Z","SessionStatus":"Finished"}}}
02:45:00.338{"StatusSeries":{"23":{"Utc":"2024-06-09T19:51:15.952Z","SessionStatus":"Finalised"}}}
02:45:00.898{"StatusSeries":{"24":{"Utc":"2024-06-09T19:51:16.512Z","SessionStatus":"Ends"}}}

All this data is form the last gp in canada on sunday.

slowlydev commented 3 months ago

first thing i noticed: we need to proxy the request as we are getting blocked by cors

Okay thanks for checking 👍🏻

second thing: can someone help me figure out what exactly the time present before the json data is representing i cant figure out what excactly is specified there 🤔 My guess would be it is the time elapsed since the start of the broadcast or something and to get the time in the race i would need to calculate the difference to the timestap at which the SessionStatus is updated to started. But please correct me if i am wrong or you have another idea

If it's not anything to do with jsonStream itself (maybe it could tell jsonStream to wait x amount before sending the next line).

Then I think it's just a timestamp from the start of the session as you said.

I would approach this by loading the json, maybe doing formatting on it (camel case it) (maybe in backend as we need to proxy anyways) and then load everything into the buffer of 1 or multiple instances of the "state engine" in the frontend. Then we need to have a timestamp when the replay has started or where we are currently at.

And making this perform well is the part I'm most scared about.

I hope this helps!