普通视图

Received yesterday — 2026年4月7日

四月天

作者obaby
2026年4月7日 13:55

清明节假期还是如约而至了,跟着一起来的还有临近下班的时候收到的一条竞岗通知,让假期最后一天十二点之前提交竞岗申请表。

下班收到这条通知,我并不想现在去填那个申请表,还要领导签字之后上交。由他去吧,到家之后看到手机又有一些消息,打开大概浏览了一下,意思是,如果无法提交纸质版,或者领导无法签字,可以先提交电子版。跟对象提及此事,她说,『该交就交吧。该走的流程还是要走的,如果视在不行,那就拿补偿走人,也挺好的。现在我觉得,你能不能继续干下去都挺好的,能干就干,不能干就走。』稍微顿了以下,继续说:『找时间咱们去看看把公积金提出来吧,我同事都提了好多次了。不过咱们的契税单子没了,不知道能不能提。』

『嗐,担心那个干嘛,直接用手机申请下不就知道了』我一边说,一边去拿手机。支付宝打开公积金小程序,一堆查询走下去,并且有什么异常提示。尝试直接提取,理由选择偿还商业贷款。一步步操作,到最后验证贷款的时候,选择贷款银行,最后竟然只需要一个贷款时间和贷款金额就能查询到贷款信息了,这一点做得的确不错。选择金额之后,点击提交申请,没有提示需要提交任何资料。提交完了才发现,忘了选择银行卡了。竟然填写的是多年以前的交通银行的银行卡。

对象担心银行卡还能不能用,索性直接登录手机银行,发现申请提现的金额已经到账了。现在该想一下怎么处理这笔钱了,第一步想着再去存个定期。然而,前段时间存的一张定期的单子,五年年利率只有1.75。打开兴业银行的贷款明细,看了下贷款利率石3.2。 这还存什么定期,干脆还款得了。

从兴业银行的手机银行再申请提前还款,于是这一笔钱就在手里打个转,过几天就又成了别人的了。看了下贷款信息,70万,还了十年,一共出去了30万,实际剩余的贷款还剩50万。相当于交了10万利息。不过反过来想,这十年租房子十万也不够,两室一厅的房子,十年房租下来也得二十多万了。这么一想,还是得感谢对象的眼光,房子买的早,想尽办法借钱买了这套房子,也得感谢自己不是犟种,觉得租房子也可,没坚持租房子。

至于假期,其实也没什么好的打算,还是带宝子回老家。四月天,正好是在户外放飞的时候。

晚上教练还问,第一天要不要上网球课。刚开始想着可以下课之后再走,晚上八点多开始下雨,十一点多的时候雨逐渐变大,路上也慢慢有了积水,既然如此,那室外的网球场第二天可能也没法打了,不如干脆请假。对象最近牙疼,假期也就不跟着回了,找时间去查一下看看怎么处理。

回老家的路上,前一段还算是比较顺利,绕行机场高速,绕过了最堵的市区高速。然而,等往青银转的时候,提示拥堵距离五公里,磨蹭到匝道入口才发现,车流量实在是太大了,只有一个车道,所有的车不得不慢慢悠悠的往里蹭。高速路况除了这一段,剩下的基本倒是顺畅,下了高速之后,开始另一段拥堵。高速工作人员指挥右转车辆走应急车道。左转的两个车道就只能等交警指挥放行了。

远远的就能看到省道上密密麻麻的车,下高速之后虽然之后十几公里的路程,却开了接近五十分钟,这还是最后到镇上之后抄小道绕过了一部分拥堵路段。

到家之后,宝子的姐姐躲在屋里的帐篷里。就是在室内又搭了一个帐篷,藏在里面。早上走的匆忙,也没买什么东西,让宝子给老太太一个红包,这件事算是过去了。在回来之前还给宝子的姐姐定了一份外卖,拉丝芝士棒,说想吃这个。六个芝士棒拿出来之后,实际他就吃了一个。剩下的几个到了中午才被其他人吃掉。

虽然晚上还在下雨,但是假期第一天的天气还算不错,虽然气温低了点。中午收拾好东西,去上坟。山路边的地里,已经又开始种满了杨树苗,几年前禁止耕地种树的决定,现在看来应该是又被废弃了。现在杨树的价格,却一言难尽,很多租地种树的甚至连租地的钱都挣不出来。尽管如此,还是有大面积的耕地被种满了树苗,好处是不用怎么管理,稍微去外面干点活,总是比种那点粮食收入能好很多。偶尔在破败的院落边上能看到一树桃花,娇艳欲滴。

下午孩子们在玩的时候,突然记起来去年买的那条绳子和滑轮。年前的时候在院子里玩过几次,受限于场地只能拴在门框上,另外一头拴在了墙上。现在孩子们比去年肿了,尼龙绳子又有一定的弹力,稍微一拉伸可能就拖到地上了。想着去户外的树林子重新搭一套滑道,试了几棵树都不大行。这时候姐姐提议用邻居宅基地里面的那几棵树,刚好一头比较高,另外一头比较低。

搬梯子拴上去,试了以下,刚好。

几个孩子就这么在这个简易滑索上玩了大半个下午,剩下的时间爬门楼的平台,通过那个手工捆绑的梯子,爬上来,爬下去。有时候还要带着猫咪一起爬。

坐在月台上,猫咪和小狗就在身边嬉闹。

不过并不是总是那么和谐,有时候狗子也会直接张大嘴咬猫咪的脑袋,这时候猫咪就只剩下望风而逃了。

在家的日子过的也快,转眼一下午的时间就没了。晚上宝子跟她姐姐挤在那个帐篷里睡了一晚上,虽然地方小,但是睡得挺好,第二天早上九点多过去看的时候,还没起。等起床洗刷完依然过了十点,连早饭都省了。

中午包水饺,宝子跟她姐姐一起上阵,包的饺子挺好的,有模有样,这时候二姐说到:『你想想办法,把抽屉的锁给弄开吧,钥匙丢了,已经半年多没开了。』

这个锁其实已经换过一次了,上次也是钥匙丢了。用钢锯条锯开之后,换了一把新的,这次,自然也是同样的方法。出门骑电动车到镇上五金店,买了五根锯条,一把锁,一共花了七块五。老板对于我怎么锯开写字台的锁表示很好奇,我解答说:『就那么直接把锯条伸进去锯就行了。』我说完,他依然一脸不可置信。

到家,带上一副厚手套,大约五分钟,在崩了三根锯条之后终于成功了。

拆掉旧的,装上新的。

不过,这次买的锁头稍微小了一点,周边留出很多缝隙。也无所谓了,能用就行。给老太太留下一把钥匙,另外一把钥匙找地方放了起来。以防哪天钥匙又丢了。

下午吃完饭,宝子们又嚷嚷着要爬梯子。但是鉴于之前扣车上苹果模型的熊孩子还没走,自己就把梯子给撤了。然而,过了不一会儿,宝子跑进来说,滑索坏掉了,拖到地上了。用屁股想也知道,肯定是那个熊孩子上去了,目测近一百斤的体重,那一根尼龙绳子怎么能提供那么大的张力。绳子已经被全部拉了下来,关键是还怕熊孩子玩的时候万一受伤,说都说不清楚,只好把滑索给拆掉了。

下午跟姐姐带着宝子们去外面溜达,小狗也一直跟着,一会儿跑的无影无踪了,不知道什么时候又跑了回来,乐此不疲。路边开满了野花,孩子们也去折了一些。

