import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; import puppeteer from 'puppeteer'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); class MusicRenderer { constructor() { this.tempDir = path.join(__dirname, '..', '..','..','..', 'temp'); this.browser = null; } /** * 初始化渲染器 */ async init() { try { this.browser = await puppeteer.launch({ headless: true, args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--disable-accelerated-2d-canvas', '--no-first-run', '--no-zygote', '--single-process', '--disable-gpu' ] }); } catch (error) { logger.error('[crystelf-music] 浏览器初始化失败:', error); throw error; } } /** * 渲染音乐列表图片 * @param {Array} songs 歌曲列表 * @param {string} query 搜索关键词 * @param {string} groupId 群聊ID * @returns {Promise} 图片文件路径 */ async renderMusicList(songs, query, groupId) { try { if (!this.browser) { await this.init(); } const page = await this.browser.newPage(); await page.setViewport({ width: 800, height: Math.max(600, songs.length * 80 + 200) }); const htmlContent = this.generateHtml(songs, query); await page.setContent(htmlContent, { waitUntil: 'networkidle0', timeout: 30000 }); const filename = `music_list_${groupId}_${Date.now()}.png`; const outputPath = path.join(this.tempDir, filename); await page.screenshot({ path: outputPath, type: 'jpeg', fullPage: true, quality: 90 }); await page.close(); return outputPath; } catch (error) { logger.error('[crystelf-music] 渲染音乐列表失败:', error); throw new Error(`渲染失败: ${error.message}`); } } /** * 生成HTML内容 * @param {Array} songs 歌曲列表 * @param {string} query 搜索关键词 * @returns {string} HTML字符串 */ generateHtml(songs, query) { const currentTime = new Date().toLocaleString('zh-CN'); const songItems = songs.map((song, index) => `
${this.escapeHtml(song.displayTitle)}
${this.escapeHtml(song.displayArtist)} ${this.escapeHtml(song.displayAlbum)}
${song.duration} ${song.format}
${index + 1}
`).join(''); return ` 音乐搜索结果

音乐搜索结果

搜索:${this.escapeHtml(query)} | 时间:${currentTime}
${songItems}
`; } /** * HTML转义 * @param {string} text 原始文本 * @returns {string} 转义后的文本 */ escapeHtml(text) { if (!text) return ''; const map = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; return text.toString().replace(/[&<>"']/g, (m) => map[m]); } /** * 关闭浏览器 */ async close() { if (this.browser) { await this.browser.close(); this.browser = null; } } } export default MusicRenderer;