-
Notifications
You must be signed in to change notification settings - Fork 1.2k
feat: Add deeplink actions and Raycast extension #1542
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
e924893
a4a8587
ea92442
71f55bf
53fc491
b90d11a
934804c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -26,6 +26,18 @@ pub enum DeepLinkAction { | |||||||||||||||||||
| mode: RecordingMode, | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| StopRecording, | ||||||||||||||||||||
| PauseRecording, | ||||||||||||||||||||
| ResumeRecording, | ||||||||||||||||||||
| TogglePauseRecording, | ||||||||||||||||||||
| TakeScreenshot { | ||||||||||||||||||||
| target: ScreenCaptureTarget, | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| SetCamera { | ||||||||||||||||||||
| camera_id: Option<DeviceOrModelID>, | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| SetMicrophone { | ||||||||||||||||||||
| mic_label: Option<String>, | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| OpenEditor { | ||||||||||||||||||||
| project_path: PathBuf, | ||||||||||||||||||||
| }, | ||||||||||||||||||||
|
|
@@ -146,6 +158,28 @@ 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::TogglePauseRecording => { | ||||||||||||||||||||
| crate::recording::toggle_pause_recording(app.clone(), app.state()).await | ||||||||||||||||||||
| } | ||||||||||||||||||||
| DeepLinkAction::TakeScreenshot { target } => { | ||||||||||||||||||||
| crate::recording::take_screenshot(app.clone(), target) | ||||||||||||||||||||
| .await | ||||||||||||||||||||
| .map(|_| ()) | ||||||||||||||||||||
| } | ||||||||||||||||||||
| DeepLinkAction::SetCamera { camera_id } => { | ||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Follow-up for the
Suggested change
|
||||||||||||||||||||
| let state = app.state::<ArcLock<App>>(); | ||||||||||||||||||||
| crate::set_camera_input(app.clone(), state, camera_id).await | ||||||||||||||||||||
| } | ||||||||||||||||||||
| DeepLinkAction::SetMicrophone { mic_label } => { | ||||||||||||||||||||
| let state = app.state::<ArcLock<App>>(); | ||||||||||||||||||||
| crate::set_mic_input(state, mic_label).await | ||||||||||||||||||||
| } | ||||||||||||||||||||
| DeepLinkAction::OpenEditor { project_path } => { | ||||||||||||||||||||
| crate::open_project_from_path(Path::new(&project_path), app.clone()) | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| # Cap Raycast Extension | ||
|
|
||
| Control Cap screen recording directly from Raycast. | ||
|
|
||
| ## Features | ||
|
|
||
| - **Start Recording**: Start a new Cap recording | ||
| - **Stop Recording**: Stop the current recording | ||
| - **Pause/Resume**: Pause and resume recordings | ||
| - **Toggle Pause**: Toggle pause state with one command | ||
| - **Take Screenshot**: Capture screenshots with Cap | ||
|
|
||
| ## Installation | ||
|
|
||
| 1. Make sure you have [Cap](https://cap.so) installed | ||
| 2. Install this extension in Raycast | ||
| 3. Use the commands to control Cap | ||
|
|
||
| ## Usage | ||
|
|
||
| All commands use Cap's deeplink protocol to communicate with the desktop app. Make sure Cap is running before using these commands. | ||
|
|
||
| ## Development | ||
|
|
||
| ```bash | ||
| npm install | ||
| npm run dev | ||
| ``` | ||
|
|
||
| ## License | ||
|
|
||
| MIT | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| { | ||
| "$schema": "https://www.raycast.com/schemas/extension.json", | ||
| "name": "cap", | ||
| "title": "Cap", | ||
| "description": "Control Cap screen recording from Raycast", | ||
| "icon": "icon.png", | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: missing Prompt To Fix With AIThis is a comment left during a code review.
Path: raycast-cap-extension/package.json
Line: 6:6
Comment:
**logic:** missing `icon.png` file - extension will fail to load in Raycast without this required asset
How can I resolve this? If you propose a fix, please make it concise. |
||
| "author": "bikramadhikari001", | ||
| "categories": [ | ||
| "Productivity", | ||
| "Media" | ||
| ], | ||
| "license": "MIT", | ||
| "commands": [ | ||
| { | ||
| "name": "start-recording", | ||
| "title": "Start Recording", | ||
| "description": "Start a new Cap recording", | ||
| "mode": "no-view" | ||
| }, | ||
| { | ||
| "name": "stop-recording", | ||
| "title": "Stop Recording", | ||
| "description": "Stop the current recording", | ||
| "mode": "no-view" | ||
| }, | ||
| { | ||
| "name": "pause-recording", | ||
| "title": "Pause Recording", | ||
| "description": "Pause the current recording", | ||
| "mode": "no-view" | ||
| }, | ||
| { | ||
| "name": "resume-recording", | ||
| "title": "Resume Recording", | ||
| "description": "Resume the paused recording", | ||
| "mode": "no-view" | ||
| }, | ||
| { | ||
| "name": "toggle-pause-recording", | ||
| "title": "Toggle Pause Recording", | ||
| "description": "Toggle pause/resume for the current recording", | ||
| "mode": "no-view" | ||
| }, | ||
| { | ||
| "name": "take-screenshot", | ||
| "title": "Take Screenshot", | ||
| "description": "Take a screenshot with Cap", | ||
| "mode": "no-view" | ||
| } | ||
| ], | ||
| "dependencies": { | ||
| "@raycast/api": "^1.87.0", | ||
| "@raycast/utils": "^1.19.0" | ||
| }, | ||
| "devDependencies": { | ||
| "@raycast/eslint-config": "^1.0.11", | ||
| "@types/node": "20.8.10", | ||
| "@types/react": "18.3.3", | ||
| "eslint": "^8.57.0", | ||
| "prettier": "^3.2.5", | ||
| "typescript": "^5.4.5" | ||
| }, | ||
| "scripts": { | ||
| "build": "ray build -e dist", | ||
| "dev": "ray develop", | ||
| "fix-lint": "ray lint --fix", | ||
| "lint": "ray lint", | ||
| "publish": "npx @raycast/api@latest publish" | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import { open, showToast, Toast } from "@raycast/api"; | ||
|
|
||
| export default async function Command() { | ||
| try { | ||
| const action = { pause_recording: {} }; | ||
| const url = `cap-desktop://action?value=${encodeURIComponent(JSON.stringify(action))}`; | ||
| await open(url); | ||
| await showToast({ style: Toast.Style.Success, title: "Pause recording requested" }); | ||
| } catch (error) { | ||
| await showToast({ style: Toast.Style.Failure, title: "Failed to pause recording", message: String(error) }); | ||
| } | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import { open, showToast, Toast } from "@raycast/api"; | ||
|
|
||
| export default async function Command() { | ||
| try { | ||
| const action = { resume_recording: {} }; | ||
| const url = `cap-desktop://action?value=${encodeURIComponent(JSON.stringify(action))}`; | ||
| await open(url); | ||
| await showToast({ style: Toast.Style.Success, title: "Resume recording requested" }); | ||
| } catch (error) { | ||
| await showToast({ style: Toast.Style.Failure, title: "Failed to resume recording", message: String(error) }); | ||
| } | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| import { open, showToast, Toast } from "@raycast/api"; | ||
|
|
||
| export default async function Command() { | ||
| try { | ||
| const action = { | ||
| start_recording: { | ||
| capture_mode: { screen: "" }, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using |
||
| camera: null, | ||
| mic_label: null, | ||
| capture_system_audio: true, | ||
| mode: "studio" | ||
| } | ||
| }; | ||
| const url = `cap-desktop://action?value=${encodeURIComponent(JSON.stringify(action))}`; | ||
| await open(url); | ||
| await showToast({ style: Toast.Style.Success, title: "Start recording requested" }); | ||
| } catch (error) { | ||
| await showToast({ style: Toast.Style.Failure, title: "Failed to start recording", message: String(error) }); | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import { open, showToast, Toast } from "@raycast/api"; | ||
|
|
||
| export default async function Command() { | ||
| try { | ||
| const action = { stop_recording: {} }; | ||
| const url = `cap-desktop://action?value=${encodeURIComponent(JSON.stringify(action))}`; | ||
| await open(url); | ||
| await showToast({ style: Toast.Style.Success, title: "Stop recording requested" }); | ||
| } catch (error) { | ||
| await showToast({ style: Toast.Style.Failure, title: "Failed to stop recording", message: String(error) }); | ||
| } | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| import { open, showToast, Toast } from "@raycast/api"; | ||
|
|
||
| export default async function Command() { | ||
| try { | ||
| const action = { | ||
| take_screenshot: { | ||
| target: { variant: "display", id: "0" } | ||
| } | ||
| }; | ||
| const url = `cap-desktop://action?value=${encodeURIComponent(JSON.stringify(action))}`; | ||
| await open(url); | ||
| await showToast({ style: Toast.Style.Success, title: "Screenshot requested" }); | ||
| } catch (error) { | ||
| await showToast({ style: Toast.Style.Failure, title: "Failed to take screenshot", message: String(error) }); | ||
| } | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import { open, showToast, Toast } from "@raycast/api"; | ||
|
|
||
| export default async function Command() { | ||
| try { | ||
| const action = { toggle_pause_recording: {} }; | ||
| const url = `cap-desktop://action?value=${encodeURIComponent(JSON.stringify(action))}`; | ||
| await open(url); | ||
| await showToast({ style: Toast.Style.Success, title: "Toggle pause requested" }); | ||
| } catch (error) { | ||
| await showToast({ style: Toast.Style.Failure, title: "Failed to toggle pause", message: String(error) }); | ||
| } | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| { | ||
| "$schema": "https://json.schemastore.org/tsconfig", | ||
| "compilerOptions": { | ||
| "target": "ES2022", | ||
| "lib": ["ES2022"], | ||
| "module": "commonjs", | ||
| "jsx": "react", | ||
| "strict": true, | ||
| "esModuleInterop": true, | ||
| "skipLibCheck": true, | ||
| "forceConsistentCasingInFileNames": true, | ||
| "resolveJsonModule": true, | ||
| "moduleResolution": "node" | ||
| }, | ||
| "include": ["src/**/*"] | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small thing:
set_camera_input/set_mic_inputalready acceptOption<...>so callers can clear the selection; making the deeplink payload acceptnullhere would keep things consistent withStartRecordingand avoid needing separate actions.