田里也有些许忙碌的身影,在整理田地。有的在浇麦子,一个熊孩子在低头跑来跑去,看着我们过去,前面有个小狗。熊孩子拾起一块石头开始去追狗子,朝着狗子扔了过去。好在没打中狗子,狗子跑回来了。

刚开始狗子并没发怒,看熊子过来,开始围着自己转圈跑,熊孩子就在后面追,追了一会儿熊孩子看追不上,捡起石头来继续扔狗子。这时候狗子明显怒了,停下来朝着熊孩子龇牙咧嘴,眼看如果熊孩子敢再扔的话,狗子就扑上去了。我只好喝退狗子,把熊孩子也训了一顿,让他赶紧走远点。

回去的时候,也不想再见到那个熊孩子,就直接带着他们下到了沟里,顺便弄了几根杨树条给他们扭了一个哨子。

村里但凡能种树的地方,都种满了杨树。自从没人种地之后,原本经常走的一些小路也就没了踪迹,只能沿着沟底前进。

原本在路上看到几株野果的乔木,想扒出来带回家种下去的,因为没走回头路也未能如愿。现在都开花了,可能哪怕带回家了也不容易成活吧。

夜晚总是如期而至,从来都不会迟到。吃完晚饭也就该回县城了,天黑之后,路况反而没那么拥堵了。

刚开始以为是车贴的膜太黑了,右侧总是看不清楚。路上别到一辆大本,过了一会儿,从右侧超了上来,打开窗户,超我一通比划,可能还有问候吧。不过我没开窗户,一句都没听到。大哥笔画半天之后,超到了自己前面,既然是自己做得不对。那就认怂认骂,老老实实的跟在后面。等到了一个右侧的岔路口,大哥先打了个右转向,又开了双闪。还以为这无牌大哥要停车跟自己干架呢,不过自己超过去之后,对方也没什么反应,应该是对方到了目的地了。停车之后,才发现右侧车床应该是自己用湿巾擦玻璃上的鸟屎的时候,没擦干净,反而抹的那一块更加不清楚了。

把身上的衣服换下来,全部扔到洗衣机,让宝子去洗澡。衣服上占满了猫毛,狗毛,粘了半天也没粘干净,最后直接扔洗衣机给洗了。而至于鞋子,只能等回家之后再洗了。洗衣店的会员卡,基本都用来洗鞋了,价格也挺合适的9.9一双。

最后一天,八点多宝子还没醒。过去把她叫醒,洗刷吃饭,开始往回赶,毕竟作业没写完,下午还有网球课。两天疯玩,体力消耗也蛮厉害的。只是玩的时候从来都不会觉得累吧。

有时候真的羡慕这样的童年,有陪自己一起折腾的父母,也有长时间的陪伴。只是,现在,还是得为了工作绞尽脑汁,甚至有可能哪一天依然需要背井离乡。

人间四月天,总是生机勃勃,至于明天不确定的事情,明天再说吧。

Received before yesterday

RSS阅读器安利:Fluent Reader

作者Echo
2023年8月1日 19:34

前言

由于之前在网上搜寻到RSS订阅工具都差强人意,今天闲来无事,偶然发现了一款颜值非常高的开源免费RSS订阅器:Fluent Reader , 于是便想写一篇文章安利下

如果想要使用,微软商店直接搜索下载即可,也可以前往 GitHub 上下载,此仓库包含了APP端软件包

至于更多RSS订阅源可跳转相关链接处

RSS 介绍

RSS(Really Simple Syndication,真正简单的分发)是一种用于发布和订阅网站内容的数据格式和协议。它通过简单的 XML 格式来传递网站的文章、新闻、博客等信息,允许用户通过订阅器(RSSReader)获取网站内容的最新更新,而无需直接访问网站。
RSS 最早出现在 1999 年,由 Netscape 公司创立。随后,RSS 标准逐渐发展,演变为不同的版本和格式。常见的 RSS 版本包括 RSS 0.9x、RSS 1.0、RSS 2.0 和 Atom 等。

RSS 的工作原理如下:

  1. 网站创建并维护 RSS 文件:网站管理员会将网站的文章、新闻、博客等内容整理成 XML 格式的 RSS 文件,并将其发布在网站的特定位置,通常是一个预定义的 RSS Feed URL。
  2. 用户使用订阅器订阅 RSS Feed:用户可以使用 RSS 订阅器(也称为 RSS Reader 或 Feed Reader)来订阅感兴趣的网站的 RSS Feed。订阅器会定期检查订阅的 RSSFeed,以获取其中的更新。
  3. 订阅器获取更新:当订阅的网站有新的文章或内容发布时,RSS Feed 文件会被更新。订阅器会检测到这些更新,并将最新的内容显示在用户的订阅列表中。

RSS 的优点包括:

  • 方便获取信息:用户可以一站式地收集和查看多个网站的内容更新,无需频繁访问每个网站。
  • 自动化更新:订阅器会定期检查更新,用户不需要手动去查看是否有新的内容发布。
  • 隐私保护:RSS 订阅不需要提供个人信息,保护用户的隐私。

随着社交媒体和其他内容分发平台的兴起,RSS 的使用逐渐减少。然而,RSS 仍然被许多网站和博客用于提供内容更新,并且一些专门的订阅器应用程序仍然广泛使用,满足了一部分用户对于个性化内容订阅的需求。

软件截图




相关链接

GitHub地址:Fluent Reader
RSS入门指南:高效获取信息,你需要这份 RSS 入门指南 - 少数派 (sspai.com)
使用体验:Windows平台最美RSS阅读器-Fluent Reader上手体验 - 知乎 (zhihu.com)

友情提醒:卸载软件时,记得导出相关订阅源进行备份

Baby Anti-Spam 自建反垃圾评论系统

作者obaby
2026年4月6日 18:05

很久之前,就经常收到akismet的授权提醒,对应一个错误码10010。

刚开始还以为是多域名访问导致的授权校验出问题了。后来换了n个key,同时添加了插件hook掉所有的垃圾评论检测逻辑,让全部走统一的域名,结果前几天又收到这个提醒了。

插件代码:

<?php
/**
 * Plugin Name: Akismet 单一主域名(多域名站点)
 * Description: 当站点配置了多个域名时,强制发往 Akismet 的请求只使用一个主域名,避免被计为多站点触发 10010。
 * Version: 1.0
 * Author: obaby
 *
 * 使用:在下方设置 AKISMET_CANONICAL_HOME 为主域名(或留空则用 WordPress「设置」里的站点地址)。
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/**
 * 主域名(规范 URL,不要末尾斜杠)。留空则使用 get_option( 'home' )。
 * 例如: https://www.example.com
 */
if ( ! defined( 'AKISMET_CANONICAL_HOME' ) ) {
    define( 'AKISMET_CANONICAL_HOME', 'https://zhongxiaojie.cn' );
}

/**
 * 获取发往 Akismet 时使用的唯一主域名 URL。
 */
function akismet_single_domain_get_canonical_home() {
    $home = AKISMET_CANONICAL_HOME;
    if ( $home === '' || $home === null ) {
        $home = get_option( 'home' );
    }
    return untrailingslashit( $home );
}

/**
 * 将任意 URL 替换为使用主域名的版本(只改 host,保留 path/query)。
 */
