Skip to content

Add Find My Phone sound playing script command using Playwright #992

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

Merged
merged 1 commit into from
Jun 12, 2025
Merged
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
8 changes: 8 additions & 0 deletions commands/README.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions commands/apps/find-my/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ICLOUD_EMAIL=
ICLOUD_PASSWORD=
DEVICE=
58 changes: 58 additions & 0 deletions commands/apps/find-my/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Find My Phone Raycast

I lose my phone often, so I made this.

This is a Node.js script that uses Playwright to automate iCloud Find My and trigger a sound on your Apple device. It's perfect for people like me who misplace their phones and want a quick, automated way to make them ring—with Raycast.

## Usage

```sh
git clone https://github.com/vsvaidya27/fmp-raycast
cd fmp-raycast
npm install
cp .env.example .env
# Edit .env with your real credentials
chmod +x fmp.js
```

### Add to Raycast

1. Open Raycast and go to **Extensions**.
2. Click **Add**.
3. Select **Add Script Directory**.
4. Choose the `fmp-raycast` directory you just cloned.
5. Set fmp as your alias for calling the script.

Now you can trigger the script directly from Raycast!

## How it works

- Automates login to iCloud Find My using Playwright
- Selects your device by name
- Triggers the "Play Sound" feature to help you locate your device

**Note:** You'll need to provide your iCloud credentials and device name in the `.env` file. Sometimes a 2FA check may pop up, but usually they allow you to bypass this and manual intervention is not neccesary (since you often need the very thing you are trying to find for 2FA).

---

## 🛠 Troubleshooting

### If you get the error `env: node: No such file or directory`

Raycast uses a limited shell environment, so it may not find your Node.js install.

To fix it:

1. Run this in Terminal to find your full Node path:
```bash
which node
```
2. Edit the top of `fmp.js`:
Replace:
```sh
#!/usr/bin/env node
```
With:
```sh
#!/full/path/to/node
```
62 changes: 62 additions & 0 deletions commands/apps/find-my/fmp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/usr/bin/env node

// Required parameters:
// @raycast.schemaVersion 1
// @raycast.title Find My Phone (Auto Sound)
// @raycast.mode silent
// @raycast.packageName FindMy
// @raycast.icon images/find-my-icon.png

require('dotenv').config();
const { chromium } = require('playwright');

(async () => {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();

// 1. Go to iCloud Find Devices
await page.goto('https://www.icloud.com/find');

// 2. Click "Sign In"
await page.waitForSelector('text=Sign In', { timeout: 20000 });
await page.click('text=Sign In');

// 3. Wait for the Apple login iframe to appear
const frameLocator = page.frameLocator('iframe[name="aid-auth-widget"]');

// 4. Wait for the email/phone input inside the iframe
await frameLocator.getByRole('textbox', { name: 'Email or Phone Number' }).waitFor({ timeout: 20000 });

// 5. Fill in the email/phone
await frameLocator.getByRole('textbox', { name: 'Email or Phone Number' }).fill(process.env.ICLOUD_EMAIL);

// 6. Click the right-arrow button
await frameLocator.getByRole('button').first().click();

// 7. Wait for the "Continue with Password" button to appear, then click it
await frameLocator.getByRole('button', { name: /Continue with Password/i }).waitFor({ timeout: 20000 });
await frameLocator.getByRole('button', { name: /Continue with Password/i }).click();

// 8. Wait for password input
await frameLocator.getByRole('textbox', { name: 'Password' }).waitFor({ timeout: 20000 });
await frameLocator.getByRole('textbox', { name: 'Password' }).fill(process.env.ICLOUD_PASSWORD);

// 9. Click the arrow button to continue
await frameLocator.getByRole('button').first().click();

// 10. Wait for 2FA if needed; Hopefully not because this kinda defeats the purpose of automation even though its prob for the best security-wise :(
console.log('If prompted, please complete 2FA in the browser window. :(');

// 12. Click on your iPhone using the precise selector inside the second iframe
await page.locator('iframe').nth(1).contentFrame().getByTitle(process.env.DEVICE).getByTestId('show-device-name').click();

// 13. Wait for the device details panel to load
await page.waitForTimeout(2000);

// 14. Click the "Play Sound" button
await page.locator('iframe').nth(1).contentFrame().getByRole('button', { name: 'Play Sound' }).click();

console.log('✅ Play Sound triggered for ' + process.env.DEVICE + '!');
await browser.close();
})();

Binary file added commands/apps/find-my/images/find-my-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions commands/apps/find-my/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "findmyraycast",
"version": "1.0.0",
"main": "fmp.js",
"scripts": {
"start": "node fmp.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"dependencies": {
"dotenv": "^16.5.0",
"playwright": "^1.52.0"
}
}