From 4b5599422fd18e3e952c58a81ffa3c06065e61db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?hbj=E7=99=BD=E5=A4=9C?= Date: Fri, 15 Sep 2023 21:09:33 +0000 Subject: [PATCH 1/6] update lib/puppeteer/puppeteer.js. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: hbj白夜 --- lib/puppeteer/puppeteer.js | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/lib/puppeteer/puppeteer.js b/lib/puppeteer/puppeteer.js index 7c615c6..7c76b59 100644 --- a/lib/puppeteer/puppeteer.js +++ b/lib/puppeteer/puppeteer.js @@ -1,24 +1,27 @@ -import { segment } from 'oicq' -import Renderer from '../renderer/loader.js' +import Renderer from '../renderer/Renderer.js' /** * 暂时保留对手工引用puppeteer.js的兼容 * 后期会逐步废弃 * 只提供截图及分片截图功能 */ -let renderer = Renderer.getRenderer('puppeteer') -renderer.screenshot = async (name, data) => { +export default { + // 截图 + async screenshot (name, data = {}) { + let renderer = Renderer.getRenderer() let img = await renderer.render(name, data) return img ? segment.image(img) : img -} -renderer.screenshots = async (name, data) => { + }, + + // 分片截图 + async screenshots (name, data = {}) { + let renderer = Renderer.getRenderer() data.multiPage = true let imgs = await renderer.render(name, data) || [] let ret = [] for (let img of imgs) { - ret.push(img ? segment.image(img) : img) + ret.push(img ? segment.image(img) : img) } return ret.length > 0 ? ret : false -} - -export default renderer \ No newline at end of file + } +} \ No newline at end of file From a6478b91acb51c3573b2a964ed931545506481be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?hbj=E7=99=BD=E5=A4=9C?= Date: Fri, 15 Sep 2023 21:10:20 +0000 Subject: [PATCH 2/6] update lib/renderer/Renderer.js. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: hbj白夜 --- lib/renderer/Renderer.js | 99 ++++++++++++---------------------------- 1 file changed, 28 insertions(+), 71 deletions(-) diff --git a/lib/renderer/Renderer.js b/lib/renderer/Renderer.js index a6dfe14..33c8aa9 100644 --- a/lib/renderer/Renderer.js +++ b/lib/renderer/Renderer.js @@ -1,82 +1,39 @@ -import template from 'art-template' -import chokidar from 'chokidar' -import path from 'node:path' import fs from 'node:fs' +import yaml from 'yaml' +import lodash from 'lodash' +import cfg from '../config/config.js' +import { Data } from '#miao' -export default class Renderer { - /** - * 渲染器 - * @param data.id 渲染器ID - * @param data.type 渲染器类型 - * @param data.render 渲染器入口 - */ - constructor(data) { - /** 渲染器ID */ - this.id = data.id || 'renderer' - /** 渲染器类型 */ - this.type = data.type || 'image' - /** 渲染器入口 */ - this.render = this[data.render || 'render'] - this.dir = './temp/html' - this.html = {} - this.watcher = {} - this.createDir(this.dir) - } - - /** 创建文件夹 */ - createDir(dirname) { - if (fs.existsSync(dirname)) { - return true - } else { - if (this.createDir(path.dirname(dirname))) { - fs.mkdirSync(dirname) - return true - } - } - } - - /** 模板 */ - dealTpl(name, data) { - let { tplFile, saveId = name } = data - let savePath = `./temp/html/${name}/${saveId}.html` - - /** 读取html模板 */ - if (!this.html[tplFile]) { - this.createDir(`./temp/html/${name}`) +let rendererBackends = {} +async function registerRendererBackends () { + const subFolders = fs.readdirSync(`${process.cwd()}/renderers`, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()) + for (let subFolder of subFolders) { + let name = subFolder.name + const rendererFn = await Data.importDefault(`/renderers/${name}/index.js`) + let configFile = `./renderers/${name}/config.yaml` + let rendererCfg = {} + if (fs.existsSync(configFile)) { try { - this.html[tplFile] = fs.readFileSync(tplFile, 'utf8') - } catch (error) { - logger.error(`加载html错误:${tplFile}`) - return false + rendererCfg = yaml.parse(fs.readFileSync(configFile, 'utf8')) + } catch (e) { + rendererCfg = {} } - - this.watch(tplFile) } - - data.resPath = `./resources/` - - /** 替换模板 */ - let tmpHtml = template.render(this.html[tplFile], data) - - /** 保存模板 */ - fs.writeFileSync(savePath, tmpHtml) - - logger.debug(`[图片生成][使用模板] ${savePath}`) - - return savePath + let renderer = rendererFn(rendererCfg) + if (!renderer.id || !renderer.type || !renderer.render || !lodash.isFunction(renderer.render)) { + logger.warn('渲染后端 ' + (renderer.id || subFolder.name) + ' 不可用') + } + rendererBackends[renderer.id] = renderer + logger.info(`加载渲染后端 ${renderer.id}`) } +} - /** 监听配置文件 */ - watch(tplFile) { - if (this.watcher[tplFile]) return +await registerRendererBackends() - const watcher = chokidar.watch(tplFile) - watcher.on('change', path => { - delete this.html[tplFile] - logger.mark(`[修改html模板] ${tplFile}`) - }) - - this.watcher[tplFile] = watcher +export default { + getRenderer () { + // TODO 渲染器降级 + return rendererBackends[cfg.renderer?.name || 'puppeteer'] } } \ No newline at end of file From ee1008b75816c2962e8f03fe34de9e688db2c348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?hbj=E7=99=BD=E5=A4=9C?= Date: Fri, 15 Sep 2023 21:10:50 +0000 Subject: [PATCH 3/6] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=96=87=E4=BB=B6=20lib/?= =?UTF-8?q?renderer/loader.js?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/renderer/loader.js | 56 ------------------------------------------ 1 file changed, 56 deletions(-) delete mode 100644 lib/renderer/loader.js diff --git a/lib/renderer/loader.js b/lib/renderer/loader.js deleted file mode 100644 index f750611..0000000 --- a/lib/renderer/loader.js +++ /dev/null @@ -1,56 +0,0 @@ -import fs from 'node:fs' -import yaml from 'yaml' -import lodash from 'lodash' -import cfg from '../config/config.js' -import { Data } from '#miao' -import Renderer from './Renderer.js' - -/** 全局变量 Renderer */ -global.Renderer = Renderer - -/** - * 加载渲染器 - */ -class RendererLoader { - constructor() { - this.renderers = new Map() - this.dir = './renderers' - // TODO 渲染器热加载 - this.watcher = {} - } - - static async init() { - const render = new RendererLoader() - await render.load() - return render - } - - async load() { - const subFolders = fs.readdirSync(this.dir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()) - for (let subFolder of subFolders) { - let name = subFolder.name - try { - const rendererFn = await Data.importDefault(`${this.dir}/${name}/index.js`) - let configFile = `${this.dir}/${name}/config.yaml` - let rendererCfg = fs.existsSync(configFile) ? yaml.parse(fs.readFileSync(configFile, 'utf8')) : {} - let renderer = rendererFn(rendererCfg) - if (!renderer.id || !renderer.type || !renderer.render || !lodash.isFunction(renderer.render)) { - logger.warn('渲染后端 ' + (renderer.id || subFolder.name) + ' 不可用') - } - this.renderers.set(renderer.id, renderer) - logger.info(`加载渲染后端 ${renderer.id}`) - } catch (err) { - logger.error(`渲染后端 ${name} 加载失败`) - logger.error(err) - } - } - } - - getRenderer(name = cfg.renderer?.name || 'puppeteer') { - // TODO 渲染器降级 - return this.renderers.get(name) - } -} - - -export default await RendererLoader.init() \ No newline at end of file From cc9a7fecad6d9cef1ffea349f0018662f8391d06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?hbj=E7=99=BD=E5=A4=9C?= Date: Fri, 15 Sep 2023 21:11:25 +0000 Subject: [PATCH 4/6] update renderers/puppeteer/index.js. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: hbj白夜 --- renderers/puppeteer/index.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/renderers/puppeteer/index.js b/renderers/puppeteer/index.js index 1684f12..ecb4dc3 100644 --- a/renderers/puppeteer/index.js +++ b/renderers/puppeteer/index.js @@ -10,5 +10,13 @@ import Puppeteer from './lib/puppeteer.js' */ export default function (config) { // TODO Puppeteer待简化重构 - return new Puppeteer(config) + const PuppeteerRender = new Puppeteer(config) + + return { + id: 'puppeteer', + type: 'image', + async render (name, data) { + return await PuppeteerRender.screenshot(name, data) + } + } } \ No newline at end of file From feffb2076baf0a396e8938bc6009ece5bda204c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?hbj=E7=99=BD=E5=A4=9C?= Date: Fri, 15 Sep 2023 21:11:58 +0000 Subject: [PATCH 5/6] update renderers/puppeteer/lib/puppeteer.js. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: hbj白夜 --- renderers/puppeteer/lib/puppeteer.js | 79 ++++++++++++++++++++++++---- 1 file changed, 69 insertions(+), 10 deletions(-) diff --git a/renderers/puppeteer/lib/puppeteer.js b/renderers/puppeteer/lib/puppeteer.js index f2c5d25..f86a98c 100644 --- a/renderers/puppeteer/lib/puppeteer.js +++ b/renderers/puppeteer/lib/puppeteer.js @@ -1,22 +1,20 @@ -import Renderer from '../../../lib/renderer/Renderer.js' +import fs from 'node:fs' import os from 'node:os' import lodash from 'lodash' +import template from 'art-template' +import chokidar from 'chokidar' import puppeteer from 'puppeteer' // 暂时保留对原config的兼容 import cfg from '../../../lib/config/config.js' import { Data } from '#miao' -import path from 'path' + +const _path = process.cwd() // mac地址 let mac = '' -export default class Puppeteer extends Renderer { +export default class PuppeteerRenderer { constructor(config) { - super({ - id: 'puppeteer', - type: 'image', - render: 'screenshot' - }) this.browser = false this.lock = false this.shoting = [] @@ -41,6 +39,22 @@ export default class Puppeteer extends Renderer { /** chromium其他路径 */ this.config.wsEndpoint = config.puppeteerWS || cfg?.bot?.puppeteer_ws } + + this.html = {} + this.watcher = {} + this.createDir('./temp/html') + } + + createDir(dir) { + if (!fs.existsSync(dir)) { + let dirs = dir.split('/') + for (let idx = 1; idx <= dirs.length; idx++) { + let temp = dirs.slice(0, idx).join('/') + if (!fs.existsSync(temp)) { + fs.mkdirSync(temp) + } + } + } } /** @@ -176,7 +190,7 @@ export default class Puppeteer extends Renderer { try { const page = await this.browser.newPage() let pageGotoParams = lodash.extend({ timeout: 120000 }, data.pageGotoParams || {}) - await page.goto('file://' + path.resolve(savePath), pageGotoParams) + await page.goto(`file://${_path}${lodash.trim(savePath, '.')}`, pageGotoParams) let body = await page.$('#container') || await page.$('body') // 计算页面高度 @@ -268,6 +282,51 @@ export default class Puppeteer extends Renderer { return data.multiPage ? ret : ret[0] } + /** 模板 */ + dealTpl(name, data) { + let { tplFile, saveId = name } = data + let savePath = `./temp/html/${name}/${saveId}.html` + + /** 读取html模板 */ + if (!this.html[tplFile]) { + this.createDir(`./temp/html/${name}`) + + try { + this.html[tplFile] = fs.readFileSync(tplFile, 'utf8') + } catch (error) { + logger.error(`加载html错误:${tplFile}`) + return false + } + + this.watch(tplFile) + } + + data.resPath = `${_path}/resources/` + + /** 替换模板 */ + let tmpHtml = template.render(this.html[tplFile], data) + + /** 保存模板 */ + fs.writeFileSync(savePath, tmpHtml) + + logger.debug(`[图片生成][使用模板] ${savePath}`) + + return savePath + } + + /** 监听配置文件 */ + watch(tplFile) { + if (this.watcher[tplFile]) return + + const watcher = chokidar.watch(tplFile) + watcher.on('change', path => { + delete this.html[tplFile] + logger.mark(`[修改html模板] ${tplFile}`) + }) + + this.watcher[tplFile] = watcher + } + /** 重启 */ restart() { /** 截图超过重启数时,自动关闭重启浏览器,避免生成速度越来越慢 */ @@ -283,4 +342,4 @@ export default class Puppeteer extends Renderer { } } } -} +} \ No newline at end of file From 41c50b8f4a124883c4e7c6ea3c69be3ea9a9dd08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?hbj=E7=99=BD=E5=A4=9C?= Date: Fri, 15 Sep 2023 21:13:46 +0000 Subject: [PATCH 6/6] update package.json. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: hbj白夜 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 11ec127..2606210 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "miao-yunzai", - "version": "3.1.0", + "version": "3.1.1", "author": "Yoimiya-Kokomi, Le-niao", "description": "QQ group Bot", "main": "app.js",