-
Notifications
You must be signed in to change notification settings - Fork 1.2k
feat: Deeplink enhancements + Raycast extension (#1540) #1572
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
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 | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,59 @@ | ||||||
| # Cap Raycast Extension | ||||||
|
|
||||||
| Control Cap screen recorder directly from Raycast. | ||||||
|
|
||||||
| ## Features | ||||||
|
|
||||||
| - **Start Recording** - Begin a new screen recording | ||||||
| - **Stop Recording** - End the current recording | ||||||
| - **Pause Recording** - Pause the current recording | ||||||
| - **Resume Recording** - Resume a paused recording | ||||||
| - **Toggle Pause** - Toggle between paused/recording states | ||||||
|
|
||||||
| ## Installation | ||||||
|
|
||||||
| 1. Install the Cap desktop app from [cap.so](https://cap.so) | ||||||
| 2. Open Raycast | ||||||
| 3. Search for "Cap" in the Raycast Store | ||||||
| 4. Install the extension | ||||||
|
|
||||||
| ## Development | ||||||
|
|
||||||
| ```bash | ||||||
| cd extensions/raycast | ||||||
| npm install | ||||||
| npm run dev | ||||||
| ``` | ||||||
|
|
||||||
| ## How it Works | ||||||
|
|
||||||
| This extension uses Cap's deeplink protocol (`cap-desktop://`) to communicate with the desktop app. Each command sends a specific deeplink action: | ||||||
|
|
||||||
| | Command | Deeplink Action | | ||||||
| |---------|-----------------| | ||||||
| | Start Recording | `start_recording` | | ||||||
|
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. Docs mismatch:
Suggested change
|
||||||
| | Stop Recording | `stop_recording` | | ||||||
| | Pause Recording | `pause_recording` | | ||||||
| | Resume Recording | `resume_recording` | | ||||||
| | Toggle Pause | `toggle_pause_recording` | | ||||||
|
|
||||||
| ## Deeplink Format | ||||||
|
|
||||||
| ``` | ||||||
| cap-desktop://action?value={"action_name": {...params}} | ||||||
| ``` | ||||||
|
|
||||||
| Example: | ||||||
| ``` | ||||||
| cap-desktop://action?value={"pause_recording":null} | ||||||
| ``` | ||||||
|
|
||||||
| ## Requirements | ||||||
|
|
||||||
| - macOS 11.0 or later | ||||||
| - Cap desktop app installed | ||||||
| - Raycast installed | ||||||
|
|
||||||
| ## License | ||||||
|
|
||||||
| MIT | ||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,61 @@ | ||||||
| { | ||||||
| "$schema": "https://www.raycast.com/schemas/extension.json", | ||||||
| "name": "cap", | ||||||
| "title": "Cap", | ||||||
| "description": "Control Cap screen recorder with Raycast", | ||||||
|
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. The referenced icon file
Suggested change
Prompt To Fix With AIThis is a comment left during a code review.
Path: extensions/raycast/package.json
Line: 5:5
Comment:
The referenced icon file `cap-icon.png` is missing from the `extensions/raycast/` directory. Ensure the icon file is added before publishing.
```suggestion
"icon": "cap-icon.png",
```
How can I resolve this? If you propose a fix, please make it concise. |
||||||
| "icon": "assets/cap-icon.png", | ||||||
| "author": "cap-software", | ||||||
| "categories": ["Productivity", "Media"], | ||||||
| "license": "MIT", | ||||||
| "commands": [ | ||||||
| { | ||||||
| "name": "start-recording", | ||||||
| "title": "Start Recording", | ||||||
| "description": "Start a screen recording with Cap", | ||||||
| "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", | ||||||
|
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. Small formatting nit: stray trailing whitespace.
Suggested change
|
||||||
| "description": "Resume a paused recording", | ||||||
| "mode": "no-view" | ||||||
| }, | ||||||
| { | ||||||
| "name": "toggle-pause", | ||||||
| "title": "Toggle Pause", | ||||||
| "description": "Toggle pause/resume on current recording", | ||||||
| "mode": "no-view" | ||||||
| } | ||||||
| ], | ||||||
| "dependencies": { | ||||||
| "@raycast/api": "^1.83.0" | ||||||
| }, | ||||||
| "devDependencies": { | ||||||
| "@raycast/eslint-config": "^1.0.11", | ||||||
| "@types/node": "20.8.10", | ||||||
| "@types/react": "18.3.3", | ||||||
| "eslint": "^8.57.0", | ||||||
| "prettier": "^3.3.3", | ||||||
| "typescript": "^5.4.5" | ||||||
| }, | ||||||
| "scripts": { | ||||||
| "build": "ray build --skip-types -e dist -o dist", | ||||||
| "dev": "ray develop", | ||||||
| "fix-lint": "ray lint --fix", | ||||||
| "lint": "ray lint", | ||||||
| "prepublishOnly": "echo \"\\n\\nIt seems like you are trying to publish the Raycast extension to npm.\\n\\nIf you did intend to publish it to npm, remove the \\`prepublishOnly\\` script and rerun \\`npm publish\\` again.\\nIf you wanted to publish it to the Raycast Store instead, use \\`npm run publish\\` instead.\\n\\n\" && exit 1", | ||||||
| "publish": "npx @raycast/api@latest publish" | ||||||
| } | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,13 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { open, showHUD } from "@raycast/api"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export default async function Command() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const action = { pause_recording: null }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const deeplink = `cap-desktop://action?value=${encodeURIComponent(JSON.stringify(action))}`; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await open(deeplink); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await showHUD("⏸️ Recording paused"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await showHUD("❌ Failed to pause recording"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+1
to
+13
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. Minor TS/ESLint cleanup: the caught
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import { open, showHUD } from "@raycast/api"; | ||
|
|
||
| export default async function Command() { | ||
| const action = { resume_recording: null }; | ||
| const deeplink = `cap-desktop://action?value=${encodeURIComponent(JSON.stringify(action))}`; | ||
|
|
||
| try { | ||
| await open(deeplink); | ||
| await showHUD("▶️ Recording resumed"); | ||
| } catch (error) { | ||
| await showHUD("❌ Failed to resume recording"); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| import { open, showHUD, getApplications } from "@raycast/api"; | ||
|
|
||
| export default async function Command() { | ||
| const apps = await getApplications(); | ||
| const capInstalled = apps.some( | ||
| (app) => app.bundleId === "so.cap.desktop" || app.bundleId === "so.cap.desktop.dev" | ||
| ); | ||
|
|
||
| if (!capInstalled) { | ||
| await showHUD("❌ Cap is not installed"); | ||
| return; | ||
| } | ||
|
|
||
| const action = { | ||
| open_settings: { page: "recording" } | ||
| }; | ||
|
|
||
| const deeplink = `cap-desktop://action?value=${encodeURIComponent(JSON.stringify(action))}`; | ||
|
|
||
| try { | ||
| await open(deeplink); | ||
| await showHUD("📺 Opening Cap recording settings..."); | ||
| } catch (error) { | ||
| await showHUD("❌ Failed to open Cap"); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import { open, showHUD } from "@raycast/api"; | ||
|
|
||
| export default async function Command() { | ||
| const action = { stop_recording: null }; | ||
| const deeplink = `cap-desktop://action?value=${encodeURIComponent(JSON.stringify(action))}`; | ||
|
|
||
| try { | ||
| await open(deeplink); | ||
| await showHUD("⏹️ Recording stopped"); | ||
| } catch (error) { | ||
| await showHUD("❌ Failed to stop recording"); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import { open, showHUD } from "@raycast/api"; | ||
|
|
||
| export default async function Command() { | ||
| const action = { toggle_pause_recording: null }; | ||
| const deeplink = `cap-desktop://action?value=${encodeURIComponent(JSON.stringify(action))}`; | ||
|
|
||
| try { | ||
| await open(deeplink); | ||
| await showHUD("⏯️ Recording pause toggled"); | ||
| } catch (error) { | ||
| await showHUD("❌ Failed to toggle pause"); | ||
| } | ||
| } |
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.
With the new deeplink actions, an empty payload like
{"set_camera":{}}parses asNoneand gets forwarded to the setters. IfNoneisn't meant to clear the selection, it may be worth rejecting missing params explicitly.