|
| 1 | +#!/usr/bin/env node |
| 2 | + |
| 3 | +// Required parameters: |
| 4 | +// @raycast.schemaVersion 1 |
| 5 | +// @raycast.title Find My Phone (Auto Sound) |
| 6 | +// @raycast.mode silent |
| 7 | +// @raycast.packageName FindMy |
| 8 | +// @raycast.icon images/find-my-icon.png |
| 9 | + |
| 10 | +require('dotenv').config(); |
| 11 | +const { chromium } = require('playwright'); |
| 12 | + |
| 13 | +(async () => { |
| 14 | + const browser = await chromium.launch({ headless: false }); |
| 15 | + const page = await browser.newPage(); |
| 16 | + |
| 17 | + // 1. Go to iCloud Find Devices |
| 18 | + await page.goto('https://www.icloud.com/find'); |
| 19 | + |
| 20 | + // 2. Click "Sign In" |
| 21 | + await page.waitForSelector('text=Sign In', { timeout: 20000 }); |
| 22 | + await page.click('text=Sign In'); |
| 23 | + |
| 24 | + // 3. Wait for the Apple login iframe to appear |
| 25 | + const frameLocator = page.frameLocator('iframe[name="aid-auth-widget"]'); |
| 26 | + |
| 27 | + // 4. Wait for the email/phone input inside the iframe |
| 28 | + await frameLocator.getByRole('textbox', { name: 'Email or Phone Number' }).waitFor({ timeout: 20000 }); |
| 29 | + |
| 30 | + // 5. Fill in the email/phone |
| 31 | + await frameLocator.getByRole('textbox', { name: 'Email or Phone Number' }).fill(process.env.ICLOUD_EMAIL); |
| 32 | + |
| 33 | + // 6. Click the right-arrow button |
| 34 | + await frameLocator.getByRole('button').first().click(); |
| 35 | + |
| 36 | + // 7. Wait for the "Continue with Password" button to appear, then click it |
| 37 | + await frameLocator.getByRole('button', { name: /Continue with Password/i }).waitFor({ timeout: 20000 }); |
| 38 | + await frameLocator.getByRole('button', { name: /Continue with Password/i }).click(); |
| 39 | + |
| 40 | + // 8. Wait for password input |
| 41 | + await frameLocator.getByRole('textbox', { name: 'Password' }).waitFor({ timeout: 20000 }); |
| 42 | + await frameLocator.getByRole('textbox', { name: 'Password' }).fill(process.env.ICLOUD_PASSWORD); |
| 43 | + |
| 44 | + // 9. Click the arrow button to continue |
| 45 | + await frameLocator.getByRole('button').first().click(); |
| 46 | + |
| 47 | + // 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 :( |
| 48 | + console.log('If prompted, please complete 2FA in the browser window. :('); |
| 49 | + |
| 50 | + // 12. Click on your iPhone using the precise selector inside the second iframe |
| 51 | + await page.locator('iframe').nth(1).contentFrame().getByTitle(process.env.DEVICE).getByTestId('show-device-name').click(); |
| 52 | + |
| 53 | + // 13. Wait for the device details panel to load |
| 54 | + await page.waitForTimeout(2000); |
| 55 | + |
| 56 | + // 14. Click the "Play Sound" button |
| 57 | + await page.locator('iframe').nth(1).contentFrame().getByRole('button', { name: 'Play Sound' }).click(); |
| 58 | + |
| 59 | + console.log('✅ Play Sound triggered for ' + process.env.DEVICE + '!'); |
| 60 | + await browser.close(); |
| 61 | +})(); |
| 62 | + |
0 commit comments