const { chromium } = require('playwright'); const express = require('express'); const path = require('path'); const app = express(); const port = 3120; app.use(express.json()); app.use(express.static(path.join(__dirname))); let clients = []; function sendToAllClients(message, paginationInfo = null) { const data = JSON.stringify({ message: message, paginationInfo: paginationInfo }); console.log(`Sending to ${clients.length} clients: ${message}`); clients.forEach(client => { try { client.res.write(`data: ${data}\n\n`); } catch (error) { console.error(`Error sending to client ${client.id}:`, error); // Remove problematic client clients = clients.filter(c => c.id !== client.id); } }); } app.get('/delete-progress', (req, res) => { res.setHeader('Content-Type', 'text/event-stream'); res.setHeader('Cache-Control', 'no-cache'); res.setHeader('Connection', 'keep-alive'); res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept'); const clientId = Date.now(); clients.push({ id: clientId, res }); // Send initial connection confirmation res.write(`data: ${JSON.stringify({message: '事件流连接已建立'})}\n\n`); console.log(`Client ${clientId} connected to event stream`); req.on('close', () => { clients = clients.filter(client => client.id !== clientId); console.log(`Client ${clientId} disconnected from event stream`); }); }); async function deleteEmails(email, password, startPage, endPage) { let browser = null; let context = null; let page = null; console.log(`deleteEmails called with: email=${email}, startPage=${startPage}, endPage=${endPage || 'not specified'}`); try { console.log('Launching browser...'); sendToAllClients('正在启动浏览器...'); try { browser = await chromium.launch({ headless: true, channel: 'chrome', args: ['--no-sandbox', '--disable-setuid-sandbox'] }); console.log('Browser launched successfully'); } catch (browserError) { console.error('Failed to launch browser:', browserError); sendToAllClients(`浏览器启动失败: ${browserError.message}`); return; } try { context = await browser.newContext(); page = await context.newPage(); console.log('Browser context and page created'); } catch (contextError) { console.error('Failed to create browser context or page:', contextError); sendToAllClients(`浏览器上下文创建失败: ${contextError.message}`); return; } console.log('Navigating to login page...'); sendToAllClients('正在登录...'); await page.goto('https://webmail.lolipop.jp/login'); await page.fill('input[type="email"]', email); await page.fill('input[type="password"]', password); await page.click('button[type="submit"]'); await page.waitForSelector('.css-1f8bwsm', { timeout: 10000 }); sendToAllClients('登录成功'); let currentPage = startPage; let totalProcessed = 0; let continueDeleting = true; while (continueDeleting) { // Navigate to specific page await page.goto(`https://webmail.lolipop.jp/mail/INBOX?p=${currentPage}`); await page.waitForSelector('.css-1f8bwsm', { timeout: 100000 }); // Select all emails on current page const emailsToDelete = await page.evaluate(() => { const checkboxes = document.querySelectorAll('.css-1f8bwsm .css-1rlbz42 .css-1m9pwf3'); let count = 0; checkboxes.forEach((checkbox) => { checkbox.click(); count++; }); return count; }); if (emailsToDelete > 0) { totalProcessed += emailsToDelete; sendToAllClients(`当前页面选中 ${emailsToDelete} 封邮件`); // Delete selected emails await page.click('.css-i9gxme .css-zy67up .css-1yxmbwk[aria-label="削除"]'); await page.waitForTimeout(1000); sendToAllClients(`已删除第 ${currentPage} 页的 ${emailsToDelete} 封邮件`); } // Check if we should continue to next page if (endPage && currentPage >= endPage) { continueDeleting = false; } else { // Check if there is a next page const nextPageButton = await page.$('.MuiBox-root.css-0 .css-1yxmbwk:nth-child(3)'); const isNextPageDisabled = await nextPageButton.evaluate(button => button.disabled || button.classList.contains('disabled') ); if (isNextPageDisabled) { continueDeleting = false; } else { currentPage++; sendToAllClients(`进入第 ${currentPage} 页`); } } } sendToAllClients(`删除完成,共处理 ${totalProcessed} 封邮件`); } catch (error) { sendToAllClients(`发生错误: ${error.message}`); console.error('Delete emails error:', error); } finally { try { if (page) await page.close().catch(e => console.error('Error closing page:', e)); if (context) await context.close().catch(e => console.error('Error closing context:', e)); if (browser) await browser.close().catch(e => console.error('Error closing browser:', e)); } catch (closeError) { console.error('Error in cleanup:', closeError); } } } app.post('/start-delete', async (req, res) => { const { email, password, startPage, endPage } = req.body; console.log('Received delete request:', { email, startPage, endPage }); if (!email || !password || !startPage) { console.error('Missing required parameters'); return res.status(400).json({ status: 'error', message: '缺少必要参数' }); } // Send response immediately res.json({ status: 'started' }); console.log('Starting delete operation...'); // Set timeout to allow response to be sent before potentially long operation setTimeout(() => { console.log('Executing deleteEmails function...'); // Call the function without await to not block deleteEmails(email, password, parseInt(startPage), endPage ? parseInt(endPage) : null) .then(() => console.log('Delete emails operation completed')) .catch(err => console.error('Delete emails operation failed:', err)); }, 100); }); async function getLastPageDate() { let browser = null; let context = null; let page = null; try { browser = await chromium.launch({ headless: true, channel: 'chrome', args: ['--no-sandbox', '--disable-setuid-sandbox'] }); context = await browser.newContext(); page = await context.newPage(); await page.goto('https://webmail.lolipop.jp/login'); await page.fill('input[type="email"]', 'spdrakuten@spdsystem.com'); await page.fill('input[type="password"]', 'YzFiMTJlYT2a4-4a'); await page.click('button[type="submit"]'); await page.waitForSelector('.css-1f8bwsm', { timeout: 10000 }); // 点击最后一页按钮 await page.waitForSelector('.MuiBox-root.css-0 .css-1yxmbwk'); await page.click('.MuiBox-root.css-0 .css-1yxmbwk:nth-child(4)'); await page.waitForTimeout(1000); // 获取分页信息和最后一封邮件的日期 const lastDate = await page.evaluate(() => { const dates = document.querySelectorAll('.css-1e7qmj6'); if (dates.length > 0) { const lastDateStr = dates[dates.length - 1].textContent.replace(/:\d+0*$/, ''); return lastDateStr; } return null; }); return lastDate; } catch (error) { console.error('Error getting last date:', error); return null; } finally { try { if (page) await page.close().catch(e => console.error('Error closing page:', e)); if (context) await context.close().catch(e => console.error('Error closing context:', e)); if (browser) await browser.close().catch(e => console.error('Error closing browser:', e)); } catch (closeError) { console.error('Error in cleanup:', closeError); } } } app.get('/get-last-date', async (req, res) => { const lastDate = await getLastPageDate(); res.json({ lastDate }); }); // Add a test endpoint app.get('/test-event', (req, res) => { console.log('Current clients:', clients.length); clients.forEach((client, index) => { console.log(`Client ${index} (ID: ${client.id}): ${typeof client.res}`); }); sendToAllClients('测试事件 - ' + new Date().toISOString()); res.json({ status: 'Test event sent to ' + clients.length + ' clients', clientInfo: clients.map(c => ({ id: c.id })) }); }); app.listen(port, () => { console.log(`Server running at http://localhost:${port}`); });