function akismet_single_domain_normalize_url( $url, $canonical_home ) {
    if ( empty( $url ) || ! is_string( $url ) ) {
        return $url;
    }
    $parsed = wp_parse_url( $url );
    $canon  = wp_parse_url( $canonical_home );
    if ( empty( $canon['scheme'] ) || empty( $canon['host'] ) ) {
        return $url;
    }
    $scheme = isset( $parsed['scheme'] ) ? $parsed['scheme'] : $canon['scheme'];
    $host   = $canon['host'];
    $path   = isset( $parsed['path'] ) ? $parsed['path'] : '/';
    $query  = isset( $parsed['query'] ) ? '?' . $parsed['query'] : '';
    $frag   = isset( $parsed['fragment'] ) ? '#' . $parsed['fragment'] : '';
    return $scheme . '://' . $host . $path . $query . $frag;
}

/**
 * 统一 verify-key / get-subscription / get-stats 的 blog 为主域名。
 */
add_filter( 'akismet_request_args', function ( $request_args, $path ) {
    $paths = array( 'verify-key', 'get-subscription', 'get-stats' );
    if ( ! in_array( $path, $paths, true ) ) {
        return $request_args;
    }
    $canon = akismet_single_domain_get_canonical_home();
    if ( ! empty( $request_args['blog'] ) ) {
        $request_args['blog'] = $canon;
    }
    return $request_args;
}, 10, 2 );

/**
 * 统一 comment-check(以及 recheck)的 blog、permalink,并把请求里的 HTTP_HOST 等改为主域名。
 */
add_filter( 'akismet_request_args', function ( $request_args, $path ) {
    if ( $path !== 'comment-check' ) {
        return $request_args;
    }
    $canon = akismet_single_domain_get_canonical_home();
    $parsed = wp_parse_url( $canon );
    if ( empty( $parsed['host'] ) ) {
        return $request_args;
    }
    $canon_host = $parsed['host'];

    $request_args['blog'] = $canon;
    if ( ! empty( $request_args['permalink'] ) ) {
        $request_args['permalink'] = akismet_single_domain_normalize_url( $request_args['permalink'], $canon );
    }

    // 让服务端看到的“当前请求”也统一为主域名,减少被计为多站点
    if ( isset( $request_args['HTTP_HOST'] ) ) {
        $request_args['HTTP_HOST'] = $canon_host;
    }
    if ( isset( $request_args['REQUEST_URI'] ) ) {
        $uri = $request_args['REQUEST_URI'];
        $request_args['REQUEST_URI'] = ( is_string( $uri ) && ( $p = wp_parse_url( $uri, PHP_URL_PATH ) ) !== null ) ? $p : '/';
    }
    if ( isset( $request_args['DOCUMENT_URI'] ) ) {
        $uri = $request_args['DOCUMENT_URI'];
        $request_args['DOCUMENT_URI'] = ( is_string( $uri ) && ( $p = wp_parse_url( $uri, PHP_URL_PATH ) ) !== null ) ? $p : '/';
    }
    return $request_args;
}, 10, 2 );

/**
 * 统一 submit-spam / submit-ham 的 blog、permalink。
 */
add_filter( 'akismet_request_args', function ( $request_args, $path ) {
    if ( ! in_array( $path, array( 'submit-spam', 'submit-ham' ), true ) ) {
        return $request_args;
    }
    $canon = akismet_single_domain_get_canonical_home();
    $request_args['blog'] = $canon;
    if ( ! empty( $request_args['permalink'] ) ) {
        $request_args['permalink'] = akismet_single_domain_normalize_url( $request_args['permalink'], $canon );
    }
    return $request_args;
}, 10, 2 );

这次授权的密钥撑得时间稍微长了点,但是最终还是收到了这个提醒,意思是需要订购商业版授权。我这个人站点为了发垃圾评论订购一个商业版授权,确实有些难以接受。

于是,我决定自建反垃圾评论系统,基于scikit-learn实现了现在的这套垃圾评论检测系统,训练数据一部分来源于github的开源数据,另外一个就是我自己博客的评论数据。为了保证样本正例和负例数量差别不至于过大,经过各种方式进行了多轮数据清洗。

如果想要评论识别更加准确,可以提供自己的博客评论数据,如果能提供垃圾评论更好。现在欠缺的主要是垃圾评论数据,正常的评论数据我已经提供几千条数据。

效果测试:

测试地址:https://anti-spam.zhongxiaojie.cn/test/spam

简介:

面向 中英混合 评论的 WordPress 垃圾识别方案:PHP 插件在评论入库前调用 本机 Python 服务,由小型多语种向量模型 + 分类器(或演示用规则)给出垃圾概率。

适合评论量不大、单机部署(例如 4 核 / 8GB RAM 的 Ubuntu),服务与 WordPress 同机时使用 127.0.0.1 即可。

目录结构:

baby_anti_spam/
├── README.md
├── screenshots/             # 文档:服务启动与 curl 自测示意
│   ├── service.png
│   └── test.png
├── service/                 # Python FastAPI 侧车服务
│   ├── .env.example
│   ├── requirements.txt
│   ├── requirements-ml.txt
│   ├── run.py
│   ├── app/
│   │   └── stats_backends/   # 统计存储:sqlite / mysql
│   └── scripts/
│       ├── init_stats_mysql.sql
│       └── init_stats_mysql.py
│       ├── train_sklearn.py
│       ├── download_embedding_model.py
│       └── download_embedding_model.sh
└── wordpress/baby-anti-spam/
    └── baby-anti-spam.php # WordPress 插件

关键配置:

| 变量 | 说明 |
|------|------|
| `SPAM_HOST` | 监听地址,同机建议 `127.0.0.1` |
| `SPAM_PORT` | 端口,默认 `8765` |
| `SPAM_API_SECRET` | **单密钥模式(兼容旧版)**:未配置 `SPAM_API_KEYS` 且未配置 `SPAM_API_KEYS_FILE` 时,仅此密钥有效,等价于 name=`default`、不限流(`max_rpm=0`)。与 WP 插件里填写的密钥一致 |
| `SPAM_API_KEYS` | **多密钥**:JSON 数组。每项为 `name`(唯一,用于统计与限流分组)、`key` 或 `secret`(与请求头一致)、`max_rpm` 或 `rpm`(每分钟最大请求数,`0` 表示不限制)。与 `SPAM_API_KEYS_FILE` 合并时:**先读文件条目,再追加本变量** |
| `SPAM_API_KEYS_FILE` | 可选,指向 JSON 文件,根节点为与上表相同结构的**数组**。文件必须存在,否则进程启动失败 |
| `SPAM_MODEL_PATH` | 训练得到的 `*.joblib` 路径;留空则取决于 `SPAM_FALLBACK_RULES` |
| `SPAM_FALLBACK_RULES` | 无模型文件时是否启用内置极简规则(演示用);生产训练后应设为 `false` 并配置 `SPAM_MODEL_PATH` |
| `SPAM_LABEL_THRESHOLD` | 可选,默认 `0.8`。`spam_score` ≥ 此值时 JSON 中 `label` 为 `spam`,否则为 `normal` |
| `SPAM_DFA_ENABLED` | 默认 `true`。为 `true` 时使用 `dfa-python-filter/keywords` 做敏感词检测;命中则直接 `spam_score=1`、`detail=dfa_sensitive`(早于 sklearn) |
| `SPAM_DFA_KEYWORDS_PATH` | 可选,自定义敏感词文件路径;留空则用 `service/dfa-python-filter/keywords` |
| `SPAM_NON_CHINESE_FLOOR_ENABLED` | 默认 `true`。为 `true` 时若合并后的 author/email/url/text 中**无任何 CJK 表意字符**(主要针对中文训练语料),则将 `spam_score` **至少**抬到 `SPAM_NON_CHINESE_SPAM_FLOOR` |
| `SPAM_NON_CHINESE_SPAM_FLOOR` | 默认 `0.9`。与上项配合,在「无中文」评论上与 sklearn / 规则分取 `max` |
| `SPAM_STATS_ENABLED` | 默认 `true`。为 `true` 时记录每次**成功**返回的 `/v1/classify` 请求与响应(失败 / 401 不落库),并允许 `/v1/mark-spam` 写入 `spam_marks` 表 |
| `SPAM_STATS_BACKEND` | `sqlite`(默认)或 `mysql`。选 `mysql` 时需安装 `pymysql`(已在 `requirements.txt`)并配置下方 MySQL 变量 |
| `SPAM_STATS_DB_PATH` | 仅 `sqlite`:数据库文件路径;留空则为 `service/data/stats.sqlite`(已加入 `.gitignore`) |
| `SPAM_STATS_MYSQL_HOST` / `SPAM_STATS_MYSQL_PORT` | 仅 `mysql`:默认 `127.0.0.1` / `3306` |
| `SPAM_STATS_MYSQL_USER` / `SPAM_STATS_MYSQL_PASSWORD` | 仅 `mysql`:连接账号(`user` 必填) |
| `SPAM_STATS_MYSQL_DATABASE` | 仅 `mysql`:库名(必填),默认示例 `baby_spam_stats` |
| `SPAM_STATS_MYSQL_CHARSET` | 仅 `mysql`:默认 `utf8mb4` |

 

