Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions apps/desktop/src-tauri/src/deeplink_actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::{App, ArcLock, recording::StartRecordingInputs, windows::ShowCapWindo
pub enum CaptureMode {
Screen(String),
Window(String),
PrimaryScreen,
}

#[derive(Debug, Serialize, Deserialize)]
Expand All @@ -26,6 +27,14 @@ pub enum DeepLinkAction {
mode: RecordingMode,
},
StopRecording,
PauseRecording,
ResumeRecording,
SwitchMicrophone {
mic_label: Option<String>,
},
SwitchCamera {
camera: Option<DeviceOrModelID>,
},
OpenEditor {
project_path: PathBuf,
},
Expand Down Expand Up @@ -121,6 +130,11 @@ impl DeepLinkAction {
crate::set_mic_input(state.clone(), mic_label).await?;

let capture_target: ScreenCaptureTarget = match capture_mode {
CaptureMode::PrimaryScreen => cap_recording::screen_capture::list_displays()
.into_iter()
.next()
.map(|(s, _)| ScreenCaptureTarget::Display { id: s.id })
.ok_or("No screens available".to_string())?,
CaptureMode::Screen(name) => cap_recording::screen_capture::list_displays()
.into_iter()
.find(|(s, _)| s.name == name)
Expand All @@ -147,6 +161,18 @@ impl DeepLinkAction {
DeepLinkAction::StopRecording => {
crate::recording::stop_recording(app.clone(), app.state()).await
}
DeepLinkAction::PauseRecording => {
crate::recording::pause_recording(app.clone(), app.state()).await
}
DeepLinkAction::ResumeRecording => {
crate::recording::resume_recording(app.clone(), app.state()).await
}
DeepLinkAction::SwitchMicrophone { mic_label } => {
crate::set_mic_input(app.state(), mic_label).await
}
DeepLinkAction::SwitchCamera { camera } => {
crate::set_camera_input(app.clone(), app.state(), camera, None).await
}
DeepLinkAction::OpenEditor { project_path } => {
crate::open_project_from_path(Path::new(&project_path), app.clone())
}
Expand Down
79 changes: 79 additions & 0 deletions apps/raycast/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
{
"$schema": "https://www.raycast.com/downloads/extension.schema.json",
"name": "cap-controls",
"title": "Cap Controls",
"description": "Control the Cap screen recording app directly from Raycast",
"icon": "command-icon.png",
"author": "Ojas2095",
"license": "MIT",
"commands": [
{
"name": "start",
"title": "Start Recording",
"description": "Start a Cap recording",
"mode": "no-view"
},
{
"name": "stop",
"title": "Stop Recording",
"description": "Stops the current Cap recording",
"mode": "no-view"
},
{
"name": "pause",
"title": "Pause Recording",
"description": "Pauses the current Cap recording",
"mode": "no-view"
},
{
"name": "resume",
"title": "Resume Recording",
"description": "Resumes the paused Cap recording",
"mode": "no-view"
},
{
"name": "switch-mic",
"title": "Switch Microphone",
"description": "Switch Cap's recording microphone",
"mode": "no-view",
"arguments": [
{
"name": "micLabel",
"type": "text",
"placeholder": "Microphone Name (or 'none')",
"required": true
}
]
},
{
"name": "switch-camera",
"title": "Switch Camera",
"description": "Switch Cap's recording camera",
"mode": "no-view",
"arguments": [
{
"name": "cameraId",
"type": "text",
"placeholder": "Camera ID (or 'none')",
"required": true
}
]
}
],
"dependencies": {
"@raycast/api": "^1.65.0"
},
"devDependencies": {
"@raycast/eslint-config": "^1.0.6",
"@types/node": "20.8.10",
"@types/react": "18.2.27",
"eslint": "^8.51.0",
"prettier": "^3.0.3",
"typescript": "^5.2.2"
},
"scripts": {
"build": "ray build -e dist",
"dev": "ray develop",
"publish": "npx @raycast/api@latest publish"
}
}
5 changes: 5 additions & 0 deletions apps/raycast/src/pause.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { sendCapCommand } from "./utils";

export default async function Command() {
await sendCapCommand("pause_recording");
}
5 changes: 5 additions & 0 deletions apps/raycast/src/resume.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { sendCapCommand } from "./utils";

export default async function Command() {
await sendCapCommand("resume_recording");
}
11 changes: 11 additions & 0 deletions apps/raycast/src/start.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { sendCapCommand } from "./utils";

export default async function Command() {
await sendCapCommand("start_recording", {
capture_mode: "primary_screen",
camera: null,
mic_label: null,
capture_system_audio: true,
mode: "Screen"
});
}
5 changes: 5 additions & 0 deletions apps/raycast/src/stop.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { sendCapCommand } from "./utils";

export default async function Command() {
await sendCapCommand("stop_recording");
}
8 changes: 8 additions & 0 deletions apps/raycast/src/switch-camera.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { LaunchProps } from "@raycast/api";
import { sendCapCommand } from "./utils";

export default async function Command(props: LaunchProps<{ arguments: { cameraId: string } }>) {
await sendCapCommand("switch_camera", {
camera: props.arguments.cameraId === "none" ? null : { DeviceID: props.arguments.cameraId }
});
}
8 changes: 8 additions & 0 deletions apps/raycast/src/switch-mic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { LaunchProps } from "@raycast/api";
import { sendCapCommand } from "./utils";

export default async function Command(props: LaunchProps<{ arguments: { micLabel: string } }>) {
await sendCapCommand("switch_microphone", {
mic_label: props.arguments.micLabel === "none" ? null : props.arguments.micLabel
});
}
17 changes: 17 additions & 0 deletions apps/raycast/src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { open, showHUD } from "@raycast/api";

export async function sendCapCommand(action: string, objectValue?: Record<string, unknown>) {

const valuePayload = objectValue
? JSON.stringify({ [action]: objectValue })
: `"${action}"`;

const url = `cap://action?value=${encodeURIComponent(valuePayload)}`;
try {
await open(url);
await showHUD(`Sent to Cap`);
} catch (error) {
await showHUD("Failed to communicate with Cap. Is it installed?");
console.error(error);
}
}
14 changes: 14 additions & 0 deletions apps/raycast/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"module": "CommonJS",
"target": "ES2021",
"jsx": "react",
"lib": ["ES2021", "DOM"],
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node"
},
"include": ["src/**/*"]
}