From 448d19d4022203e0e7f04025eb953ff12a0b105b Mon Sep 17 00:00:00 2001 From: Oyasuminasai <61616918+nfnfgo@users.noreply.github.com> Date: Sun, 7 Jul 2024 13:38:35 +0800 Subject: [PATCH 1/8] feat: Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 3c4a5fa..2c0f374 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ settings.json # ignore dist/ dist +log release.zip \ No newline at end of file From bbfa34033d992a7f7722ac1106aa878daaa1de25 Mon Sep 17 00:00:00 2001 From: Oyasuminasai <61616918+nfnfgo@users.noreply.github.com> Date: Sun, 7 Jul 2024 13:39:30 +0800 Subject: [PATCH 2/8] feat: Add log file persist support. --- manifest.json | 2 +- src/main.js | 82 ++++++++++++++++++------------------ src/preload.js | 21 ++++----- src/utils/liteloader_type.ts | 53 +++++++++++++++++++---- src/utils/logger.ts | 9 +++- src/utils/logger_main.ts | 46 ++++++++++++++++++++ tsconfig.json | 1 + webpack.common.js | 8 ++-- 8 files changed, 157 insertions(+), 65 deletions(-) create mode 100644 src/utils/logger_main.ts diff --git a/manifest.json b/manifest.json index e775daf..6f22d4a 100644 --- a/manifest.json +++ b/manifest.json @@ -27,7 +27,7 @@ ], "injects": { "renderer": "./dist/renderer.js", - "main": "./src/main.js", + "main": "./dist/main.js", "preload": "./src/preload.js" } } \ No newline at end of file diff --git a/src/main.js b/src/main.js index cf40889..f228d30 100644 --- a/src/main.js +++ b/src/main.js @@ -1,58 +1,60 @@ // 运行在 Electron 主进程 下的插件入口 const { shell, ipcMain } = require("electron"); -const fs = require('fs/promises'); +import { generateMainProcessLogerWriter } from '@/utils/logger_main'; -const plugin_path = LiteLoader.plugins["markdown_it"].path.plugin; +// const setttingsJsonFilePath = `${plugin_path}/settings.json`; -// import { shell, ipcMain } from "electron"; +// async function getSettings(key) { +// var json = JSON.parse(await fs.readFile(setttingsJsonFilePath)); +// return json[key]; +// } -const setttingsJsonFilePath = `${plugin_path}/settings.json`; +// async function updateSettings({ name, value }) { +// var json = {}; +// try { json = JSON.parse(await fs.readFile(setttingsJsonFilePath)); } catch (e) { +// ; +// } +// json[name] = value; +// await fs.writeFile(setttingsJsonFilePath, JSON.stringify(json)); +// } -async function getSettings(key) { - var json = JSON.parse(await fs.readFile(setttingsJsonFilePath)); - return json[key]; -} +// async function removeSettings(key) { +// var json = JSON.parse(await fs.readFile(setttingsJsonFilePath)); +// json[key] = undefined; +// await fs.writeFile(setttingsJsonFilePath, JSON.stringify(json)); +// } -async function updateSettings({ name, value }) { - var json = {}; - try { json = JSON.parse(await fs.readFile(setttingsJsonFilePath)); } catch (e) { - ; - } - json[name] = value; - await fs.writeFile(setttingsJsonFilePath, JSON.stringify(json)); -} - -async function removeSettings(key) { - var json = JSON.parse(await fs.readFile(setttingsJsonFilePath)); - json[key] = undefined; - await fs.writeFile(setttingsJsonFilePath, JSON.stringify(json)); -} +const loggerWriter = generateMainProcessLogerWriter(); onLoad(); // 加载插件时触发 function onLoad() { - ipcMain.handle("LiteLoader.markdown_it.open_link", (event, content) => { - if (content.indexOf("http") != 0) { - content = "http://" + content; - } - return shell.openExternal(content); + // ipcMain.handle("LiteLoader.markdown_it.open_link", (event, content) => { + // if (content.indexOf("http") != 0) { + // content = "http://" + content; + // } + // return shell.openExternal(content); + // }); + + // ipcMain.handle('LiteLoader.markdown_it.get_settings', (e, key) => { + // return getSettings(key); + // }); + + // ipcMain.handle('LiteLoader.markdown_it.update_settings', (e, { name, value }) => { + // return updateSettings({ name, value }); + // }); + + // ipcMain.handle('LiteLoader.markdown_it.remove_settings', (e, key) => { + // return removeSettings(key); + // }) + + ipcMain.handle('LiteLoader.markdown_it.log', (e, consoleMode, ...args) => { + loggerWriter(consoleMode, ...args); }); - - ipcMain.handle('LiteLoader.markdown_it.get_settings', (e, key) => { - return getSettings(key); - }); - - ipcMain.handle('LiteLoader.markdown_it.update_settings', (e, { name, value }) => { - return updateSettings({ name, value }); - }); - - ipcMain.handle('LiteLoader.markdown_it.remove_settings', (e, key) => { - return removeSettings(key); - }) } // 这两个函数都是可选的 -module.exports = { +export { onLoad, }; diff --git a/src/preload.js b/src/preload.js index 2286ca7..17a5ab2 100644 --- a/src/preload.js +++ b/src/preload.js @@ -3,14 +3,15 @@ const { contextBridge, ipcRenderer } = require("electron"); // 在window对象下导出只读对象 contextBridge.exposeInMainWorld("markdown_it", { - render: (content) => - ipcRenderer.invoke("LiteLoader.markdown_it.render", content), - open_link: (content) => - ipcRenderer.invoke("LiteLoader.markdown_it.open_link", content), - get_settings: (key) => - ipcRenderer.invoke("LiteLoader.markdown_it.get_settings", key), - update_settings: ({ name, value }) => - ipcRenderer.invoke("LiteLoader.markdown_it.update_settings", { name, value }), - remove_settings: (key) => - ipcRenderer.invoke("LiteLoader.markdown_it.remove_settings", key), + // render: (content) => + // ipcRenderer.invoke("LiteLoader.markdown_it.render", content), + // open_link: (content) => + // ipcRenderer.invoke("LiteLoader.markdown_it.open_link", content), + // get_settings: (key) => + // ipcRenderer.invoke("LiteLoader.markdown_it.get_settings", key), + // update_settings: ({ name, value }) => + // ipcRenderer.invoke("LiteLoader.markdown_it.update_settings", { name, value }), + // remove_settings: (key) => + // ipcRenderer.invoke("LiteLoader.markdown_it.remove_settings", key), + log: (consoleType, ...args) => ipcRenderer.invoke('LiteLoader.markdown_it.log', consoleType, ...args), }); diff --git a/src/utils/liteloader_type.ts b/src/utils/liteloader_type.ts index 03c3527..6cc9379 100644 --- a/src/utils/liteloader_type.ts +++ b/src/utils/liteloader_type.ts @@ -3,13 +3,50 @@ * * Notice the `new_config` and `default_config` should all be a Object. Passing string will cause unexpected behaviour. */ -export interface LiteLoaderInterFace { + +export interface LiteLoaderInterFace { + path: { + root: string; // 本体目录路径 + profile: string; // 存储目录路径(如果指定了 LITELOADERQQNT_PROFILE 环境变量) + data: string; // 数据目录路径 + plugins: string; // 插件目录路径 + }; + versions: { + qqnt: string; // QQNT 版本号 + liteloader: string; // LiteLoaderQQNT 版本号 + node: string; // Node.js 版本号 + chrome: string; // Chrome 版本号 + electron: string; // Electron 版本号 + }; + os: { + platform: string; // 系统平台名称 + }; + package: { + liteloader: object; // LiteLoaderQQNT package.json 文件内容 + qqnt: object; // QQNT package.json 文件内容 + }; + plugins: { + markdown_it: { + incompatible: boolean; // 插件是否兼容 + disabled: boolean; // 插件是否禁用 + manifest: object; // 插件 manifest.json 文件内容 + path: { + plugin: string; // 插件本体根目录路径 + data: string; // 插件数据根目录路径 + injects: { + main: string; // 插件主进程脚本文件路径 + renderer: string; // 插件渲染进程脚本文件路径 + preload: string; // 插件预加载脚本文件路径 + }; + }; + }; + }; api: { - openPath(path: string): any; - openExternal(uri: string): any; + openPath(path: string): void; // 打开指定目录 + openExternal(uri: string): void; // 打开外部连接 config: { - set(slug: string, new_config: T): Promise; - get(slug: string, default_config: T): Promise; - } - }, -}; \ No newline at end of file + set(slug: string, newConfig: ConfigInfoType): Promise; // 设置配置文件 + get(slug: string, defaultConfig: ConfigInfoType): Promise; // 获取配置文件 + }; + }; +} diff --git a/src/utils/logger.ts b/src/utils/logger.ts index c49c477..bdd2ed8 100644 --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -4,6 +4,10 @@ import { useSettingsStore } from '@/states/settings'; +declare const markdown_it: { + log: (consoleType: string, ...args: any[]) => any +}; + type DistributiveFilter = Origin extends Filter ? Origin : never; /** @@ -32,6 +36,8 @@ function showOuputToConsole() { * ``` */ export function mditLogger(consoleFunction: SupportedLoggerFuncKey, ...params: any[]) { + markdown_it.log(consoleFunction, ...params); + if (!showOuputToConsole()) { return undefined; } @@ -39,5 +45,4 @@ export function mditLogger(consoleFunction: SupportedLoggerFuncKey, ...params: a '%c [MarkdownIt] ', 'background-color: rgba(0, 149, 204, 0.8); border-radius: 6px;padding-block: 2px; padding-inline: 0px; color: white;', ...params); -} - +} \ No newline at end of file diff --git a/src/utils/logger_main.ts b/src/utils/logger_main.ts new file mode 100644 index 0000000..2a9d928 --- /dev/null +++ b/src/utils/logger_main.ts @@ -0,0 +1,46 @@ +import * as path from 'path'; +import { existsSync, mkdirSync, createWriteStream } from 'fs'; +import { writeFile } from 'fs/promises'; +import { LiteLoaderInterFace } from '@/utils/liteloader_type'; + +declare const LiteLoader: LiteLoaderInterFace; + +export function generateMainProcessLogerWriter() { + var startTimeStr: string = new Date().toISOString(); + startTimeStr = startTimeStr.replaceAll(':', '-'); + var logFolderPath = path.join(LiteLoader.plugins.markdown_it.path.plugin, 'log'); + var logFilePath = path.join(LiteLoader.plugins.markdown_it.path.plugin, 'log', `${startTimeStr}.log`); + console.log(`[markdown-it] logFolderPath: ${logFolderPath}`); + console.log(`[markdown-it] logFilePath: ${logFilePath}`); + + // create dir if not exists + try { + if (!existsSync(logFolderPath)) { + mkdirSync(logFolderPath, { recursive: true }); + } + } catch (err) { + console.error(err); + } + + var stream = createWriteStream(logFilePath, { + flags: 'a+', + }) + + return async function (consoleMode: string, ...args: any[]) { + var timeStr = new Date().toISOString(); + + var argsStr = args.reduce(function (str, value) { + if (typeof value === 'string') { + return str + value; + } + return str + JSON.stringify(value); + }, ''); + + var logStr = `${consoleMode.toUpperCase()} | ${timeStr} | ${argsStr}`; + stream.write(`${logStr}\n`); + try { + } catch (e) { + console.log(`[markdown-it] Log file failed to update`, e); + } + } +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 85dcb2c..f86fd4c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "target": "ES2021", "baseUrl": "./", "paths": { "@/*": [ diff --git a/webpack.common.js b/webpack.common.js index b45acfe..f1fe2fd 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -62,16 +62,16 @@ const mainProcessConfig = { // Explicitly resolve files with following extension as modules. extensions: ['', '.js', '.jsx', '.ts', '.tsx'], }, - experiments: { - outputModule: true, - }, + // experiments: { + // outputModule: true, + // }, target: 'electron-main', entry: "./src/main.js", output: { path: path.resolve(__dirname, "dist"), filename: 'main.js', library: { - type: 'commonjs', // necessary in order to work with liteloader. + type: 'commonjs-static', // necessary in order to work with liteloader. }, chunkFormat: 'module', // or 'module' }, From 373d5ae884377b3fa137410464145f6e83cb41b6 Mon Sep 17 00:00:00 2001 From: Oyasuminasai <61616918+nfnfgo@users.noreply.github.com> Date: Sun, 7 Jul 2024 16:59:29 +0800 Subject: [PATCH 3/8] fix: Run main script after electron window created. This could solve the memory leak relative issue. --- src/main.js | 6 ++++-- src/utils/logger_main.ts | 6 ++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main.js b/src/main.js index f228d30..028bdde 100644 --- a/src/main.js +++ b/src/main.js @@ -26,7 +26,9 @@ import { generateMainProcessLogerWriter } from '@/utils/logger_main'; const loggerWriter = generateMainProcessLogerWriter(); -onLoad(); +function onBrowserWindowCreated() { + onLoad(); +} // 加载插件时触发 function onLoad() { @@ -56,5 +58,5 @@ function onLoad() { // 这两个函数都是可选的 export { - onLoad, + onBrowserWindowCreated, }; diff --git a/src/utils/logger_main.ts b/src/utils/logger_main.ts index 2a9d928..5a8504c 100644 --- a/src/utils/logger_main.ts +++ b/src/utils/logger_main.ts @@ -5,6 +5,8 @@ import { LiteLoaderInterFace } from '@/utils/liteloader_type'; declare const LiteLoader: LiteLoaderInterFace; +var _logWriter: any = undefined; + export function generateMainProcessLogerWriter() { var startTimeStr: string = new Date().toISOString(); startTimeStr = startTimeStr.replaceAll(':', '-'); @@ -38,9 +40,5 @@ export function generateMainProcessLogerWriter() { var logStr = `${consoleMode.toUpperCase()} | ${timeStr} | ${argsStr}`; stream.write(`${logStr}\n`); - try { - } catch (e) { - console.log(`[markdown-it] Log file failed to update`, e); - } } } \ No newline at end of file From 9ea6b93b175f2af7fedc457ab9892e627f9c1bef Mon Sep 17 00:00:00 2001 From: Oyasuminasai <61616918+nfnfgo@users.noreply.github.com> Date: Sun, 7 Jul 2024 18:42:29 +0800 Subject: [PATCH 4/8] feat: Add ElementCapture feature. Update docs. --- docs/debuging.md | 38 +++++++++++++++ docs/dev/renderer.md | 20 +++++++- src/components/setting_page.jsx | 10 ++++ src/main.js | 6 ++- src/renderer.jsx | 9 ++-- src/states/settings.ts | 4 ++ src/utils/logger.ts | 85 ++++++++++++++++++++++++++++----- tsconfig.json | 4 +- 8 files changed, 156 insertions(+), 20 deletions(-) create mode 100644 docs/debuging.md diff --git a/docs/debuging.md b/docs/debuging.md new file mode 100644 index 0000000..34ec81a --- /dev/null +++ b/docs/debuging.md @@ -0,0 +1,38 @@ +部分情况下,您可能需要获取本插件的调试信息。 + +# 确保已开启调试输出 + +首先,请确保您已经开启本插件的调试信息输出功能,包括 控制台输出 以及 日志文件输出。 + +![image](https://github.com/d0j1a1701/LiteLoaderQQNT-Markdown/assets/61616918/ca06d6e6-60b7-45c2-85bc-111b69bf47be) + +## 开启元素抓取 + +部分情况下,开发者可能需要相关的元素调试信息来定位问题,您可以开启本插件设置中的 启用元素调试 功能。 + +启用该功能后,当您发送的消息包含:\`--mdit-debug-capture-element\` 时(需包含\`符号,该标志将会被渲染为`code`元素),该消息会被作为调试用消息进行抓取,并将相关信息保存到日志文件中。**在本功能启用时,请确保您发送的调试消息不包含任何您不想让其他人看到的敏感信息。**请看下例: + +![image](https://github.com/d0j1a1701/LiteLoaderQQNT-Markdown/assets/61616918/db4b29ee-1ec3-4c76-85ce-d5c2639ef254) + +![image](https://github.com/d0j1a1701/LiteLoaderQQNT-Markdown/assets/61616918/4dab43b9-6988-4f55-be0a-e84514e2e8f8) + +为保证隐私性,只有自己发送的消息才能被标记为调试消息。 + + +# 进入日志文件目录 + +首先进入 `LiteLoaderQQNT` 插件设置页面,进入数据目录。 + +![image](https://github.com/d0j1a1701/LiteLoaderQQNT-Markdown/assets/61616918/bbbae1b8-fdd1-4daa-848f-1ec654dc9407) + +随后依次进入 `plugins -> markdown_it -> log`,便能看到所有日志文件。 + +> 如果目录不存在,一般是由于之前从未开启过日志文件输出功能。在完成上一步开启调试输出后,重启QQ即可。 + +# 提供文件给开发者 + +您可以直接将文件发送给相关的开发者,也可以选择用文本编辑工具打开 `.log` 文件并复制其内容进行分享。如果目录内存在多个文件,一般情况下请提供最新的文件。 + +# 清理日志文件 + +您可以在 `QQNT` 未启动的情况下,直接删除日志文件中的所有日志。 \ No newline at end of file diff --git a/docs/dev/renderer.md b/docs/dev/renderer.md index 2f6c594..aa0d8c6 100644 --- a/docs/dev/renderer.md +++ b/docs/dev/renderer.md @@ -5,8 +5,9 @@ - [Introduction](#introduction) - [Start Developing](#start-developing) + - [Logging](#logging) - [Create Release Version](#create-release-version) -- [UI Development](#ui-development) + - [UI Development](#ui-development) - [Content Rendering Test Example](#content-rendering-test-example) @@ -30,6 +31,21 @@ npm run dev This will start `webpack` in watch mode with `development` flag enabled. +## Logging + +A custom `conole` wrapper `mditLogger` is recommend when you need to log something in *Renderer Process*. You can import the logger by: + +```javascript +import { mditLogger } from './utils/logger'; + +function someFunc() { + mditLogger('debug', 'debug info here.'); // Output: [MarkdownIt] debug info here. +} +``` + + + +Use `mditLogger` whenever possible. ## Create Release Version @@ -45,7 +61,7 @@ The script `npm run release` will: 2. Run `git archive` to create a `release.zip` file contains all code included in `git`. 3. Run `zip -r` to add `dist` directory into previously generated `release.zip`. -# UI Development +## UI Development You could use `React` to develop plugin settings UI interface. The entrance of user settings page is `src/components/setting_page.js` diff --git a/src/components/setting_page.jsx b/src/components/setting_page.jsx index c9795f7..1887cc6 100644 --- a/src/components/setting_page.jsx +++ b/src/components/setting_page.jsx @@ -83,6 +83,16 @@ export function SettingPage() { title='控制台输出' caption='关闭后,将屏蔽 MarkdownIt 插件向控制台输出的信息,目前仅能屏蔽部分信息。' /> + + + + { if (get().unescapeAllHtmlEntites === true) { diff --git a/src/utils/logger.ts b/src/utils/logger.ts index bdd2ed8..02689d2 100644 --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -19,30 +19,93 @@ type LoggerFuncKey = { export type SupportedLoggerFuncKey = DistributiveFilter; -function showOuputToConsole() { +function outputToConsoleSettingEnabled() { return useSettingsStore.getState().consoleOutput; } +function outputToFileSettingEnabled() { + return useSettingsStore.getState().fileOutput; +} + +export interface MditLoggerOptions { + /** + * Determine if a log will be output in DevTools console + */ + consoleOutput: boolean; + /** + * Determine if a log will be persisted in file + */ + fileOutput: boolean; +} + +const defaultMditLoggerOptions: MditLoggerOptions = { + consoleOutput: true, + fileOutput: true, +} + +export function mditLoggerGenerator(options: MditLoggerOptions = defaultMditLoggerOptions): + (consoleFunction: SupportedLoggerFuncKey, ...params: any[]) => (undefined) { + return function (consoleFunction: SupportedLoggerFuncKey, ...params: any[]) { + if (outputToConsoleSettingEnabled() && options.consoleOutput) { + console[consoleFunction]( + '%c [MarkdownIt] ', + 'background-color: rgba(0, 149, 204, 0.8); border-radius: 6px;padding-block: 2px; padding-inline: 0px; color: white;', + ...params); + } + + if (outputToFileSettingEnabled() && options.fileOutput) { + markdown_it.log(consoleFunction, ...params); + } + + return undefined; + } +} + /** * Markdown it console output wrapper. * - * @param consoleFunction The function key of `console`. For exmaple: `'debug'` + * @param consoleFunction The name of the member function you want to use in `console`. For exmaple: `'debug'` or `'info'` * @param params Params that passed to `console` function. * * @example * * ```js - * mditLogger('debug', 'This is a debug message'); + * mditLogger('debug', 'This is a debug message', {name: 'Jobs', age: 17}); * ``` */ -export function mditLogger(consoleFunction: SupportedLoggerFuncKey, ...params: any[]) { - markdown_it.log(consoleFunction, ...params); +export const mditLogger = mditLoggerGenerator(); - if (!showOuputToConsole()) { - return undefined; + +const loggedClassName = '--mdit-debug-capture-element-logged'; +const logFlagClassName = '--mdit-debug-capture-element'; + +export function elementDebugLogger() { + var enabled = useSettingsStore.getState().enableElementCapture; + if (!enabled) { + return; } - return console[consoleFunction]( - '%c [MarkdownIt] ', - 'background-color: rgba(0, 149, 204, 0.8); border-radius: 6px;padding-block: 2px; padding-inline: 0px; color: white;', - ...params); + mditLogger('info', 'ElementCapture triggered'); + var codeEle = document.querySelectorAll('div.message-content__wrapper div.container--self code'); + + // Add flag class for all marked --mdit-debug-capture-element + Array.from(codeEle) + .filter((ele) => !ele.classList.contains(loggedClassName)) // ensure one message box will only be logged one time + .filter((ele) => ele.innerHTML == logFlagClassName) + .forEach((ele) => { ele.classList.add(logFlagClassName) }); + + // find all self sent message box that has been marked to capture, then log it. + var flaggedMsgBoxs = document.querySelectorAll(`div.message-content__wrapper div.container--self:has(.${logFlagClassName})`); + + Array.from(flaggedMsgBoxs).forEach((ele) => { + // file-only logger + mditLoggerGenerator({ + ...defaultMditLoggerOptions, + consoleOutput: false, + })('log', ele.outerHTML); + ele.classList.add(loggedClassName); + + mditLogger('debug', `Element captured: ${ele.tagName}`); + }); + + mditLogger('info', 'Element Capture Finished:', `${flaggedMsgBoxs.length} element(s) has been logged`); } \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index f86fd4c..c88b6c2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,5 @@ { "compilerOptions": { - "target": "ES2021", "baseUrl": "./", "paths": { "@/*": [ @@ -11,6 +10,9 @@ "noImplicitAny": true, "jsx": "react", "allowJs": true, + "target": "ES2021", + "module": "NodeNext", + "moduleResolution": "NodeNext" }, "exclude": [ "./dist/**/*" // This is what fixed it! From 1389014dd563ec6b7f788502b0a9bf1ef890b818 Mon Sep 17 00:00:00 2001 From: Oyasuminasai <61616918+nfnfgo@users.noreply.github.com> Date: Sun, 7 Jul 2024 19:58:50 +0800 Subject: [PATCH 5/8] feat: Update settings UI. --- docs/debuging.md | 13 ++++++-- src/components/setting_page.jsx | 56 +++++++++++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/docs/debuging.md b/docs/debuging.md index 34ec81a..da523bf 100644 --- a/docs/debuging.md +++ b/docs/debuging.md @@ -2,18 +2,25 @@ # 确保已开启调试输出 -首先,请确保您已经开启本插件的调试信息输出功能,包括 控制台输出 以及 日志文件输出。 +首先,请确保您已经开启本插件的调试信息输出功能,包括 `控制台输出` 以及 `日志文件输出` 。 ![image](https://github.com/d0j1a1701/LiteLoaderQQNT-Markdown/assets/61616918/ca06d6e6-60b7-45c2-85bc-111b69bf47be) ## 开启元素抓取 -部分情况下,开发者可能需要相关的元素调试信息来定位问题,您可以开启本插件设置中的 启用元素调试 功能。 +部分情况下,开发者可能需要相关的元素调试信息来定位问题,您可以开启本插件设置中的 `启用元素调试` 功能。 -启用该功能后,当您发送的消息包含:\`--mdit-debug-capture-element\` 时(需包含\`符号,该标志将会被渲染为`code`元素),该消息会被作为调试用消息进行抓取,并将相关信息保存到日志文件中。**在本功能启用时,请确保您发送的调试消息不包含任何您不想让其他人看到的敏感信息。**请看下例: +![image](https://github.com/d0j1a1701/LiteLoaderQQNT-Markdown/assets/61616918/1bf4e4d5-e3f4-4190-9c10-4b6153103fb7) + + +启用该功能后,当您发送的消息包含:\`--mdit-debug-capture-element\` 时(需包含\`符号,该标志将会被渲染为`code`元素),该消息会被作为调试用消息进行抓取,并将相关信息保存到日志文件中。**在本功能启用时,请确保您发送的调试消息不包含任何您不想让其他人看到的敏感信息。** 请看下例: + +- 消息框中输入的消息 ![image](https://github.com/d0j1a1701/LiteLoaderQQNT-Markdown/assets/61616918/db4b29ee-1ec3-4c76-85ce-d5c2639ef254) +- 消息渲染结果 + ![image](https://github.com/d0j1a1701/LiteLoaderQQNT-Markdown/assets/61616918/4dab43b9-6988-4f55-be0a-e84514e2e8f8) 为保证隐私性,只有自己发送的消息才能被标记为调试消息。 diff --git a/src/components/setting_page.jsx b/src/components/setting_page.jsx index 1887cc6..2194e64 100644 --- a/src/components/setting_page.jsx +++ b/src/components/setting_page.jsx @@ -1,6 +1,7 @@ import React from 'react'; import { useSettingsStore } from '@/states/settings'; +import { mditLogger } from '@/utils/logger'; export function SettingPage() { @@ -9,7 +10,6 @@ export function SettingPage() { // use encapsulated and whenever possible. return (<> - @@ -77,6 +77,11 @@ export function SettingPage() { + + + + + + + + + + + + + - { updateSetting(settingName, !settings[settingName]) }} is-active={settingsValue == true ? true : undefined} is-disabled={getForceValue()} + style={{ + 'flex': 'none', + }} > ); @@ -155,7 +175,8 @@ function TextAndCaptionBlock({ title, caption }) { 'display': 'flex', 'flexWrap': 'wrap', 'flexDirection': 'column', - 'width': '92%', + // 'width': '92%', + 'flex': '1 1 auto', }}> {title} {caption}

); +} + +function ButtonTile({ title, caption, href, path, callback, actionName }) { + callback ??= function () { + if (href !== undefined && href !== null) { + LiteLoader.api.openExternal(href); + return; + } + if (path !== undefined && path !== null) { + LiteLoader.api.openPath(path); + return; + } + mditLogger('debug', 'Button with no action clicked'); + + } + + return ( + + + + {actionName} + + + ); } \ No newline at end of file From e304fe92ab7058a8f3d3d43e31556e426a4095ff Mon Sep 17 00:00:00 2001 From: Oyasuminasai <61616918+nfnfgo@users.noreply.github.com> Date: Sun, 7 Jul 2024 20:06:05 +0800 Subject: [PATCH 6/8] fix: Fix ElementCapture `rendered` flag doesn't work. --- src/utils/logger.ts | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/utils/logger.ts b/src/utils/logger.ts index 02689d2..a7952e6 100644 --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -89,23 +89,30 @@ export function elementDebugLogger() { // Add flag class for all marked --mdit-debug-capture-element Array.from(codeEle) - .filter((ele) => !ele.classList.contains(loggedClassName)) // ensure one message box will only be logged one time .filter((ele) => ele.innerHTML == logFlagClassName) - .forEach((ele) => { ele.classList.add(logFlagClassName) }); + .forEach((ele) => { + ele.classList.add(logFlagClassName); + }); // find all self sent message box that has been marked to capture, then log it. var flaggedMsgBoxs = document.querySelectorAll(`div.message-content__wrapper div.container--self:has(.${logFlagClassName})`); - Array.from(flaggedMsgBoxs).forEach((ele) => { - // file-only logger - mditLoggerGenerator({ - ...defaultMditLoggerOptions, - consoleOutput: false, - })('log', ele.outerHTML); - ele.classList.add(loggedClassName); + var loggedCount = 0; + Array + .from(flaggedMsgBoxs) + .filter((ele) => !ele.classList.contains(loggedClassName)) // ensure one message box will only be logged one time + .forEach((ele) => { + // file-only logger + mditLoggerGenerator({ + ...defaultMditLoggerOptions, + consoleOutput: false, + })('log', ele.outerHTML); + + mditLogger('debug', `Element captured: ${ele.tagName}`); - mditLogger('debug', `Element captured: ${ele.tagName}`); - }); + ele.classList.add(loggedClassName); + loggedCount++; + }); - mditLogger('info', 'Element Capture Finished:', `${flaggedMsgBoxs.length} element(s) has been logged`); + mditLogger('info', 'Element Capture Finished:', `${loggedCount} element(s) has been logged`); } \ No newline at end of file From cb0a810a9f57439dcc82dd56422c31c5a9f02d87 Mon Sep 17 00:00:00 2001 From: Oyasuminasai <61616918+nfnfgo@users.noreply.github.com> Date: Sun, 7 Jul 2024 23:55:44 +0800 Subject: [PATCH 7/8] feat: Add Github info in Settings UI. --- src/components/setting_page.jsx | 16 ++++++------ src/main.js | 44 +++------------------------------ src/preload.js | 1 + src/utils/logger_main.ts | 29 ++++++++++++++++++---- 4 files changed, 37 insertions(+), 53 deletions(-) diff --git a/src/components/setting_page.jsx b/src/components/setting_page.jsx index 2194e64..99f37c4 100644 --- a/src/components/setting_page.jsx +++ b/src/components/setting_page.jsx @@ -13,11 +13,14 @@ export function SettingPage() { - - 设置更新 - 在此页面更新设置后,需要重启QQ后方可生效 - + + + + + + + @@ -101,8 +104,8 @@ export function SettingPage() {
@@ -175,7 +178,6 @@ function TextAndCaptionBlock({ title, caption }) { 'display': 'flex', 'flexWrap': 'wrap', 'flexDirection': 'column', - // 'width': '92%', 'flex': '1 1 auto', }}> {title} diff --git a/src/main.js b/src/main.js index fc043bc..3a2faec 100644 --- a/src/main.js +++ b/src/main.js @@ -1,28 +1,6 @@ // 运行在 Electron 主进程 下的插件入口 const { ipcMain } = require("electron"); -import { generateMainProcessLogerWriter } from '@/utils/logger_main'; - -// const setttingsJsonFilePath = `${plugin_path}/settings.json`; - -// async function getSettings(key) { -// var json = JSON.parse(await fs.readFile(setttingsJsonFilePath)); -// return json[key]; -// } - -// async function updateSettings({ name, value }) { -// var json = {}; -// try { json = JSON.parse(await fs.readFile(setttingsJsonFilePath)); } catch (e) { -// ; -// } -// json[name] = value; -// await fs.writeFile(setttingsJsonFilePath, JSON.stringify(json)); -// } - -// async function removeSettings(key) { -// var json = JSON.parse(await fs.readFile(setttingsJsonFilePath)); -// json[key] = undefined; -// await fs.writeFile(setttingsJsonFilePath, JSON.stringify(json)); -// } +import { generateMainProcessLogerWriter, LogPathHelper } from '@/utils/logger_main'; const loggerWriter = generateMainProcessLogerWriter(); @@ -34,28 +12,12 @@ function onBrowserWindowCreated() { // 加载插件时触发 function onLoad() { - // ipcMain.handle("LiteLoader.markdown_it.open_link", (event, content) => { - // if (content.indexOf("http") != 0) { - // content = "http://" + content; - // } - // return shell.openExternal(content); - // }); - - // ipcMain.handle('LiteLoader.markdown_it.get_settings', (e, key) => { - // return getSettings(key); - // }); - - // ipcMain.handle('LiteLoader.markdown_it.update_settings', (e, { name, value }) => { - // return updateSettings({ name, value }); - // }); - - // ipcMain.handle('LiteLoader.markdown_it.remove_settings', (e, key) => { - // return removeSettings(key); - // }) ipcMain.handle('LiteLoader.markdown_it.log', (e, consoleMode, ...args) => { loggerWriter(consoleMode, ...args); }); + + ipcMain.handle('LiteLoader.markdown_it.get_log_path', (e) => LogPathHelper.getLogFolderPath()); } // 这两个函数都是可选的 diff --git a/src/preload.js b/src/preload.js index 17a5ab2..37a1fe8 100644 --- a/src/preload.js +++ b/src/preload.js @@ -14,4 +14,5 @@ contextBridge.exposeInMainWorld("markdown_it", { // remove_settings: (key) => // ipcRenderer.invoke("LiteLoader.markdown_it.remove_settings", key), log: (consoleType, ...args) => ipcRenderer.invoke('LiteLoader.markdown_it.log', consoleType, ...args), + get_log_path: () => ipcRenderer.invoke('LiteLoader.markdown_it.get_log_path'), }); diff --git a/src/utils/logger_main.ts b/src/utils/logger_main.ts index 5a8504c..c63000e 100644 --- a/src/utils/logger_main.ts +++ b/src/utils/logger_main.ts @@ -5,13 +5,32 @@ import { LiteLoaderInterFace } from '@/utils/liteloader_type'; declare const LiteLoader: LiteLoaderInterFace; -var _logWriter: any = undefined; +export const LogPathHelper = { + getLogFolderPath() { + return path.join(LiteLoader.plugins.markdown_it.path.plugin, 'log'); + }, + + /** + * Get absolute file path of a log file. + * + * @param logFileName Name of the log file. If `undefined`, + * will generate automatically based on current time. + */ + getLogFilePath(logFileName?: string | undefined) { + // generate log file name if not received + logFileName ??= (new Date().toISOString()).replaceAll(':', '-'); + + return path.join(LiteLoader.plugins.markdown_it.path.plugin, 'log', `${logFileName}.log`); + } +}; +/** + * Generate a writer function that used to write log into log file. + */ export function generateMainProcessLogerWriter() { - var startTimeStr: string = new Date().toISOString(); - startTimeStr = startTimeStr.replaceAll(':', '-'); - var logFolderPath = path.join(LiteLoader.plugins.markdown_it.path.plugin, 'log'); - var logFilePath = path.join(LiteLoader.plugins.markdown_it.path.plugin, 'log', `${startTimeStr}.log`); + var logFolderPath = LogPathHelper.getLogFolderPath(); + var logFilePath = LogPathHelper.getLogFilePath(); + console.log(`[markdown-it] logFolderPath: ${logFolderPath}`); console.log(`[markdown-it] logFilePath: ${logFilePath}`); From f890d834e1948d5eb3de1a44a2f03d628a0933f1 Mon Sep 17 00:00:00 2001 From: Oyasuminasai <61616918+nfnfgo@users.noreply.github.com> Date: Mon, 8 Jul 2024 11:03:55 +0800 Subject: [PATCH 8/8] fix: Fix typo. --- docs/{debuging.md => debugging.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/{debuging.md => debugging.md} (100%) diff --git a/docs/debuging.md b/docs/debugging.md similarity index 100% rename from docs/debuging.md rename to docs/debugging.md