系统服务启动截图:

wp插件配置:

项目地址:https://anti-spam.zhongxiaojie.cn

代码地址:https://cnb.cool/oba.by/baby-wp-anti-spam

说明:如果自己不想训练数据,下载发布版的spam_pipeline.joblib 放入指定目录下配置服务启动即可,baby-anti-spam.zip 为wp插件。

训练耗时大约11分钟:

清明假期收尾碎碎念

作者Hary
2026年4月6日 16:10

三天清明假期一晃就结束啦!
算算日子,上班还不到一个月,再过没几天又盼来五一假期,节奏还挺舒服。这三天懒得来回折腾回老家,就在合肥安安静静待着放松。

周五晚上窝着刷李世鑫的短剧,一看就停不下来,直接追到半夜,剧情看得我都跟着有种重生代入感,特别上头。结果假期第一天,生物钟根本不由人,早上八点准时醒,啥重生懒觉福利都没有,哈哈!

白天太阳特别好,气温一下子回升好几度,干脆把夏天的衣服都翻出来收拾,足足洗了四洗衣机,天气给力、阳光足,中午过后衣裳就全都晒干晾透了。
在宿舍待久了实在闷得慌,总不出去见见人,感觉人都要憋出毛病来。

本来打算自己骑车去罍街逛一逛,顺便在那边吃点东西再回来。刚好室友睡醒出门找吃的,随口聊了几句,俩人一拍即合,临时改主意想去爬大蜀山,后来他又喊上同小区另一位同事,我们三个人结伴出发。

之前也来过两次大蜀山,那时候带着孩子、推着遛娃车,顶多走到半山腰盘山公路就折返了,上段台阶路不好走,也没法往上登。这次算是实打实第一次成功登顶!

我们大概四点半从小区附近坐地铁到大蜀山,爬山的人特别多,合肥平时能逛的室外地方也不多,节假日大家都扎堆过来散心。
三人一人备一瓶水,顺着山路往上走,不知不觉就到了半山腰盘山路段。再往上就是陡峭石阶,同事说早年这里还没有防护栏杆,石阶也是后来翻新修缮的,应该是近几年游人太多,景区设施都整修升级了不少。

后半段台阶爬着真心累,上山的人挤人、挨着走,也快不起来,我们咬咬牙一路不停总算冲到山顶。山顶有两个观景平台,一处专门看日落,一处俯瞰合肥城区街景。
当天傍晚有点雾气,远处灰蒙蒙一片看不真切,我们到山顶差不多六点,夕阳快要落山,雾蒙蒙的拍景也不出片,有点小可惜,上面这个信号塔应该是最高处。

在城景平台看了会儿周边,往东正对着黄山路,天气通透的话应该能远远看到我们住的楼栋,可惜有雾找了半天也没对上位置。后来找路人帮忙拍了三人合照,也算打卡留念,第一次登顶圆满啦!能看出来下面这个书法大厦是在哪个位置么。


下山就快很多,全程上山加下山,一共花了一个半小时,运动量感觉跟在小区来回爬好几趟30层高楼差不多。
下山后几个人就近找地方吃饭,还喝了不少小麦果汁,一个个吃得肚饱喝足,之后全程走路溜达回去,硬生生走了一个多小时,当天累得浑身发沉。

昨天起床还没什么感觉,今早一醒,小腿、屁股两侧酸得厉害,刚下地走路都费劲。平时不怎么运动,突然来一波高强度爬山暴走,身体根本扛不住,看样子得缓好几天才能歇过来。
今晚没事就骑车出去溜达溜达了,今天可不敢猛走猛造了!
(上面内容用豆包润色了一下,意思跟我编辑的都一样,不同的人嘴里说出来是不一样哈)

两岁半小棉袄的快乐时光

作者Hary
2026年3月29日 16:30

 闺女在家向来能睡到十点多才起床,今天一大早刚醒就打来了视频。洗漱完之后,便跟着妈妈在梳妆台前有模有样地学化妆,小模样认真得很。

 不由得感叹,现在的小孩子真是聪明,接触新鲜事物也早。这才不到三岁的小家伙,做起事来常常透着一股小大人的模样,不像我们小时候,六七岁还在玩泥巴。
 奶奶给她做好吃的,她会竖起大拇指,按在奶奶额头上,奶声奶气地夸:“奶奶真棒,给你点个赞。” 穿衣服也讲究搭配,尤其偏爱小裙子,买衣服时必须让她自己挑,不喜欢的连试都不肯试,看上的便攥在手里不肯撒手。晚上妈妈搂着她睡觉,她会软软地说:“妈妈抱,爱妈妈。” 嘴甜的时候,心都要被她融化了。
 当然,撒泼耍赖的时候也毫不含糊,满地打滚、鬼哭狼嚎,真是让人又气又笑。可转念一想,孩子嘛,不哭不闹反倒不正常了。
 原本打算过完年送她去幼儿园适应一下,去学校一问,年龄太小人家不收,加上之前还不会自己上厕所,便作罢了。最近天气暖和,她才慢慢学会自理,干脆再玩几个月,等下半年满三岁再正式入园。
 前些天刚学会用筷子,之前一直用辅助筷都不太会,换成正常筷子,反倒用得有模有样。说来惭愧,我到现在都握不好标准的拿筷姿势,跟她一比还不如个小朋友。
 就让她好好享受这最后几个月无忧无虑的春日时光吧,等秋天,再正式开启她的小小 “修炼之路”。
[vplayer url="https://img.hxy.cc/file/blog/260329-2suiban2.mp4" /]

注册两个免费域名玩玩

