UNPKG

@yuiseki/devin-gyazo

Version:

A CLI tool for Devin to capture and upload screenshots to Gyazo.

156 lines (135 loc) 4.46 kB
const { chromium } = require('playwright'); const { execSync } = require('child_process'); const fs = require('fs'); const path = require('path'); const https = require('https'); const FormData = require('form-data'); // Ensure screenshots directory exists const screenshotsDir = '/home/ubuntu/screenshots'; if (!fs.existsSync(screenshotsDir)) { fs.mkdirSync(screenshotsDir, { recursive: true }); } function getDebugPort() { try { const processes = execSync( "ps aux | grep -v grep | grep chrome | grep remote-debugging-port" ).toString(); const lines = processes.split("\n").filter((line) => line.trim()); for (const line of lines) { const portMatch = line.match(/--remote-debugging-port=(\d+)/); if (portMatch && portMatch[1]) { const port = portMatch[1]; try { execSync(`nc -z localhost ${port}`); return port; } catch (e) { continue; } } } throw new Error("No active Chrome debugging port found"); } catch (error) { if (error.message.includes("No active Chrome")) { console.error( "Error: No Chrome instance found with remote debugging enabled" ); } else { console.error("Error finding Chrome debug port:", error.message); } process.exit(1); } } async function getBrowserInfo() { const port = getDebugPort(); const browser = await chromium.connectOverCDP(`http://localhost:${port}`); const contexts = browser.contexts(); if (contexts.length === 0) { throw new Error("No browser contexts found"); } const pages = contexts[0].pages(); if (pages.length === 0) { throw new Error("No pages found in browser context"); } const page = pages[0]; await page.waitForLoadState("networkidle"); const screenshotsDir = '/home/ubuntu/screenshots'; if (!fs.existsSync(screenshotsDir)) { fs.mkdirSync(screenshotsDir, { recursive: true }); } const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); const screenshotPath = path.join(screenshotsDir, `browser_${timestamp}.png`); await page.screenshot({ path: screenshotPath }); const info = { title: await page.title(), url: page.url(), screenshotPath }; await browser.close(); return info; } async function uploadToGyazo(filePath, title, refererUrl) { if (!process.env.GYAZO_ACCESS_TOKEN) { throw new Error('GYAZO_ACCESS_TOKEN environment variable is not set'); } const form = new FormData(); form.append('imagedata', fs.createReadStream(filePath)); form.append('app', 'Devin Browser'); if (title) form.append('title', title); if (refererUrl) form.append('referer_url', refererUrl); return new Promise((resolve, reject) => { const req = https.request({ hostname: 'upload.gyazo.com', path: '/api/upload', method: 'POST', headers: { Authorization: `Bearer ${process.env.GYAZO_ACCESS_TOKEN}`, ...form.getHeaders() } }, (res) => { let data = ''; res.on('data', chunk => data += chunk); res.on('end', () => { try { const response = JSON.parse(data); resolve(response.permalink_url); } catch (error) { reject(new Error('Failed to parse Gyazo response')); } }); }); req.on('error', reject); form.pipe(req); }); } async function handleBrowserCommand(args) { try { let title, url, screenshotPath; // Default to auto mode if no arguments or 'auto' is specified if (args.length === 0 || args[0] === 'auto') { const info = await getBrowserInfo(); title = info.title; url = info.url; screenshotPath = info.screenshotPath; } else if (args.length >= 2) { title = args[0]; url = args[1]; // Take screenshot using current browser info const info = await getBrowserInfo(); screenshotPath = info.screenshotPath; } else { console.error('Error: Invalid arguments'); console.error('Usage:'); console.error(' devin-gyazo browser auto'); console.error(' devin-gyazo browser <webpage_title> <url>'); process.exit(1); } const gyazoUrl = await uploadToGyazo(screenshotPath, title, url); console.log(gyazoUrl); // Clean up screenshot file fs.unlinkSync(screenshotPath); } catch (error) { console.error('Error:', error.message); process.exit(1); } } module.exports = { handleBrowserCommand };