tuveplaywright / index.js
deepak191z's picture
Update index.js
68adc7a verified
const express = require('express');
const { chromium } = require('playwright');
const bodyParser = require('body-parser');
const cors = require('cors');
const app = express();
app.use(bodyParser.json());
app.use(cors());
// Launch browser once to reuse
let browser;
(async () => {
browser = await chromium.launch({ headless: true });
})();
// Route: serve minimal HTML
const html = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>YouTube Transcript Generator</title>
<style>
body { font-family: Arial, sans-serif; max-width: 600px; margin: 20px auto; }
input, button { width: 100%; padding: 8px; margin: 8px 0; }
#result { white-space: pre-wrap; background: #f5f5f5; padding: 10px; border-radius: 4px; }
</style>
</head>
<body>
<h2>YouTube Transcript Generator</h2>
<form id="form">
<input type="text" id="videoUrl" placeholder="YouTube Video URL" required />
<button type="submit">Generate</button>
</form>
<div id="result"></div>
<script>
document.getElementById('form').addEventListener('submit', async e => {
e.preventDefault();
const url = document.getElementById('videoUrl').value;
const resDiv = document.getElementById('result');
resDiv.textContent = 'Loading...';
try {
const r = await fetch('/transcript', {
method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ url })
});
const { transcript, error } = await r.json();
resDiv.textContent = transcript || error;
} catch (err) {
resDiv.textContent = 'Unexpected error';
}
});
</script>
</body>
</html>
`;
app.get('/', (_, res) => res.send(html));
app.post('/transcript', async (req, res) => {
const { url } = req.body;
if (!url) return res.status(400).json({ error: 'URL required' });
const context = await browser.newContext();
// Block images, styles, fonts, media for speed
await context.route('**/*', route => {
const req = route.request();
const t = req.resourceType();
if (['image', 'stylesheet', 'font', 'media'].includes(t))
route.abort();
else
route.continue();
});
const page = await context.newPage();
try {
await page.goto(url, { waitUntil: 'domcontentloaded' });
// Open transcript menu
const moreBtn = await page.$('button[aria-label="More actions"]');
if (moreBtn) await moreBtn.click();
await page.click('tp-yt-paper-item[role="menuitem"]:has-text("Open transcript")');
await page.waitForSelector('ytd-transcript-renderer', { timeout: 5000 });
const transcript = await page.$$eval(
'ytd-transcript-segment-renderer .segment-text', els => els.map(el => el.textContent.trim()).join('\n')
);
res.json({ transcript });
} catch (err) {
console.error(err);
res.json({ error: 'Failed to extract transcript' });
} finally {
await context.close();
}
});
const PORT = process.env.PORT || 7860;
app.listen(PORT, () => console.log(`Server running on ${PORT}`));