作者Hary
2026年3月27日 21:30

 前两天看见军爸发的可托管CF的免费域名注册,本来是没需求的,昨天晚上收到了西部数码发过来的邮件,唯一闲置的域名也被一口价出掉了,那就没有闲置域名了,主要想要一个域名用来做博客站的境内外分路解析,用作CF的SAAS的中转域名,通过军爸的链接注册了一下,可以免费注册两个前缀,其实就是一个二级域名,主要是可以作为一个独立域名托管在CF上,刚好可以满足这个需求,省的再去单独注册一个域名了,注册好之后托管在彩虹的NS域名管理程序,到时候1年到期会有提醒,挺好。

 原本手里的域名和服务器该卖的卖,该丢的丢,现在就剩两个域名和一个虚拟主机了,不再购入新的了,说不定有朝一日也转去静态博客,虚拟主机也不要了。

周六和室友小酌一杯

作者Hary
2026年3月22日 13:26

 之前说过我的一个同学被优化了,当时没过多久,我们这边也收到了通知,要有7个人被裁掉,其中有一个就是我的室友,二月初好像就通知了,说是让干到三月底,年后一过来也是各种饭局,经常喊他吃饭喝酒说送他呢,前几天有天晚上回来也是晕乎乎的,说要跟我喝点呢。
 我就从京东下单买了两瓶古5,也是昨天一大早就送过来了,本来想着晚上的时候出去吃点喝点,赖了一上午床,中午爬起来想做点东西吃,看着冰箱里的菜,这不也能整几个么,就跟室友讲了一下,中午别让他点外卖了,我简单炒几个菜一块吃点。
 他说最近喝酒喝的有点多了,最后我整的古5也没喝,他去楼下超市搞了一箱啤的上来。应该是一点多开始吃的,最后干到了晚上六七点,就一直喝着聊天啥的,一箱啤的被我俩造完才算结束。
 最近也在和公司谈赔偿的事,他在这边干了七年多了,想的是至少能赔个N,但是之前领导找他谈过一次,说能赔个小几万,赔不了N,现在还在僵持着,下周再找机会再和领导PK一波吧,实在谈不妥再想别的办法。
 附个随手拍的图片吧,最后闷了个从家带回来的鸡肉,吃了一半才想起来拍个照片,哈哈,在家养了几个月的鸡还挺好吃。

修理修理几个手机

作者Hary
2026年3月14日 15:36

 距离上次更新已经一个月了,好像还没有间隔这么长时间断更过。主要还是今年春节放假时间太长了,前后将近放假一个月了。在家的时候基本上就跟家人在一起很少看手机,也就没有动力来更新博客了。
 本来公司通知的是3月10号上班,我本来最开始抢的是3月4号的票,后来了解了一下,挺多同事都是10号才过来,我又改了个票,从4号改到了8号,上周末才过来,新的一年的第一周已经过去,5天一过,又是一周。一天一天上班过的感觉比在家过的还快,还有一个半月,五一假期又能回家了。
 我之前用的有一个小米11的手机,一直做备用机。过年回家拿回家了,给我奶奶用了,把她原来的vivo Z1换了下来,原来那个手机太卡了。她日常用来微信视频通话和刷抖音,换下来的vivo Z1我就拿回来了,不安装任何APP,专门用来开热点使用。
 回去之前又购入了一台iPhone17,回家给我媳妇儿的新年礼物。然后我媳妇儿这边又退休下来一个iPhone13 Pro,我也拿回来了,专门收破烂,哈哈,之前她就就一直吐槽,他的iPhone13 Pro不存电,这次我拿回来直接在网上买了个电池,好像是有一个活动吧,然后100多拿下,日常是210左右,这带的还有安装服务,只贵了10块钱,周二的时候快递一到就去附近店里让人家给换上了,直接满血复活,续航杠杠的,备用机+1。

 再一个就是我的主用机小米14,用了有两年半了,日常工作用手机还是挺多的,算是重度使用,现在基本上就是需要一天三充。干脆也换个电池得了,然后就单独买了一块电池,回来自己换,实际操作下来倒也不难,只不过可能是第一次没经验,没把握好尺度,有一个角还没有完全撬开,抬了一下后盖,直接给后盖玻璃干碎了。。。又紧急在闲鱼淘一个小米14的原装拆机后壳,晚一会应该快递就到了,再给它换上,这样密封性良好,防水好一点吧。


 这个电池说是小米15移植到小米14和小米13使用的,比原装电池容量大,用了两天确实续航提升不少,又能再战三年,等着换小米20。

没心思上班了,准备开溜

作者Hary
2026年2月11日 16:28

 春节前的最后一周了,大家都没心思上班了,各种花样摸鱼,这两天云闪付上有个活动,徽动消费 合肥GO,二月份新开的合肥区域公司的发票,上传上去可以抽奖,都是大额优惠券,大的100,小的也得有20,这两天周围的同事也是玩的不亦乐乎,都抽了几百几百的优惠券,应该是政府发优惠券推动消费,利用开发票可以增加企业纳税,真是一箭三雕。
 周日晚上公司例会,通知了放假安排事宜,准备从2月12号放到3月10号,反正中间各种事吧,不好明说,这整的放假时间太长了,这期间绩效是要扣除的,只有基本工资,如果按照这个时间休,差不多要被扣五六千,其实是想放假时间长一点的,但是这也太长了,前后冗余两天都差不多了,反正准备3月初提前一周过来吧,到时候按照每天工作报备,还能少扣一点,公司去年春节还有礼品,今年毛线都没。
 上周还想着奋战到最后一天呢,结果这通知的猝不及防的,也没有买高铁票,正好老丈人丈母娘他们准备这两天回,从金华回来经过合肥带上我,正好我可以开下半程,也省的我再单独找顺风车了,晚会回去准备收拾收拾东西,再去理个发,下次再理发就要等二月份了,虽然不可证实的正月不理发的习俗,但是也保持了29年了,还是继续保持下去吧。

老同学被优化了

作者Hary
2026年2月3日 20:33

 中午回来吃饭正吃的香呢,老同学发来了个微信,说他被优化了,赶紧扒拉扒拉吃完饭,给他去了个电话问了下啥情况。

 我们是大学同一个宿舍的室友,毕业之后我基本上无缝衔接,去了上海待了两年,然后就来了合肥,他是毕业之后先在他们本地那边待了两年,然后报培训班学习考了个行业内高级证书,应该是23年的时候他入职了郑州那边,我们算是干的一样的工作,一直干到现在,虽然是背靠大厂,但是也从去年11月12月份开始,新出了各种规则,取消加班工时调休和超额加班费,各种降本增效,其中有一项就是人员配置优化,我们这暂时还是一个萝卜一个坑,大刀可能还没砍到头上,今天他给我发消息,我才意识到,要开始了,不知道什么时候优化到我们这里。
 我这老同学那边据他描述,已知的就暂时通知了他自己,让干到三月底,还有一些老资历员工都没被优化,他说别人干的他不一定能搞下来,但是他做的事情别人能接住,所以被优化的只能是他,唉,想想他去年6月份才结的婚,这刚结婚半年结果工作没了,也是比较难顶。
 如今各行业都是比较难过,也别想太大了,现在能有个相对稳定的工作已经很难得了,老家一些在外面打工的也是老早就回家过年了,外面一些厂子里面也是活不多,早早就放假了。

宽带改公网投诉小记

