Skip to content

Commit c411b02

Browse files
restructure project file again
1 parent 476a649 commit c411b02

File tree

7 files changed

+107
-72
lines changed

7 files changed

+107
-72
lines changed

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

Lines changed: 28 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ use auth::{AuthStore, AuthenticationInvalid, Plan};
3030
use camera::CameraPreviewState;
3131
use cap_editor::{EditorInstance, EditorState};
3232
use cap_project::{
33-
ProjectConfiguration, RecordingMeta, RecordingMetaInner, SharingMeta, StudioRecordingMeta, XY,
34-
ZoomSegment,
33+
ProjectConfiguration, RecordingMeta, RecordingMetaInner, SharingMeta, StudioRecordingMeta,
34+
StudioRecordingStatus, XY, ZoomSegment,
3535
};
3636
use cap_recording::{
3737
RecordingMode,
@@ -901,21 +901,24 @@ async fn get_video_metadata(path: PathBuf) -> Result<VideoRecordingMetadata, Str
901901
RecordingMetaInner::Instant(_) => {
902902
vec![path.join("content/output.mp4")]
903903
}
904-
RecordingMetaInner::Studio(meta) => match meta {
905-
StudioRecordingMeta::SingleSegment { segment } => {
906-
vec![recording_meta.path(&segment.display.path)]
904+
RecordingMetaInner::Studio(meta) => {
905+
let status = meta.status();
906+
if let StudioRecordingStatus::Failed { .. } = status {
907+
return Err(format!("Unable to get metadata on failed recording"));
908+
} else if let StudioRecordingStatus::InProgress = status {
909+
return Err(format!("Unable to get metadata on in-progress recording"));
910+
}
911+
912+
match meta {
913+
StudioRecordingMeta::SingleSegment { segment } => {
914+
vec![recording_meta.path(&segment.display.path)]
915+
}
916+
StudioRecordingMeta::MultipleSegments { inner } => inner
917+
.segments
918+
.iter()
919+
.map(|s| recording_meta.path(&s.display.path))
920+
.collect(),
907921
}
908-
StudioRecordingMeta::MultipleSegments { inner, .. } => inner
909-
.segments
910-
.iter()
911-
.map(|s| recording_meta.path(&s.display.path))
912-
.collect(),
913-
},
914-
RecordingMetaInner::InProgress { .. } => {
915-
return Err(format!("Unable to get metadata on in-progress recording"));
916-
}
917-
RecordingMetaInner::Failed { .. } => {
918-
return Err(format!("Unable to get metadata on failed recording"));
919922
}
920923
};
921924

@@ -1069,11 +1072,7 @@ async fn upload_exported_video(
10691072

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

1072-
let Some(output_path) = meta.output_path() else {
1073-
notifications::send_notification(&app, notifications::NotificationType::UploadFailed);
1074-
return Err("Failed to upload video: Recording failed to complete".to_string());
1075-
};
1076-
1075+
let output_path = meta.output_path();
10771076
if !output_path.exists() {
10781077
notifications::send_notification(&app, notifications::NotificationType::UploadFailed);
10791078
return Err("Failed to upload video: Rendered video not found".to_string());
@@ -1401,17 +1400,6 @@ async fn save_file_dialog(
14011400
}
14021401
}
14031402

1404-
// #[derive(Serialize, specta::Type)]
1405-
// #[serde(tag = "status")]
1406-
// pub enum RecordingStatus {
1407-
// Recording,
1408-
// Failed { error: String },
1409-
// Complete { mode: RecordingMode },
1410-
// }
1411-
//
1412-
// #[serde(flatten)]
1413-
// pub status: RecordingStatus,
1414-
14151403
#[derive(Serialize, specta::Type)]
14161404
pub struct RecordingMetaWithMode {
14171405
#[serde(flatten)]
@@ -1425,8 +1413,6 @@ impl RecordingMetaWithMode {
14251413
mode: match &inner.inner {
14261414
RecordingMetaInner::Studio(_) => Some(RecordingMode::Studio),
14271415
RecordingMetaInner::Instant(_) => Some(RecordingMode::Instant),
1428-
RecordingMetaInner::InProgress { .. } => None,
1429-
RecordingMetaInner::Failed { .. } => None,
14301416
},
14311417
inner,
14321418
}
@@ -2498,9 +2484,15 @@ fn open_project_from_path(path: &Path, app: AppHandle) -> Result<(), String> {
24982484
let meta = RecordingMeta::load_for_project(path).map_err(|v| v.to_string())?;
24992485

25002486
match &meta.inner {
2501-
RecordingMetaInner::Studio(_) => {
2502-
let project_path = path.to_path_buf();
2487+
RecordingMetaInner::Studio(meta) => {
2488+
let status = meta.status();
2489+
if let StudioRecordingStatus::Failed { .. } = status {
2490+
return Err(format!("Unable to open failed recording"));
2491+
} else if let StudioRecordingStatus::InProgress = status {
2492+
return Err(format!("Recording in progress"));
2493+
}
25032494

2495+
let project_path = path.to_path_buf();
25042496
tokio::spawn(async move { ShowCapWindow::Editor { project_path }.show(&app).await });
25052497
}
25062498
RecordingMetaInner::Instant(_) => {
@@ -2515,10 +2507,6 @@ fn open_project_from_path(path: &Path, app: AppHandle) -> Result<(), String> {
25152507
}
25162508
}
25172509
}
2518-
RecordingMetaInner::InProgress { .. } => return Err(format!("Recording in progress")),
2519-
RecordingMetaInner::Failed { .. } => {
2520-
return Err(format!("Unable to open failed recording"));
2521-
}
25222510
}
25232511

25242512
Ok(())

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

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use cap_fail::fail;
22
use cap_project::{
3-
CursorClickEvent, Platform, ProjectConfiguration, RecordingMeta, RecordingMetaInner,
4-
SharingMeta, StudioRecordingMeta, TimelineConfiguration, TimelineSegment, ZoomMode,
5-
ZoomSegment, cursor::CursorEvents,
3+
CursorClickEvent, InstantRecordingMeta, MultipleSegments, Platform, ProjectConfiguration,
4+
RecordingMeta, RecordingMetaInner, SharingMeta, StudioRecordingMeta, StudioRecordingStatus,
5+
TimelineConfiguration, TimelineSegment, ZoomMode, ZoomSegment, cursor::CursorEvents,
66
};
77
use cap_recording::{
88
RecordingError, RecordingMode,
@@ -297,7 +297,20 @@ pub async fn start_recording(
297297
project_path: recording_dir.clone(),
298298
sharing: None, // TODO: Is this gonna be problematic as it was previously always set
299299
pretty_name: format!("{target_name} {date_time}"),
300-
inner: RecordingMetaInner::InProgress { recording: true },
300+
inner: match inputs.mode {
301+
RecordingMode::Studio => {
302+
RecordingMetaInner::Studio(StudioRecordingMeta::MultipleSegments {
303+
inner: MultipleSegments {
304+
segments: Default::default(),
305+
cursors: Default::default(),
306+
status: Some(StudioRecordingStatus::InProgress),
307+
},
308+
})
309+
}
310+
RecordingMode::Instant => {
311+
RecordingMetaInner::Instant(InstantRecordingMeta::InProgress { recording: true })
312+
}
313+
},
301314
upload: None,
302315
};
303316

@@ -688,7 +701,16 @@ async fn handle_recording_end(
688701
Err(error) => {
689702
// TODO: Error handling -> Can we reuse `RecordingMeta` too?
690703
let mut project_meta = RecordingMeta::load_for_project(&recording_dir).unwrap();
691-
project_meta.inner = RecordingMetaInner::Failed { error };
704+
match &mut project_meta.inner {
705+
RecordingMetaInner::Studio(meta) => {
706+
if let StudioRecordingMeta::MultipleSegments { inner } = meta {
707+
inner.status = Some(StudioRecordingStatus::Failed { error });
708+
}
709+
}
710+
RecordingMetaInner::Instant(meta) => {
711+
*meta = InstantRecordingMeta::Failed { error };
712+
}
713+
}
692714
project_meta.save_for_project().unwrap();
693715

694716
None

apps/desktop/src/utils/tauri.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ export type Hotkey = { code: string; meta: boolean; ctrl: boolean; alt: boolean;
394394
export type HotkeyAction = "startStudioRecording" | "startInstantRecording" | "stopRecording" | "restartRecording" | "openRecordingPicker" | "openRecordingPickerDisplay" | "openRecordingPickerWindow" | "openRecordingPickerArea" | "other"
395395
export type HotkeysConfiguration = { show: boolean }
396396
export type HotkeysStore = { hotkeys: { [key in HotkeyAction]: Hotkey } }
397-
export type InstantRecordingMeta = { fps: number; sample_rate: number | null }
397+
export type InstantRecordingMeta = { recording: boolean } | { error: string } | { fps: number; sample_rate: number | null }
398398
export type JsonValue<T> = [T]
399399
export type LogicalBounds = { position: LogicalPosition; size: LogicalSize }
400400
export type LogicalPosition = { x: number; y: number }
@@ -403,7 +403,7 @@ export type MainWindowRecordingStartBehaviour = "close" | "minimise"
403403
export type ModelIDType = string
404404
export type Mp4ExportSettings = { fps: number; resolution_base: XY<number>; compression: ExportCompression }
405405
export type MultipleSegment = { display: VideoMeta; camera?: VideoMeta | null; mic?: AudioMeta | null; system_audio?: AudioMeta | null; cursor?: string | null }
406-
export type MultipleSegments = { segments: MultipleSegment[]; cursors: Cursors }
406+
export type MultipleSegments = { segments: MultipleSegment[]; cursors: Cursors; status?: StudioRecordingStatus | null }
407407
export type NewNotification = { title: string; body: string; is_error: boolean }
408408
export type NewScreenshotAdded = { path: string }
409409
export type NewStudioRecordingAdded = { path: string }
@@ -422,8 +422,8 @@ export type ProjectConfiguration = { aspectRatio: AspectRatio | null; background
422422
export type ProjectRecordingsMeta = { segments: SegmentRecordings[] }
423423
export type RecordingDeleted = { path: string }
424424
export type RecordingEvent = { variant: "Countdown"; value: number } | { variant: "Started" } | { variant: "Stopped" } | { variant: "Failed"; error: string }
425-
export type RecordingMeta = ({ recording: boolean } | { error: string } | StudioRecordingMeta | InstantRecordingMeta) & { platform?: Platform | null; pretty_name: string; sharing?: SharingMeta | null; upload?: UploadState | null }
426-
export type RecordingMetaWithMode = (({ recording: boolean } | { error: string } | StudioRecordingMeta | InstantRecordingMeta) & { platform?: Platform | null; pretty_name: string; sharing?: SharingMeta | null; upload?: UploadState | null }) & { mode: RecordingMode | null }
425+
export type RecordingMeta = (StudioRecordingMeta | InstantRecordingMeta) & { platform?: Platform | null; pretty_name: string; sharing?: SharingMeta | null; upload?: UploadState | null }
426+
export type RecordingMetaWithMode = ((StudioRecordingMeta | InstantRecordingMeta) & { platform?: Platform | null; pretty_name: string; sharing?: SharingMeta | null; upload?: UploadState | null }) & { mode: RecordingMode | null }
427427
export type RecordingMode = "studio" | "instant"
428428
export type RecordingOptionsChanged = null
429429
export type RecordingSettingsStore = { target: ScreenCaptureTarget | null; micName: string | null; cameraId: DeviceOrModelID | null; mode: RecordingMode | null; systemAudio: boolean }
@@ -448,6 +448,7 @@ export type SingleSegment = { display: VideoMeta; camera?: VideoMeta | null; aud
448448
export type StartRecordingInputs = { capture_target: ScreenCaptureTarget; capture_system_audio?: boolean; mode: RecordingMode }
449449
export type StereoMode = "stereo" | "monoL" | "monoR"
450450
export type StudioRecordingMeta = { segment: SingleSegment } | { inner: MultipleSegments }
451+
export type StudioRecordingStatus = "inProgress" | { failed: { error: string } } | "completed"
451452
export type TargetUnderCursor = { display_id: DisplayId | null; window: WindowUnderCursor | null }
452453
export type TimelineConfiguration = { segments: TimelineSegment[]; zoomSegments: ZoomSegment[]; sceneSegments?: SceneSegment[] }
453454
export type TimelineSegment = { recordingSegment?: number; timescale: number; start: number; end: number }

crates/export/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,7 @@ impl ExporterBuilder {
9999

100100
let output_path = self
101101
.output_path
102-
.or_else(|| recording_meta.output_path())
103-
.ok_or(Error::RecordingFailed)?;
102+
.unwrap_or_else(|| recording_meta.output_path());
104103

105104
if let Some(parent) = output_path.parent() {
106105
std::fs::create_dir_all(parent)

crates/project/src/meta.rs

Lines changed: 44 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -85,16 +85,26 @@ pub enum UploadState {
8585
#[derive(Debug, Clone, Serialize, Deserialize, Type)]
8686
#[serde(untagged, rename_all = "camelCase")]
8787
pub enum RecordingMetaInner {
88-
InProgress { recording: bool },
89-
Failed { error: String },
9088
Studio(StudioRecordingMeta),
9189
Instant(InstantRecordingMeta),
9290
}
9391

92+
impl specta::Flatten for RecordingMetaInner {}
93+
9494
#[derive(Debug, Clone, Serialize, Deserialize, Type)]
95-
pub struct InstantRecordingMeta {
96-
pub fps: u32,
97-
pub sample_rate: Option<u32>,
95+
#[serde(untagged, rename_all = "camelCase")]
96+
pub enum InstantRecordingMeta {
97+
InProgress {
98+
// This field means nothing and is just because this enum is untagged.
99+
recording: bool,
100+
},
101+
Failed {
102+
error: String,
103+
},
104+
Complete {
105+
fps: u32,
106+
sample_rate: Option<u32>,
107+
},
98108
}
99109

100110
impl RecordingMeta {
@@ -142,14 +152,10 @@ impl RecordingMeta {
142152
config
143153
}
144154

145-
pub fn output_path(&self) -> Option<PathBuf> {
155+
pub fn output_path(&self) -> PathBuf {
146156
match &self.inner {
147-
RecordingMetaInner::Instant(_) => Some(self.project_path.join("content/output.mp4")),
148-
RecordingMetaInner::Studio(_) => {
149-
Some(self.project_path.join("output").join("result.mp4"))
150-
}
151-
RecordingMetaInner::InProgress { .. } => None,
152-
RecordingMetaInner::Failed { .. } => None,
157+
RecordingMetaInner::Instant(_) => self.project_path.join("content/output.mp4"),
158+
RecordingMetaInner::Studio(_) => self.project_path.join("output").join("result.mp4"),
153159
}
154160
}
155161

@@ -177,12 +183,20 @@ pub enum StudioRecordingMeta {
177183
}
178184

179185
impl StudioRecordingMeta {
186+
pub fn status(&self) -> StudioRecordingStatus {
187+
match self {
188+
StudioRecordingMeta::SingleSegment { .. } => StudioRecordingStatus::Completed,
189+
StudioRecordingMeta::MultipleSegments { inner } => inner
190+
.status
191+
.clone()
192+
.unwrap_or(StudioRecordingStatus::Completed),
193+
}
194+
}
195+
180196
pub fn camera_path(&self) -> Option<RelativePathBuf> {
181197
match self {
182-
StudioRecordingMeta::SingleSegment { segment } => {
183-
segment.camera.as_ref().map(|c| c.path.clone())
184-
}
185-
StudioRecordingMeta::MultipleSegments { inner, .. } => inner
198+
Self::SingleSegment { segment } => segment.camera.as_ref().map(|c| c.path.clone()),
199+
Self::MultipleSegments { inner, .. } => inner
186200
.segments
187201
.first()
188202
.and_then(|s| s.camera.as_ref().map(|c| c.path.clone())),
@@ -191,17 +205,17 @@ impl StudioRecordingMeta {
191205

192206
pub fn min_fps(&self) -> u32 {
193207
match self {
194-
StudioRecordingMeta::SingleSegment { segment } => segment.display.fps,
195-
StudioRecordingMeta::MultipleSegments { inner, .. } => {
208+
Self::SingleSegment { segment } => segment.display.fps,
209+
Self::MultipleSegments { inner, .. } => {
196210
inner.segments.iter().map(|s| s.display.fps).min().unwrap()
197211
}
198212
}
199213
}
200214

201215
pub fn max_fps(&self) -> u32 {
202216
match self {
203-
StudioRecordingMeta::SingleSegment { segment } => segment.display.fps,
204-
StudioRecordingMeta::MultipleSegments { inner, .. } => {
217+
Self::SingleSegment { segment } => segment.display.fps,
218+
Self::MultipleSegments { inner, .. } => {
205219
inner.segments.iter().map(|s| s.display.fps).max().unwrap()
206220
}
207221
}
@@ -227,6 +241,16 @@ pub struct MultipleSegments {
227241
pub segments: Vec<MultipleSegment>,
228242
#[serde(default, skip_serializing_if = "Cursors::is_empty")]
229243
pub cursors: Cursors,
244+
#[serde(default)]
245+
pub status: Option<StudioRecordingStatus>,
246+
}
247+
248+
#[derive(Debug, Clone, Serialize, Deserialize, Type)]
249+
#[serde(rename_all = "camelCase")]
250+
pub enum StudioRecordingStatus {
251+
InProgress,
252+
Failed { error: String },
253+
Completed,
230254
}
231255

232256
#[derive(Debug, Clone, Serialize, Deserialize, Type)]

crates/recording/src/instant_recording.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ async fn stop_recording(actor: Actor) -> CompletedRecording {
480480

481481
CompletedRecording {
482482
project_path: actor.recording_dir.clone(),
483-
meta: InstantRecordingMeta {
483+
meta: InstantRecordingMeta::Complete {
484484
fps: actor.video_info.fps(),
485485
sample_rate: None,
486486
},

crates/recording/src/studio_recording.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,7 @@ async fn stop_recording(
603603
})
604604
.collect(),
605605
),
606+
status: Some(StudioRecordingStatus::Completed),
606607
},
607608
};
608609

0 commit comments

Comments
 (0)