-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Add Raycast extension for Cap recording controls #1825
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
Open
xiongbear01
wants to merge
3
commits into
CapSoftware:main
Choose a base branch
from
xiongbear01:bounty-1540-raycast-deeplinks
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| # Cap Raycast Extension | ||
|
|
||
| Control the Cap desktop app from Raycast using Cap's `cap://action` deep links. | ||
|
|
||
| ## Commands | ||
|
|
||
| - Start Studio Recording | ||
| - Start Instant Recording | ||
| - Record Display | ||
| - Record Window | ||
| - Record Area | ||
| - Pause Recording | ||
| - Resume Recording | ||
| - Toggle Recording Pause | ||
| - Stop Recording | ||
| - Set Microphone | ||
| - Clear Microphone | ||
| - Set Camera | ||
| - Clear Camera | ||
|
|
||
| The microphone command expects the exact Cap microphone label. The camera command accepts either a camera device ID or model ID. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,106 @@ | ||
| { | ||
| "$schema": "https://www.raycast.com/schemas/extension.json", | ||
| "name": "cap", | ||
| "title": "Cap", | ||
| "description": "Control Cap recordings from Raycast.", | ||
| "icon": "extension-icon.png", | ||
| "author": "CapSoftware", | ||
| "categories": [ | ||
| "Productivity", | ||
| "Developer Tools" | ||
| ], | ||
| "license": "MIT", | ||
| "commands": [ | ||
| { | ||
| "name": "start-studio-recording", | ||
| "title": "Start Studio Recording", | ||
| "description": "Start a Cap Studio recording with saved settings.", | ||
| "mode": "no-view" | ||
| }, | ||
| { | ||
| "name": "start-instant-recording", | ||
| "title": "Start Instant Recording", | ||
| "description": "Start a Cap Instant recording with saved settings.", | ||
| "mode": "no-view" | ||
| }, | ||
| { | ||
| "name": "record-display", | ||
| "title": "Record Display", | ||
| "description": "Open Cap's display recording picker.", | ||
| "mode": "no-view" | ||
| }, | ||
| { | ||
| "name": "record-window", | ||
| "title": "Record Window", | ||
| "description": "Open Cap's window recording picker.", | ||
| "mode": "no-view" | ||
| }, | ||
| { | ||
| "name": "record-area", | ||
| "title": "Record Area", | ||
| "description": "Open Cap's area recording picker.", | ||
| "mode": "no-view" | ||
| }, | ||
| { | ||
| "name": "pause-recording", | ||
| "title": "Pause Recording", | ||
| "description": "Pause the current Cap recording.", | ||
| "mode": "no-view" | ||
| }, | ||
| { | ||
| "name": "resume-recording", | ||
| "title": "Resume Recording", | ||
| "description": "Resume the current Cap recording.", | ||
| "mode": "no-view" | ||
| }, | ||
| { | ||
| "name": "toggle-pause-recording", | ||
| "title": "Toggle Recording Pause", | ||
| "description": "Pause or resume the current Cap recording.", | ||
| "mode": "no-view" | ||
| }, | ||
| { | ||
| "name": "stop-recording", | ||
| "title": "Stop Recording", | ||
| "description": "Stop the current Cap recording.", | ||
| "mode": "no-view" | ||
| }, | ||
| { | ||
| "name": "set-microphone", | ||
| "title": "Set Microphone", | ||
| "description": "Switch Cap's selected microphone by label.", | ||
| "mode": "view" | ||
| }, | ||
| { | ||
| "name": "clear-microphone", | ||
| "title": "Clear Microphone", | ||
| "description": "Disable Cap's selected microphone.", | ||
| "mode": "no-view" | ||
| }, | ||
| { | ||
| "name": "set-camera", | ||
| "title": "Set Camera", | ||
| "description": "Switch Cap's selected camera by device or model ID.", | ||
| "mode": "view" | ||
| }, | ||
| { | ||
| "name": "clear-camera", | ||
| "title": "Clear Camera", | ||
| "description": "Disable Cap's selected camera.", | ||
| "mode": "no-view" | ||
| } | ||
| ], | ||
| "dependencies": { | ||
| "@raycast/api": "^1.104.17" | ||
| }, | ||
| "devDependencies": { | ||
| "@types/node": "22.15.17", | ||
| "typescript": "^5.8.3" | ||
| }, | ||
| "scripts": { | ||
| "build": "ray build", | ||
| "dev": "ray develop", | ||
| "lint": "ray lint", | ||
| "publish:raycast": "ray publish" | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| /// <reference types="@raycast/api"> | ||
|
|
||
| /* 🚧 🚧 🚧 | ||
| * This file is auto-generated from the extension's manifest. | ||
| * Do not modify manually. Instead, update the `package.json` file. | ||
| * 🚧 🚧 🚧 */ | ||
|
|
||
| /* eslint-disable @typescript-eslint/ban-types */ | ||
|
|
||
| type ExtensionPreferences = {} | ||
|
|
||
| /** Preferences accessible in all the extension's commands */ | ||
| declare type Preferences = ExtensionPreferences | ||
|
|
||
| declare namespace Preferences { | ||
| /** Preferences accessible in the `start-studio-recording` command */ | ||
| export type StartStudioRecording = ExtensionPreferences & {} | ||
| /** Preferences accessible in the `start-instant-recording` command */ | ||
| export type StartInstantRecording = ExtensionPreferences & {} | ||
| /** Preferences accessible in the `record-display` command */ | ||
| export type RecordDisplay = ExtensionPreferences & {} | ||
| /** Preferences accessible in the `record-window` command */ | ||
| export type RecordWindow = ExtensionPreferences & {} | ||
| /** Preferences accessible in the `record-area` command */ | ||
| export type RecordArea = ExtensionPreferences & {} | ||
| /** Preferences accessible in the `pause-recording` command */ | ||
| export type PauseRecording = ExtensionPreferences & {} | ||
| /** Preferences accessible in the `resume-recording` command */ | ||
| export type ResumeRecording = ExtensionPreferences & {} | ||
| /** Preferences accessible in the `toggle-pause-recording` command */ | ||
| export type TogglePauseRecording = ExtensionPreferences & {} | ||
| /** Preferences accessible in the `stop-recording` command */ | ||
| export type StopRecording = ExtensionPreferences & {} | ||
| /** Preferences accessible in the `set-microphone` command */ | ||
| export type SetMicrophone = ExtensionPreferences & {} | ||
| /** Preferences accessible in the `clear-microphone` command */ | ||
| export type ClearMicrophone = ExtensionPreferences & {} | ||
| /** Preferences accessible in the `set-camera` command */ | ||
| export type SetCamera = ExtensionPreferences & {} | ||
| /** Preferences accessible in the `clear-camera` command */ | ||
| export type ClearCamera = ExtensionPreferences & {} | ||
| } | ||
|
|
||
| declare namespace Arguments { | ||
| /** Arguments passed to the `start-studio-recording` command */ | ||
| export type StartStudioRecording = {} | ||
| /** Arguments passed to the `start-instant-recording` command */ | ||
| export type StartInstantRecording = {} | ||
| /** Arguments passed to the `record-display` command */ | ||
| export type RecordDisplay = {} | ||
| /** Arguments passed to the `record-window` command */ | ||
| export type RecordWindow = {} | ||
| /** Arguments passed to the `record-area` command */ | ||
| export type RecordArea = {} | ||
| /** Arguments passed to the `pause-recording` command */ | ||
| export type PauseRecording = {} | ||
| /** Arguments passed to the `resume-recording` command */ | ||
| export type ResumeRecording = {} | ||
| /** Arguments passed to the `toggle-pause-recording` command */ | ||
| export type TogglePauseRecording = {} | ||
| /** Arguments passed to the `stop-recording` command */ | ||
| export type StopRecording = {} | ||
| /** Arguments passed to the `set-microphone` command */ | ||
| export type SetMicrophone = {} | ||
| /** Arguments passed to the `clear-microphone` command */ | ||
| export type ClearMicrophone = {} | ||
| /** Arguments passed to the `set-camera` command */ | ||
| export type SetCamera = {} | ||
| /** Arguments passed to the `clear-camera` command */ | ||
| export type ClearCamera = {} | ||
| } | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,56 @@ | ||||||||||||||||||||||||||||||
| import { open, showToast, Toast } from "@raycast/api"; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| type RecordingMode = "studio" | "instant" | "screenshot"; | ||||||||||||||||||||||||||||||
| type RecordingTargetMode = "display" | "window" | "area" | "camera"; | ||||||||||||||||||||||||||||||
| type DeviceOrModelID = | ||||||||||||||||||||||||||||||
| | { | ||||||||||||||||||||||||||||||
| DeviceID: string; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| | { | ||||||||||||||||||||||||||||||
| ModelID: string; | ||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| type DeepLinkAction = | ||||||||||||||||||||||||||||||
| | { | ||||||||||||||||||||||||||||||
| start_recording_with_settings: { | ||||||||||||||||||||||||||||||
| mode: RecordingMode; | ||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| | "stop_recording" | ||||||||||||||||||||||||||||||
| | "pause_recording" | ||||||||||||||||||||||||||||||
| | "resume_recording" | ||||||||||||||||||||||||||||||
| | "toggle_pause_recording" | ||||||||||||||||||||||||||||||
| | { | ||||||||||||||||||||||||||||||
| open_recording_picker: { | ||||||||||||||||||||||||||||||
| target_mode: RecordingTargetMode | null; | ||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| | { | ||||||||||||||||||||||||||||||
| set_mic_input: { | ||||||||||||||||||||||||||||||
| label: string | null; | ||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| | { | ||||||||||||||||||||||||||||||
| set_camera_input: { | ||||||||||||||||||||||||||||||
| id: DeviceOrModelID | null; | ||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| export async function runCapAction(action: DeepLinkAction, title: string) { | ||||||||||||||||||||||||||||||
| const url = new URL("cap://action"); | ||||||||||||||||||||||||||||||
| url.searchParams.set("value", JSON.stringify(action)); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| await open(url.toString()); | ||||||||||||||||||||||||||||||
| await showToast({ | ||||||||||||||||||||||||||||||
| style: Toast.Style.Success, | ||||||||||||||||||||||||||||||
| title, | ||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| export function deviceId(value: string): DeviceOrModelID { | ||||||||||||||||||||||||||||||
| return { DeviceID: value }; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| export function modelId(value: string): DeviceOrModelID { | ||||||||||||||||||||||||||||||
| return { ModelID: value }; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
Comment on lines
+50
to
+56
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.
Suggested change
Prompt To Fix With AIThis is a comment left during a code review.
Path: extensions/raycast/src/cap.ts
Line: 50-56
Comment:
The `deviceId` and `modelId` helpers produce objects with snake_case keys (`device_id`, `model_id`), which won't match the expected PascalCase keys after fixing the type definition above.
```suggestion
export function deviceId(value: string): DeviceOrModelID {
return { DeviceID: value };
}
export function modelId(value: string): DeviceOrModelID {
return { ModelID: value };
}
```
How can I resolve this? If you propose a fix, please make it concise. |
||||||||||||||||||||||||||||||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| import { runCapAction } from "./cap"; | ||
|
|
||
| export default async function Command() { | ||
| await runCapAction({ set_camera_input: { id: null } }, "Clearing camera"); | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
DeviceOrModelIDfield names are snake_case (device_id,model_id) but the Rust enumDeviceOrModelIDserializes without anyrename_allattribute, defaulting to PascalCase —{"DeviceID": "..."}and{"ModelID": "..."}. The existing TypeScript type inapps/desktop/src/utils/tauri.tsconfirms this:{ DeviceID: string } | { ModelID: ModelIDType }. As written,set-camerawill send a payload that fails serde deserialization on the Rust side and the action will silently be dropped.Prompt To Fix With AI