作者Hary
2026年1月29日 18:20

 老家的两条联通宽带安装的时候就是装的PPPOE公网的,本来家里有网络摄像头做的有DDNS映射,非标端口外面可以直接访问,前几天发现不行了,从联通APP里面查光猫看了下,竟然私自给我改成NAT私网了,小联通竟然在用户毫不知情的情况下私自变更用户业务类型。
 前天晚上越想越气,搞的晚上都没睡好觉,脑海里一直在想第二天怎么怎么投诉,说什么硬气的话。上周三还有个营业厅的固话给我打电话问我最近宽带用的怎么样,我也没多想,纯粹支持他们工作,就给了好评,现在回过来想想,搞不好就是他们私自改了,然后做下回访,看用户有没有感知呢。
 昨天上午一直在忙,中午得空直接打了10010客服进行投诉,倒也算处理的积极,一会省投诉中心,一会市投诉中心,一下午接了几个电话,又挨个给他们解释一边投诉原因,我就说我安装的是公网,为什么在用户不知情的情况下给我改成私网,现在搞的在外地看老家摄像头都延迟很大,挂机游戏老掉线(编的,不打游戏),一路转派投诉单,最后给派到了乡镇营业厅。
 早上营业厅人员给我打电话,还给我说了一顿,她问我,你知道什么是公网吗,只有企业,医院这种才是公网,家里面的都是私网,。。。我寻思我天天搞这些,我不知道我还能投诉到这??还说她干了15年了,也没听说过宽带搞公网的,我让她不知道就给我往上报,找技术支撑去问,也就不到一个小时,就有市公司的技术人员给我打电话,说私网改公网改好了,让我重启光猫试一下,我远程重启了一把,终于又恢复了公网。


 我在想肯定是后台做什么改造,或者批量回收公网的操作,如果用户不投诉,改了就改了,有投诉再改回来,真是让人恼火,以后还想着有公网IP可以搞点家里云自己用呢,这指定是不能再给我改了。

身份证到期更换

作者Hary
2026年1月25日 21:00

 25年应该有很多人的身份证到期吧,我应该算是赶到了末尾,目前在用的是截止到2026年2月23日到期,还剩下不到一个月的时间了,说是提前两三个月就可以申请办理了,我这本来也没着急,一个月前应该就有各种APP和短信给我推送发消息说身份证即将到期让及时更新,否则影响相关服务的,这周五公司也找过来了,让传新的证件信息,哈哈,我还没办啊。
 其实在两周前就在皖事通上申请了,预约的今天去办理,预约的时候按照提示说是可以自己拍照上传,审核通过后可以直接用自己拍的照片,上周得空让同事帮忙拍个大头照,准备去上传呢,结果提示我非安徽户籍,我申请的时候怎么不提示啊,还引导我可以提前拍照,白期待了,还是等到今天乖乖去线下办理。
 预约的我们这最近的蜀山区政务中心,上午九点过去的,骑车十几分钟,到那问了下工作人员,也挺简单的,基本上去办事的大部分都是办理身份证业务的,人倒也不多,就先排队拍照,也没让看一眼,拍完照接着取号等着窗口喊号办理,等了有两分钟吧,就喊号了,看来人是真的不多,到了办理窗口也就确认一下信息,然后录取指纹,说是做信息比对,确认一下是本人,然后让我看了一眼拍的照片,让我确认一下是不是,就看了一下侧着的电脑屏幕,不说了,真的不是很好看,自己拍出来也不是这样啊,看到时候拿到证是什么效果吧,确认好信息之后让付了20块钱的办理费用,整个过程不到五分钟。
 业务人员说是20天后过来取,我媳妇之前是六七月份吧,来办理的说是可以邮寄,好像是一周多就寄过来了,我也去问了一下办理了邮寄业务,是邮政承办的,扫码把办理的业务号进去,填好收件地址,又付了12块钱的邮寄费用。
 整个过程还是比较顺利,本来以为周末人会多的,结果不到半个小时就搞定了,我这是第三个身份证了,第一次是5年,第二次是10年,这次办理的应该是该20年有效期了,记得10年前办理第二张的时候还要回老家户籍地派出所办理,现在整的是挺方便,跨省也可以直接办理,期待新证,希望不要太丑。。
1月31日更新:
 25号上午去办理,31号上午收到证件,快递送货上门,不得不说还挺快,这次是20年有效期,照片还行,看得过去,除了双下巴有点明显,不过也是真实情况,哈哈。

姥姥和奶奶

作者Hary
2026年1月23日 20:09

 前几天老家下了大雪,从家里监控看到在下雪的第二天妈妈把姥姥接过来了,说是接过来住几天,难得妈妈在家这么长时间,临近春节了,也是想和她的妈妈待一起照顾几天吧。
 今天看到姥姥和奶奶在院子里面晒太阳,挺温暖的一幕,他们俩的日常生活轨迹完全不同的,也难得待在一起晒太阳。

 姥姥是胖胖的,好几年前还因为胆的问题做过两次手术,也就导致平常也不能干重活,走路干啥的都慢慢的,平常也就待在我的三舅家的小卖部帮忙照看一下,记得我小的时候就喜欢去姥姥家,那时候还是姥爷开的有间小卖铺,就喜欢去里面拿些小玩具啥的,每到春节还都能得到姥姥姥爷给的一把“枪”,那时候有一把玩具枪别提有多开心了,但是我的姥爷好像就停留在了那时候的某一年,就剩下我姥姥一个人了,应该都有快二十年了,我记得姥姥一直是这个样子,一直都是不紧不慢的,也可能是身体原因吧,反正每次有机会回老家都会回去看看姥姥。
 奶奶就不一样了,同样都是七十几岁的人,奶奶还是干劲十足,现在家里都是各种各样的农活,给人家扒红薯、种蒜、种辣椒、摘辣椒、电商打包、打玉米等等,真是啥活都干,一天有时候挣个三四十,有时候整个一百多,比人家年轻人都能干,尽管家里人都各种劝说,不要出去干活了,不要出去干活了,但是没一个人说的动,只要有活,别人打电话给她,肯定去。我的爷爷也是在我订婚的那一年走了,每次回家都盼望着能看到孙媳妇,如果再坚持半个月也就能看见了,最后还是没等到,爷爷的时间也就停留在了22年的春节,好像就是自从那之后,正好也是家里流行起来了日结干农活,专门找家里的老头老太太干些农活,管饭还给钱,也就很多人可以去,奶奶就经常出去干活,我想着,也可能是她自己一个人待在家无聊吧,出去干活好歹能多几个人唠唠嗑,反正各有利弊吧,有啥轻活重活都去干,最后再给身体累出病来还是不划算。
 树欲静而风不止,子欲养而亲不待,如果能有空还是抽出时间陪陪家里人,不要说真等百年之后再去后悔,那其实没有任何意义的,就算陪家里人在太阳底下晒暖,那也无疑不是一种尽孝。

给博客所有图片加个水印

