AndyYan's Blog - 调优
type: channel
link: https://www.andy-y.cn/index.php/category/refine/
items: Typecho + JOE 主题下 Mermaid 渲染的解决方案
items: 使用screen/tmux命令实现SSH中任务后台运行
items: 搭建Grafana监测Bird运行状态
items: MaiBot+AstrBot+Napcat分离部署，实用、稳定且拟人化的QQBot部署方案

Typecho + JOE 主题下 Mermaid 渲染的解决方案
type: item
date: 2026-04-05T12:04:00+00:00
description: 阅前须知：由于博主现在 并没有太多自己写代码甚至脚本的能力 ，本篇文章在我和AI共同解决了这个问题之后 直接由AI生成 ，若你对此感到反感，可以现在 关闭该帖 （ 我是废物 ）一、问题背景在 Typecho 中使用 Mermaid 一直不算难，但一旦换成 JOE 主题，问题就开始变得复杂：写好的 `mermaid 代码块被当成普通代码高亮插件明明启用了，但图表不渲染翻页（PJAX）后 Mermaid 直接失效我一开始也尝试用常规方案（正则替换 HTML），结果发现：👉 根本不稳定二、问题的本质JOE 主题做了很多“增强”，包括：自定义代码高亮（Prism / Highlight.js）改写 Markdown 输出结构使用 PJAX（局部刷新页面）这导致一个核心问题：你在后端生成的 HTML，很可能在前端被再次修改甚至覆盖例如你期望的是： 但实际可能变成： 甚至： ... 👉 结构不稳定 → 正则必炸三、传统方案为什么不行？常见插件思路：Markdown → HTML → 正则替换 → 问题在于：依赖 HTML 结构（不可靠）容易被主题覆盖PJAX 后不会重新执行结论：后端改 HTML，在 JOE 这种强主题下是错误方向四、最终解决方案：前端接管我最后采用的是：✅ 完全绕过后端，前端动态解析 Mermaid核心流程：页面加载 ↓ 扫描所有 language-mermaid 代码块 ↓ 替换为 .mermaid DOM ↓ 调用 Mermaid 渲染五、核心实现解析1. 扫描代码块const blocks = document.querySelectorAll( 'pre code.language-mermaid, pre.language-mermaid' );为什么这样写？👉 兼容两种结构： 2. 提取原始代码let code = codeBlock.textContent;👉 直接拿文本，不依赖 HTML 结构3. 重建 DOMconst container = document.createElement('div'); container.className = 'mermaid-container'; const mermaidDiv = document.createElement('div'); mermaidDiv.className = 'mermaid'; mermaidDiv.textContent = code; container.appendChild(mermaidDiv);最终结构： ... 4. 替换原代码块pre.replaceWith(container);👉 关键点：删除原代码高亮 DOM避免主题再次干扰5. 渲染 Mermaidmermaid.initialize({ startOnLoad: false, theme: getTheme() }); mermaid.init(undefined, document.querySelectorAll('.mermaid'));为什么不用自动加载？👉 因为 DOM 是动态生成的6. 防止重复渲染if (codeBlock.dataset.mermaidDone) return;👉 防止：PJAX 重复执行多次渲染报错7. 适配 PJAX（关键）document.addEventListener('pjax:complete', run);👉 没有这行：❌ 翻页后 Mermaid 全部失效六、主题适配（暗黑模式）function getTheme() { if (document.body.classList.contains('dark')) { return 'dark'; } return 'default'; }👉 自动跟随主题切换七、为什么这个方案最稳？对比一下：方案稳定性原因后端正则替换❌依赖 HTML修改 Markdown 解析❌被主题覆盖前端接管（本方案）✅直接操作 DOM八、核心设计思想这次优化本质上是一次“架构调整”：1️⃣ 不和主题抢控制权JOE 已经接管了渲染链：👉 你再插手，只会冲突2️⃣ 前端才是最终执行层只要页面上存在：language-mermaid👉 就一定能识别3️⃣ 幂等设计data-mermaidDone👉 保证多次执行不会出问题九、最终效果✅ 支持所有 Mermaid 图✅ 支持 PJAX✅ 不受代码高亮影响✅ 自动暗黑模式✅ 主题无关（通用）十、一句话总结与其试图修补被主题打乱的 HTML，不如直接绕过它，在前端重建渲染链。十一、源码附上{collapse}{collapse-item label="过长，已折叠，点击查看" close}<?php if (!defined('__TYPECHO_…

使用screen/tmux命令实现SSH中任务后台运行
type: item
date: 2026-04-05T11:29:00+00:00
description: 前言：在我们使用ssh的时候正常情况下，如果我们退出ssh，进程会被杀掉，导致一些需要运行较长时间（比如 rsync/cp ）的命令中断，十分的难受，这里提供两种解决办法：1.使用screen1.1开启 screen：screen -S upload1.2执行命令##举例 rsync -avh --progress /data/myfolder/ /mnt/myfolder/1.3退出SSH保持后台运行：按：Ctrl + A 然后按 D1.4重新连接后恢复screen -r upload2.使用tmux2.1启动tmuxtmux new -s upload2.2执行命令后，退出保持后台Ctrl + B 然后按 D2.3重新连接后恢复tmux attach -t upload

搭建Grafana监测Bird运行状态
type: item
date: 2026-02-19T14:39:00+00:00
description: 写在前面本人在dn42网络中有4个节点，本来搭建了LookingGlass来监测节点运行状态，但考虑到不够直观 其实是想折腾，所以打算搭建一个可以图形化监控每台节点Bird运行状态的仪表盘，在社区里面发现可以用Grafana搭配Prometheus作为数据源实现拓扑图如下：graph TD subgraph DN42 Network N1[Node 1] --> NE1(Node Exporter) N1 --> BE1(Bird/FRR Exporter) N2[Node 2] --> NE2(Node Exporter) N2 --> BE2(Bird/FRR Exporter) N3[Node 3] --> NE3(Node Exporter) N3 --> BE3(Bird/FRR Exporter) N4[Node 4] --> NE4(Node Exporter) N4 --> BE4(Bird/FRR Exporter) end NE1 --> P(Prometheus Server) NE2 --> P NE3 --> P NE4 --> P BE1 --> P BE2 --> P BE3 --> P BE4 --> P P --> G(Grafana Server) User[用户] --> G搭建部署 Prometheus ServerPrometheus Server 将运行在独立的监控服务器上。创建工作目录mkdir -p /opt/prometheus/config /opt/prometheus/data创建 Prometheus 配置文件 (/opt/prometheus/config/prometheus.yml)global: scrape_interval: 15s # 默认抓取间隔 scrape_configs: - job_name: 'prometheus' static_configs: - targets: ['localhost:9090'] # 监控 Prometheus 自身 - job_name: 'node_exporter' static_configs: - targets: ['<node1_ip>:9100', '<node2_ip>:9100', '<node3_ip>:9100', '<node4_ip>:9100'] # 替换为您的 DN42 节点 IP - job_name: 'bird_exporter' static_configs: - targets: ['<node1_ip>:9324', '<node2_ip>:9324', '<node3_ip>:9324', '<node4_ip>:9324'] # 替换为您的 DN42 节点 IP注意: 请将 <nodeX_ip> 替换为您的 DN42 节点的实际 IP 地址。使用 Docker Compose 部署 Prometheus创建 docker-compose.yml 文件：services: prometheus: image: prom/prometheus container_name: prometheus network_mode: host ports: - "9090:9090" volumes: - /opt/prometheus/config/prometheus.yml:/etc/prometheus/prometheus.yml - /opt/prometheus/data:/prometheus command: - '--config.file=/etc/prometheus/prometheus.yml' - '--storage.tsdb.path=/prometheus' - '--web.enable-lifecycle' restart: unless-stopped将数据目录的权限赋予 Prometheus 用户：chown -R 65534:65534 /opt/prometheus/data启动 Prometheus：docker-compose up -d通过访问 http://<监控服务器IP>:9090 来验证 Prometheus 是否正常运行。部署 Node Exporter (每个 DN42 节点上)创建工作目录mkdir -p /opt/node_exporter方式1：使用 Docker 部署 Node Exporterdocker run -d \ --name node_exporter \ --net="host" \ --pid="host" \ -v "/:/host:ro,rslave" \ quay.io/promethe…

MaiBot+AstrBot+Napcat分离部署，实用、稳定且拟人化的QQBot部署方案
type: item
date: 2026-01-23T08:02:00+00:00
description: 灵感来源最近一直在捣鼓QQ机器人，目前后端比较有名的就是AstrBot和 MaiBot 项目，其中AstrBot注重功能性（有多样化的插件服务）而MaiBot注重LLMs聊天与拟人化，遂想要同时给我的机器人接入两个项目，而由于TX的风控，部署在云服务器上的NapCat容易被下号，而由于网络环境问题，MaiBot最好运行在海外服务器上（可以方便的访问Gemini等AI的api），故想到了将AstrBot与NapCat部署在家里NAS上，MaiBot部署在公网服务器上的思路，拓扑图如下：graph LR subgraph NAS AstrBot <--> NapCat end subgraph Server MaiBot end NapCat <-- WebSocket --> MaiBot{message type="info" content="这里将NapCat和AstrBot部署在同一个服务器上，这是因为AstrBot在执行一些功能的时候需要和NapCat共用文件夹，若分开部署则会出现很多问题"/}部署前期准备{x} 一台公网服务器（最好2c2g及以上配置） {x} 一台家宽网络下的Linux服务器 {x} docker环境开始部署首先进入家里云sshmkdir astrbot cd astrbot wget https://raw.githubusercontent.com/NapNeko/NapCat-Docker/main/compose/astrbot.yml sudo docker compose -f astrbot.yml up -d完成然后进入公网服务器{message type="info" content="该部分以下内容大多直接来自官方文档"/}一、准备麦麦部署环境1.1 创建项目目录mkdir -p maim-bot/docker-config/{mmc,adapters} && cd maim-bot1.2 获取 Docker 编排文件wget https://raw.githubusercontent.com/Mai-with-u/MaiBot/main/docker-compose.yml备用下载方式 若 GitHub 直连不稳定，可使用镜像源：wget https://fastly.jsdelivr.net/gh/Mai-with-u/MaiBot@main/docker-compose.yml1.3删除其中的NapCat容器并取消注释adapter的端口映射使用vim docker-compose.yml编辑，编辑完成后如下:services: adapters: container_name: maim-bot-adapters #### prod #### image: unclas/maimbot-adapter:latest # image: infinitycat/maimbot-adapter:latest #### dev #### # image: unclas/maimbot-adapter:dev # image: infinitycat/maimbot-adapter:dev environment: - TZ=Asia/Shanghai ports: #<--此处修改 - "8095:8095" #<--此处修改 volumes: - ./docker-config/adapters/config.toml:/adapters/config.toml # 持久化adapters配置文件 - ./data/adapters:/adapters/data # adapters 数据持久化 restart: always networks: - maim_bot core: container_name: maim-bot-core #### prod #### image: sengokucola/maibot:dev # image: infinitycat/maibot:latest #### dev #### # image: sengokucola/maibot:dev # image: infinitycat/maibot:dev environment: - TZ=Asia/Shanghai - EULA_AGREE=99f08e0cab0190de853cb6af7d64d4de # 同意EULA - PRIVACY_AGREE=9943b855e72199d0f5016ea39052f1b6 # 同意EULA # ports: # - "8000:8000" volumes: - ./docker-config/mmc/.env:/MaiMBot/.en…