@@ -13,7 +13,6 @@ interface UploadBatch {
1313
1414const uploadBatches = new Map < string , UploadBatch > ( ) ;
1515
16- // Track initialization to prevent double-initialization
1716let isInitialized = false ;
1817
1918/**
@@ -22,7 +21,6 @@ let isInitialized = false;
2221 * Call this once when the app starts (outside React component lifecycle)
2322 */
2423export function initializeRecordingService ( ) {
25- // Prevent double-initialization
2624 if ( isInitialized ) {
2725 console . warn ( "[RecordingService] Already initialized, skipping" ) ;
2826 return ;
@@ -31,8 +29,6 @@ export function initializeRecordingService() {
3129 console . log ( "[RecordingService] Initializing..." ) ;
3230 isInitialized = true ;
3331
34- // Handle crash recovery after checking auth client is ready
35- // This prevents the race condition where recovery tries to upload before client exists
3632 const authStore = useAuthStore . getState ( ) ;
3733 if ( authStore . client ) {
3834 handleCrashRecovery ( ) ;
@@ -42,27 +38,22 @@ export function initializeRecordingService() {
4238 ) ;
4339 }
4440
45- // Listen for recording started events
4641 window . electronAPI . onRecallRecordingStarted ( ( recording ) => {
4742 console . log ( "[RecordingService] Recording started:" , recording ) ;
4843
4944 const store = useActiveRecordingStore . getState ( ) ;
50- // Pass full DesktopRecording object to store
5145 store . addRecording ( recording ) ;
5246
53- // Initialize upload batch tracker
5447 uploadBatches . set ( recording . id , {
5548 recordingId : recording . id ,
5649 timer : null ,
5750 segmentCount : 0 ,
5851 } ) ;
5952 } ) ;
6053
61- // Listen for transcript segments
6254 window . electronAPI . onRecallTranscriptSegment ( ( data ) => {
6355 const store = useActiveRecordingStore . getState ( ) ;
6456
65- // Add segment to store
6657 store . addSegment ( data . posthog_recording_id , {
6758 timestamp : data . timestamp ,
6859 speaker : data . speaker ,
@@ -71,19 +62,16 @@ export function initializeRecordingService() {
7162 is_final : data . is_final ,
7263 } ) ;
7364
74- // Track batch for upload
7565 const batch = uploadBatches . get ( data . posthog_recording_id ) ;
7666 if ( batch ) {
7767 batch . segmentCount ++ ;
7868
79- // Start timer if not already running
8069 if ( ! batch . timer ) {
8170 batch . timer = setTimeout ( ( ) => {
8271 uploadPendingSegments ( data . posthog_recording_id ) ;
8372 } , BATCH_TIMEOUT_MS ) ;
8473 }
8574
86- // Upload if batch size reached
8775 if ( batch . segmentCount >= BATCH_SIZE ) {
8876 if ( batch . timer ) {
8977 clearTimeout ( batch . timer ) ;
@@ -94,7 +82,6 @@ export function initializeRecordingService() {
9482 }
9583 } ) ;
9684
97- // Listen for meeting ended events
9885 window . electronAPI . onRecallMeetingEnded ( ( data ) => {
9986 console . log ( "[RecordingService] Meeting ended:" , data ) ;
10087
@@ -104,14 +91,50 @@ export function initializeRecordingService() {
10491 }
10592 uploadBatches . delete ( data . posthog_recording_id ) ;
10693
107- // Upload any pending segments, then update status to uploading
108- uploadPendingSegments ( data . posthog_recording_id ) . then ( ( ) => {
94+ uploadPendingSegments ( data . posthog_recording_id ) . then ( async ( ) => {
10995 const store = useActiveRecordingStore . getState ( ) ;
96+
97+ const recording = store . getRecording ( data . posthog_recording_id ) ;
98+ if ( recording ) {
99+ const participants = [
100+ ...new Set (
101+ recording . segments
102+ . map ( ( s ) => s . speaker )
103+ . filter ( ( s ) : s is string => s !== null && s !== undefined ) ,
104+ ) ,
105+ ] ;
106+
107+ if ( participants . length > 0 ) {
108+ console . log (
109+ `[RecordingService] Extracted ${ participants . length } participants:` ,
110+ participants ,
111+ ) ;
112+
113+ try {
114+ const authStore = useAuthStore . getState ( ) ;
115+ const client = authStore . client ;
116+
117+ if ( client ) {
118+ await client . updateDesktopRecording ( data . posthog_recording_id , {
119+ participants,
120+ } ) ;
121+ console . log (
122+ `[RecordingService] Updated recording with participants` ,
123+ ) ;
124+ }
125+ } catch ( error ) {
126+ console . error (
127+ "[RecordingService] Failed to update participants:" ,
128+ error ,
129+ ) ;
130+ }
131+ }
132+ }
133+
110134 store . updateStatus ( data . posthog_recording_id , "uploading" ) ;
111135 } ) ;
112136 } ) ;
113137
114- // Listen for recording ready events
115138 window . electronAPI . onRecallRecordingReady ( ( data ) => {
116139 console . log ( "[RecordingService] Recording ready:" , data ) ;
117140
@@ -123,9 +146,6 @@ export function initializeRecordingService() {
123146 console . log ( "[RecordingService] Initialized successfully" ) ;
124147}
125148
126- /**
127- * Upload pending transcript segments to backend
128- */
129149async function uploadPendingSegments ( recordingId : string ) : Promise < void > {
130150 const store = useActiveRecordingStore . getState ( ) ;
131151 const recording = store . getRecording ( recordingId ) ;
@@ -153,7 +173,6 @@ async function uploadPendingSegments(recordingId: string): Promise<void> {
153173 throw new Error ( "PostHog client not initialized" ) ;
154174 }
155175
156- // Upload segments to backend
157176 await client . updateDesktopRecordingTranscript ( recordingId , {
158177 segments : pendingSegments . map ( ( seg ) => ( {
159178 timestamp_ms : seg . timestamp ,
@@ -164,7 +183,6 @@ async function uploadPendingSegments(recordingId: string): Promise<void> {
164183 } ) ) ,
165184 } ) ;
166185
167- // Update last uploaded index
168186 const newIndex =
169187 recording . lastUploadedSegmentIndex + pendingSegments . length ;
170188 store . updateLastUploadedIndex ( recordingId , newIndex ) ;
@@ -173,7 +191,6 @@ async function uploadPendingSegments(recordingId: string): Promise<void> {
173191 `[RecordingService] Successfully uploaded ${ pendingSegments . length } segments` ,
174192 ) ;
175193
176- // Reset batch tracker
177194 const batch = uploadBatches . get ( recordingId ) ;
178195 if ( batch ) {
179196 batch . segmentCount = 0 ;
@@ -196,11 +213,9 @@ async function uploadPendingSegments(recordingId: string): Promise<void> {
196213
197214/**
198215 * Handle crash recovery - upload any pending segments and clear from IDB
199- * Called on app startup. Keeps things simple: save what we have and move on.
200216 *
201217 * Tradeoff: Might lose last ~10 segments if upload fails during crash recovery.
202- * Acceptable because: (1) Backend already has 90%+ from batched uploads during meeting
203- * (2) Crashes are rare, (3) Crash + upload failure is even rarer
218+ * Acceptable because backend already has 90%+ from batched uploads during meeting.
204219 */
205220function handleCrashRecovery ( ) {
206221 const store = useActiveRecordingStore . getState ( ) ;
@@ -220,36 +235,28 @@ function handleCrashRecovery() {
220235 `[RecordingService] Uploading pending segments for ${ recording . id } (best effort)` ,
221236 ) ;
222237
223- // Upload pending segments in background (best effort, don't block startup)
224238 uploadPendingSegments ( recording . id ) . catch ( ( error ) => {
225239 console . error (
226240 `[RecordingService] Failed to upload segments during recovery (acceptable):` ,
227241 error ,
228242 ) ;
229243 } ) ;
230244
231- // Clear from IDB immediately - recording is already in backend
232245 store . clearRecording ( recording . id ) ;
233246 console . log ( `[RecordingService] Cleared ${ recording . id } from IDB` ) ;
234247 }
235248}
236249
237- /**
238- * Clean up the recording service
239- * Call this when the app shuts down
240- */
241250export function shutdownRecordingService ( ) {
242251 console . log ( "[RecordingService] Shutting down..." ) ;
243252
244- // Clear all upload batch timers
245253 for ( const batch of uploadBatches . values ( ) ) {
246254 if ( batch . timer ) {
247255 clearTimeout ( batch . timer ) ;
248256 }
249257 }
250258 uploadBatches . clear ( ) ;
251259
252- // Reset initialization flag to allow re-initialization after logout/login
253260 isInitialized = false ;
254261
255262 console . log ( "[RecordingService] Shutdown complete" ) ;
0 commit comments