作者Hary
2026年1月18日 16:37

 此方法为又拍云存储+腾讯云EdgeOne的组合,实现免费10G存储+无限流量的图片外链,理论上适用于所有对象存储和所有CDN的组合。
 正常一些技术博客发的技术文章还是比较有价值的,文章附图最好还是加个水印,也减少一点被盗的风险,我这生活水文博客那就看心情了,也没啥值得盗的,纯属折腾哈,简单记录一下。
 首先是要用云存储作为图床,无论是直接上传或者通过图床程序,在对应的云存储内找到图片处理功能

 接着设置一个间隔标识符,后面会用到,又拍云是有三个可选(! _ –),然后设置一个图片处理规则,这里面就按需配置,如果上传之前已经对图片进行过处理了,这里就推荐不要进行压缩或者更改格式的其他处理了,只开启添加水印一个功能,可以设置文字水印或者图片水印,选好水印放置的位置,设置好对应的参数之后,点击右侧的小喵咪可以进行刷新预览看一下最终呈现的样式,达到想要的效果之后进行保存此规则,注意样式命名,后面会用到。


 到此就可以进行实际图片测试了,比如原来的图片外链是https://img.hxy.cc/2026-ceshitupian.webp,加上前面设置的图片处理参数之后的格式就是https://img.hxy.cc/2026-ceshitupian.webp-shuiyin,这样其实还是没有达到目的,因为访问不带图片处理规则的原链接,还是没有水印效果的,想要最终实现不加参数又能加上水印,这就要去CDN加速那边设置了。
 又拍云的处理规则设置好之后,到腾讯EO的对应图床域名的规则引擎中设置回源URL重写,可以按照如下函数进行配置

正则表达式: ^/(.*\.(jpg|jpeg|png|gif|webp|bmp))$   (这里加上实际使用的图片格式的后缀)
替换为: /$1-shuiyin  (这里的-就是上面设置的间隔标识符,shuiyin就是上面设置的图片处理规则的名称)


 这样配置好之后,把EO这边的图床域名的缓存清除一下,然后再刷新文章内的外链图片,此时看到不用每张图片进行添加后缀,已经成功添加水印,这样设置的好处就是不用每张图片都单独进行添加,而且万一以后有换域名,直接把水印规则里面的水印换一下就行了,原图片不受影响。
 看了下七牛云的云存储,基本上一样的方式,也可以达到上面的效果。

 经常看到用对象存储的博友被刷多少多少流量,以至于产生巨额账单而劝退使用对象存储,我觉得还是没有做好防护措施吧,使用不限量的EO或者ESA,还有可以设置达量拉闸的多吉云,然后用http回源到对象存储,因为https可能会收费,这样基本上不会产生费用啊,我用了好几年的又拍云联盟,一年有61块的券,我25年按照这种方式设置之后才产生不到1块钱的费用。

下载微信公众号的视频

作者obaby
2026年4月2日 16:46

作为一个专业的程序媛,前端时间折腾龙虾转发公众号的文章到闺蜜圈wiki,之前已经处理了图片和文章的问题,今天转发的时候发现另外一个问题:文章里面的视频无法正常播放。

刚开始的时候想着直接去chrome的缓存里面找,但是试了下chrome://cache发现无效,又不想去找插件来干这件事情。直接去调试工具找对应的视频地址:

然而直接贴到地址栏,直接报403了。

唉,好尴尬,既然有本地缓存文件了。那么直接尝试将接收到的数据流写入到文件呗。找了半天没发现怎么直接把请求到的数据写入到文件,点击开始播放等待缓冲结束。

加载完了右下角的数据也就有了,直接切换成base64,复制粘贴:

然而,尝试decode 之后,播放不了,缺少mp4的头文件,这就挺奇怪的。文件头哪里去了?my_video为通过代码下载的mp4,video为通过base64 处理的图片。

文章测试地址:https://mp.weixin.qq.com/s/heoer_zm4SFwFKsk4tRecQ

看了下是video标签实现的:

<div data-v-c66e8e28="" class="js_inner inner not_fullscreen"><div data-v-c66e8e28="" class="js_video_poster video_poster"><div data-v-c66e8e28="" class="video_mask"></div><video data-v-c66e8e28="" src="https://mpvideo.qpic.cn/0bc3pidsgaahauamxiglsruvo6wden5aoiya.f10002.mp4?dis_k=247900efb8791f0718998ea0813793c9&amp;dis_t=1775118363&amp;play_scene=10120&amp;auth_info=d9/5u/dlYUBWn6qY0Sp2SXM9PUdEOj5CZmQ3H2k2TzNOXXtjTwYQen0+WTMXEzdWIDNuS0hkIHgTMSlENWAcfUpBcQ==&amp;auth_key=ed4a91866522f27b4b89c5e71e04d115&amp;vid=wxv_4453415887525888005&amp;format_id=10002&amp;support_redirect=0&amp;mmversion=false" poster="http://mmbiz.qpic.cn/sz_mmbiz_jpg/GAVxEAgJstytcf0uF3dpdZKia9G96C3loxCNaBrbFLHCiak3GvJDfASC7uYqNjjAZ5e2OHSmHoBQrONRJ8UIq6icJjjFXMfUBtdhy7VWlfb3MM/0?wx_fmt=jpeg&amp;wxfrom=16" webkit-playsinline="isiPhoneShowPlaysinline" playsinline="isiPhoneShowPlaysinline" preload="metadata" crossorigin="anonymous" controlslist="nodownload" class="" style="display: block; width: 655px; height: 492px;"> 您的浏览器不支持 video 标签 </video></div><div data-v-f4ee5450="" data-v-c66e8e28="" class="video_poster__info__play" style="display: none;"><i data-v-f4ee5450="" data-v-c66e8e28="" class=""></i></div><div data-v-f4ee5450="" data-v-c66e8e28="" class="video_poster__info" style="display: none;"><p data-v-f4ee5450="" data-v-c66e8e28="" class="video_poster__info__title" style="font-size: 17px;">继续观看</p><p data-v-f4ee5450="" data-v-c66e8e28="" class="video_poster__info__desc" style="font-size: 12px;"> 孤独症,就是不爱说话吗? </p></div><div data-v-f4ee5450="" data-v-c66e8e28="" class="video_poster__info__mask" style="width: 100%; display: none;"></div></div>

还是说着这个东西还有另外的处理逻辑?哪位大神知道原因还望不吝赐教。

既然decode不行,那就直接上代码吧:

#!/usr/bin/env python3
"""
下载 mpvideo.qpic.cn 等需 Referer 的 MP4(微信视频 CDN)。

Author: obaby
  https://zhongxiaojie.cn
  https://oba.by
"""

import argparse
import sys
import urllib.error
import urllib.request

# 与常见微信内嵌页一致,避免 403
DEFAULT_REFERER = "https://mp.weixin.qq.com/"
DEFAULT_UA = (
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
    "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 "
    "MicroMessenger/7.0.20"
)


def main() -> None:
    p = argparse.ArgumentParser(description="带 Referer 下载 mpvideo MP4")
    p.add_argument("url", help="完整 mp4 URL(含查询参数)")
    p.add_argument(
        "-o",
        "--output",
        default="downloaded.mp4",
        help="保存路径(默认 downloaded.mp4)",
    )
    p.add_argument("--referer", default=DEFAULT_REFERER, help="Referer 头")
    p.add_argument("--user-agent", default=DEFAULT_UA, help="User-Agent")
    args = p.parse_args()

    req = urllib.request.Request(
        args.url,
        headers={
            "User-Agent": args.user_agent,
            "Referer": args.referer,
        },
        method="GET",
    )
    try:
        with urllib.request.urlopen(req, timeout=120) as resp:
            data = resp.read()
    except urllib.error.HTTPError as e:
        print(f"HTTP {e.code}: {e.reason}", file=sys.stderr)
        sys.exit(1)

    out = open(args.output, "wb") if args.output != "-" else sys.stdout.buffer
    try:
        out.write(data)
    finally:
        if out is not sys.stdout.buffer:
            out.close()
            print(f"已写入 {args.output},{len(data)} 字节")
            if len(data) >= 8 and data[4:8] == b"ftyp":
                print("魔数检测:疑似标准 MP4(含 ftyp)")


