Skip to content

Commit c813c07

Browse files
store recordings into project meta?
1 parent 313d7f1 commit c813c07

File tree

7 files changed

+120
-89
lines changed

7 files changed

+120
-89
lines changed

apps/desktop/src-tauri/src/lib.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -910,7 +910,12 @@ async fn get_video_metadata(path: PathBuf) -> Result<VideoRecordingMetadata, Str
910910
.map(|s| recording_meta.path(&s.display.path))
911911
.collect(),
912912
},
913-
RecordingMetaInner::InProgress { .. } => todo!(),
913+
RecordingMetaInner::InProgress { .. } => {
914+
return Err(format!("Unable to get metadata on in-progress recording"));
915+
}
916+
RecordingMetaInner::Failed { .. } => {
917+
return Err(format!("Unable to get metadata on failed recording"));
918+
}
914919
};
915920

916921
let duration = display_paths
@@ -1063,7 +1068,11 @@ async fn upload_exported_video(
10631068

10641069
let mut meta = RecordingMeta::load_for_project(&path).map_err(|v| v.to_string())?;
10651070

1066-
let output_path = meta.output_path();
1071+
let Some(output_path) = meta.output_path() else {
1072+
notifications::send_notification(&app, notifications::NotificationType::UploadFailed);
1073+
return Err("Failed to upload video: Recording failed to complete".to_string());
1074+
};
1075+
10671076
if !output_path.exists() {
10681077
notifications::send_notification(&app, notifications::NotificationType::UploadFailed);
10691078
return Err("Failed to upload video: Rendered video not found".to_string());
@@ -1304,6 +1313,7 @@ async fn take_screenshot(app: AppHandle, _state: MutableState<'_, App>) -> Resul
13041313
cursor: None,
13051314
},
13061315
}),
1316+
upload: None,
13071317
}
13081318
.save_for_project()
13091319
.unwrap();
@@ -1415,6 +1425,7 @@ impl RecordingMetaWithMode {
14151425
RecordingMetaInner::Studio(_) => Some(RecordingMode::Studio),
14161426
RecordingMetaInner::Instant(_) => Some(RecordingMode::Instant),
14171427
RecordingMetaInner::InProgress { .. } => None,
1428+
RecordingMetaInner::Failed { .. } => None,
14181429
},
14191430
inner,
14201431
}
@@ -2502,7 +2513,10 @@ fn open_project_from_path(path: &Path, app: AppHandle) -> Result<(), String> {
25022513
}
25032514
}
25042515
}
2505-
RecordingMetaInner::InProgress { recording } => todo!(),
2516+
RecordingMetaInner::InProgress { .. } => return Err(format!("Recording in progress")),
2517+
RecordingMetaInner::Failed { .. } => {
2518+
return Err(format!("Unable to open failed recording"));
2519+
}
25062520
}
25072521

25082522
Ok(())

apps/desktop/src-tauri/src/recording.rs

Lines changed: 79 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ pub async fn start_recording(
298298
sharing: None, // TODO: Is this gonna be problematic as it was previously always set
299299
pretty_name: format!("{target_name} {date_time}"),
300300
inner: RecordingMetaInner::InProgress { recording: true },
301+
upload: None,
301302
};
302303

