<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>科技分享 on Mason's Blog</title><link>https://2e1a95c2.masonblog-b7a.pages.dev/tags/%E7%A7%91%E6%8A%80%E5%88%86%E4%BA%AB/</link><description>Recent content in 科技分享 on Mason's Blog</description><generator>Hugo</generator><language>en</language><lastBuildDate>Sun, 26 Apr 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://2e1a95c2.masonblog-b7a.pages.dev/tags/%E7%A7%91%E6%8A%80%E5%88%86%E4%BA%AB/index.xml" rel="self" type="application/rss+xml"/><item><title>借助 AI，我做了一个各省假期政策查询网站</title><link>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20260426/</link><pubDate>Sun, 26 Apr 2026 00:00:00 +0000</pubDate><guid>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20260426/</guid><description>我是如何借助 Vibe Coding，用一个周末做出了这个各省假期政策查询网站的。</description><content:encoded><![CDATA[<h2 id="起心动念一个法学生的不务正业">起心动念：一个法学生的&quot;不务正业&quot;</h2>
<p>作为一名公司律师，我每天打交道最多的就是各种法规条文，以及来咨询各种法律条文的亲戚朋友。其中一个最常被问到的问题，就是各种劳动法规。尤其是各地假期政策，比如婚假怎么请，产假有多长……这些是每个人都会遇到的问题。</p>
<p>前段时间，我有个朋友跳槽到一家深圳的公司，问我：&ldquo;深圳的陪产假到底是几天？网上查的乱七八糟的。&ldquo;我翻了一圈，发现确实如此。国家层面有一套规定，各省又有各自补充的地方规定，信息散落在各级人社厅的官网、政府公报、地方性法规里，没有一个能一站式对比查看的地方。</p>
<p>我当时就想：要是有一个网站，选一个省份，所有假期政策一目了然，中央规定和地方特别规定并列展示，每条规则还附上法律出处，那该多好。</p>
<p>然后我脑子里蹦出另一个念头——<strong>我为什么不自己做一个呢？</strong></p>
<p>放在以前，这个念头冒出来三秒钟就会被我自己摁回去。我不会写前端，不会画地图，不知道怎么部署网站。但最近这一年，情况变了。</p>
<h2 id="当法学撞上-vibe-coding">当法学撞上 Vibe Coding</h2>
<p>先聊聊什么是 Vibe Coding。这个词是 Andrej Karpathy 在 2025 年初提出来的，大意是：你不再需要逐行手写代码，而是用自然语言描述你想要什么，AI 帮你写。你要做的不是&quot;编程&rdquo;，而是&quot;指挥&rdquo;。<strong>你负责想法和品位，AI 负责执行。</strong></p>
<p>我刚接触 Vibe Coding 的时候，也经历过一段迷茫期。看别人用 Cursor、用 Claude Code 三下五除二搞出一个项目，自己上去一试，发现根本不是那么回事。AI 确实能写代码，但写出来的东西经常有这样那样的问题：组件渲染不出来、类型报错、样式错乱、路由不对……</p>
<p>后来我慢慢悟出来一个道理：<strong>Vibe Coding 不是&quot;不用动脑子&quot;，而是&quot;换一种方式动脑子&quot;。</strong> 你不能真的完全放手，你得学会审阅代码、提出精准的修改指令、在 AI 卡壳的时候指出方向。某种意义上，这和 review 一篇法学论文没什么区别——你不是从头到尾自己写每一个字，但你必须判断哪里有问题、该怎么改。</p>
<p>而我的法律背景，在这个项目里扮演了一个意想不到的角色。</p>
<h2 id="法律思维如何重塑我的开发流程">法律思维如何重塑我的开发流程</h2>
<p>法学的核心训练是什么？如果只让我说一点，那就是<strong>体系化的分类与归入</strong>。面对一个案件，你要做的第一件事不是拍脑袋下结论，而是把事实拆解成若干个法律要件，逐一检视，最后得出结论。</p>
<p>这套思维方式，在我做这个假期政策查询网站的时候，天然地映射到了数据结构的搭建上。</p>
<p>假期政策说白了，就是一个多层级的规则体系：</p>
<ul>
<li><strong>第一层，国家法定基准</strong>。比如产假 98 天、婚假 3 天，这是写在《女职工劳动保护特别规定》和《人口与计划生育法》里的，全国通用。</li>
<li><strong>第二层，各省地方补充规定</strong>。比如上海在 98 天基础上再加 30 天产假，广东的陪产假是 15 天，少数民族自治地方还有特殊政策。</li>
<li><strong>第三层，兜底规则</strong>。如果地方没有特别规定，就自动沿用中央标准。</li>
</ul>
<p>这个三层结构，我用法学里&quot;一般法与特别法&quot;的关系来理解：特别法优先于一般法，特别法没有规定的，适用一般法。这恰恰就是代码里 <code>mergePolicy()</code> 函数的核心逻辑——先加载中央基准数据，再用各省的覆盖字段去 merge，本地有的覆盖中央，本地没有的 fallback 到中央。</p>
<p>所以当 AI 问我要怎么设计数据结构的时候，我几乎没有犹豫就画出了这个 YAML schema：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">婚姻假</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">天数</span>: <span style="color:#ae81ff">3</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">适用条件</span>: <span style="color:#ae81ff">依法办理结婚登记的夫妻</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">工资待遇</span>: <span style="color:#ae81ff">正常发放</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">法律依据</span>:
</span></span><span style="display:flex;"><span>    - <span style="color:#f92672">名称</span>: <span style="color:#ae81ff">国家劳动总局、财政部关于国营企业职工请婚丧假和路程假问题的通知</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">条款</span>: <span style="color:#ae81ff">第一条</span>
</span></span></code></pre></div><p>然后在各省的文件里，只写和中央不同的部分。比如江苏：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">婚姻假</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">天数</span>: <span style="color:#ae81ff">13</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">法律依据</span>:
</span></span><span style="display:flex;"><span>    - <span style="color:#f92672">名称</span>: <span style="color:#ae81ff">江苏省人口与计划生育条例</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">条款</span>: <span style="color:#ae81ff">第二十七条</span>
</span></span></code></pre></div><p>这个设计思路，法学圈的人一眼就能看出来是&quot;特别法优于一般法&quot;的逻辑，但你要让我从头手写代码实现这个 merge 逻辑，放一年前的我绝对写不出来。现在呢？我把思路描述给 AI，半分钟代码就出来了，而且类型检查全过。</p>
<p>Zod 数据校验也是同样的道理。法律讲究&quot;形式要件&quot;，合同缺了某个必要条款就无效。映射到项目里，就是数据文件必须有严格的 schema 验证——<code>central.yaml</code> 必须包含全部 7 类假期，省份文件里每个假期必须包含&quot;天数&quot;字段，法律依据不能为空。我把这些约束用自然语言描述给 AI，它生成了一套 Zod schema，build 之前自动跑一遍验证脚本，任何一个省份的 YAML 格式不对，整个 CI 直接报错。</p>
<p>说起来有点好笑，我的导师要是知道我拿法律方法论去&quot;调教&quot; AI 写代码，不知道会怎么想。但说实话，<strong>这种跨学科的思维迁移，恰恰是 Vibe Coding 时代最有意思的部分</strong>——你不需要是一个科班出身的软件工程师，但你需要有一套成体系的思考框架，不管这套框架是来自法律、医学、建筑还是音乐。</p>
<h2 id="从想法到产品一个周末的构建记录">从想法到产品：一个周末的构建记录</h2>
<p>想法有了，方法论也理顺了，接下来就是动手。</p>
<p>整个项目的技术栈选择，我基本遵循一个原则：<strong>选最主流、AI 最熟悉的方案</strong>。这不是炫技的时候，我是拿来主义的信徒——Next.js + Tailwind CSS + shadcn/ui，这套组合是 AI 训练数据里最充分的技术栈，意味着 AI 出错的概率最低。</p>
<h3 id="数据层31-个省的假期政策汇编">数据层：31 个省的假期政策汇编</h3>
<p>这其实是最耗时的部分。代码可以靠 AI 生成，但内容不行。</p>
<p>我花了差不多两个完整的周末，逐一翻查了 31 个省级行政区的卫健委、人社厅官网，以及各地方人大发布的计划生育条例修正案。每一条规则我都在旁边标注了原文件的名称、条款号和官方链接。有些省份的规定藏得特别深——比如某个自治区的陪产假规定，写在一份 2016 年的《关于修改〈XX 自治区人口与计划生育条例〉的决定》里，要顺着修正案的指示往前翻原文才能拼出完整的规则。</p>
<p>这件事 AI 帮不了忙，至少现在帮不了。它可能会&quot;编造&quot;一些看起来很像真的法条，但在这种事上，一个法律人的底线还是有的——<strong>数据必须可溯源</strong>。</p>
<p>所有整理好的数据，我按照 <code>XX-pinyin.yaml</code> 的命名规范放在 <code>data/provinces/</code> 目录里，一共 31 个文件，加上一个 <code>central.yaml</code> 做基准。</p>
<h3 id="前端svg-中国地图的三天折磨">前端：SVG 中国地图的三天折磨</h3>
<p>整个项目里最让我头疼的部分，是中国地图。</p>
<p>一开始我想得很简单：找个现成的 ECharts 图表库，把中国地图渲染出来就完了。结果发现 ECharts 的中国地图用的是 GeoJSON 格式，数据量巨大不说，暗黑模式下的颜色适配也很麻烦。AI 建议我用原生 SVG，但网上找到的中国地图 SVG 大多质量堪忧——边界线粗糙，有些省份的路径数据甚至不完整。</p>
<p>最后我采取了一个折中方案：让 AI 帮我生成一个精确的 SVG 路径数据，存储为 JSON 文件，每个省份一条 path，包含 viewBox、路径坐标和省份中心的经纬度。然后自己写了一个 React 组件来做交互。</p>
<p>这里有个细节值得一提：<strong>小省份的点击区域</strong>。北京、天津、上海这些直辖市在地图上实在太小了，鼠标根本点不到。我当时跟 AI 反复来回了好几轮，最后想到一个办法——在路径外面套一层不可见的圆形点击热区，半径放大 3 倍，覆盖周围的空白区域。这个方案 AI 没有主动提出来，但当我描述给它之后，它很快就实现了。</p>
<p>地图的热力图配色也调了很久。我定义了一个&quot;假期热度值&quot;，把婚假天数、产假天数和陪产假天数相加，然后分成四档：</p>
<ul>
<li><strong>绿色（≥200）</strong>：假期福利比较到位的省份</li>
<li><strong>黄色（190-199）</strong>：中上水平</li>
<li><strong>红色（180-189）</strong>：中等偏下</li>
<li><strong>深红色（&lt;180）</strong>：假期天数较少的地方</li>
</ul>
<p>说实话，这个&quot;热度值&quot;的算法相当粗糙，但我就是想给用户一个直观的视觉感受——一眼扫过去，大致知道哪个&quot;颜色区域&quot;假期多一些。未来如果有时间，我打算引入更多权重因素，比如育儿假、探亲假也纳入计算。</p>
<h3 id="每个省的详情页七类假期的卡片式展示">每个省的详情页：七类假期的卡片式展示</h3>
<p>省份详情页的设计灵感来自我手机上的健康 App 仪表盘——每一类假期是一张独立的信息卡片，顶部显示天数，中间是适用条件和工资待遇，底部折叠了资格认定和注意事项的详细说明。</p>
<p>最有价值的设计是 <strong>&ldquo;来源标签&quot;系统</strong>。每条规则右侧都会有一个小标签：</p>
<ul>
<li><strong>&ldquo;中央规定&rdquo;</strong>（灰色标签）：表示这条来自国家层面的法律法规</li>
<li><strong>&ldquo;本地特别规定&rdquo;</strong>（蓝色标签）：表示这是该省在中央基础上额外制定的政策</li>
</ul>
<p>两者并列展示，用户一眼就能分辨出哪些是国家给的、哪些是本省额外补充的。</p>
<h3 id="部署github-actions--github-pages零成本上线">部署：GitHub Actions + GitHub Pages，零成本上线</h3>
<p>部署部分反而是整个项目最简单的一环。</p>
<p>Next.js 有个特性叫 Static Export，简单说就是把整个网站预渲染成纯静态的 HTML + CSS + JS 文件，不需要服务器。我只需要在 <code>next.config.mjs</code> 里加一行 <code>output: &quot;export&quot;</code>，然后配置 GitHub Actions 在每次 push 代码到 main 分支的时候自动 <code>npm run build</code>，把产物推到 GitHub Pages 上。</p>
<p>CI 流水线也很干净：</p>
<ol>
<li>Checkout 代码</li>
<li><code>npm ci</code> 装依赖</li>
<li><code>npm run validate-data</code> 校验所有 YAML 数据文件的格式</li>
<li><code>npm run typecheck</code> TypeScript 类型检查</li>
<li><code>npm run build</code> 构建静态产物</li>
<li>部署到 GitHub Pages</li>
</ol>
<p>从 push 代码到网站更新，全自动，整个过程不到两分钟。</p>
<p>最终线上地址：<a href="https://masonblog.github.io/HolidayGO-CN">masonblog.github.io/HolidayGO-CN</a></p>
<h2 id="写在最后ai-时代创意才是真正的稀缺资源">写在最后：AI 时代，创意才是真正的稀缺资源</h2>
<p>这个项目做完，我最大的感触不是&quot;AI 好厉害&rdquo;，而是——<strong>在 AI 时代，有想法的人太少了，能把想法落地的人更少。</strong></p>
<p>你不信的话，想想看：全中国每年有多少法学生、律师、HR 从业者，每天都在查假期政策，查完之后该干嘛干嘛。有多少人会冒出&quot;我为什么不做一个查询工具&quot;这个念头？又有多少人冒出了这个念头之后，真的打开电脑，开始做了？</p>
<p>AI 拉平了技术实现的鸿沟，但没有拉平&quot;想不想做&quot;和&quot;能不能坚持做完&quot;的鸿沟。</p>
<p>我不是什么编程大神。在开始这个项目之前，我连 Next.js 的路由是怎么写的都不知道。但现在呢？一个可用的产品摆在这里，31 个省的数据覆盖齐全，有暗黑模式、有交互地图、有来源溯源，CI/CD 全自动部署。这些东西，<strong>放在两年前，是我一个文科生想都不敢想的事情</strong>。而在 2026 年，我用业余时间，借助 AI，做到了。</p>
<p>所以我想说的是：如果你的脑子里一直有一个&quot;要是能有个什么东西就好了&quot;的想法，别犹豫，现在就动手。不需要等到你&quot;学会了编程&quot;才开始——那个时代已经过去了。你只需要：</p>
<ul>
<li><strong>一个清晰的想法</strong>（这是你最独特的资产，AI 抢不走）</li>
<li><strong>一套成体系的思维框架</strong>（不管来自哪个学科）</li>
<li><strong>愿意花时间去打磨细节的耐心</strong>（AI 能帮你写代码，但打磨产品只能靠你自己）</li>
</ul>
<p>剩下的，交给 AI 和时间。</p>
<hr>
<p><em>这个项目的所有代码开源在 GitHub：<a href="https://github.com/masonblog/HolidayGO-CN">masonblog/HolidayGO-CN</a>。如果你对假期政策数据有补充或纠错，欢迎提 PR。</em></p>
<p><em>如果你也是一个非技术背景、但用 AI 做出了自己作品的&quot;野生开发者&quot;，欢迎在评论区聊聊你的故事——我很想听听。</em></p>
]]></content:encoded></item><item><title>Claude Code 源代码泄露：一个 .npmignore 引发的连锁风暴</title><link>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20260406/</link><pubDate>Mon, 06 Apr 2026 00:00:00 +0000</pubDate><guid>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20260406/</guid><description>深度解析 2026 年 3 月 Anthropic 意外泄露 Claude Code 全部源代码的事件始末。</description><content:encoded><![CDATA[<p>2026 年 3 月 31 日，AI 圈迎来了一场意想不到的&quot;愚人节前夕大礼&quot;：Anthropic 旗下明星产品 <strong>Claude Code</strong> 的全部源代码，因一个打包失误意外流向了互联网。</p>
<p>这不是黑客攻击，不是内鬼泄密，而是有人忘记在 <code>.npmignore</code> 里加了一行 <code>*.map</code>。</p>
<p>就这样，51 万行 TypeScript 代码、44 个隐藏功能开关、以及一个叫做 KAIROS 的神秘&quot;后台自主代理&quot;，在几小时内暴露在所有人面前。</p>
<h2 id="事件经过一个-map-文件引发的雪崩">事件经过：一个 .map 文件引发的雪崩</h2>
<h3 id="泄露是如何发生的">泄露是如何发生的？</h3>
<p>2026 年 3 月 31 日，Anthropic 在 npm 上发布了 <code>@anthropic-ai/claude-code</code> 的 <strong>2.1.88 版本</strong>。这次更新本是例行维护，但却附带了一个巨大的&quot;彩蛋&quot;——一个 <strong>59.8 MB 的 JavaScript Source Map 文件</strong>（<code>.map</code> 后缀）。</p>
<p>Source Map 是开发者用于调试压缩/混淆代码的工具，它能将编译后的代码映射回原始的 TypeScript 源码。正是这个本应只存在于内部的调试文件，被意外打入了公开发布的 npm 包里。</p>
<p>更关键的是，这个 <code>.map</code> 文件还指向了一个 Anthropic 自家云存储上的 ZIP 压缩包，里面存放着<strong>完整的源代码仓库</strong>。所有人只需要顺着这条线索，就能下载到全部代码。</p>
<p><strong>根本原因</strong>：有人忘记在 <code>.npmignore</code> 文件中添加 <code>*.map</code> 规则，导致 Source Map 文件随包一起发布。</p>
<h3 id="传播有多快">传播有多快？</h3>
<p>代码在公开后数小时内便被开发者社区察觉，随即被备份到 GitHub 上。根据 Layer5 的统计，相关仓库的 Fork 数量迅速突破 <strong>41,500 次</strong>，一度成为 <strong>GitHub 历史上增长最快的仓库</strong>。</p>
<p>Anthropic 很快确认了这一事件，但表示这只是一次&quot;发布打包失误&quot;，没有泄露用户数据或凭证信息。</p>
<h2 id="泄露的内容512000-行代码里藏着什么">泄露的内容：512,000 行代码里藏着什么？</h2>
<p>源代码共包含 <strong>1,906 个 TypeScript 文件</strong>，整个 AI 圈的开发者和研究者们开始像考古学家一样，在代码里挖掘 Anthropic 从未公开过的秘密。</p>
<h3 id="秘密一kairos--始终在线的自主-ai-代理">秘密一：KAIROS —— 始终在线的自主 AI 代理</h3>
<p>这是泄露内容中最受关注的发现之一。代码中一个名为 <strong>KAIROS</strong> 的功能标志被提及超过 <strong>150 次</strong>。</p>
<p>KAIROS 来自古希腊语，意为&quot;恰当的时机&quot;。从代码逻辑来看，它代表着 Claude Code 的一次重大范式转变：<strong>从被动响应变为主动的后台自主守护进程（Daemon）</strong>。</p>
<p>具体来说，KAIROS 模式包含一个叫做 <strong>autoDream</strong> 的子机制：当用户处于空闲状态时，Claude 会在后台自动进行&quot;记忆整合&quot;，将分散的观察合并、消除逻辑矛盾，并将模糊的认知转化为具体的知识。</p>
<p>这本质上是让 AI 拥有了一种<strong>持续学习和自我优化</strong>的能力——不仅是在你主动使用时，而是随时随地都在运转。</p>
<h3 id="秘密二buddy--一只赛博电子宠物">秘密二：BUDDY —— 一只赛博电子宠物</h3>
<p>是的，你没看错。代码里藏着一个完整的<strong>电子宠物系统</strong>，叫做 <strong>BUDDY</strong>。</p>
<p>它有：</p>
<ul>
<li><strong>18 个物种</strong>可供选择</li>
<li><strong>稀有度分级</strong>：普通（60%）→ 稀有 → 史诗 → 传说（1%）</li>
<li><strong>闪光变体</strong>（类似宝可梦的色违）</li>
<li><strong>专属属性值</strong>，包括 <code>DEBUGGING</code>（调试力）、<code>PATIENCE</code>（耐心）、<code>CHAOS</code>（混乱值）、<code>WISDOM</code>（智慧）和 <code>SNARK</code>（毒舌度）</li>
</ul>
<p>根据代码注释，BUDDY 原本计划作为<strong>愚人节彩蛋</strong>于 4 月 1 日悄悄上线预告，并在 5 月正式发布。结果，在 3 月 31 日就被这次意外泄露提前&quot;剧透&quot;了——时机不可谓不讽刺。</p>
<h3 id="秘密三隐身模式--anthropic-员工的马甲">秘密三：隐身模式 —— Anthropic 员工的&quot;马甲&quot;</h3>
<p>代码中还发现了一个被称为&quot;隐身模式&quot;（Stealth Mode）的功能，其设计目的是<strong>隐藏 Anthropic 员工对开源项目的贡献</strong>。</p>
<p>简单来说，当 Anthropic 工程师使用 Claude Code 向开源社区提交代码时，该模式会对外屏蔽其 Anthropic 员工的身份。这一发现在开源社区引发了一定的讨论和争议。</p>
<h3 id="秘密四反蒸馏机制--给竞争对手的毒药">秘密四：反蒸馏机制 —— 给竞争对手的&quot;毒药&quot;</h3>
<p>代码中的 <code>ANTI_DISTILLATION_CC</code> 功能标志揭示了一个更具攻击性的策略：<strong>向 API 请求中注入虚假的工具定义</strong>。</p>
<p>其目的在于污染那些监听 API 流量、试图通过&quot;知识蒸馏&quot;来学习和复制 Claude 能力的竞争对手的训练数据。此外，代码还会对 AI 的推理过程进行摘要并附上加密签名，使得窃听者只能获取摘要，而非完整的思维链输出。</p>
<h2 id="安全警告趁火打劫的黑客">安全警告：趁火打劫的黑客</h2>
<p>意外泄露事件本身危害有限，但随之而来的安全风险不可小觑。</p>
<h3 id="axios-npm-遭投毒北朝鲜黑客的精准狙击">Axios npm 遭投毒：北朝鲜黑客的精准狙击</h3>
<p>就在同一天（3 月 31 日），黑客攻陷了流行 HTTP 库 <strong>Axios 的 npm 账号</strong>，发布了两个恶意版本（<code>1.14.1</code> 和 <code>0.30.4</code>）。这些版本通过一个名为 <code>plain-crypto-js</code> 的隐藏依赖，植入了一个<strong>跨平台远程访问木马（RAT）</strong>。</p>
<p>恶意版本在被 npm 下架前存活了约 <strong>2-3 小时</strong>。</p>
<p>Google 威胁情报团队将此次攻击归因于 <strong>UNC1069</strong>——一个具有朝鲜背景的、以经济利益为驱动的威胁行为者，所使用的恶意软件为 <strong>WAVESHAPER.V2</strong>。</p>
<p><strong>高危时间窗口</strong>：如果你在 <strong>3 月 31 日 00:21 UTC 至 03:29 UTC</strong> 之间通过 npm 安装或更新了 Claude Code，你的机器可能已被植入恶意代码。</p>
<h3 id="github-上的假冒仓库">GitHub 上的假冒仓库</h3>
<p>除了 npm 投毒，威胁行为者还在 GitHub 上散布了伪装成&quot;Claude Code 源代码镜像&quot;的恶意仓库。这些仓库诱骗用户运行一个 Rust 编写的投放程序，最终部署 <strong>Vidar Stealer</strong>（信息窃取木马）和 <strong>GhostSocks</strong>（代理恶意软件）。</p>
<h3 id="应急自查步骤">应急自查步骤</h3>
<p>如果你是开发者，请立即执行以下检查：</p>
<ol>
<li>检查你的项目 <code>lockfile</code>（<code>package-lock.json</code> 或 <code>yarn.lock</code>），查找 <code>axios</code> 版本 <code>1.14.1</code> 或 <code>0.30.4</code>。</li>
<li>检查是否存在 <code>plain-crypto-js</code> 依赖项。</li>
<li>如果发现上述任一情况，<strong>立即将该主机视为已完全沦陷</strong>：轮换所有密钥和凭证，并考虑重装操作系统。</li>
</ol>
<h2 id="影响与反思">影响与反思</h2>
<h3 id="对-anthropic-的影响">对 Anthropic 的影响</h3>
<p>这次事件对 Anthropic 的直接损失是<strong>竞争情报的泄露</strong>。KAIROS、反蒸馏机制等未发布的战略功能，已被竞争对手和研究者提前看到。</p>
<p>但从另一个角度看，Anthropic 的处理方式——快速承认、如实说明原因——在一定程度上维护了公众信任。</p>
<h3 id="对供应链安全的警示">对供应链安全的警示</h3>
<p>这次事件是一个关于 <strong>软件供应链安全</strong> 的经典案例：</p>
<ul>
<li><strong>开发侧</strong>：一个被遗忘的打包规则（<code>.npmignore</code>）可以造成灾难性的信息泄露。</li>
<li><strong>攻击侧</strong>：黑客能够以惊人的速度（同日）利用高关注度事件实施供应链攻击。</li>
<li><strong>用户侧</strong>：在重大事件发酵期间，来自&quot;官方渠道&quot;之外的任何下载都极度危险。</li>
</ul>
<p>这提醒每一个维护开源项目的团队：<strong>发布流程的审计和自动化检查，与代码本身的质量同等重要。</strong></p>
<h2 id="结语">结语</h2>
<p>Claude Code 源代码泄露事件，是 2026 年 AI 领域最戏剧性的事故之一。它以一种意想不到的方式，让公众得以一窥顶尖 AI 工具背后的工程逻辑与产品野心——从重塑人机交互范式的 KAIROS，到充满极客趣味的电子宠物 BUDDY。</p>
<p>然而，伴随着这场意外透明化而来的，是供应链攻击的真实威胁。它再次提醒我们：在这个软件高度依赖开源生态的时代，安全从来不只是代码里的事，更是发布流程、依赖管理和应急响应能力的综合体现。</p>
<hr>
<p><strong>延伸阅读：</strong></p>
<ul>
<li><a href="https://venturebeat.com/technology/claude-codes-source-code-appears-to-have-leaked-heres-what-we-know">Claude Code 源代码泄露事件详情 - VentureBeat</a></li>
<li><a href="https://thehackernews.com/2026/04/claude-code-tleaked-via-npm-packaging.html">Anthropic 确认 npm 打包失误 - The Hacker News</a></li>
<li><a href="https://decodethefuture.org/en/axios-npm-attack-rat-claude-code/">Axios npm 投毒与 RAT 事件 - Decode the Future</a></li>
<li><a href="https://www.theregister.com/2026/04/02/trojanized_claude_code_leak_github/">伪造 Claude Code 下载传播恶意软件 - The Register</a></li>
<li><a href="https://wavespeed.ai/blog/posts/claude-code-leaked-source-hidden-features/">KAIROS 与隐藏功能完整分析 - WaveSpeed AI</a></li>
<li><a href="https://coder.com/blog/what-the-claude-code-leak-tells-us-about-supply-chain-security">供应链安全的启示 - Coder Blog</a></li>
</ul>
]]></content:encoded></item><item><title>为了寻找 ATMB 美国住宅地址，我专门写了一个小程序</title><link>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20260214/</link><pubDate>Sat, 14 Feb 2026 00:00:00 +0000</pubDate><guid>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20260214/</guid><description>介绍一个能帮你快速筛选美国住宅地址的开源小工具</description><content:encoded><![CDATA[<p>如果你是“云居民”或数字游民，相信你对 <strong>Anytime Mailbox (ATMB)</strong> 一定不陌生。它是目前最流行的美国云信箱服务之一，提供了海量的美国地址供我们租赁使用。</p>
<p>但是，对于很多需要申请美国银行账户（如 Capital One, Chase 等）或注册美国券商账号的朋友来说，ATMB 最大的痛点在于：<strong>绝大多数地址都是“商业地址” (Commercial / CMRA)，而银行往往要求提供“住宅地址” (Residential / RDI)。</strong></p>
<p>要在 ATMB 浩如烟海的地址列表中，手动一个个去查哪个是住宅地址，简直是大海捞针，费时费力。</p>
<p>为了解决这个问题，我写了一个开源的小程序：<strong>ATMB-Addresses</strong>。</p>
<h2 id="这个工具能做什么">这个工具能做什么？</h2>
<p>简单来说，它就像一个自动化的“探针”，可以帮我们：</p>
<ol>
<li><strong>自动爬取</strong> ATMB 上指定州（或全美）的所有地址信息。</li>
<li><strong>自动识别</strong> 每个地址的属性，帮我们判断它究竟是 <strong>住宅 (Residential)</strong> 还是 <strong>商业 (Commercial)</strong> 地址。</li>
<li><strong>整理成表</strong>，将结果保存为 Excel/CSV 文件，方便我们筛选。</li>
</ol>
<h2 id="如何使用无需编程基础">如何使用（无需编程基础！）</h2>
<p>虽然这是一个 Python 程序，但我知道很多朋友可能对代码并不熟悉。没关系！为了方便大家，我已经把<strong>爬取并验证好的现成数据</strong>直接上传到了仓库里。</p>
<p>如果你懒得自己跑程序，只需要直接下载我跑好的数据即可。</p>
<h3 id="步骤如下">步骤如下：</h3>
<ol>
<li>访问我的 GitHub 仓库：<a href="https://github.com/masonblog/ATMB-Addresses">https://github.com/masonblog/ATMB-Addresses</a></li>
<li>点击页面上的 <strong>&ldquo;Public&rdquo;</strong> 文件夹。</li>
<li>在里面找到你感兴趣的州（比如 <code>new-york.csv</code> 或 <code>california.csv</code>）。</li>
<li>下载这个 CSV 文件，用 Excel 打开。</li>
<li>在表格中寻找 <strong><code>rdi</code></strong> 这一列：
<ul>
<li>如果显示 <strong><code>Residential</code></strong>，恭喜你！这很可能就是一个银行认可的住宅地址。</li>
<li>如果显示 <code>Commercial</code>，那就是普通的商业地址。</li>
</ul>
</li>
</ol>
<p>就是这么简单！</p>
<h2 id="进阶玩家如何自己运行代码">进阶玩家：如何自己运行代码</h2>
<p>如果你是技术党，或者你想获取最新的实时数据（毕竟地址库会更新），你也可以把代码下载到本地自己运行。</p>
<h3 id="1-准备工作">1. 准备工作</h3>
<p>首先，你需要确保电脑上安装了 Python 3.x 环境，并安装必要的依赖库。在终端中运行以下命令：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>pip install requests beautifulsoup4
</span></span></code></pre></div><p>其次，这个工具最核心的“验证”功能依赖于 <strong>Smarty API</strong>。你需要去 <a href="https://www.smarty.com/">Smarty.com</a> 注册一个账号（它提供免费1000条地址验证的试用额度，够我们跑很多数据了）。注册好后，获取你的 <code>Auth ID</code> 和 <code>Auth Token</code>，把它们保存好，后面会用到。</p>
<p>然后，访问我的 GitHub 仓库：<a href="https://github.com/masonblog/ATMB-Addresses">https://github.com/masonblog/ATMB-Addresses</a>，点击<strong>Code</strong>按钮，再点击<strong>Download ZIP</strong>打包下载代码。</p>
<p><img alt="Download_ZIP" loading="lazy" src="/images/blog20260214/download_zip.png"></p>
<p>在代码**根目录（解压后的文件夹）**下创建一个名为 <code>smarty_api_key.txt</code> 的文件，将刚刚保存的 Smarty API 的 <code>Auth ID</code> 和 <code>Auth Token</code> 填入这个文件并保存：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>auth_id=你的AUTH_ID
</span></span><span style="display:flex;"><span>auth_token=你的AUTH_TOKEN
</span></span></code></pre></div><h3 id="2-开始运行">2. 开始运行</h3>
<p>整个流程分为三步：爬取 -&gt; 补充详情（可选） -&gt; 验证。</p>
<h4 id="第一步爬取基本地址信息">第一步：爬取基本地址信息</h4>
<p>在代码文件夹右键单击，选择“在终端中打开”，然后输入以下命令运行 <code>ATMB_scrape.py</code>。你可以指定爬取某个州，或者直接爬取全美所有地址。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># 爬取纽约州</span>
</span></span><span style="display:flex;"><span>python ATMB_scrape.py --input new-york
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 爬取全美（耗时较长）</span>
</span></span><span style="display:flex;"><span>python ATMB_scrape.py --input us
</span></span></code></pre></div><p>程序运行后，会在 <code>Public</code> 文件夹下生成一个 CSV 文件，比如 <code>Public/new-york.csv</code>，里面包含了 ATMB 上最新爬取的地址信息，包括街道地址、城市、州、邮编等。</p>
<h4 id="第二步补充单元号信息可选">第二步：补充单元号信息（可选）</h4>
<p>ATMB 的列表页通常只显示街道地址，但很多时候我们需要知道具体的<strong>单元号信息</strong>，比如 <code>Suite #</code> 或 <code>Unit #</code>。这一步就要在终端中输入以下命令，程序会访问每个地址的详情页，把这些信息抓取下来：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>python ATMB_detail.py --input Public/new-york.csv
</span></span></code></pre></div><p>运行完成后，会生成一个新的文件 <code>Public/new-york_detailed.csv</code>。</p>
<h4 id="第三步验证地址性质关键步骤">第三步：验证地址性质（关键步骤）</h4>
<p>最后，我们使用 Smarty API 来验证这些地址是<strong>住宅</strong>还是<strong>商业</strong>。在终端中运行以下命令：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>python ATMB_verify.py --input Public/new-york_detailed.csv
</span></span></code></pre></div><p>程序会逐行验证，并生成最终的文件 <code>Public/new-york_detailed_verified.csv</code>。</p>
<p>打开这个最终文件，查看 <strong><code>rdi</code></strong> 列：</p>
<ul>
<li><strong><code>Residential</code></strong>: 住宅地址（银行喜欢这个！✅）</li>
<li><strong><code>Commercial</code></strong>: 商业地址（⚠️）</li>
</ul>
<p>详细的技术文档和使用参数，我都写在仓库的 <code>README.md</code> 里了，欢迎大家去 Star 和 Fork！</p>
<h2 id="结语">结语</h2>
<p>寻找一个靠谱的美国住宅地址是很多“云居民”迈向全球化的第一步。希望这个小工具能帮你节省宝贵的时间，少走弯路。</p>
<p>如果你觉得好用，别忘了分享给身边有需要的朋友！</p>
]]></content:encoded></item><item><title>如何在 Windows 上使用 ClawdBot ：用 Gemini 和 Telegram 打造你的私人 AI 助理</title><link>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20260127/</link><pubDate>Tue, 27 Jan 2026 00:00:00 +0000</pubDate><guid>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20260127/</guid><description>在 Windows 上安装 ClawdBot 的详细教程</description><content:encoded><![CDATA[<p>你听说过 <strong>ClawdBot</strong> 吗？这是一个目前非常热门的开源个人 AI 助手。与那些只会“坐等指令”的传统聊天机器人不同，ClawdBot 具有 <strong>主动性</strong>——它可以主动给你发消息、管理任务，而且是运行在你自己的本地设备上。</p>
<p>虽然很多教程都推荐在 Mac Mini 或 Linux 服务器上运行它，但其实 <strong>在 Windows 上运行它也完全没问题</strong>。</p>
<p>在这篇文章中，我将手把手教你在 <strong>Windows</strong> 上安装 ClawdBot，将其配置为使用 Google 的 <strong>Gemini API</strong>（目前最好的 AI 模型，并且赠送有免费额度），并连接到 <strong>Telegram</strong>，让你随时随地都能与你的 AI 助手聊天。</p>
<hr>
<h2 id="-准备工作">🛠️ 准备工作</h2>
<p>在开始之前，请确保你准备好了以下几样东西：</p>
<ol>
<li>一台运行 <strong>Windows 11</strong> 的电脑。</li>
<li><strong>一个 Google Gemini API Key（密钥）：</strong> 你可以在 <a href="https://aistudio.google.com/">Google AI Studio</a> 免费获取。</li>
<li><strong>一个 Telegram 账号：</strong> 用于创建你的机器人。</li>
</ol>
<h2 id="第一步安装-wsl2-windows-subsystem-for-linux">第一步：安装 WSL2 (Windows Subsystem for Linux)</h2>
<p><strong>关键点：</strong> ClawdBot 无法直接在 Windows 的 PowerShell 或 CMD 中原生运行。它需要一个 Linux 环境。幸运的是，Windows 自带了一个完美的工具——<strong>WSL2</strong>。</p>
<ol>
<li>
<p>点击 Windows 开始菜单，找到 <strong>PowerShell</strong>，右键选择 <strong>“以管理员身份运行”</strong>。</p>
</li>
<li>
<p>输入以下命令并回车：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>wsl --install
</span></span></code></pre></div></li>
<li>
<p><strong>重启你的电脑。</strong></p>
</li>
<li>
<p>重启后，打开 应用商店（Microsoft Store），搜索“Ubuntu”，下载并安装 “<strong>Ubuntu 24.04.1 LTS</strong>” 。</p>
</li>
<li>
<p>打开 Ubuntu ，它会要求你创建一个 <strong>用户名和密码</strong>。
<em>提示：输入密码时屏幕上不会显示任何字符，这是正常的，输完回车即可。</em></p>
</li>
</ol>
<p>一旦你进入了这个 Ubuntu 终端窗口，我们就可以继续了。</p>
<h2 id="第二步安装-nodejs-正确姿势">第二步：安装 Node.js (正确姿势)</h2>
<p>ClawdBot 需要较新版本的 <strong>Node.js (v22+)</strong>。Ubuntu 默认自带的版本通常太旧了，所以我们要使用 <strong>NVM</strong> (Node Version Manager) 来安装最新版。</p>
<p><strong>请在刚才打开的 Ubuntu 终端中运行以下命令：</strong></p>
<ol>
<li>
<p><strong>下载并安装 NVM：</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
</span></span></code></pre></div></li>
<li>
<p><strong>刷新环境变量</strong> (让系统识别 NVM)：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>source ~/.bashrc
</span></span></code></pre></div></li>
<li>
<p><strong>安装 Node.js 最新版：</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>nvm install --lts
</span></span></code></pre></div></li>
<li>
<p><strong>验证安装是否成功：</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>node -v
</span></span><span style="display:flex;"><span>npm -v
</span></span></code></pre></div></li>
</ol>
<p>只要这两个命令能打印出版本号，就说明安装成功了！</p>
<h2 id="第三步安装并配置-clawdbot">第三步：安装并配置 ClawdBot</h2>
<p>最简单的部分来了。ClawdBot 提供了一键安装脚本。在你的 Ubuntu 终端中运行：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>curl -fsSL https://clawd.bot/install.sh | bash
</span></span></code></pre></div><p>脚本会自动下载必要的文件，并将 ClawdBot 全局安装到你的虚拟 Linux 系统中。</p>
<p>安装完成后，看到如下界面，说明已经安装成功了：</p>
<p><img alt="Clawdbot 初始化界面" loading="lazy" src="/images/blog20260127/cli_setup.png"></p>
<p>安装完成后，我们需要进行简单的快速配置</p>
<ol>
<li>
<p><strong>启动设置向导的命令如下：</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>clawdbot onboard
</span></span></code></pre></div></li>
<li>
<p><strong>按照提示操作：</strong></p>
<ul>
<li>Understand this is risky（同意风险）: 选 <strong>Yes.</strong></li>
<li>Onboarding mode（启动模式）: 选 <strong>QuickStart.</strong></li>
<li>Model provider: <strong>按需选择</strong>，这里选择 Google Gemini.</li>
<li>API key: 粘贴你之前申请的 Google AI <strong>密钥</strong>。</li>
<li>Defualt model: <strong>按需选择</strong>，推荐选择 gemini-2.0-flash (速度快/成本低) 或 gemini-2.0-pro (更聪明)。</li>
<li>Select channel: <strong>按需选择</strong>，推荐选择 Telegram.</li>
</ul>
</li>
</ol>
<h2 id="第四步配置-telegram-机器人">第四步：配置 Telegram 机器人</h2>
<p>选择 Telegram ，它会要求你输入 <strong>Bot Token</strong>。打开手机或电脑上的 Telegram，搜索 <a href="https://t.me/BotFather"><strong>@BotFather</strong></a>。</p>
<p>发送消息 <code>/newbot</code> 给它，它会让你给你的机器人起个名字（例如 &ldquo;My Jarvis&rdquo;）和用户名（例如 <code>my_private_clawd_bot</code>）。BotFather 会给你一串 API Token（看起来像 <code>123456:ABC-DEF...</code>）。<strong>将这个 Token 粘贴回 Ubuntu 终端窗口中。</strong></p>
<p>继续配置 Clawdbot ，<strong>Skills 和 Hooks 这些都可以先暂时跳过</strong>，监看方式 (how to hatch your bot) 可以按需选择，这里推荐直接在 <strong>命令行 (TUI)</strong> 上监看。</p>
<p>上面这些都配置完成后，你的 Clawbot 就正式开始运行了。</p>
<h2 id="第五步设备配对-pairing">第五步：设备配对 (Pairing)</h2>
<p>为了安全起见，你的机器人不会随便理睬陌生人。你需要将它与 <em>你</em> 的 Telegram 账号进行配对。</p>
<ol>
<li>确保 ClawdBot 正在终端中运行。打开 Telegram 中你刚才创建的机器人，点击 <strong>Start</strong> (或发送 <code>/start</code>)。</li>
<li>机器人会回复一个 <strong>配对码 (Pairing Code)</strong>。</li>
<li>回到你的 Ubuntu 终端。你应该会看到一个请求批准的提示。</li>
<li>根据屏幕提示输入刚才的配对码批准命令。</li>
</ol>
<p><strong>🎉 成功！你的机器人上线，随时待命。</strong></p>
<h2 id="第六步如何使用">第六步：如何使用</h2>
<p>现在，你可以直接在 Telegram 上与你的机器人聊天了。试试这些指令：</p>
<ul>
<li><strong>&ldquo;帮我总结这篇文章：&rdquo;</strong> (粘贴一个文章链接)</li>
<li><strong>&ldquo;提醒我 20 分钟后关烤箱。&rdquo;</strong> (它到时候会主动给你发消息！)</li>
<li><strong>&ldquo;东京现在的天气怎么样？&rdquo;</strong></li>
</ul>
<p><img alt="how to use" loading="lazy" src="/images/blog20260127/bot_chat.jpg"></p>
<h3 id="如何保持后台运行">如何保持后台运行</h3>
<p>因为这个程序运行在你的电脑上，如果你关闭了 Ubuntu 窗口或关机，机器人就会下线。 为了让它在你使用 Windows 时保持后台运行，你可以：</p>
<ol>
<li>简单地将 Ubuntu 终端窗口 <strong>最小化</strong>（不要关闭）。</li>
<li>或者在 Ubuntu 中学习使用 <code>tmux</code> 或 <code>screen</code> 等工具来保持会话。</li>
</ol>
<h3 id="常见问题排查">常见问题排查</h3>
<ul>
<li><strong>错误：&ldquo;Command not found&rdquo;：</strong> 确保你是在 Ubuntu (WSL) 终端中输入命令，而不是在 Windows 的 PowerShell 中。</li>
<li><strong>机器人不回复：</strong> 检查终端里的日志。如果你看到 Gemini API 报错，可能是你的 Key 无效，或者因为请求过多触发了限制（如果用量大，可能需要在 Google Cloud 开启按量付费）。</li>
</ul>
<p><strong>享受你的新 AI 伙伴吧！</strong> 与 ChatGPT 不同，它住在你的硬盘里，了解你的上下文，并且会在 <em>它</em> 觉得你需要知道某些事情时，主动联系你。</p>
]]></content:encoded></item><item><title>年费15元的奥地利 eSIM 电话卡：RedteaGo</title><link>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20250317/</link><pubDate>Mon, 17 Mar 2025 00:00:00 +0000</pubDate><guid>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20250317/</guid><description>可在国内漫游的奥地利保号神卡介绍，支持eSIM</description><content:encoded><![CDATA[<p>由于个人的一些特殊需求，我经常需要用到海外手机号，也因此一直在寻找经济实惠、性能稳定的海外电话卡。之前，我一直在使用美国 UltraMobile 每月 3 美元 的 PayGo 卡，以及香港 3HK 每年 268HKD、45G 流量的漫游卡。这两张卡都各有各的劣势：PayGo 卡在国内只能接打电话、收发短信，无法漫游上网；3HK 可以在国内漫游上网，但它使用的 IP 地址是香港的，无法登录 ChatGPT，也无法接打电话或收发短信。因此，长久以来我一直在寻找一款既能在国内漫游上网（非香港 IP 地址）、又能接收短信，并且价格不能太贵的海外电话卡，直到我发现了一家奥地利运营商 RedteaMobile 的全球上网手机卡——<a href="https://www.redteamobile.com/redtea-go-consumer/#">RedteaGo</a>。</p>
<p>RedteaGo 的全球套餐有以下几点优势：</p>
<ol>
<li>
<p>有效期内（最长365天，可续费）可<strong>免费接收短信</strong>，注册各类 APP【仅全球套餐】</p>
</li>
<li>
<p>支持全球130+地区（包括中国大陆）的漫游上网，<strong>且 IP 地址在欧洲</strong>，可以轻松登录 ChatGPT【仅全球套餐】</p>
</li>
<li>
<p>价格低廉，100MB 保号套餐仅需 3.2 美元/年，若叠加邀请码赠金，则<strong>最低 2 美元（约合人民币15元）即可保号一年</strong></p>
</li>
<li>
<p><strong>支持 eSIM</strong>，无需实体卡即可轻松激活</p>
</li>
<li>
<p>无需实名登记</p>
</li>
</ol>
<p><img loading="lazy" src="/images/blog20250317/plan.jpg"></p>
<p>RedteaGo 的套餐可以在<a href="https://www.redteamobile.com/redtea-go-consumer/#">官方网站</a>或者<a href="https://www.bing.com/search?q=Redteago%20app&amp;qs=n&amp;form=QBRE&amp;sp=-1&amp;ghc=1&amp;lq=0&amp;pq=redteago%20ap&amp;sc=10-11&amp;sk=&amp;cvid=D381E19FE4DF4851B12936EAE9837E7E&amp;ghsh=0&amp;ghacc=0&amp;ghpl=">官方APP</a>上直接购买，如果你的手机支持 eSIM，那么可以通过官方APP直接购买；如果你的手机不支持 eSIM，需要借助第三方实体 eSIM 卡，那么最好在官方网站上下单，因为<strong>只有官方网站下单的套餐才会提供 eSIM 二维码</strong>。</p>
<p>先用邮箱注册一个 RedteaGo 账号，注册时可以使用我的邀请码<code>MASO0042</code>，这样你和我都可以获得 3 美元的赠金，后续购买套餐时可以直接抵用。叠加邀请码赠金后，最低只要 2 美元就能保号一整年。</p>
<p>注册完成后，就可以选购套餐了。<strong>如果想要在购买套餐时使用上面的 3 美元赠金，一定要先往账户里充值，再购买套餐</strong>，因为如果购买套餐时账户余额低于套餐金额的话，就只能选择直接支付套餐金额，无法抵扣邀请码赠金，这点一定切记。</p>
<p>账户充值的最小金额是 2 美元，支付方式可以选择Apple Pay、国际信用卡或支付宝等，下图为  RedteaGo APP 内的充值演示。<strong>注意充值前先看好你想购买套餐的价格，确保充值金额+3美元赠金要大于套餐价格，才能在购买套餐时抵扣</strong>。</p>
<p>以最便宜的 3.2 美元套餐为例，用邀请码注册账号的初始余额为 3 美元（赠送），那么我们只要充值最低的 2 美元，即可拥有 3+2=5 美元的余额。购买套餐时选择用余额支付，则购买完成后，账户中还剩下 5-3.2=1.8 美元，可用于下次购买其他套餐使用。 <img loading="lazy" src="/images/blog20250317/topup.jpg"></p>
<p>充值完成后，就可以开始购买套餐了。这里我推荐以下三个套餐：</p>
<ol>
<li>
<p>全球（130+地区）100MB/365天 免费接收短信 3.2 美元（欧洲 IP）</p>
</li>
<li>
<p>全球（130+地区）1GB/365天 免费接收短信 19.9 美元（欧洲 IP）</p>
</li>
<li>
<p>中国大陆 50GB/365天 不支持短信 26.19 美元（香港 IP）</p>
</li>
</ol>
<p>以上 3 个套餐均可在中国大陆漫游上网，其中<strong>全球套餐为欧洲 IP、中国大陆套餐为香港 IP</strong>。<strong>全球套餐带一个 +43 电话号码，可以免费收短信，中国大陆套餐没有号码，无法收短信</strong>，各位可以按需选择。可以看到，同样是 365 天有效的香港 IP 漫游，第 3 个套餐的价格仅为 190 元，远低于 268 元的 3HK 45G 的套餐（但比 3HK 少了电话号码和短信功能）。如果考虑邀请码赠送的 3 美元，那么最低 170 元即可拿下 50GB/365 天的漫游，岂不美哉~</p>
<p><img loading="lazy" src="/images/blog20250317/check.jpg"></p>
<p>套餐的激活方式也很简单，以支持 eSIM 的 iPhone 为例，直接点击激活按钮，按步骤操作即可。</p>
<p><img loading="lazy" src="/images/blog20250317/activate.jpg"></p>
<p>激活成功后，可以看到手机左上角的运营上是 RedteaMobile，且套餐页面有套餐剩余的流量和有效期。</p>
<p><img loading="lazy" src="/images/blog20250317/use.jpg"></p>
<p>套餐自激活成功后开始计算有效期，不管是什么套餐，遇到以下条件之一即告失效，<strong>失效后必须重新购买套餐才能继续使用，且无法找回之前的电话号码</strong>：</p>
<ol>
<li>
<p>激活后连续 30 天未使用</p>
</li>
<li>
<p>套餐内流量用尽</p>
</li>
<li>
<p>套餐有效期结束</p>
</li>
</ol>
<p><strong>如果想在套餐失效前保留自己的电话号码，那么请务必记得在以上三个条件达成前续费套餐</strong>，否则一旦套餐失效，原先的号码也就离你而去了。</p>
<p>综上，RedteaGo 是一款能够以较低成本获得原生欧洲 IP 的海外手机卡产品，适合有特殊需求的用户，可以完美平替 3HK，且无需实名登记。最后，再次贴出我的邀请码：<code>MASO0042</code>，使用我的邀请码注册，你和我都能获得 3 美金的赠金，可以直接抵扣套餐费用。</p>
]]></content:encoded></item><item><title>利用第三方 Deepseek API 实现 AI 辅助应用</title><link>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20250207/</link><pubDate>Fri, 07 Feb 2025 00:00:00 +0000</pubDate><guid>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20250207/</guid><description>利用硅基流动等第三方API替代Deepseek官方</description><content:encoded><![CDATA[<p>最近一段时间，AI 圈最热的话题莫过于 <a href="https://www.deepseek.com/">Deepseek</a>。它作为国内团队“弯道超车”的典型案例，同时受到两种不同立场群体的吹捧与批评。不过，抛开政治和技术上的争论，单从普通人使用 AI 的成本与门槛来看，Deepseek 确实做到了“AI 的普惠性”。与 OpenAI 等国外大模型运营商相比，Deepseek 的价格极为低廉，对想要学习 AI 应用，而经济条件又非常有限的用户来说，确实是最好的选择。</p>
<p>然而，<strong>受自身承载能力和大规模黑客攻击的限制，Deepseek 的官方服务器在最近一段时间经常会出现连接不稳定的问题</strong>，这给用户带来了不便。<strong>所幸，Deepseek 大模型的开源属性使其能够被部署在任何第三方服务器上</strong>。<a href="https://siliconflow.cn/zh-cn/">硅基流动</a>便是众多第三方 AI 大模型供应商之一，它与<a href="https://www.huaweicloud.com/intl/zh-cn/">华为云</a>合作，以低廉的价格，向用户提供Deepseek r1大模型的API接口应用。用户可以通过这一接口顺利使用 Deepseek 的模型功能。</p>
<p><img loading="lazy" src="/images/blog20250207/SiliconFlow.png"></p>
<h2 id="获取第三方-deepseek-api">获取第三方 Deepseek API</h2>
<p>首先，我们需要在硅基流动的<a href="https://cloud.siliconflow.cn/i/1MwHUt0X">官网</a>注册一个账号。你可以使用我的邀请码<code>1MwHUt0X</code>注册，这样，<strong>你和我都会得到 14 CNY 的免费额度</strong>，可以用来免费体验各个大模型的功能。<strong>如果免费额度用完，想要付费充值的话，就必须完成实名认证</strong>，这也是中国特色的监管要求。</p>
<p>登录硅基流动的后台，我们就能看到它所支持的一系列大模型，其中就包含当下最热门的 Deepseek R1。</p>
<p><img loading="lazy" src="/images/blog20250207/SiliconFlow2.png"></p>
<p>想要调用这些大模型为我们服务，首先要生成我们自己的 API Key。点击硅基流动后台左侧的<code>API 密钥</code>，再点击右上角的<code>新建 API 密钥</code>按钮，来新建一个 API Key。</p>
<p><img loading="lazy" src="/images/blog20250207/SiliconFlow3.png"></p>
<h2 id="结合-chatbox-使用-deepseek-r1-大模型">结合 Chatbox 使用 Deepseek R1 大模型</h2>
<p><a href="https://chatboxai.app/zh">Chatbox</a> 是一款开源的AI聊天机器人客户端，支持包括个人电脑和移动端几乎所有平台（包括网页端），能够调用多种AI模型，以实现文字对话、文生图、程序编写、文案创作等诸多用途。</p>
<p><img loading="lazy" src="/images/blog20250207/Chatbox.png"></p>
<p>出于数据安全与隐私保护的考虑，Chatbox 的所有运行数据都只存储在本地。也就是说，Chatbox 本身只是一个向AI大模型传递数据的工具，它本身并不记录用户的数据。因此，即使我们在不同设备上同时使用 Chatbox，也无法做到配置设置和历史记录的多设备共享。</p>
<p>硅基流动的<a href="https://docs.siliconflow.cn/usercases/use-siliconcloud-in-chatbox">官方文档</a>中提供了将其API接入 Chatbox 的指引。这里简单讲一下配置的重点。软件安装好以后，第一次打开会自动弹出设置界面。<del>选择&quot;添加自定义提供方&quot;，API 域名填写https://api.siliconflow.cn即可</del>。<strong>更新版本的 Chatbox 已经原生支持了硅基流动的 API 接口</strong>，只要在模型提供方处选择<code>SILICONFLOW API</code>，再填写自己的 API Key，并选择想要调用的模型即可。</p>
<p><img loading="lazy" src="/images/blog20250207/Chatbox2.png"></p>
<p>值得注意的是，硅基流动同时提供了<code>Pro/deepseek-ai/DeepSeek-R1</code>和<code>deepseek-ai/DeepSeek-R1</code>两个R1模型，只有不带<code>Pro</code>的那个模型支持消耗平台赠送的免费额度，带<code>Pro</code>的必须付费充值后才能使用，选的时候不要选错了。</p>
<p>配置好后点击保存，就可以开始和我们的AI大模型聊天了。Chatbox 软件内预置了很多好用的 Prompt 场景，可以都尝试一下。</p>
<p><img loading="lazy" src="/images/blog20250207/Chatbox3.png"></p>
<h2 id="结合vs-code的cline插件使用deepseek-r1大模型">结合VS Code的Cline插件使用Deepseek R1大模型</h2>
<p>对于开发者，<a href="https://code.visualstudio.com/">Visual Studio Code</a> 是一个非常流行的代码编辑器，同时也支持丰富的AI插件。我们可以通过这些插件让 VS Code 调用硅基流动的 Deepseek R1 大模型 API，以实现AI辅助编程的应用。</p>
<p>下载和安装好 VS Code 软件后，在它的扩展市场中搜索“AI”相关插件，比如<a href="https://github.com/cline/cline">Cline</a>，它是一款能够调用各种AI大模型来辅助用户编写程序的插件，可以提供超越代码完成或技术支持的帮助。Cline 支持 OpenRouter、Deepseek、OpenAI、Google Gemini 和 GCP Vertex 等 API 提供商。你还可以配置任何兼容 OpenAI 的 API，或通过 LM Studio/Ollama 使用本地模型。</p>
<p><img loading="lazy" src="/images/blog20250207/Cline.png"></p>
<p>打开 VS Code 软件，点击左侧的<code>插件商店</code>按钮，在搜索框中输入<code>Cline</code>，再搜索到的 Cline 页面中点击<code>安装</code>，即可在VS Code软件中安装 Cline 插件。</p>
<p><img loading="lazy" src="/images/blog20250207/Cline2.png"></p>
<p>安装完成后，点击左侧多出来的 Cline 小机器人图标打开插件。点击插件右上角的设置按钮，开始配置我们的 API 接口。在对应位置选择或填写相应的内容即可。</p>
<ul>
<li>
<p>API Provider：<code>OpenAI Compatible</code></p>
</li>
<li>
<p>Base URL：<code>https://api.siliconflow.cn/</code></p>
</li>
<li>
<p>API Key：<code>你的硅基流动API Key</code></p>
</li>
<li>
<p>Model ID：<code>deepseek-ai/DeepSeek-R1</code></p>
</li>
</ul>
<p><img loading="lazy" src="/images/blog20250207/Cline3.png"></p>
<p>最后点击保存，就可以开始通过和AI大模型聊天的方式进行代码编写了。Cline 支持一键创建目录和文件，只要使用得当，即使零基础的人也可以编写出对应需求的程序。</p>
<h2 id="结语">结语</h2>
<p>由于 Deepseek 官方服务器偶尔出现连接不上的情况，我们仍然可以通过硅基流动的第三方 API 顺利使用 Deepseek R1 大模型。通过结合 Chatbox 和 VS Code 两大工具，我们不仅可以轻松进行 AI 对话，还可以获得专业的代码编写建议。</p>
]]></content:encoded></item><item><title>Hugo &amp; PaperMod 建站技术记录</title><link>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20241230/</link><pubDate>Mon, 30 Dec 2024 00:00:00 +0000</pubDate><guid>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20241230/</guid><description>此页面记录了我利用 Hugo 搭建本站的部分技术细节</description><content:encoded><![CDATA[<p>早在4年前刚开始搭建本博客时，我曾写过一篇简短的<a href="/post/blog20200310/">文章</a>，介绍了我建站时使用的一些工具。如今，那篇文章中提到的很多工具都已过时。加之本次博客整体迁移，又使用了全新的 <a href="https://github.com/adityatelange/hugo-PaperMod">PaperMod </a>主题，很多功能的配置方式都发生了变化。于是我决定重新写一篇文章，记录一下我在折腾这个新主题过程中的一些技术细节。</p>
<h1 id="配置文件语法">配置文件语法</h1>
<p>Hugo 同时支持3钟配置文件语法，分别为 <code>YAML</code>、<code>TOML</code>和<code>JSON</code>。它们都是常用的数据序列化和配置文件格式，且各有特点和适用场景。</p>
<h2 id="yaml-yaml-aint-markup-language">YAML (YAML Ain&rsquo;t Markup Language)</h2>
<p><code>YAML</code>是一种人类可读的数据序列化格式，常用于配置文件和数据交换，它的语法格式为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">name</span>: <span style="color:#ae81ff">John Doe</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">age</span>: <span style="color:#ae81ff">30</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">city</span>: <span style="color:#ae81ff">New York</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">hobbies</span>:
</span></span><span style="display:flex;"><span>- <span style="color:#ae81ff">reading</span>
</span></span><span style="display:flex;"><span>- <span style="color:#ae81ff">traveling</span>
</span></span></code></pre></div><p>它的特点为：</p>
<ul>
<li>
<p>语法简洁，易于阅读和编写</p>
</li>
<li>
<p>支持注释、多行字符串和复杂的数据结构</p>
</li>
<li>
<p>使用缩进表示层级关系</p>
</li>
</ul>
<h2 id="toml-toms-obvious-minimal-language">TOML (Tom&rsquo;s Obvious, Minimal Language)</h2>
<p><code>TOML</code>是一种旨在成为最小配置文件格式的语言，设计目标是易于阅读和编写，它的语法格式为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-toml" data-lang="toml"><span style="display:flex;"><span>[<span style="color:#a6e22e">person</span>]
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">name</span> = <span style="color:#e6db74">&#34;John Doe&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">age</span> = <span style="color:#ae81ff">30</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">city</span> = <span style="color:#e6db74">&#34;New York&#34;</span>
</span></span><span style="display:flex;"><span>[<span style="color:#a6e22e">person</span>.<span style="color:#a6e22e">hobbies</span>]
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">favorite</span> = <span style="color:#e6db74">&#34;reading&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">others</span> = [<span style="color:#e6db74">&#34;traveling&#34;</span>, <span style="color:#e6db74">&#34;photography&#34;</span>]
</span></span></code></pre></div><p>它的特点为：</p>
<ul>
<li>
<p>语法直观，易于理解</p>
</li>
<li>
<p>支持注释</p>
</li>
<li>
<p>支持多种数据类型，包括日期时间</p>
</li>
<li>
<p>允许创建嵌套的数据结构</p>
</li>
</ul>
<h2 id="json-javascript-object-notation">JSON (JavaScript Object Notation)</h2>
<p>JSON是一种轻量级的数据交换格式，最初源于JavaScript，但现在已广泛应用于各种编程语言，它的语法格式为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#e6db74">&#34;name&#34;</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;John Doe&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#e6db74">&#34;age&#34;</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">30</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#e6db74">&#34;city&#34;</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;New York&#34;</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>它的特点为：</p>
<ul>
<li>
<p>简洁易读</p>
</li>
<li>
<p>解析速度快</p>
</li>
<li>
<p>与JavaScript高度兼容</p>
</li>
<li>
<p>支持基本数据类型：字符串、数字、布尔值、null、对象和数组</p>
</li>
</ul>
<p>综合考虑易读性及与当前主题的兼容性，我选择的配置文件语法为<code>YAML</code>，以下所有配置命令，都将以<code>YAML</code>格式呈现。值得注意的是，<strong>YAML对缩进非常敏感，在利用 Hugo 进行渲染时，哪怕某一行少了一个空格，都会渲染失败，所以要特别注意</strong>。</p>
<h1 id="添加文章时间轴页面archives">添加文章时间轴页面（Archives）</h1>
<p>在<code>/Content/</code>目录下新建<code>archieves.md</code>，写入以下内容：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>---
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>title: &#34;Archive&#34;
</span></span><span style="display:flex;"><span>layout: &#34;archives&#34;
</span></span><span style="display:flex;"><span>url: &#34;/archives/&#34;
</span></span><span style="display:flex;"><span>summary: archives
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>---
</span></span></code></pre></div><h1 id="添加搜索页面search">添加搜索页面（Search）</h1>
<p>第1步：在配置文件<code>config.yml</code>中添加以下内容：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">outputs</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">home</span>:
</span></span><span style="display:flex;"><span>    - <span style="color:#ae81ff">HTML</span>
</span></span><span style="display:flex;"><span>    - <span style="color:#ae81ff">RSS</span>
</span></span><span style="display:flex;"><span>    - <span style="color:#ae81ff">JSON</span> <span style="color:#75715e"># 搜索页所必需</span>
</span></span></code></pre></div><p>第2步：在<code>/Content/</code>目录下新建<code>archieves.md</code>，写入以下内容：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span>---
</span></span><span style="display:flex;"><span><span style="color:#f92672">title</span>: <span style="color:#e6db74">&#34;Search&#34;</span> <span style="color:#75715e"># 以你想要的任何语言</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">layout</span>: <span style="color:#e6db74">&#34;search&#34;</span> <span style="color:#75715e"># 搜索页所必需</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># url: &#34;/archive&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># description: &#34;Description for Search&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">summary</span>: <span style="color:#e6db74">&#34;search&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">placeholder</span>: <span style="color:#e6db74">&#34;在此输入搜索关键词&#34;</span>
</span></span><span style="display:flex;"><span>---
</span></span></code></pre></div><h1 id="添加菜单">添加菜单</h1>
<p>在配置文件<code>config.yml</code>中添加以下内容：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">menu</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">main</span>:
</span></span><span style="display:flex;"><span>    - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">文章</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">url</span>: <span style="color:#ae81ff">archives</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">weight</span>: <span style="color:#ae81ff">5</span>
</span></span><span style="display:flex;"><span>    - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">搜索</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">url</span>: <span style="color:#ae81ff">search/</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">weight</span>: <span style="color:#ae81ff">10</span>
</span></span><span style="display:flex;"><span>    - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">标签</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">url</span>: <span style="color:#ae81ff">tags/</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">weight</span>: <span style="color:#ae81ff">10</span>
</span></span><span style="display:flex;"><span>    - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">关于</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">url</span>: <span style="color:#ae81ff">about/</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">weight</span>: <span style="color:#ae81ff">10</span>
</span></span></code></pre></div><h1 id="启用-emoji-white_check_mark">启用 Emoji &#x2705;</h1>
<p>Hugo 原生支持 Emoji 渲染，只要在配置文件<code>config.yml</code>中添加以下内容：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">enableEmoji</span>: <span style="color:#66d9ef">true</span>
</span></span></code></pre></div><p>这样，只要在<code>.md</code>文件中输入符合 Markdown 语法的<code>:emojiname:</code>（两个半角冒号中间写上 Emoji 名称），即可输入一个 Emoji。你可以在<a href="https://gist.github.com/rxaviers/7360908">这个列表</a>中查询 Markdown 语法中的 Emoji 名称。</p>
<h1 id="添加-favicon-图标">添加 Favicon 图标</h1>
<p>可以参考我的这篇<a href="/post/blog20210527/">文章</a>，访问<a href="https://favicon.io/">这个网站</a>，将你喜欢的站点图标图片转换成<code>Favicon</code>专用格式，将生成的所有文件放入<code>/static/</code>目录下。</p>
<p>可选：如果想将图标文件放入<code>/static/</code>的子目录下，例如<code>/static/favicon/</code>，则还需在配置文件<code>config.yml</code>中添加以下内容：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">params</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">assets</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">favicon</span>: <span style="color:#e6db74">&#34;/favicon/favicon.ico&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">favicon16x16</span>: <span style="color:#e6db74">&#34;/favicon/favicon-16x16.png&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">favicon32x32</span>: <span style="color:#e6db74">&#34;/favicon/favicon-32x32.png&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">apple_touch_icon</span>: <span style="color:#e6db74">&#34;/favicon/apple-touch-icon.png&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">safari_pinned_tab</span>: <span style="color:#e6db74">&#34;/favicon/safari-pinned-tab.svg&#34;</span> 
</span></span></code></pre></div><h1 id="启用代码复制按钮">启用代码复制按钮</h1>
<p>在配置文件<code>config.yml</code>中添加以下内容：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">params</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">ShowCodeCopyButtons</span>: <span style="color:#66d9ef">true</span>
</span></span></code></pre></div><h1 id="翻页按钮显示页数">翻页按钮显示页数</h1>
<p>在配置文件<code>config.yml</code>中添加以下内容：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">params</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">ShowPageNums</span>: <span style="color:#66d9ef">true</span>
</span></span></code></pre></div><h1 id="文章列表页面添加rss订阅按钮">文章列表页面添加RSS订阅按钮</h1>
<p>在配置文件<code>config.yml</code>中添加以下内容：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">params</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">ShowRssButtonInSectionTermList</span>: <span style="color:#66d9ef">true</span>
</span></span></code></pre></div><h1 id="rss-feed-输出全文">RSS Feed 输出全文</h1>
<p>在配置文件<code>config.yml</code>中添加以下内容：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">params</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">ShowFullTextinRss</span>: <span style="color:#66d9ef">true</span>
</span></span></code></pre></div><h1 id="以新标签页打开站外链接">以新标签页打开站外链接</h1>
<p>在<code>/themes/主题名/layouts/_default/_markup/</code>目录下新建<code>render-link.html</code>，写入以下内容：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;<span style="color:#f92672">a</span> <span style="color:#a6e22e">href</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;{{ .Destination | safeURL }}&#34;</span><span style="color:#960050;background-color:#1e0010">{{</span> <span style="color:#a6e22e">with</span> <span style="color:#960050;background-color:#1e0010">.</span><span style="color:#a6e22e">Title</span><span style="color:#960050;background-color:#1e0010">}}</span> <span style="color:#a6e22e">title</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;{{ . }}&#34;</span><span style="color:#960050;background-color:#1e0010">{{</span> <span style="color:#a6e22e">end</span> <span style="color:#960050;background-color:#1e0010">}}{{</span> <span style="color:#a6e22e">if</span> <span style="color:#a6e22e">strings</span><span style="color:#960050;background-color:#1e0010">.</span><span style="color:#a6e22e">HasPrefix</span> <span style="color:#960050;background-color:#1e0010">.</span><span style="color:#a6e22e">Destination</span> <span style="color:#960050;background-color:#1e0010">&#34;</span><span style="color:#a6e22e">http</span><span style="color:#960050;background-color:#1e0010">&#34;</span> <span style="color:#960050;background-color:#1e0010">}}</span> <span style="color:#a6e22e">target</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;_blank&#34;</span> <span style="color:#a6e22e">rel</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;noopener&#34;</span><span style="color:#960050;background-color:#1e0010">{{</span> <span style="color:#a6e22e">end</span> <span style="color:#960050;background-color:#1e0010">}}</span>&gt;{{ .Text | safeHTML }}&lt;/<span style="color:#f92672">a</span>&gt;
</span></span></code></pre></div><h1 id="自定义超链接样式">自定义超链接样式</h1>
<p>PaperMod 主题支持自定义CSS，我们可以通过自定义CSS改变网站默认的超链接样式，如颜色、下划线，以及鼠标悬停时的变化等。</p>
<p>在<code>/themes/主题名/assets/css/extended/</code>目录下新建<code>custom.css</code>，写入以下内容：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-css" data-lang="css"><span style="display:flex;"><span>.<span style="color:#a6e22e">post-content</span> <span style="color:#f92672">a</span> {
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">color</span>: <span style="color:#ae81ff">#0969da</span>;
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">box-shadow</span>: <span style="color:#66d9ef">none</span>;
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">text-decoration</span>: <span style="color:#66d9ef">none</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>.<span style="color:#a6e22e">post-content</span> <span style="color:#f92672">a</span>:<span style="color:#a6e22e">hover</span> {
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">text-decoration</span>: <span style="color:#66d9ef">underline</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>这段代码会将文章内容中的超链接颜色设置为蓝色(#0969da)，并在鼠标悬停时添加下划线。</p>
<h1 id="seo-优化相关">SEO 优化相关</h1>
<p><strong>SEO (Search Engine Optimization) 是一种通过优化网站内容和结构来提高网站在搜索引擎结果页面中自然排名的方法</strong>。SEO的目标是增加网站的有机流量，提升网站的可见度，吸引更多目标受众。要为 Hugo 站点做 SEO 优化，我们需要做好以下工作：</p>
<h2 id="配置文件优化">配置文件优化</h2>
<p>在配置文件<code>config.yml</code>中添加网站描述：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">params</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">description</span>: <span style="color:#e6db74">&#34;您的网站描述&#34;</span>
</span></span></code></pre></div><p>同样，我们也可以为每篇文章设置标题、关键词和描述，在<code>.md</code>文件的头部添加以下内容，来定义文章的基本信息：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>---
</span></span><span style="display:flex;"><span>title: &#34;文章标题&#34;
</span></span><span style="display:flex;"><span>keywords:
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">-</span> 关键词1
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">-</span> 关键词2
</span></span><span style="display:flex;"><span>description: &#34;文章描述&#34;
</span></span><span style="display:flex;"><span>---
</span></span></code></pre></div><h2 id="创建-sitemap-站点地图">创建 sitemap 站点地图</h2>
<p>站点地图是一个重要的网站文件，它为搜索引擎和用户提供了网站结构的概览。要为 Hugo 站点创建站点地图，在配置文件<code>config.yml</code>中添加以下内容：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">sitemap</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">changefreq</span>: <span style="color:#ae81ff">weekly</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">filename</span>: <span style="color:#ae81ff">sitemap.xml</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">priority</span>: <span style="color:#ae81ff">0.5</span>
</span></span></code></pre></div><p>其中，<code>changefreq</code>表示更新频率，<code>filename</code>表示生成的站点地图文件名，<code>priority</code>表示页面的默认优先级。这样，Hugo 会在网站根目录下生成一个<code>sitemap.xml</code>文件，以便搜索引擎了解网站结构。</p>
<h2 id="创建-robotstxt-爬虫索引">创建 robots.txt 爬虫索引</h2>
<p><code>Robots.txt</code>是一个位于网站根目录的纯文本文件，用于将站点地图提交给搜索引擎，指导搜索引擎如何访问和索引网站内容。要为 Hugo 站点创建<code>robots.txt</code>，在配置文件<code>config.yml</code>中添加以下内容：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">enableRobotsTXT</span>: <span style="color:#66d9ef">true</span>
</span></span></code></pre></div><p>这样，Hugo 会自动在网站根目录下生成<code>Robots.txt</code>文件。</p>
<h1 id="参考链接">参考链接</h1>
<p><a href="https://gohugo.io/about/introduction/">Introduction | Hugo</a></p>
<p><a href="https://github.com/adityatelange/hugo-PaperMod/wiki">Home · adityatelange/hugo-PaperMod Wiki</a></p>
<p><a href="https://dvel.me/posts/hugo-papermod-config/">折腾 Hugo &amp; PaperMod 主题 - Dvel&rsquo;s Blog</a></p>
<p><a href="https://eddy.lu/posts/hugo/">搭建 Hugo 个人网站｜PaperMod 主题 | ed</a></p>
<p><a href="https://www.shaohanyun.top/posts/env/blog_build2/">PaperMod主题配置 | 🚀 田少晗的个人博客</a></p>
]]></content:encoded></item><item><title>HomeAssistant 米家官方集成的安装与使用</title><link>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20241227/</link><pubDate>Fri, 27 Dec 2024 00:00:00 +0000</pubDate><guid>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20241227/</guid><description>日常技术记录</description><content:encoded><![CDATA[<h2 id="背景">背景</h2>
<p>我在2022年4月的<a href="/post/blog20220409/">一篇文章</a>中介绍了 <a href="https://www.home-assistant.io/">Home Assistant</a> 的安装与配置方法。彼时，要将小米的众多智能家居接入 HA，我们必须安装一个第三方 HA 集成，即 <a href="https://github.com/al-one/hass-xiaomi-miot">Hass-Xiaomi-Miot</a>。它由个人开发者 <a href="https://github.com/al-one">al-one</a> 在 Github 上发布，一直以来都是我们将米家接入 HA 的唯一选择。直到最近，<a href="https://github.com/XiaoMi">小米</a>在 Github 上发布了官方的 HA 集成：<a href="https://github.com/XiaoMi/ha_xiaomi_home">HA_Xiaomi_Home</a>，填补了米家接入 HA 的空白。</p>
<p>虽然这又是一个“官方逼死同人”的故事，但小米的开源精神仍然值得称赞。与第三方集成相比，小米官方的集成对自家产品支持更好， 能够帮助我们更加轻松地将米家接入 HA，进而实现米家与 Homekit 生态的互联互通。今天，我们将跟随 HA_Xiaomi_Home 的<a href="https://github.com/XiaoMi/ha_xiaomi_home/blob/main/doc/README_zh.md">官方文档</a>，详细介绍一下这个集成的安装及使用方法。</p>
<h2 id="通过-hasc-安装米家官方集成">通过 HASC 安装米家官方集成</h2>
<p>米家官方集成有多种安装方式，其中最简单，也是最新手友好的方式，就是通过 <a href="https://www.hacs.xyz/">HACS</a> 进行安装。HASC 的安装方法详见我的这篇文章，此处不再赘述。<strong>由于米家官方集成暂未加入 HASC 的官方库，我们需要通过添加自定义库链接的方式，将米家官方集成的库链接添加到 HASC 目录</strong>。登入 HA 后台，点击左侧的<code>HASC</code>，再点右上角的三个点，选择<code>Custom Repositories</code>，新建一个自定义库链接，如下图所示。</p>
<p><img alt="image" loading="lazy" src="/images/blog20241227/hacs1.png"></p>
<p>库类型（Catagory）选择<code>Integration</code>；库链接填写下面的链接：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>https://github.com/XiaoMi/ha_xiaomi_home.git
</span></span></code></pre></div><p>最后点击ADD按钮，如果网络没有问题的话，米家官方集成的安装链接就会被添加到 HASC 的自定目录中。再依次点击设置—设备与集成—添加集成，在搜索框中输入<code>Xiaomi</code>，在弹出的结果中选择<code>XIaomi Home</code>。接下来，按照提示登录米家账号即可。</p>
<p><img alt="image" loading="lazy" src="/images/blog20241227/hacs2.png"></p>
<p><img loading="lazy" src="/images/blog20241227/xiaomi-home-auth1.png"></p>
<p>注意&#x26a0;&#xfe0f;：<strong>如果你和我一样，使用 Docker 作为 HA 的安装环境，那么大概率会在米家账号验证时遇到无法跳转的问题</strong>。无法跳转的核心原因在于，米家官方集成默认使用 <code>homeassistant.local:8123</code>这个本地域名来跳转回 HA 页面，而 Docker 容器中的 HA 无法在本地局域网中广播<code>.local</code>本地域名。因此，在验证米家账号并跳转回 HA 页面时，我们需要手动将浏览器地址栏中的<code>homeassistant.local:8123</code>改为<code>IP:8123</code>。这样就能完成米家账号的验证工作。以上方法参考自米家集成仓库的 <a href="https://github.com/XiaoMi/ha_xiaomi_home/issues/8">Issue#8</a>。</p>
<p><img loading="lazy" src="/images/blog20241227/xiaomi-home-auth.png"></p>
<h1 id="停用多余的米家实体">停用多余的米家实体</h1>
<p>当我们安装好米家官方集成并完成账号验证后，HA 就会自动搜索并添加米家的各种设备。同时，我们的家庭中会出现一堆乱七八糟的实体。<strong>所谓实体（Unit）是 HA 用来定义设备最小子功能单元的概念</strong>。通常一个设备会对应多个实体。例如，一台『热水器』设备，可以同时拥有『当前水温』、『目标水温』、『预热开关』、『增压开关』等多个实体。</p>
<p>然而在日常使用过程中，我们并不需要将每一个设备都拆分成诸多零碎的子功能单元，这样不仅使人迷惑，还会让我们的家庭界面变得极其繁琐。因此，在将 HA 链接到 Homekit 之前，我们需要对米家集成添加进来的众多实体进行筛选，仅保留我们日常使用过程中最需要的开关和数值即可。</p>
<p>依次点击设置—设备与集成—实体，在列表中点击我们不需要的实体，在弹出的对话框中关闭该实体，最后点击保存。这样，我们便停用了一个不需要的实体。</p>
<p><img loading="lazy" src="/images/blog20241227/ha-unit.png"></p>
<h1 id="将-ha-桥接到-homekit">将 HA 桥接到 Homekit</h1>
<p>筛选掉不需要的米家实体后，我们就可以将 HA 桥接到 Homekit 了。对于大多数人而言，将米家接入 HA 的唯一目的，便是实现米家与 Homekit 的联通。Homekit 是苹果原生的智能家居协议，能够让用户在 iOS、Mac 和 Apple Watch 等苹果设备上直接操控家中的电器，而无需借助第三方 APP。众所周知，Homekit 家居生态远不如米家繁荣，且支持 Homekit 协议的产品价格大多高昂。因此，如果将米家生态接入 Homekit，便能实现便利性与性价比的两全。而 HA 正是联通米家与 Homekit 的最佳桥梁。</p>
<p>将 HA 实体桥接到 Homekit，我们需要安装另一个集成：<a href="https://www.home-assistant.io/integrations/homekit/">Homekit Bridge</a>。依次点击设置—设备与集成—添加集成，在搜索框中输入<code>Homekit Bridge</code>，再按提示安装即可。安装完成后，HA 通知栏会弹出一个二维码。打开苹果设备的 Home APP，点击右上角加号——添加配件，扫描通知中的这个二维码，就能将 HA 上现有的实体全部桥接到 Home APP中了。</p>
]]></content:encoded></item><item><title>如何配置路由器的 DHCP ?</title><link>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20220518/</link><pubDate>Wed, 18 May 2022 00:00:00 +0000</pubDate><guid>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20220518/</guid><description>日常技术记录</description><content:encoded><![CDATA[<h2 id="开场">开场</h2>
<hr>
<p>经常折腾家里网络的你，一定经常遇到这些问题：</p>
<ol>
<li>为什么明明插上了网线，却<strong>打不开</strong>路由器的后台？</li>
<li>为什么 NAS 的 IP 地址经常<strong>变化</strong>？</li>
<li>为什么用上了高价的软路由，打开网页的速度反而<strong>变慢</strong>？</li>
<li>为什么跟着大佬的视频一通配置，却还是玩不转<strong>旁路由</strong>？</li>
</ol>
<p>以上这些问题其实都和 DHCP 有关。</p>
<h2 id="什么是-dhcp">什么是 DHCP？</h2>
<hr>
<p>DHCP 是 Dynamic Host Configuration Protocol 的缩写，意思是<strong>动态主机配置协议</strong>。它的作用，是为每一个接入局域网的设备自动分配一个 IP 地址，并为这些设备自动配置默认网关和 DNS 服务器。</p>
<h3 id="名词解释">名词解释</h3>
<p>如果你不理解网关和 DNS 是什么意思，也不要紧。你可以把<strong>网关</strong>理解成一个中转站，局域网内的所有设备都要通过这个中转站来与外界联系，而家用网络的网关通常只有一个，那就是路由器。<strong>DNS</strong> 则要更加复杂一点，我后面会单独制作一期视频来讲解。这里你只要把它理解成一个“电话簿”就可以了。</p>
<h2 id="dhcp-的工作原理">DHCP 的工作原理</h2>
<hr>
<p>DHCP 协议由一个服务端，和多个客户端组成。<strong>服务端</strong>一般就是你的路由器，而<strong>客户端</strong>就是你用来上网的设备。</p>
<h3 id="discoer">Discoer</h3>
<p>每当一个<strong>新设备</strong>初次连入局域网，它就会向整个网络广播自己的 MAC 地址。所谓的 <strong>MAC 地址</strong>，是每个设备的硬件地址，它被写在设备的网卡上，一般情况下无法更改，相当于设备的“身份证号码”。当新设备初次连入，它会向局域网广播自己的 MAC 地址，相当于新员工的自我介绍。这段自我介绍有一个很洋气的名字，叫做 <strong>Discover</strong>。</p>
<h3 id="offer">Offer</h3>
<p>当路由器接收到新设备的广播，就会在现有的 IP 地址中，挑选一个还没有被其他设备占用的空缺地址，并将这个地址和其他配置信息（比如默认网关和 DNS）打包发给这个设备，相当于领导给新员工安排工位。这段安排也有一个非常洋气的名字，叫做 <strong>Offer</strong>。</p>
<h3 id="request">Request</h3>
<p>接下来的事情就非常简单了，当设备收到路由器发出的配置信息，并且决定套用这些配置，会再次答复路由器，相当于接受领导的安排。这段答复同样有一个很洋气的名字，叫做 <strong>Request</strong>。</p>
<p>这里要注意一点，如果局域网内有两个以上路由器，并且这些路由都开启了 DHCP 服务，那么它们在收到新设备的广播后，会同时给这个设备发送配置信息。当设备同时收到多个配置信息，会优先回复最先收到的那个。因此，为了避免网络混乱，即使你家里有多个路由器，也最好只开启一个 DHCP 服务。</p>
<h3 id="ack">ACK</h3>
<p>回到正题，当路由器收到设备的肯定答复后，就会再给设备回个话，表示占位成功。这时，设备会根据路由器下发的 IP 地址、默认网关和 DNS 服务器，自动配置自己的网络，实现成功联网。路由器的这个回话，叫做 <strong>ACK</strong>。</p>
<h4 id="解答问题一">解答问题一</h4>
<p>说到这里，我们就解决了视频开头提到的第一个问题：</p>
<ul>
<li>为什么明明插上了网线，却<strong>打不开</strong>路由器的后台？</li>
</ul>
<p>这里有两种可能：
1. 你的路由器没有开启 DHCP 服务，你的电脑没有收到路由器下发的 IP 地址。
2. 你的路由器开启了 DHCP 服务，但你的电脑之前设置了静态 IP 地址，而这个静态地址和路由器的地址，不在同一个网段。</p>
<p>要解决”打不开后台“的问题，方法也很简单：
1. 如果是第一种情况，那么我们就要先在电脑上手动配置一个静态 IP 地址，并且这个地址要和路由器在同一个网段。比如路由器的 IP 地址是 192.168.31.1，那么电脑的静态地址就要设置成 192.168.31.x，这里的 x 可以是 2~255中的任何一个数字，但要注意不能和其他设备重合。
2. 如果是第二种情况，那么我们就要清除电脑的静态 IP 地址，并将 IP 地址的获取方式改为”自动获得 IP 地址“。这样，我们的电脑就会重新接受 DHCP 服务的分配。</p>
<h3 id="nak-报文">NAK 报文</h3>
<p>再次回到正题，上面提到的这一整个流程，都是新设备<strong>初次</strong>连入局域网的流程。如果不是初次连入的新设备，而是之前连过的老设备，断开后重新连入，就会跳过前两个步骤，直接从 Request 切入，相当于老员工离职后又重新回归，直接省略客套的过程，让领导给个工位。</p>
<p>这时，路由器会检查之前的 <strong>DHCP 租约表</strong>。如果设备之前对应的 IP 地址仍然空缺，则照旧返回一个 ACK。租约继续有效，设备继续沿用之前的 IP 地址。如果设备之前对应的 IP 地址已被其他设备占用，则只能拒绝设备的这次请求。那么这个拒绝的动作，叫做 <strong>NAK</strong>。</p>
<h4 id="解答问题二">解答问题二</h4>
<p>说到这里，我们又解决了视频开头提到的第二个问题：</p>
<ul>
<li>为什么 NAS 的 IP 地址经常<strong>发生变化</strong>？</li>
</ul>
<p>原因就是，NAS 关机下线期间，原本占用的 IP 地址空缺出来，并被其他设备占用，当 NAS 重新开机上线时，路由器只能为它重新分配一个新的 IP 地址。这时候我们就会找不到 NAS 的后台，而要借用 Synology finder 这类软件才能重新搜索到 NAS 的新地址。</p>
<p>要解决这个问题也很简单，那就是开启路由器的 <strong>IP/MAC 绑定</strong>，将某个固定的 IP 地址分配给特定的 MAC 地址，做到”一个萝卜一个坑“，这样就不会发生混乱了。</p>
<h2 id="dhcp-的应用">DHCP 的应用</h2>
<hr>
<p>知道了 DHCP 的工作原理，我们就可以解决上网过程中的很多问题。</p>
<h3 id="解答问题三">解答问题三</h3>
<ul>
<li>为什么用上了高价的软路由，打开网页的速度反而<strong>变慢</strong>？</li>
</ul>
<p>打开网页的速度很慢，或者明明 QQ 可以联网，但网页却死活打不开，多半是因为 DNS 服务器出了问题。我们家用网络的 DNS 服务器，一般是通过光猫从运营商处获得，再经过路由器的 DHCP 服务层层下发。如果我们在路由器的 DHCP 服务里没有指定 DNS 服务器，那么路由器就会默认适用运营商的 DNS，众所周知，运营商的 DNS 经常被劫持，用起来既不安全也不稳定。</p>
<p>所以，要解决”浏览网页慢“的问题，我们可以在路由器的 DHCP 服务里，手动指定一个稳定的 DNS 服务器地址，让局域网里的所有设备，都套用路由器 DHCP 下发的 DNS。至于有哪些好用的公共 DNS 服务器，网上一搜一大堆，比较常见的，国外的有著名的谷歌 8.8.8.8，国内的有阿里 223.5.5.5 等。</p>
]]></content:encoded></item><item><title>利用 Home Assistant 搭建智能家居中枢</title><link>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20220409/</link><pubDate>Sat, 09 Apr 2022 00:00:00 +0000</pubDate><guid>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20220409/</guid><description>日常技术记录</description><content:encoded><![CDATA[<h2 id="背景">背景</h2>
<p>随着智能家居的日益普及，各大互联网巨头纷纷进场，导致智能家居的平台和品牌越来越多，且各个平台和品牌间的产品无法互通。例如，你无法用米家的智能开关来控制 homekit 的智能灯，除非你的产品支持双平台，但目前同时支持两个以上平台的智能家居少之又少。</p>
<p><a href="https://www.home-assistant.io/">Home Assistant</a>（以下简称 HA）很好地解决了智能家居平台不互通的问题，它是一个开源的智能家居集成平台，可将各个常见平台的产品接入，并通过网页、<a href="https://apps.apple.com/us/app/home-assistant/id1099568401">手机app</a>等多种客户端统一操控，实现真正的「万物互联」。并且最重要的是，这么好用的工具不仅支持 Windows、MacOS、Linux 等多种操作系统，其本身也是开源免费的，并且其极高的扩展性也为爱折腾的数码爱好者提供了全新的研究对象。</p>
<h2 id="通过-docker-部署-ha-容器">通过 Docker 部署 HA 容器</h2>
<p>正如前文所述，HA 支持多种操作系统，但如果我们打算将其作为 7x24 小时待机的智能家庭中枢，那么最好的选择就是 Linux 系统，因为它可以运行在诸如<a href="https://www.raspberrypi.org/">树莓派</a>这类低功耗的设备上，随时准备着为我们提供服务。</p>
<p>提到 Linux，我们就不得不提 Docker，它是一种兼容性极高的容器系统，可以适应几乎所有 Linux 环境，做到即装即用。今天，我们将着重介绍通过 Docker 容器部署 HA 的方法。</p>
<p>我的<a href="/post/blog20210909/">这篇文章</a>详细介绍了 <a href="https://hub.docker.com/r/portainer/portainer-ce">Portainer</a> 这个非常好用的 Docker 管理容器，<strong>由于每位读者的系统环境不尽相同，因此本博客往后介绍的所有 Docker 容器安装，不再拘泥于群晖、威联通或者 Unraid，而是统一通过 Portainer 进行</strong>。</p>
<p>Portainer 本身的安装可以参考上面提到的文章，本文不再赘述。要安装 HA，我们首先需要登录 Portainer 后台，然后进入本地终端界面，也就是 Local，接着点击左侧的 Containers，进入本地容器管理界面。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20220409/portainer01.png"></p>
<p>点击 Add container，创建一个新容器，Name 随便填，Image 写 HA 官方提供的映像索引 <code>homeassistant/home-assistant:latest</code>，Always pull the image 可以打开，这样以后每次修改容器配置，都会从服务器重新拉取最新的映像。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20220409/portainer02.png"></p>
<p>接着点击下方 Advanced container settings 中的 Volumes，进入目录映射选项卡，点击 map additional volume 按钮新增一个目录映射，右侧的映射方式选 bind，container 里的目录只能写 <code>/config</code>，这是 HA 配置文件的所在目录，host 上的目录可以根据自己需要填写。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20220409/portainer03.png"></p>
<p>继续点击 Advanced container settings 中的 Env，进入环境变量选项卡，点击 add environment variable 按钮新增一条环境变量，左侧的 name 填写 <code>TZ</code>，右侧的 value 填写 <code>Asia/Shanghai</code>，这是将 HA 的默认时区（Time Zone）设置为亚洲/上海。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20220409/portainer04.png"></p>
<p>剩下的高级设置就比较简单了，Network 设置成 host，Restart policy 设置成 Always 即可。最后点击 Deploy the container，等待一段时间，如果网络连接通畅的话，即可完成 HA 容器的部署。</p>
<p>HA 的后台默认端口是 8123，因此只要我们在局域网中访问 HA 运行设备的 <code>ip地址:8123</code> 即可登录 HA 的网页端。初次打开 HA 网页端需要进行一些基本的初始化配置，例如用户名、密码这些，此处不再赘述。需要注意的是，<strong>HA 管理员账户的密码无法找回，如果我们忘记此处设置的密码，后面只能通过重装容器的方式解决</strong>。</p>
<h2 id="安装-hacs-集成">安装 HACS 集成</h2>
<p><a href="https://hacs.xyz">HACS</a> 的全称是 Home Assistant Community Store，是一个 HA 社区商店，里面提供了各种外观主题，以及第三方集成的下载，使用起来非常方面，建议所有 HA 用户安装。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20220409/hacs.png"></p>
<p>要安装 HACS，首先需要将它的安装包放入 HA 容器。在 HA 映射的 /config 目录中创建两个新目录，名称分别为 <code>www</code> 和 <code>custom components</code>，点击<a href="/resources/blog20220409/hacs.zip">这里</a>下载 HACS 安装包，将压缩包内的 hacs 目录解压到刚刚创建的 <code>personal components</code> 目录，然后重启 HA 容器。登录 HA 网页端，依次点击左下角配置—设备与服务—集成，进入集成选项卡。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20220409/ha01.png"></p>
<p>点击右下角的添加集成按钮，搜索 HACS，点击安装 HACS 集成，接着按照提示走流程就能顺利安装。安装过程中需要跳转登录一次 Github，如果没有账号需要注册一个。此外就是安装过程需要科学的网络环境，这个只能靠各位自行解决。安装完成后再次重启 HA 容器。不出意外的话，网页端的左侧会多出一个 HACS 按钮，点击它就能进入 HACS 的商店界面了。</p>
<h1 id="将米家接入-ha">将米家接入 HA</h1>
<p>以往，要将小米的众多智能家居接入 HA，我们必须安装一个第三方 HA 集成，即 <a href="https://github.com/al-one/hass-xiaomi-miot">Hass-Xiaomi-Miot</a>。它由个人开发者 <a href="https://github.com/al-one">al-one</a> 在 Github 上发布，一直以来都是我们将米家接入 HA 的唯一选择。直到2024年12月，<a href="https://github.com/XiaoMi">小米</a>在 Github 上发布了官方的 HA 集成：<a href="https://github.com/XiaoMi/ha_xiaomi_home">HA_Xiaomi_Home</a>，填补了米家接入 HA 的空白。</p>
<p>虽然这又是一个“官方逼死同人”的故事，但小米的开源精神仍然值得称赞。与第三方集成相比，小米官方的集成对自家产品支持更好， 能够帮助我们更加轻松地将米家接入 HA，进而实现米家与 Homekit 生态的互联互通。小米官方集成的安装与使用方法详见我的<a href="/post/blog20241227/">最新文章</a>，此处不再更新。</p>
]]></content:encoded></item><item><title>利用 Portainer 实现 Docker 端 Jellyfin 硬件解码</title><link>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20210909/</link><pubDate>Thu, 09 Sep 2021 00:00:00 +0000</pubDate><guid>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20210909/</guid><description>日常技术记录</description><content:encoded><![CDATA[<h2 id="原理及环境检测">原理及环境检测</h2>
<p>随着版本的不断迭代，<a href="https://jellyfin.org">Jellyfin</a> 已经逐渐超过 <a href="https://www.plex.tv">Plex</a>  和自家兄弟 <a href="https://emby.media">Emby</a>，成为用户数量最所的个人媒体管理方案，这不仅因为它的所有功能均为免费，更是因为它的源代码完全开源，具有极高的维护与拓展空间。</p>
<p>不论用于运行 Jellyfin 的具体是哪款操作系统，只要该系统是基于 Linux，我们就可以通过 Docker 容器来实现极为简单且方式一致的部署。<strong>但相比于原生套件，Docker 有一个显而易见的缺点，即无法直接调用各类系统资源</strong>，核显驱动就是其中之一。</p>
<p>要让 Jellyfin 的 Docker 容器实时调用核显驱动（也就是人们常说的开启硬解），要满足两个条件：</p>
<ol>
<li>拥有支持视频解码的核心显卡，且核心显卡的<strong>驱动程序</strong>运行正常；</li>
<li>将核显驱动<strong>直通</strong>给 Docker 容器，并赋予 Docker 容器调用该驱动的权限。</li>
</ol>
<p>对于系统是否满足上述第一个条件，可以通过以下方式进行检验：首先用 ssh 工具连接到服务器，确保登陆 ssh 的账户拥有系统管理权限，再输入以下命令：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>ls /dev/dri
</span></span></code></pre></div><p>如果返回的结果为 <code>card0 renderD128</code> ，那么恭喜，核显驱动运行正常，硬件系统满足视频解码的基本条件。接下来便是将 renderD128 这个核显驱动直通给 Docker 容器的方法。</p>
<h2 id="为什么必须用-portainer">为什么必须用 Portainer?</h2>
<p>无论是群辉、威联通还是 <a href="https://www.unraid.net">Unraid</a>，市场上绝大多数 NAS 系统都提供了图形化的 Docker 容器管理工具。但无论上述哪一个，都不支持核显驱动的直通功能。群辉的 Docker 套件无法编辑容器的系统资源参数，威联通的 Container Station 干脆无法编辑已经创建好的容器。</p>
<p><strong>这里所说的“直通”，其实是将 <code>/dev/dri/renderD128</code> 这个驱动文件映射到 Docker 容器的相同位置</strong>。这一点利用命令行可以非常轻松地实现，即在 Jellyfin 容器的拉取命令中加入下列参数：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>--device<span style="color:#f92672">=</span>/dev/dri/renderD128 <span style="color:#ae81ff">\
</span></span></span></code></pre></div><p>因此，要快速拉取并创建一个开启硬件解码的 Jellyfin 容器，只要在 NAS 的命令行界面输入以下命令即可：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>sudo docker run -d --name jellyfin <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>-v /share/Container/Jellyfin/config:/config <span style="color:#ae81ff">\ </span><span style="color:#75715e">#冒号左边为存放配置文件的目录</span>
</span></span><span style="display:flex;"><span>-v /share/Container/Jellyfin/cache:/cache <span style="color:#ae81ff">\ </span><span style="color:#75715e">#冒号左边为存放媒体缓存的目录</span>
</span></span><span style="display:flex;"><span>-v /share/Media/:/media <span style="color:#ae81ff">\ </span><span style="color:#75715e">#冒号左边为存放电影文件的目录</span>
</span></span><span style="display:flex;"><span>-p 8096:8096 <span style="color:#ae81ff">\ </span><span style="color:#75715e">#web界面访问端口（http）</span>
</span></span><span style="display:flex;"><span>-p 8920:8920 <span style="color:#ae81ff">\ </span><span style="color:#75715e">#web界面访问端口（https）</span>
</span></span><span style="display:flex;"><span>--device<span style="color:#f92672">=</span>/dev/dri/renderD128 <span style="color:#ae81ff">\ </span><span style="color:#75715e">#映射核显驱动</span>
</span></span><span style="display:flex;"><span>--restart<span style="color:#f92672">=</span>always <span style="color:#ae81ff">\ </span><span style="color:#75715e">#重启策略</span>
</span></span><span style="display:flex;"><span>jellyfin/jellyfin
</span></span></code></pre></div><p>但对许多轻度用户来说，命令行不仅不便理解，也断绝了后续对容器进行修改和自定义的空间。因此对于绝大多数日常用户来说，我个人强烈推荐使用 <a href="https://hub.docker.com/r/portainer/portainer-ce">Portainer</a>。它本身也是一个运行在 Docker 容器里的程序，但它拥有强大的 Docker 管理功能，是目前市面上功能最完善的网页端 Docker 容器管理界面。</p>
<p>因此，对于那些既不想用命令行，又希望对 Docker 有较为全面管控的用户来说，Portainer 几乎是唯一的选择。通过 Portainer，即使是初学者也能轻松为 Jellyfin 开启硬件解码。</p>
<h2 id="portainer-的安装与使用">Portainer 的安装与使用</h2>
<p>由于 Portainer 需要调用 <code>/var/run/docker.sock</code> 这个文件以实现对 Docker 的直接管理，因此 Portainer 也无法通过群辉或威联通自带的 Docker 管理界面进行安装，因为上述管理界面均不支持针对单个文件的映射。但由于 Portainer 需要配置的参数较少，且容器创建完成后不需要频繁修改，因此普通用户可以直接复制一以下命令进行安装。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>sudo docker run -d --name prtainer <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>-v /var/run/docker.sock:/var/run/docker.sock <span style="color:#ae81ff">\ </span><span style="color:#75715e">#关键</span>
</span></span><span style="display:flex;"><span>-p 9000:9000 <span style="color:#ae81ff">\ </span><span style="color:#75715e">#web界面访问端口</span>
</span></span><span style="display:flex;"><span>--restart<span style="color:#f92672">=</span>always <span style="color:#ae81ff">\ </span><span style="color:#75715e">#重启策略</span>
</span></span><span style="display:flex;"><span>portainer/portainer
</span></span></code></pre></div><p>容器创建完成后，即可通过 IP:端口的方式访问 Portainer 的管理界面，Portainer 的默认访问端口是 9000。初次登陆需要设置管理员账号和密码。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20210909/portainer-1.png"></p>
<p>因为是单机使用，所以连接模式选择“local”，然后点击“Connect”即可连接到服务器上的docker。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20210909/portainer-2.png"></p>
<p>配置完成后，再次点击 local，选择左侧的 Container 便可使用 Portainer 对系统上现有的所有 Docker 容器进行管理了。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20210909/portainer-3.png"></p>
<h2 id="安装-jellyfin-并直通核显驱动开启硬解">安装 Jellyfin 并直通核显驱动（开启硬解）</h2>
<p>后续的安装及配置过程都将在 Portainer 界面上完成。首先点击“Containers”选项卡上的“Add container”按钮添加新容器，进入容器创建界面。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20210909/portainer-4.png"></p>
<p>“Name”随便写，“Image”填写 Jellyfin 官方的 Docker Hub 映像路径 <code>jellyfin/jellyfin</code>，“Always pull the image”可以打开，这样当我们配置完成创建容器时，Portainer 会自动从 Docker Hub 拉取最新的官方映像。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20210909/portainer-5.png"></p>
<p>“Network ports configuration”处选择“Manual network port publishing”，点击“publish a new network port”创建两个端口映射，分别是 8096 和 8920，作为 Jellyfin 网页界面的访问端口。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20210909/portainer-6.png"></p>
<p>接着点击“volumes”选项卡，进行容器内目录的映射。Jellyfin 默认需要映射的目录分别是 <code>/media</code>、<code>/cache</code> 和 <code>/config</code>，点击“bind”按钮选择服务器上对应的目录进行映射。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20210909/portainer-7.png"></p>
<p>“Network”选择“host”，“Restart policy”选择“always”。最重要的是，“Runtime &amp; Resources”处一定要点击“add device”，两边分别输入 <code>/dev/dri/renderD128</code>，这是开启硬解的关键步骤。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20210909/portainer-8.png"></p>
<p>以上配置完成后，即可点击“Deploy the container”按钮创建容器。如果网络环境较好，等待半分钟左右即可完成容器的创建。至此，我们不仅手动配置完成了 jellyfin 的 Docker 容器，还将核心显卡的驱动文件直通给了该容器。最后，只要进入 Jellyfin 的控制台，在“播放”选项卡中，将“硬件加速”类型选为“Video Acceleration API (VAAPI)”，并在“VA API 设备”处填写 <code>/dev/dri/renderD128</code>，即可调用服务器的核显驱动进行硬件解码了。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20210909/jellyfin-config.png"></p>
]]></content:encoded></item><item><title>利用 Favicon 为 Hugo 静态站点添加图标</title><link>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20210527/</link><pubDate>Thu, 27 May 2021 00:00:00 +0000</pubDate><guid>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20210527/</guid><description>日常技术记录</description><content:encoded><![CDATA[<p>我们在使用 <a href="https://gohugo.io">Hugo</a> 生成静态站点时，经常会遇到一些虽不致命，但很不爽的小问题，例如没有自定义站点图标的问题。假如我们跟随了所用主题的默认配置，通常情况下生成的站点要么没有图标，要么直接套用主题自带的图标，这显然无法满足我那强烈的 DIY 欲望。</p>
<p>经常访问本博客的读者可能会注意到，我所使用的 Hugo 主题是一个支持自动切换明暗模式的第三方主题——<a href="https://github.com/dsrkafuu/hugo-theme-fuji">AutoFuji</a>. 今天在阅读这个主题的说明文档时，我发现原来它是支持 <a href="https://baike.baidu.com/item/favicon">Favicon</a> 图标代码的。于是经过一通简单的操作，我的博客终于有了自己的图标。</p>
<p>为 Hugo 站点添加 Favicon 代码的方法非常简单。首先访问<a href="https://realfavicongenerator.net">这个网站</a>上传一张图片作为网站图标的母本。其实类似的 Favicon 生成器还有很多，大家可以根据自己的习惯或喜好自由选择，基本功能都是一样的。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20210527/favicon-generator.png"></p>
<p>图片上传完成后，会自动跳转到参数配置页面。如无特殊需求，保持默认配置即可。点击页面下方的生成按钮生成我们的图标和代码。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20210527/favicon-generator2.png"></p>
<p>生成完成后，点击如图所示按钮下载各类格式的图标包，再将自动生成的 HTML 代码复制到剪贴板。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20210527/favicon-generator3.png"></p>
<p>之后，来到 Hugo 站点的根目录，将刚刚下载的压缩包里的所有文件解压到 <code>/static/</code> 文件夹下。</p>
<p>用文本编辑器打开 <code>/layouts/partials/favicon.html</code> 文件，清空原有代码，将刚刚复制到代码粘贴进去，保存并退出。</p>
<p>最后，打开 <code>/themes/正在使用的主题名/layouts/partials/head.html</code> 文件（不同主题需要编辑的文件可能不同，例如我所使用的 Fuji 主题就是直接编辑同一目录下的 favicon.html 文件），找到下列代码：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;<span style="color:#f92672">link</span> <span style="color:#a6e22e">rel</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;shortcut icon&#34;</span> <span style="color:#a6e22e">href</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;xxx&#34;</span> /&gt;
</span></span></code></pre></div><p>将 xxx 替换成 <code>favicon.ico</code> ，保存并退出即可。</p>
<p>此时，我们的 favicon 图标安装工作就宣告完成了。使用 <code>hugo</code> 命令重新生成站点，不出意外的话，就能看到我们刚才上传的站点图标了。</p>
]]></content:encoded></item><item><title>桥接模式下 Openwrt 软路由直接访问光猫后台</title><link>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20210505/</link><pubDate>Wed, 05 May 2021 00:00:00 +0000</pubDate><guid>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20210505/</guid><description>日常技术记录</description><content:encoded><![CDATA[<p>光猫开启桥接模式后，软路由作为默认网关进行拨号与 NAT，导致客户端设备无法获取与光猫相同网段的 IP 地址，进而也就无法登陆光猫的后台管理界面。虽然在日常使用的过程中，光猫的配置几乎是一次性的，其后台管理界面的使用频率很低，但是每次登陆光猫后台都要通过有线或无线（若有）的方式将设备直接与光猫相连也着实麻烦。因此需要通过一些简单的配置，实现桥接模式下，连接软路由的同时可以随时访问光猫后台。</p>
<p>实现原理其实很简单，只要<strong>在现有 DHCP 服务端正常工作的前提下，为软路由的 WAN 口再行分配一个与光猫网段相同的 IP 地址</strong>即可，前提是你的软路由支持多 WAN。</p>
<p>以 Openwrt 系统为例，在“网络—接口”界面点击“添加新接口”，进入新接口创建页面。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20210505/wan-config-1.png"></p>
<p>接口名称随意填写，接口协议选择“静态地址”，包括的接口选择当前 WAN 口绑定的物理接口。<strong>注意，接口协议尽量不要选择 DHCP，因为桥接模式下的光猫基本都会关闭自身的 DHCP 功能，不会给新接口自动分配 IP 地址，所以此时需要通过“静态地址”协议来手动指定新接口的 IP 地址</strong>。完成上述配置后，点击“提交”按钮进入新接口的详细配置页面。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20210505/wan-config-2.png"></p>
<p><strong>IPv4 地址一定要设置成与光猫位于相同网段的地址</strong>。例如光猫连接软路由的 LAN 口的地址（即光猫后台地址）为 192.168.1.1，那么这里新接口的静态 IP 地址就要设置为 192.168.1.x。子网掩码设为 255.255.255.0，默认网关就是光猫 LAN 口的 IP 地址。有关 IP 网段和子网掩码的相关知识，可以参考<a href="https://www.zhihu.com/question/56895036">这篇文章</a>。完成上述设置后，点击“保存&amp;应用”按钮即可完成配置。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20210505/wan-config-3.png"></p>
<p>新接口配置完成后，DNS 缓存会有一定延迟，导致无法正常浏览网页，此时重启一下软路由即可解决问题。如果软路由之前配置了端口映射，则<strong>新接口创建完成后，所有的端口映射都将失效，此时仍需经过一番针对防火墙的额外设置才能恢复正常</strong>。</p>
<p>重新进入新接口的详细设置页面，在“防火墙设置”中，将原先 WAN 口的防火墙区域绑定到新接口。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20210505/wan-config-4.png"></p>
<p>然后进入“网络—防火墙—端口转发”页面，将原有的端口映射配置重新“保存&amp;应用”一下即可。</p>
<p>至此，如果不出意外的话，我们便可在桥接模式下随时随地访问光猫的后台管理界面了。</p>
]]></content:encoded></item><item><title>利用 Parsec 实现远程游戏串流</title><link>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20210502/</link><pubDate>Sun, 02 May 2021 00:00:00 +0000</pubDate><guid>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20210502/</guid><description>日常技术记录</description><content:encoded><![CDATA[<p>最近，我终于放弃了 Steam 或 Epic Games 等平台的买断制游戏模式，转而投靠了 <a href="https://www.xbox.com/zh-HK/xbox-game-pass">Xbox Game Pass (XGP)</a> 这样的订阅制模式。尽管买断制可以极大地满足“喜加一”式的收集欲，但自从开始实习之后，我已经很难抽出整块的时间来通关各类单机游戏，以致于我的游戏库中屯了大量已购买的但未通关的游戏，这不仅降低了我购买和尝试最新游戏的欲望，也在资金上造成了很大的浪费。不知从什么时候起，玩游戏竟也成了一种待完成的“任务”，失去了工作之余放松心情的初衷。</p>
<p>因此，我纠结许久，终于决定以后不再购买任何单机游戏。如果某段时间我不是那么忙了（例如辞职在家的现在），就去订阅一个月的 XGP，体验一下最新的单机游戏。事实上，Xbox 账户是可以随时切换区域的。因此我们可以简单地通过将 Win10 的系统区域切换成香港的方式来享受港区 XGP 79 港元每月（首月10港币）的优惠价格。在一个单机游戏动辄就要三百块以上的当下，XGP 确实是一种非常合算方案。毕竟，一个月的时间，完全够我通关一个中型单机游戏，而买断这款游戏的价格远远不止 79 港币。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20210502/xgp-price.png"></p>
<p>开通了 XGP 之后，我又开始琢磨如何在出差的时候利用“零碎的时间”玩游戏。例如驻场期间每天下班以后，住在酒店里的我只有一台性能羸弱的 MacBook，如何利用现有设备在酒店里玩上 XGP 上的单机游戏呢？其实解决方案只有一个：远程桌面。只要在家里的 PC 上<a href="https://zhuanlan.zhihu.com/p/302835122">开启网络唤醒功能</a>，在将某款远程桌面软件设置成开机自动启动，我就可以在任何地方，通过网络唤醒 + 远程操控的方式随时随地游玩家里电脑上的游戏。</p>
<p>思路虽然很简单，但找到合适的远程桌面软件着实费了我一番工夫。经过仔细的搜索，我发现了一款叫做 <a href="https://parsec.app/">Parsec</a> 的远程桌面软件。它不仅同时支持 Windows 和 macOS 双平台，还专门针对远程游戏进行了优化。不仅如此，Parsec 还支持 <a href="https://baike.baidu.com/item/HEVC">Hevc 编码</a>。只要客户端设备支持 Hevc 解码，就能大大降低串流数据体积，减少网络带宽和流量的消耗，提升远程游戏的体验。</p>
<p>Parsec 的使用方式非常简单，只要去官网注册一个账号并分别在服务端（用于运行游戏的设备）和客户端（用于远程操控的设备）下载安装 Parsec 客户端即可。在两台设备上同时安装并登陆软件后，软件界面应该是这样的：</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20210502/parsec-interface.png"></p>
<p>此时只要点击相应设备上的 Connect 按钮即可建立远程连接了。但为了提升我们的游戏体验，在正式使用前还需要进行一些简单的设置。点击左侧的齿轮图标进入设置界面，将客户端设备的“硬件解码”和“Hevc 编码”功能打开即可。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20210502/parsec-settings.png"></p>
<p>连接成功后，软件会自动将被操控的设备调至静音，而将所有系统声音转到操控的设备上播放，这一细节非常人性化。经测试，在局域网（千兆带宽）环境下，两台设备基本可以实现零延迟的远程控制，但在广域网环境下，由于带宽和延迟的限制，远程控制略有延迟和卡顿，但仍能满足一些对操作要求不是那么高的游戏。例如，我最近正在补完的《歧路旅人》。这是一款“高清马赛克”游戏，且所有战斗均为回合制，非常适合远程游玩。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20210502/IMG_2477.JPG"></p>
<p>由于 macOS 原生支持 Xbox 和 switch pro 手柄，同时 Parsec 也能直接识别上述两款手柄的所有按键，因此在远程游戏时，可以直接通过将手柄连接客户端设备的方式来操控服务端的游戏。网络状况较好的时候，远程游戏的体验和本地几乎没有区别。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20210502/controller.png"></p>
]]></content:encoded></item><item><title>解决蜗牛星际B双安装黑群晖失败“文件已损毁（13）”</title><link>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20210423/</link><pubDate>Fri, 23 Apr 2021 00:00:00 +0000</pubDate><guid>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20210423/</guid><description>日常技术记录</description><content:encoded><![CDATA[<p>去年疫情期间，由于滞留家中实在无聊，我开始折腾软路由和 DIY NAS，而被折腾得最多的莫过于黑<a href="https://www.synology.com/en-us/dsm">群晖</a>系统。为此，我特意买来两台蜗牛星际（B双和C），其中B双用作软路由，C则用于黑群晖。时隔一年，忙于工作的我已不再有闲暇时间折腾黑群晖，而出于对数据安全和便捷性的考虑，我于今年年初购买了一台威联通的 NAS 主机。俗话说得好，黑群晖折腾到头，就会转去白群辉。但奈何威联通的性价比要比群晖高太多，因此我只好无耻地叛变了革命。</p>
<p>昨天心血来潮，想把放在角落吃灰许久的蜗牛星际B双刷成黑群晖，用作重要数据的冷备工具，平常都会处于关机状态，只有冷备的时候才会开机。由于我的B双之前一直都用作软路由，因此从来都没有刷过黑群晖。但鉴于蜗牛星际的配置都差不多，我简单地以为直接用之前C上现成的黑群晖引导U盘即可直接安装黑群晖系统。然而天真的我还是遇到了困难。</p>
<p>问题出在新系统安装的过程中，每当进度走到 56% 的时候，都会跳出编号为 13 的错误，提示“系统安装失败，文件可能已经损毁（13）”。为了解决这一问题，我尝试了很多方法，包括但不限于格式化所有硬盘（包括 SSD）以及更换各个版本的官方或非官方 DSM 安装包，但都不奏效，错误 13 依然存在。</p>
<p>最后，在电报群里高人的指点下，我终于解决了这一问题。其实，新系统安装的过程中之所以会出现错误 13， 是因为机器主板的 BIOS 没设置好。只要给主机插上键盘和显示器，在开机时进入 BIOS 界面（通常是在开机后显示主板厂商 logo 时按键盘上的 DEL 键进入），然后依次进入 <strong>Advanced—Miscellaneous Configuration—OS Selection</strong>，将 Win 7 改为 Win 8.x 即可。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20210423/bios.jpeg"></p>
<p>忙活了半天，最后才知道原来只是这么简单的一个问题。为了不让后来的小白们像我一样浪费时间，特此记录一下。本文也谈不上什么教程了。</p>
]]></content:encoded></item><item><title>Openwrt Luci Openvpn 服务器多设备同时接入</title><link>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20210413/</link><pubDate>Tue, 13 Apr 2021 00:00:00 +0000</pubDate><guid>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20210413/</guid><description>日常技术记录</description><content:encoded><![CDATA[<p>我们日常使用的 Openwrt 软路由系统几乎都集成了 <a href="https://openwrt.org/docs/guide-user/luci/start">Luci 界面</a>，它不仅可以为用户提供便利的可视化后台管理界面，还在各路大神的贡献下，适配了众多简单易用的图形化 App。<a href="https://github.com/DavBfr/luci-app-openvpn-server">Luci-app-openvpn-server</a> 就是众多 Luci 应用中最常用的 VPN 服务器之一。</p>
<p>简单来说，luci-app-openvpn-server 就是 Openvpn 服务器端的 Luci 界面版本。有了它，你就可以告别难搞的命令行，通过图形化的网页直接配置你的 Openvpn 服务器端。结合各主流平台的 Openvpn 客户端软件，你可以随时随地接入自己家里的局域网，实现内网访问或文件传输等功能。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20210413/luci-openvpn.png"></p>
<p>正常情况下，只要按照 Luci 界面的提示填写相应的配置信息，即可成功运行 Openvpn 的服务器端。此时只要点击“一键下载.Ovpn 文件”按钮，再将下载下来的配置文件直接导入 Openvpn 客户端软件即可开始使用。但 luci-app-openvpn-server 的默认配置支支持同时登陆一个客户端，当有第二个客户端尝试接入时，先前接入的第一个客户端就会被强制断线。然而在日常使用的过程中，多设备同时接入的情况是十分常见的，那么怎样才能使 luci-app-openvpn-server 可以同时接入多个设备呢？</p>
<p>其实，Openvpn 的服务端是支持多设备同时接入的。根据 Github 上<a href="https://github.com/coolsnowwolf/lede/issues/6175">这个 Issue</a> 中的介绍，我们能够得知，只要在 Openvpn 的配置文件中加入一行代码，即可开启 Openvpn 的多设备同时接入功能：</p>
<p>具体如何操作呢？首先，用 ssh 工具登陆你的 Openwrt 软路由。具体的工具及方法可自行搜索，我日常使用的是微软官方发布的 <a href="https://www.microsoft.com/en-us/p/windows-terminal/9n0dx20hk701?activetab=pivot:overviewtab">Windows Terminal</a> 终端工具。成功登陆 ssh 后，输入以下命令开始编辑 Openvpn 的配置文件：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>vim /etc/config/openvpn
</span></span></code></pre></div><p>如果没能成功打开配置文件的编辑界面，很可能是因为你的 Openwrt 系统没有安装 vim （一款命令行文本编辑器）。至于 vim 的安装方法，还请自行搜索，本文不再赘述。</p>
<p>进入配置文件的编辑界面后，按键盘上的 I 健进入文本编辑模式，将光标移到配置文件末尾，将以下代码复制粘贴到配置文件最后一行。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>option duplicate_cn <span style="color:#e6db74">&#39;1&#39;</span>
</span></span></code></pre></div><p>编辑完成后，按键盘上的 ESC 健，再依次输入以下命令保存并退出编辑器：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>:qw
</span></span></code></pre></div><p>完成上述步骤后，重启路由器。不出意外的话，你就可以同时使用多个客户端接入自己的局域网了。</p>
]]></content:encoded></item><item><title>利用 Docker 搭建 Trilium Notes 服务器</title><link>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20210320/</link><pubDate>Sat, 20 Mar 2021 00:00:00 +0000</pubDate><guid>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20210320/</guid><description>日常技术记录</description><content:encoded><![CDATA[<p>由于平时需要处理大量结构复杂的内容，并且各内容板块间还存在相互交叉的引用关系，因此长久以来我一直在寻找一款既能满足需求，又简洁易用的内容管理工具。印象笔记或 OneNote 等笔记类服务似乎最为常见，但一来，将所有的私人内容存储在商业公司的服务器上总会让我缺乏安全感；二来这些软件要么不够轻便，要么对重要功能额外收费，因此一直都无法让我十分满意。</p>
<p>两年前，我接触到一款叫做 <a href="https://www.notion.so/">Notion</a> 的跨平台软件，无论是功能还是界面都令我十分满意，但它的价格并不便宜，我毕竟不是靠内容吃饭的职业创作者，无论如何也不愿为一款笔记软件搞月付。另外，Notion 仍然无法实现在牢牢掌控内容数据的同时实现便捷的多端同步，这也是一个不大不小的遗憾。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20210320/Notion.png"></p>
<p>直到今天，偶然在<a href="https://sspai.com/post/59739">少数派这篇文章</a>的介绍下了解到一个叫 <a href="https://github.com/zadam/trilium">Trilium</a> 的 Github 开源项目，几乎完美地满足我的所有需求。首先，它是一个开源项目，支持自建笔记服务器，可以让我在牢牢掌控笔记控制权的同时实现多端同步；其次，它界面简洁，非常轻量，甚至可以丢掉客户端，完全实现网页端访问；最后，它完全免费，这点非常重要。</p>
<p>自从买了<a href="https://www.qnap.com/zh-cn/">威联通</a> NAS 后，我越来越倾向于将自己的各种数据保存在 NAS 上，再通过各类开源软件实现多端同步。这样既能保证数据安全和个人隐私，又能方便地管理自己的文件和数据。<strong>用几千元的成本和少许的电费换得对个人数据的完全掌控，我认为是值得的</strong>。因此，在意识到 Trilium 提供开源的服务端软件后，我立刻开始本地服务器的搭建工作。</p>
<p>Trilium 的官方文档中提供了通过 <a href="https://hub.docker.com/r/zadam/trilium">Docker</a> 安装 Trilium Server 的具体方式。但由于文档为全英文，且只提供了 SSH 命令安装的方式，一些新手阅读起来可能有些困难，因此本文将以图形化的方式简单陈述 Trilium Server 的安装方式。</p>
<p>首先，在你的 NAS 上安装 Docker 套件（在威联通的 QTS 中叫做 Container Station）并打开它。</p>
<p><img alt="Container Station 介绍页面" loading="lazy" src="https://masonblog.github.io/images/blog20210320/Container-Station.png"></p>
<p>进入“创建”，并在搜索框中搜索 Trilium，找到 zadam/trilium，点击右侧的“安装”。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20210320/Docker-Trilium.png"></p>
<p>在弹出的创建窗口中，点选“高级设置”，首先在“网络”选项卡中设置 Trilium 的端口转发，trilium 的默认 web 界面默认端口是 8080，因此 Container 的端口必须写 8080，而映射出的主机端口则可以根据自身需求填写。为了记忆方便，我倾向于内外端口一致的设置，即主机端口同样设置成 8080，但如果你的 NAS 的 8080 端口已被其他程序占用，请填写其他端口。</p>
<p><img loading="lazy" src="/images/blog20210320/Docker-Trilium2.png"></p>
<p>接着，在“共享文件夹”选项卡中，将一个共享文件夹挂在到 Trilium 的容器中。容器中的挂载路径必须写 /trilium-data，而本机共享文件夹则可根据自身需求进行选择，注意挂载共享文件夹的权限必须为读取和写入均有。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20210320/Docker-Trilium3.png"></p>
<p>上述设置完成后，点击“创建”按钮，系统会自动下载镜像文件并根据你的配置安装容器。容器安装完成后，便可通过在浏览器中输入 NAS IP/端口的方式访问 Trilium 的 web 界面。初次使用 Trilium 时要进行一些简单的初始化设置，例如创建用户名和密码等。虽然界面只有英文，但非常简单，这里不做赘述。</p>
<p>至此，我们便搭建完成了自己的笔记服务器。关于 Trilium 的具体使用方法，可自行摸索或搜索，总体来说，这款工具的使用门槛并不高。我的这篇文章就是全称用 Trilium 撰写的。Trilium 支持 Marddown 语法，因此对我而言几乎没有任何使用门槛。另外，Trilium 的 web 界面支持移动端布局，只要做好 DDNS 和路由器端口映射，便可在任何地方随时随地访问自己的笔记，无论用电脑还是手机。</p>
]]></content:encoded></item><item><title>通过群晖与 Openwrt 软路由实现自动端口映射</title><link>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20200914/</link><pubDate>Mon, 14 Sep 2020 00:00:00 +0000</pubDate><guid>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20200914/</guid><description>日常技术记录</description><content:encoded><![CDATA[<p>要在家庭或公司的局域网以外（俗称外网）访问家中或公司内网的设备（例如 <a href="https://baike.baidu.com/item/NAS">NAS</a>），通常有两种方式。第一种方式是在局域网的路由器上架设一个 VPN 服务器，再将外网的终端设备作为 VPN 客户端接入内网。在这种情况下，<a href="https://baike.baidu.com/item/VPN">VPN（虚拟专有网络）</a>充当了网线的角色，即接入 VPN 的外网设备，就相当于拉了一根通往内网的网线。因此在 VPN 网络中，即使这根网线是虚拟的，也能实现如同身处局域网内一般的访问体验。</p>
<p>第二种方法则更为简单直接，即通过<a href="https://baike.baidu.com/item/DDNS">动态 DNS</a> 服务将一个域名绑定到局域网服务器的外网 ip，再议端口映射的方式将内网设备暴露在公网中，以供外网设备连接。由于众所周知的原因，我国境内的 VPN 连接并不稳定，因此大多数人都会选择第二种方式进行内网穿透。</p>
<p>在路由器上进行端口映射的操作非常简单。这里以 <a href="https://openwrt.org/">Openwrt</a> 系统为例，仅需在网络 - 防火墙 - 端口转发中新建转发规则，将相应内网设备的端口映射为外网端口即可。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20200914/port-transfer.png"></p>
<p>然而，由于内网设备的内部 ip 地址会随着 DHCP 租约的更新而不断变化，尽管我们可以通过 IP/MAC 绑定的方式人为地固定内网设备的 ip 地址，但实践证明这种方式并不稳定。因此，我们经常需要手动修改端口映射规则，这就使得相关的维护工作变得非常繁琐。如果我们长期在外，无法接入内网环境，上述规则修改的工作就很难进行。这时，我们就需要用到 UPnP（通用即插即用）服务。顾名思义，它是一种自动配置端口映射的工具。只要服务器和内网其他设备同时开启 UPnP 服务并稍加简单的配置，即可一劳永逸地解决端口映射的问题。</p>
<p>以群晖和 Openwrt 系统为例，我们首先需要在 Openwrt 路由器上安装并开启 UPnP 服务。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20200914/upnp.png"></p>
<p>然后，登陆群晖的管理后台，在控制面板 - 外部访问 - 路由器配置选项卡中，选择“设置路由器”。此时系统会自动检测网络环境以及路由器型号与配置，不出意外的话，整个过程能够由系统自动完成，无须人工配置。之后，点击“新增”按钮，并根据自己的需求选择要转发的应用和端口，再点击“保存”即可。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20200914/synology-upnp.png"></p>
<p>最后，我们可以回到路由器后台的 UPnP 页面，查看已经被系统自动添加好的端口映射规则。值得注意的是，国内的网络运营商一般会禁用个人和家庭宽带的 443 和 445 端口（前者是 https 的默认端口，后者是 smb 服务的默认端口），因此，即使我们在 UPnP 服务中添加了上述两个端口的自动映射，也无法实现 443 和 445 端口的外网访问。此时，就需要我们在防火墙的端口映射中手动进行端口映射，即将 443 和 445 两个内网端口映射到外网的非 443 或 445 端口（如 444 和 446，全凭个人喜好）。这样，我们才能绕过运营商的封锁，成功进行上述两个端口的外部访问。</p>
]]></content:encoded></item><item><title>利用 NAS、Docker 和 Calibre Web 搭建个人线上书库</title><link>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20200512/</link><pubDate>Tue, 12 May 2020 00:00:00 +0000</pubDate><guid>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20200512/</guid><description>日常技术记录</description><content:encoded><![CDATA[<p>经常阅读电子书并且用过 Kindle 的人应该都体会过整理电子书时的痛苦。尤其是像我这种经常下载电子书文件再导入到 Kindle 上进行阅读的人（或是为了省钱、或是因为 Kindle 商城中没有我们想要阅读的书），对于那些有着各自不同的标题、作者、封面，以及文件格式的纷繁复杂的电子书，缺乏一套行之有效的管理方案，进而充分管理自己的阅读进度与时间。</p>
<p>长期以来，PC 和 Mac 端的 <a href="https://calibre-ebook.com/" title="Calibre 官网">Calibre</a> 都是一个差强人意的电子书管理解决方案。它不仅支持多平台、功能强大（支持电子书整理、编辑、格式转换、一键推送到 Kindle 等），而且完全免费。那我为什么要将这么厉害的软件说成是“差强人意”呢？因为 Calibre 已经多年没有较大的功能更新，作为一款电子书管理软件，它已经无法适应当下人们已经习以为常的需求。具体而言，Calibre 具有以下缺点：</p>
<ol>
<li>界面老旧（或曰古朴？），看起来像是十年前的软件；</li>
<li>启动和运行速度较慢，操作繁琐；</li>
<li>不支持多设备同步，不提供云存储服务（这是最重要的一点）。</li>
</ol>
<p>对于像我这样学习或工作繁忙，几乎没有固定的整段时间使用同一台终端设备的人来说，多端同步和云存储几乎是不可或缺的功能。而且在网页程序和微信小程序等日益普及的今天，有时连下载一个专门的应用程序都显得繁琐（可能是被这几年的技术进步惯坏了把）。因此，最好有一款类似于 <a href="https://www.plex.tv/" title="Plex 官网">Plex</a> 影视库的电子书管理服务器应用，能够让我随时随地打开一个网页就能管理和阅读自己的电子书。幸运的是，这样的软件确实存在，它便是 Calibre 的继任者—— <a href="https://github.com/janeczku/calibre-web" title="Calibre Web 的 Github 页面">Calibre Web</a>。</p>
<p>下图就是我用 Calibre Web 在自己的 <a href="https://baike.baidu.com/item/NAS/3465615" title="NAS 的百度百科页面">NAS</a> 上搭建的个人电子书管理网站（或曰个人电子图书馆？）。通过这个网站，我可以轻松地在各种终端设备上上传、修改、整理、推送各种格式的电子书。由于是网页端，因此我不用担心海量电子书会占用手机或电脑的硬盘容量，也不用担心多端同步的问题。更加难能可贵的是，由于 Calibre Web 开发得比较晚近，因此它的界面也很符合当下的主流审美标准。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20200512/Snipaste_2020-05-13_10-29-50.jpeg"></p>
<p>关于 Calibre Web 的搭建方法，网络上有很多前辈们撰写的教程，他们已经说得非常详细了。首先，你必须拥有一台能够稳定运行的服务器或 NAS（其实任意一台普通电脑都是可以的，只要你舍得让它 7*24 小时运行）。然后，你需要在你的设备上搭建一个 <a href="https://www.docker.com/" title="docker 官网">docker</a> 环境，因为 Calibre Web 需要 docker 作为运行的载体。最后，经过简单的安装和配置，你就可以拥有一个属于自己的电子书管理网站了。</p>
<p>这里以<a href="https://www.synology.cn/zh-cn" title="群辉官网">群辉</a>为例。首先在“控制面板”中创建一个新的共享文件夹，用于存放 Calibre Web 的数据库和电子书资源。我这里将它命名为&quot;Books&quot;。创建完成后切记要开放该文件夹对所有用户的读写权限，否则 Calibre Web 将无法正常运行。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20200512/Snipaste_2020-05-13_10-59-19.jpeg"></p>
<p>共享文件夹配置完成后，在群辉的套件中心中选择安装 docker 并打开它。再在“注册表”页面中搜索“Calibre-web”，此处途中框选的三个镜像都可以下载，它们的区别并不大，这里主要推荐 linuxserver/Clibre-web，在双击后弹出的对话框中选择“latest”并点“确定”开始下载。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20200512/Snipaste_2020-05-13_10-47-03.jpeg"></p>
<p>镜像下载成功后（系统右上角会弹出提示），进入 docker 的“镜像”页面选择刚刚下载好的 linuxserver/Clibre-web 镜像，点击启动。在弹出的对话框中，点击“高级设置”，再按下图所示进行设置即可。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20200512/Snipaste_2020-05-13_10-53-51.jpeg"></p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20200512/Snipaste_2020-05-13_10-54-25.jpeg"></p>
<p>之后，启动 Calibre Web，并在浏览器地址栏中输入群辉的内网 IP 地址 + 半角冒号 + 上图中设置的端口号（默认为8083）。例如，我的群辉内网 IP 地址是 10.10.10.34，Calibre Web 的端口号是 3096，那么我输入的地址就是：</p>
<pre><code>http:10.10.10.34:3096
</code></pre>
<p>初次进入 Clibre Web 时需要进行一些简单的配置，例如指定数据库目录（一定要和上图中设置的“装载路径”相匹配）、创建用户，以及配置邮件推送等。关于 Calibre Web 的配置和使用方法，这里就不再赘述了，网上教程一搜一大把。顺带一提，如果想在非家庭内网的环境中（例如出门在外的 4G 网络）继续使用 Calibre Web，你还需要进行内网穿透或动态 DDNS 的相关配置。至于这些内容，已经超出今天这篇文章的讨论了范围了，以后我们有机会在说把。</p>
<p>最后，推荐一本我最近正在读的书——理想国译丛的《布达佩斯往事》，希望你们能够喜欢。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20200512/Snipaste_2020-05-13_11-13-44.jpeg"></p>
]]></content:encoded></item><item><title>可能是最好用的记忆辅助工具 Anki</title><link>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20200326/</link><pubDate>Thu, 26 Mar 2020 00:00:00 +0000</pubDate><guid>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20200326/</guid><description>日常科技见闻</description><content:encoded><![CDATA[<p>对包括我在内的相当一部分人来说，记单词几乎已经成为一种刚需。无论是为了应付考试、取得各类等级证书还是单纯提高语言能力，词汇都是我们不得不正面应对的挑战。而在如今这个互联网时代，捧着厚重的词汇书或者词典进行背诵的方式已经被大多数人所抛弃，因为它既枯燥又低效，不仅会消磨我们学习一门语言的热情，还不利于培养语感、付诸实用。</p>
<p>在这样的背景下，一众“背单词”软件应运而生。这其中就包括<a href="https://cichang.hujiang.com/" title="开心词场官网">开心词场</a>、<a href="https://www.shanbay.com/" title="扇贝英语官网">扇贝英语</a>和<a href="https://www.baicizhan.com/" title="百词斩官网">百词斩</a>等较为优秀的产品。但是，这些软件或多或少都存在着以下几点无法弥补的缺陷：</p>
<ul>
<li>词库多为厂商事先制作而成，缺乏根据个人情况进行定制的空间，灵活性不强。</li>
<li>支持的语种多为英、日、韩等热门语种，无法满足小语种（如希伯来语）学习者的需求。</li>
<li>出于营利目的，集成了许多不常用的花哨功能，洁面不够简洁。</li>
<li>同样出于营利目的，部分功能仅对付费用户开放，免费用户的使用体验受限。</li>
</ul>
<p>凡此种种，都构成了我长期无法找到适合自己的背单词软件的原因。然而，就在将近两年前，也就是我正在准备研究生考试的时候，我遇到了 <a href="https://apps.ankiweb.net/">Anki</a> 这个神一样的记忆软件。之所以称它为“记忆软件”而非“背单词软件”，是因为它几乎支持所有需要记忆的内容格式，而不像上文提到的众多“专业软件”那样只能用来背特定语种的单词。实际上，只要你愿意，Anki 可以被用来记忆唐诗、成语，甚至<a href="https://baike.baidu.com/item/%E7%BA%B3%E7%93%A6%E9%9C%8D%E5%AF%86%E7%A0%81/9482868?fromtitle=%E7%BA%B3%E7%93%A6%E8%8D%B7%E5%AF%86%E7%A0%81&amp;fromid=6646373" title="那瓦霍密码的百度百科词条">纳瓦霍语</a>。</p>
<p>简单来说，Anki 是一种利用类似于 Flash Cards 的卡片机制来辅助记忆的，支持高度定制化的工具。到目前为止，我发现它具有以下几个传统背单词软件所不具备的优点：</p>
<ul>
<li>支持几乎所有内容形式，只有你想不到，没有 Anki 不支持的内容。</li>
<li>不仅支持传统的翻面单词卡，还支持诸如填空题、选择题等多种答题形式，满足各类需求。</li>
<li>根据<a href="https://baike.baidu.com/item/%E9%81%97%E5%BF%98%E6%9B%B2%E7%BA%BF/7278665?fromtitle=%E8%89%BE%E5%AE%BE%E6%B5%A9%E6%96%AF%E9%81%97%E5%BF%98%E6%9B%B2%E7%BA%BF&amp;fromid=3905802" title="艾宾浩斯遗忘曲线的百度百科词条">艾宾浩斯遗忘曲线</a>科学定制学习和温习计划，保证高效利用精力和时间。</li>
<li>云端实时备份词库和学习进度，并支持包括 PC、Mac、iOS、Android 等类操作系统，让用户可以轻松跨平台同步学习进度，随时随地进行学习。</li>
<li>支持牌组导出导入，结合活跃的社区和各类资源分享渠道，使那些不愿意自己制作牌组的用户也能通过下载并导入前人制作好的卡组来高效进入学习状态。</li>
</ul>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20200326/anki3.png"></p>
<p>Anki 的桌面端（包括 Windows 和 Mac）和手机端（包括 iOS 和 Android）的功能几乎完全相同，但前者完全免费而后者必须付费。如果你既不愿意付费也不想使用盗版，那么只使用桌面版即可。这样除了无法获得多平台同步学习的体验外，不会受到任何具体功能上的限制。</p>
<p>Anki 的桌面端界非常简洁，你可以通过点击“新建记忆库”来自定义录入自己的牌组，也可以点击“获取牌组”以进入 Anki 官网浏览和下载其他用户上传的现成牌组。另外，在诸如淘宝或闲鱼等交易网站上也会有卖家有偿销售自己制作的 Anki 牌组，如果你购买了那些牌组，那么只要点击“导入文件”按钮即可将买来的牌组轻松导入。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20200326/anki2.png"></p>
<p>以手机端为例，在学习牌组的过程中，我们可以根据自己的答题状况点选下方不同颜色的按钮。这样，Anki 就会将相应卡片加入对应的温习序列中，并根据艾宾浩斯遗忘曲线，结合我们后续的回忆状况，动态地安排学习计划。可以说，Anki 的这种根据个人记忆状况动态定制学习计划的特点，是使它从众多“背单词软件”中脱颖而出的最根本原因。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20200326/anki4.jpg"></p>
<p>去年的这个时候，我正在准备所报考学校的研究生复试。如果说我的研究生外语考试能够取得理想成绩“多半”是我自己努力的结果的话，那么 Anki 便是那“少半”的原因。</p>
]]></content:encoded></item><item><title>MacOS 10.15.4 更新 iCloud 文件分享功能</title><link>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20200325/</link><pubDate>Wed, 25 Mar 2020 00:00:00 +0000</pubDate><guid>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20200325/</guid><description>日常科技见闻</description><content:encoded><![CDATA[<p>相比于国外而言，中国国内的公共网盘生态好似一潭死水。这其中固然也有厂商不思进取的缘故，但更主要的还是政府对网络信息的严密审查，使得公共网盘服务提供商很难在维持自身生存和提升用户体验之间取得平衡。</p>
<p>经过几年前的一阵腥风血雨之后，目前国内叫得上号的公共网盘只剩下<a href="https://pan.baidu.com/" title="百度网盘官网">百度网盘</a>、<a href="https://union.ctfile.com/" title="域通网盘官网">域通网盘</a>和<a href="https://www.jianguoyun.com/" title="坚果云官网">坚果云</a>等。其中最臭名昭著的非百度莫属，其不仅对非会员用户有着苛刻的功能限制（地容量+下载限速），并且身型极其臃肿、拥有很多大多数用户完全用不到的冗余功能。相比之下，坚果云就要好不少，它对免费用户只做月流量方面的限制，除此之外既不限制速度也无冗余内容，可以说非常良心了。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20200325/jianguoyun.png"></p>
<p>然而与百度网盘生成链接直接分享的便捷性相比，坚果云在文件分享方面又稍显不足。因此在目前国内的公共网盘生态中，想要免费使用一个功能简洁、分享方便又不限速的网盘产品，几乎是不可能的。在这种情况下，很多用户开始转向<a href="https://baike.baidu.com/item/NAS/3465615" title="NAS 的百度百科词条">私有云（NAS）</a>方案，即建立私人的网络存储服务器，如购买<a href="https://www.synology.cn/zh-cn" title="群晖官网">群晖</a>或 <a href="https://www.qnap.com.cn/">QNAP</a> 的 NAS 主机或自行组装一台 DIY 主机。但无论是前者还是后者，都具有一定的技术门槛，并不适合所有用户。</p>
<p>作为苹果产品生态的基础性服务，<a href="https://www.icloud.com/" title="iCloud 官网">iCloud</a> 几乎为所有苹果设备用户所使用。无论你是否意识到，只要你用 iPhone 拍过照，你的照片就会自动被存储到你的 iCloud 中。无论你是否付费，只要你注册一个 Apple ID，你就会得到 5GB 的 iCloud 存储空间。虽然这个容量并不算大，但仅用于存储日常拍摄的照片和办公文档，是完全足够的。多年来，icloud 的封闭性一致为人们诟病。可能是出于数据安全的考虑，苹果并不允许用户将自己 iCloud 网盘中的文件分享给其他人。但好消息是，这一状况在最新一次的 MacOS 系统更新中被彻底改变。</p>
<p>今天上午，当我打开电脑准备开始今天的工作时，发现苹果推送了最新版本的 MacOS 10.15.4 系统更新，更新说明里面赫然写着羡慕一段话：</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20200325/mac-update-10.15.4.png"></p>
<p>也就是说，<strong>iCloud 终于支持对外分享文件了</strong>！于是我立刻更新了系统，想尽快体验一下用 icloud 分享文件的感觉。在新版本的系统中，只要在 icloud 文件上右击鼠标，选择“共享”，再点“添加用户”，即可生成该文件的分享链接。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20200325/icloud-share-0.png"></p>
<p>打开“添加用户”对话框后，我们可以对共享链接进行相应的设置。如果我们只想对受邀请的用户共享文件，那么不仅要在下方将“有权访问的用户”设置为“仅限于受邀用户”，还要在上方填写我们所邀请用户的邮箱。注意，目前“受邀用户”功能只对其他 Apple ID 开放，填写的邮箱也必须是 Apple ID 的登陆邮箱。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20200325/icloud-share-1.png"></p>
<p>如果我们想要创建公开共享链接，而不是只针对特定用户开放浏览，那么我们可以选择“任何拥有链接的用户”。这样，只要将我们创建的共享链接发送给其他人，拥有链接的用户就可以随时打开相应链接浏览文件。</p>
<p>另外，我们可以在下方的选项中设置共享文件的访问权限。其中“仅查看”是只读权限；“可更改”是读写权限。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20200325/icloud-share-2.png"></p>
<p>设置完成后，通过点击下方的“共享”按钮，我们就为指定文件创建了一个共享链接。共享链接创建完成后，它会自动地被复制到我们的剪贴板中，并且相应 iCloud 文件的名称后面会出现“由我共享”字样，便于我们事后查找。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20200325/icloud-share-3.png"></p>
<p>现在，我们就可以将复制好的共享链接发给其他用户，让他们通过浏览器打开该共享链接来读取或更改相应文件了。值得一提的是，如果共享文件是 PDF 等格式的文件，打开共享链接即可直接预览其内容，而无需先下载再查看，非常方便。</p>
<p><img loading="lazy" src="https://masonblog.github.io/images/blog20200325/icloud-share-4.jpg"></p>
]]></content:encoded></item><item><title>利用 Hugo 和 Github Pages 搭建自己的个人博客</title><link>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20200310/</link><pubDate>Tue, 10 Mar 2020 00:00:00 +0000</pubDate><guid>https://2e1a95c2.masonblog-b7a.pages.dev/post/blog20200310/</guid><description>此页面记录了我利用 Hugo 和 Github Pages 搭建本站的全过程</description><content:encoded><![CDATA[<p>如你所见，此博客是一个完全静态的 HTML 站点。相比于 PHP 编写的动态站点，静态站点不仅访问速度更快，而且部署门槛低。一个完全不会编程的新手，只要花点时间掌握一些工具的用法，也能轻松建立属于自己的站点。</p>
<p>本站由 <a href="https://gohugo.io/" title="Hugo官网">Hugo</a> 渲染而成。它的使用方式非常简单，想要自学的朋友可以阅读 Hugo 的<a href="https://gohugo.io/documentation/" title="Hugo官方文档">官方文档</a>。与其他博客系统一样，Hugo 也拥有着众多简洁美观的<a href="https://themes.gohugo.io/" title="Hugo 官网主题页面">主题</a>，本站所使用的主题是 <a href="https://github.com/flysnow-org/maupassant-hugo" title="Github库">maupassant</a>（2024年更新：播客迁移后最新使用的主题为<a href="https://github.com/adityatelange/hugo-PaperMod">PaperMod</a>）<del>，它最初是由 <a href="https://github.com/pagecho" title="Github主页">cho</a> 开发于 <a href="https://typecho.org/" title="Typecho官网">Typecho</a> 平台的主题，后被移植到众多其他平台，并被加入了许多新功能</del>。</p>
<p>Hugo 的所有页面都支持 Markdown 语法，借助它，我们可以在任何环境下撰写出格式统一的博文，而不用担心外观问题。Markdown 的学习成本很低，任何人都可以在极短的时间内学会。如果你有兴趣，可以通过<a href="https://www.runoob.com/markdown/md-tutorial.html" title="Markdown菜鸟教程">这份教程</a>入门 Markdown。<a href="https://typora.io/" title="Typora官网">Typora</a> 是我目前正在使用的一款支持多平台的轻量级 Markdown 编辑器，界面非常干净简洁，<del>并且免费开源</del>（2024年更新：该软件已于2022年开始收费，目前我使用的编辑器是<a href="https://github.com/marktext/marktext"> MarkText</a>）。</p>
<p><img loading="lazy" src="/images/blog20200310/marktext.png"></p>
<p>通过 Hugo 生成好完整的 HTML 页面之后，我们便可以将这些页面放到我们的服务器上了。你可以购买一台虚拟主机，或者更加省时省力地，利用 Git 仓库托管自己的网站。<a href="https://git-scm.com/" title="Git官网">Git</a> 是一个应用非常广泛的版本管理工具，而 Git 仓库则是用于托管源代码的小型服务器。最著名的 Git 仓库非 <a href="https://github.com/" title="Gitlab官网">Github</a> 和 <a href="https://gitlab.com/" title="Gitlab官网">Gitlab</a>，它们在提供免费的源代码托管服务的同时，还支持 Pages 托管服务。所谓 Pages，原本是用于介绍和传播开源项目的说明文档，但其本身也是一个小型的 HTML 静态 Web 服务器。利用 Pages，我们可以轻松而免费地部署自己的静态网站。</p>
<p><img loading="lazy" src="/images/blog20200310/Github.PNG"></p>
<p>如果你不希望通过手动的方式创建页面或修改配置，而是习惯于通过类似于 PHP 动态博客后台的可视化界面来编辑自己的网站，那么你可以尝试 <a href="https://forestry.io/" title="Forestry官网">Forestry</a>。它是一个支持多种环境的可视化内容管理系统（CMS）。通过 Forestry，你可以像编辑动态博客那样管理自己的静态网站，并实时地将编辑好的网站推送到你的 Git 库中，实现真正的无代码建站。</p>
<p><img loading="lazy" src="/images/blog20200310/Forestry.PNG"></p>
<p>本站即通过 Hugo + ~~Forestry ~~+ Github 搭建而成，从开始自学到写这篇文章总共花费三天时间。在此感谢所有为开发上述工具或撰写相关教程而无偿付出时间与精力的前人们，若不是站在他们伟岸的肩膀上，本站不会有问世的这天。</p>
]]></content:encoded></item></channel></rss>