if __name__ == "__main__":
    main()

现在就可以下载之后,上传了,发布的文章地址:

孤独症,就是不爱说话吗?

💾

弱弱的问一下,我的网站怎么被镜像了嗫?

作者obaby
2026年4月1日 11:18

其实网站被镜像这件事情,本身没什么稀奇的,如果想搭建一个镜像网站,从零开始也不过个吧小时的时间。

之所以写这个东西,是因为最近有看到好几个人被镜像的,这一个(爱娃子),还有 这一个(我是军爸)。

不过,既然还有人有疑惑,那就简单的教一下大家怎么来镜像个网站吧。

为此,我创建了一个开源项目:

OpenResty + OpenCC 反向代理简繁转换


基于 OpenResty 反向代理上游站点,对 HTML 正文 做 OpenCC 简繁转换(默认:简体 → 繁体,配置文件为 s2t.json)。适合在不改源站的情况下,为访客提供另一种字体习惯版本。

功能概览

能力 说明
反向代理 HTTPS 回源(示例站点:zhongxiaojie.cn),客户端走本机证书与域名。
HTML 简繁转换 仅当 Content-Type 含 text/html 时对整页做 OpenCC UTF-8 转换。
gzip 解压 通过 Lua zlib 尝试解压响应体(与去掉 Content-Encoding 的配合视上游行为而定)。
链接与图片 URL 保护 转换前将 href / src / poster / data-src / srcset 及裸 http(s):// 链接替换为占位符,转换后还原,避免路径或查询串中的汉字被改写导致 404
IPv4 优先解析 resolver … ipv6=off + 变量 proxy_pass,减轻云主机无 IPv6 时对 AAAA 连接失败的问题。
静态资源直过 图片、CSS、JS、字体等扩展名单独 location不做 OpenCC,减轻负担、避免误伤二进制。
动态库加载 对 libopencc.so 按常见路径依次尝试 ffi.load,降低找不到共享库的概率。

限制与说明

  • JSON / JS / CSS 内嵌字符串若不在上述保护规则内,仍可能被转换;重要数据建议不要用全文 HTML OpenCC 硬转。
  • 内联样式 style="background:url(...)" 未单独做保护,若遇少数破图可再扩展规则。
  • 转换配置在 nginx/opencc/opencc-filter.lua 中的 OPENCC_CONFIG(默认 /usr/share/opencc/s2t.json);若需 繁体 → 简体 可改为 t2s.json 等(需系统已安装对应 OpenCC 数据文件)。

部署要求

  • OpenResty(带 lua-nginx-module)。
  • OpenCC 运行时:系统安装 libopencc.so 与词典数据(如 /usr/share/opencc/*.json),并保证 worker 进程能加载到 .so(见下文「共享库」)。
  • Lua 可 require('zlib') 的模块(用于 zlib.inflate,若无 gzip 体则 pcall 失败会跳过解压,不影响后续逻辑)。
  • 上游为 HTTPS 时,本机需能解析并访问该域名(已用 resolver 时 VARIABLE 形式 proxy_pass 才会走指定 resolver)。

部署步骤

1. 安装 OpenCC 与数据文件

以 Debian / Ubuntu 为例(包名因发行版略有差异):

sudo apt update 
sudo apt install -y libopencc1.1 opencc # 或 libopencc2 等,以仓库为准 
或者手工复制 lib64目录下的文件到 脚本对应的路径就是这个 /usr/lib64

 

确认存在词典,例如:

ls /usr/share/opencc/s2t.json

 

2. 确保能找到 libopencc.so

若日志出现 libopencc.so: cannot open shared object file

  • 将库放在系统默认搜索路径,例如 Ubuntu amd64:
  • ldconfig -p | grep opencc

     

  • 若库仅在 /usr/lib64 等非默认路径,可执行(与仓库 fix.md 一致):
  • echo '/usr/lib64' | sudo tee /etc/ld.so.conf.d/usr-lib64.conf sudo ldconfig

     

  • 或在 OpenResty 的 systemd 单元 中设置 Environment="LD_LIBRARY_PATH=/usr/lib64:/usr/local/lib"  后重启。

脚本内已对多路径做了 ffi.load 尝试;仍失败时请对照 ldd 与 opencc 包实际安装位置排查。

3. 部署 Lua 脚本

将 nginx/opencc/opencc-filter.lua 复制到服务端约定路径(与 nginx 配置一致),例如:

sudo mkdir -p /usr/local/openresty/lua 
sudo cp nginx/opencc/opencc-filter.lua /usr/local/openresty/lua/opencc-filter.lua

按需修改脚本顶部 OPENCC_CONFIG 指向本机实际的 JSON 配置。

4. 合并 Nginx / OpenResty 配置

  • 将 zero.zhongxiaojie.cn.conf 中的 server 块纳入主配置(include 或粘贴到 nginx.conf 的 http {} 下)。
  • 修改 证书路径日志路径上游域名 zhongxiaojie.cn、以及 body_filter_by_lua_file 的路径,使其与当前环境一致。
  • header_filter_by_lua 中去除 Content-Encoding,便于对明文 HTML 做处理;若上游与解压逻辑不匹配,需自行观察是否需要调整。

5. 校验并重载

sudo /usr/local/openresty/nginx/sbin/nginx -t 
sudo /usr/local/openresty/nginx/sbin/nginx -s reload 
# 或 systemctl reload openresty

 

6. 验证

  • 浏览器访问你的站点,查看页面简繁是否符合预期。
  • 检查 图片与站内链接是否正常(尤其含中文或 % 编码的路径)。
  • error.log 中不应再出现 OpenCC 库加载失败或大量 IPv6 unreachable(在无 IPv6 环境)。

配置项速查

项目 位置
OpenCC 配置 JSON opencc-filter.lua → OPENCC_CONFIG
Lua 脚本路径 zero.zhongxiaojie.cn.conf → body_filter_by_lua_file
上游站点 set $upstream_host … 与 proxy_pass https://$upstream_host$request_uri
DNS / 仅 IPv4 resolver 223.5.5.5 8.8.8.8 valid=300s ipv6=off
不参与转换的静态文件 `location ~* .(gif

故障排查

现象 可能原因
libopencc.so 找不到 未安装包、ldconfig 未包含库目录,或需 LD_LIBRARY_PATH
body_filter 报错、栈指向 ffi.load 同上;或架构不一致(如 32/64 位混用)
上游连接 IPv6 失败 已用 ipv6=off + 变量 proxy_pass;仍失败则检查防火墙与 DNS
图片 404 历史上多为 OpenCC 改了 URL 内汉字;当前脚本对常见属性已做保护,若仍有个别,检查是否来自 CSS url() 或 JS 动态拼接

如需改为其他域名、证书路径或 t2s 转换方向,只需改配置文件与 OPENCC_CONFIG,无需改 OpenResty 核心。

实际效果:

开源项目地址:https://gitee.com/obaby/baby-website-mirroring-tool

参考链接:https://blog.csdn.net/wzj_110/article/details/127758020

https://blog.rexskz.info/support-traditional-chinese-using-openresty-and-opencc.html

❌