303304
meta.save_for_project()
@@ -370,6 +371,7 @@ pub async fn start_recording(
370371
spawn_actor({
371372
let state_mtx = Arc::clone(&state_mtx);
372373
let general_settings = general_settings.cloned();
374+
let recording_dir = recording_dir.clone();
373375
async move {
374376
fail!("recording::spawn_actor");
375377
let mut state = state_mtx.write().await;
@@ -477,13 +479,13 @@ pub async fn start_recording(
477479

478480
let actor_done_rx = match spawn_actor_res {
479481
Ok(rx) => rx,
480-
Err(e) => {
481-
let _ = RecordingEvent::Failed { error: e.clone() }.emit(&app);
482+
Err(err) => {
483+
let _ = RecordingEvent::Failed { error: err.clone() }.emit(&app);
482484

483485
let mut dialog = MessageDialogBuilder::new(
484486
app.dialog().clone(),
485487
"An error occurred".to_string(),
486-
e.clone(),
488+
err.clone(),
487489
)
488490
.kind(tauri_plugin_dialog::MessageDialogKind::Error);
489491

@@ -494,9 +496,9 @@ pub async fn start_recording(
494496
dialog.blocking_show();
495497

496498
let mut state = state_mtx.write().await;
497-
let _ = handle_recording_end(app, None, &mut state).await;
499+
let _ = handle_recording_end(app, Err(err.clone()), &mut state, recording_dir).await;
498500

499-
return Err(e);
501+
return Err(err);
500502
}
501503
};
502504

@@ -522,7 +524,7 @@ pub async fn start_recording(
522524
let mut dialog = MessageDialogBuilder::new(
523525
app.dialog().clone(),
524526
"An error occurred".to_string(),
525-
e,
527+
e.clone(),
526528
)
527529
.kind(tauri_plugin_dialog::MessageDialogKind::Error);
528530

@@ -533,7 +535,9 @@ pub async fn start_recording(
533535
dialog.blocking_show();
534536

535537
// this clears the current recording for us
536-
handle_recording_end(app, None, &mut state).await.ok();
538+
handle_recording_end(app, Err(e), &mut state, recording_dir)
539+
.await
540+
.ok();
537541
}
538542
// Actor hasn't errored, it's just finished
539543
v => {
@@ -581,8 +585,9 @@ pub async fn stop_recording(app: AppHandle, state: MutableState<'_, App>) -> Res
581585
};
582586

583587
let completed_recording = current_recording.stop().await.map_err(|e| e.to_string())?;
588+
let recording_dir = completed_recording.project_path().clone();
584589

585-
handle_recording_end(app, Some(completed_recording), &mut state).await?;
590+
handle_recording_end(app, Ok(completed_recording), &mut state, recording_dir).await?;
586591

587592
Ok(())
588593
}
@@ -669,17 +674,24 @@ pub async fn delete_recording(app: AppHandle, state: MutableState<'_, App>) -> R
669674
// runs when a recording ends, whether from success or failure
670675
async fn handle_recording_end(
671676
handle: AppHandle,
672-
recording: Option<CompletedRecording>,
677+
recording: Result<CompletedRecording, String>,
673678
app: &mut App,
679+
recording_dir: PathBuf,
674680
) -> Result<(), String> {
675681
// Clear current recording, just in case :)
676682
app.clear_current_recording();
677683

678-
let res = if let Some(recording) = recording {
684+
let res = match recording {
679685
// we delay reporting errors here so that everything else happens first
680-
Some(handle_recording_finish(&handle, recording).await)
681-
} else {
682-
None
686+
Ok(recording) => Some(handle_recording_finish(&handle, recording).await),
687+
Err(error) => {
688+
// TODO: Error handling
689+
let mut project_meta = RecordingMeta::load_for_project(&recording_dir).unwrap();
690+
project_meta.inner = RecordingMetaInner::Failed { error };
691+
project_meta.save_for_project().unwrap();
692+
693+
None
694+
}
683695
};
684696

685697
let _ = RecordingStopped.emit(&handle);
@@ -743,8 +755,6 @@ async fn handle_recording_finish(
743755
None,
744756
));
745757

746-
let target_name = completed_recording.target_name().clone();
747-
748758
let (meta_inner, sharing) = match completed_recording {
749759
CompletedRecording::Studio { recording, .. } => {
750760
let recordings = ProjectRecordingsMeta::new(&recording_dir, &recording.meta)?;
@@ -766,7 +776,6 @@ async fn handle_recording_finish(
766776
video_upload_info,
767777
..
768778
} => {
769-
// shareable_link = Some(video_upload_info.link.clone());
770779
let app = app.clone();
771780
let output_path = recording_dir.join("content/output.mp4");
772781

@@ -796,58 +805,58 @@ async fn handle_recording_finish(
796805

797806
let _ = screenshot_task.await;
798807

799-
if video_upload_succeeded {
800-
if let Ok(result) =
801-
compress_image(display_screenshot).await
802-
.map_err(|err|
803-
error!("Error compressing thumbnail for instant mode progressive upload: {err}")
804-
) {
805-
let (stream, total_size) = bytes_into_stream(result);
806-
do_presigned_upload(
807-
&app,
808-
stream,
809-
total_size,
810-
crate::upload::PresignedS3PutRequest {
811-
video_id: video_upload_info.id.clone(),
812-
subpath: "screenshot/screen-capture.jpg".to_string(),
813-
method: PresignedS3PutRequestMethod::Put,
814-
meta: None,
815-
},
816-
|p| {} // TODO: Progress reporting
817-
)
818-
.await
819-
.map_err(|err| {
820-
error!("Error updating thumbnail for instant mode progressive upload: {err}")
821-
})
822-
.ok();
823-
}
824-
} else {
825-
if let Ok(meta) = build_video_meta(&output_path)
826-
.map_err(|err| error!("Error getting video metdata: {}", err))
827-
{
828-
// The upload_video function handles screenshot upload, so we can pass it along
829-
match upload_video(
830-
&app,
831-
video_upload_info.id.clone(),
832-
output_path,
833-
display_screenshot.clone(),
834-
video_upload_info.config.clone(),
835-
meta,
836-
None,
837-
)
838-
.await
839-
{
840-
Ok(_) => {
841-
info!(
842-
"Final video upload with screenshot completed successfully"
843-
)
844-
}
845-
Err(e) => {
846-
error!("Error in final upload with screenshot: {}", e)
847-
}
848-
}
849-
}
850-
}
808+
// if video_upload_succeeded {
809+
// if let Ok(result) =
810+
// compress_image(display_screenshot).await
811+
// .map_err(|err|
812+
// error!("Error compressing thumbnail for instant mode progressive upload: {err}")
813+
// ) {
814+
// let (stream, total_size) = bytes_into_stream(result);
815+
// do_presigned_upload(
816+
// &app,
817+
// stream,
818+
// total_size,
819+
// crate::upload::PresignedS3PutRequest {
820+
// video_id: video_upload_info.id.clone(),
821+
// subpath: "screenshot/screen-capture.jpg".to_string(),
822+
// method: PresignedS3PutRequestMethod::Put,
823+
// meta: None,
824+
// },
825+
// |p| {} // TODO: Progress reporting
826+
// )
827+
// .await
828+
// .map_err(|err| {
829+
// error!("Error updating thumbnail for instant mode progressive upload: {err}")
830+
// })
831+
// .ok();
832+
// }
833+
// } else {
834+
// if let Ok(meta) = build_video_meta(&output_path)
835+
// .map_err(|err| error!("Error getting video metdata: {}", err))
836+
// {
837+
// // The upload_video function handles screenshot upload, so we can pass it along
838+
// match upload_video(
839+
// &app,
840+
// video_upload_info.id.clone(),
841+
// output_path,
842+
// display_screenshot.clone(),
843+
// video_upload_info.config.clone(),
844+
// meta,
845+
// None,
846+
// )
847+
// .await
848+
// {
849+
// Ok(_) => {
850+
// info!(
851+
// "Final video upload with screenshot completed successfully"
852+
// )
853+
// }
854+
// Err(e) => {
855+
// error!("Error in final upload with screenshot: {}", e)
856+
// }
857+
// }
858+
// }
859+
// }
851860
}
852861
});
853862

@@ -864,6 +873,7 @@ async fn handle_recording_finish(
864873
// TODO: Can we avoid reloading it from disk by parsing as arg?
865874
let mut meta = RecordingMeta::load_for_project(&recording_dir).unwrap();
866875
meta.inner = meta_inner;
876+
meta.sharing = sharing;
867877
meta.save_for_project()
868878
.map_err(|e| format!("Failed to save recording meta: {e}"))?;
869879

@@ -973,6 +983,7 @@ pub fn generate_zoom_segments_from_clicks(
973983
pretty_name: String::new(),
974984
sharing: None,
975985
inner: RecordingMetaInner::Studio(recording.meta.clone()),
986+
upload: None,
976987
};
977988

978989
generate_zoom_segments_for_project(&recording_meta, recordings)

apps/desktop/src-tauri/src/upload.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -577,10 +577,6 @@ impl InstantMultipartUpload {
577577
pre_created_video: VideoUploadInfo,
578578
realtime_video_done: Option<Receiver<()>>,
579579
) -> Result<(), String> {
580-
use std::time::Duration;
581-
582-
use tokio::time::sleep;
583-
584580
// --------------------------------------------
585581
// basic constants and info for chunk approach
586582
// --------------------------------------------

apps/desktop/src/utils/tauri.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -420,8 +420,8 @@ export type ProjectConfiguration = { aspectRatio: AspectRatio | null; background
420420
export type ProjectRecordingsMeta = { segments: SegmentRecordings[] }
421421
export type RecordingDeleted = { path: string }
422422
export type RecordingEvent = { variant: "Countdown"; value: number } | { variant: "Started" } | { variant: "Stopped" } | { variant: "Failed"; error: string }
423-
export type RecordingMeta = (StudioRecordingMeta | InstantRecordingMeta | { recording: boolean }) & { platform?: Platform | null; pretty_name: string; sharing?: SharingMeta | null }
424-
export type RecordingMetaWithMode = ((StudioRecordingMeta | InstantRecordingMeta | { recording: boolean }) & { platform?: Platform | null; pretty_name: string; sharing?: SharingMeta | null }) & { mode: RecordingMode | null }
423+
export type RecordingMeta = ({ recording: boolean } | { error: string } | StudioRecordingMeta | InstantRecordingMeta) & { platform?: Platform | null; pretty_name: string; sharing?: SharingMeta | null; upload?: UploadState | null }
424+
export type RecordingMetaWithMode = (({ recording: boolean } | { error: string } | StudioRecordingMeta | InstantRecordingMeta) & { platform?: Platform | null; pretty_name: string; sharing?: SharingMeta | null; upload?: UploadState | null }) & { mode: RecordingMode | null }
425425
export type RecordingMode = "studio" | "instant"
426426
export type RecordingOptionsChanged = null
427427
export type RecordingSettingsStore = { target: ScreenCaptureTarget | null; micName: string | null; cameraId: DeviceOrModelID | null; mode: RecordingMode | null; systemAudio: boolean }
@@ -452,6 +452,7 @@ export type TimelineSegment = { recordingSegment?: number; timescale: number; st
452452
export type UploadMode = { Initial: { pre_created_video: VideoUploadInfo | null } } | "Reupload"
453453
export type UploadProgress = { progress: number }
454454
export type UploadResult = { Success: string } | "NotAuthenticated" | "PlanCheckFailed" | "UpgradeRequired"
455+
export type UploadState = "Uploading" | { Failed: string } | "Complete"
455456
export type Video = { duration: number; width: number; height: number; fps: number; start_time: number }
456457
export type VideoMeta = { path: string; fps?: number;
457458
/**

crates/export/src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ pub enum ExporterBuildError {
3939
MetaLoad(#[source] Box<dyn std::error::Error>),
4040
#[error("Recording is not a studio recording")]
4141
NotStudioRecording,
42+
#[error("Unable to export a failed recording")]
43+
RecordingFailed,
4244
#[error("Failed to load recordings meta: {0}")]
4345
RecordingsMeta(String),
4446
#[error("Failed to setup renderer: {0}")]
@@ -97,7 +99,8 @@ impl ExporterBuilder {
9799

98100
let output_path = self
99101
.output_path
100-
.unwrap_or_else(|| recording_meta.output_path());
102+
.or_else(|| recording_meta.output_path())
103+
.ok_or(Error::RecordingFailed)?;
101104

102105
if let Some(parent) = output_path.parent() {
103106
std::fs::create_dir_all(parent)

0 commit comments

Comments
 (0)