阅读视图

最近动态

时间过得真快,转眼间这一年已所剩无几。虫虫接下来的一个月时间,在重庆好好陪陪妈妈。自从去年妈妈查出癌症以来,一直没能长时间在她身边照顾。由于每月都需要去医院复查、抓中药,妈妈暂时住在了重庆弟弟家里,爸爸也在那儿照料她的日常起居。而我则一个人留在老家,处理家里的一些杂事,也好让妈妈不用担心老家,安心在重庆养病。

比起前一阵子的情况,妈妈近来的状态并不算特别乐观,但她自己的心态始终很好,坚强又平和。眼下我能做的,就是多陪陪她,多说说话,尽量让这段时光温暖一些。

在我动身来重庆之前,还有三位朋友参与了明信片活动。虽然我特意用了挂号信寄出,但截至目前,只有一位朋友顺利收到了我的实体祝福。另外两位的物流信息显示“代签收”,却迟迟没有拿到。其中一位朋友地址在武汉——不知是不是我与这地方有点“犯冲”,寄往武汉的明信片似乎总有些波折。不过没关系,等我回去之后,如果还是没收到,我会一一补寄。始终相信,心意一定要送达,不能让任何一位参与活动的朋友留下遗憾。

就先写这么多吧,也算记录一下近况。陪伴与等待,皆需耐心,皆含深情。

  •  

微信终于可以将聊天记录合并到电脑端了

今天发现微信可以让聊天记录合并到电脑端了。之前只能迁移到手机上,或者备份到电脑上,但只能恢复到手机上。这个苹果系统微信双开怎么就不行呢?以前没觉得,自从到这个公司上班之后,突然就想微信工作号和个人号分开。很烦!

ScreenShot_2025 12 12_215211_189.png
版权声明: 本文采用 BY-NC-SA 协议进行授权,如无注明均为原创,转载请注明转自 皇家元林
本文链接: 微信终于可以将聊天记录合并到电脑端了
  •  

20251212

用上昨天开发的唱片封面识别功能了!还发现不少可以改进的点。这次录入速度明显比上次快多了。花了不少时间整理分类,一共九十五张,大部分还是 Hard Bop,这次 Jazz Vocal 也不少。

image.jpeg

书架又腾出一格给黑胶,差不多要装满一整行。这样看,要是想装满整个书架,那得几千张的量。经过我自己测试,这个功能就提交审核了,预计明天大家就能用上。

image.jpeg

晚上来了份羊肉汤和肠包肉,真不错。

image.jpeg
  •  

20251211

起床准备看书,突然来了一个交互灵感💡。明天要到九十几张黑胶,我会一张一张通过 SnapVinyl 录入进来。九十几张是个大工程,估计需要花费我几个小时。如何提升这个速度呢?一个个界面在脑子里呈现。就这样上帝告诉我今天要实现什么功能了。

下午修复了 SnapVinyl 的一些小 bug,到了下班时间,我觉得是以后看看 one shot 的效果了!我先画了个线框图,配合我的描述丢给 Codex,果然第一把保持和以前一样,完成 70%!继续和他探讨如何优化,变改我边拿着黑胶测试识别封面信息,有一种我是 Codex 测试小弟的感觉了!

我还没写完代码呢,老关 Couple 已经来喝酒了。他们刚从欧洲回来,我推荐布拉格的金虎酒吧给他们,他这是我最喜欢的捷克作家赫拉巴尔在世的时候天天去的地方,没想到他们不但去了,还给我带了个金虎酒吧的杯垫!太牛逼了!

image.jpeg

今晚让十一从我的柜子随便拿唱片,开盲盒。选到一张非常非常不错的西班牙风情的音乐,太适合今夜喝酒了,完美!我们喝了四五种 Whisky,飘了。

image.jpeg
  •  

20251210

今天的网球课,教练开始溜我了。三轮下来心率爆表,差点蹲边上吐了,痛苦并且爽。

最近冲每杯咖啡我都测 TDS 计算萃取率,然后优化下一杯参数。终于,同一个豆子在好多好多杯之后,我有了好喝的感觉。看数据,TDS 和萃取率都在金杯里面。太开心了!数据驱动做事没毛病。

  •  

20251209

早上看书看到一段我很喜欢的话,概括一下就是

艺术、电影、音乐和文学的作用就是让我们可以感同身受的沉浸在他人的生命中,由此获得新的眼睛和耳朵。

说这句话的人叫阿诺德·温斯坦,我不知道他是谁。看的书还是《意识的河流》,再分享两段深有感触的文字,关于灵感和抄袭,我认为他讲的太好了,对原因的分析也很深入。

两个剧作家从本书的作者的作品里得到了灵感,分别都把它改编为了剧本。一个没有给作者造成困扰,一个他认为被抄袭了。这种事情在 APP 设计领域每天都能见到,每个设计师当然都无时无刻接受着别人优秀设计的滋养,当我们自己做设计的时候,永远都是从当前的需求出发,从要解决的问题出发,从使用的便利性考虑,从脑海里拾取素大量的素材,找出最佳组合,同时挖掘出属于这个产品独特的风格,并且保持一致。这是一件顺其自然并且轻松有趣的事情。抄袭的快乐大概来源于不费吹灰之力的省力感,但始终有一种偷感伴随着这个抄来的东西。

image.jpeg
image.jpeg

晚上找出了唯一有的一张贝九黑胶,尤金·奥曼迪指挥费城交响乐。听的很开心,突然发现昨天优化 SnapVinyl 的时候也造了一个新的 bug。当然必须立马解决了,但这个问题着实难度很大,可能是迄今为止我最有耐心陪 Codex 一起解决的一次,我不断的告诉他错了,我们重新梳理问题,我自己一边继续总结各种可能和不可能性给他。终于过了两个小时,他给出了一个最可能的原因,果然,搞定。时间又到了快十二点钟。解决难题也很快乐!

image.jpeg
  •  

郊游(第41期):丽江绿道 亲子徒步暴走八公里

原本今天(12月11日)不该我带孩子,但因为午间一件事,不得不由我带了。事情是这样的:孩子妈妈要做凉拌面条,让我去房东院子里的菜地摘些香菜、小葱和一棵大白菜。

她看到房东在家,特意提醒我下楼如果遇到房东,要打声招呼说摘点菜。我下楼后在院子里看了一圈,没见到人,厨房和客厅也没人,所以就没打招呼,摘完菜就回屋了。

孩子妈妈没听到我打招呼的声音,以为我是故意没打招呼,再次提醒我摘菜要大大方方的,不能小偷小摸似的,说了几句。我回了一句:“没遇到房东,左看右看也没找到人,总不能到处敲门说要摘菜吧。”

孩子妈妈就来气了,又多说了我几句,结果就是:“今天我不带孩子了,你带吧。”女人想生气总有理由,不想做什么或想做什么,也总能找到理由。咱也没办法,只能听着、顺着。其实她就是想休息一下,只是可能不太好直说,毕竟我也没闲着。

房东两口子碰到我们时,经常喊我们去摘菜吃,微信里也叫了好多次,说不用和他们说,直接摘就行。他们种的菜确实不错,不打任何药还长得好,是适合孩子吃的健康绿色蔬菜。他们吃不完,不吃也是浪费,所以多次招呼之后,我们也就习惯了时不时摘一些来吃。

反正,菜这事随便摘,他们压根不在乎。看到我们吃,他们还蛮高兴,因为比烂在地里有成就感。


隐私保护:因涉及隐私内容RSS已做隐藏,请通过原文链接阅读更多
版权声明:如无注明均为原创,未经允许不得任何形式转载
原文链接郊游(第41期):丽江绿道 亲子徒步暴走八公里
  •  

工资

2023年9月到龙岩培训云客服,从当年的11月结业以来,经历三个月才熟练一些,也就是说从2024年2月下旬才开始真正的赚钱。每次上到2000元左右也就不太想上了,所以工资都是2000元/月上下。

上个月双11,原本想休息一下,但人多奖励也多,又有好几天是剔除考核,所以上个月上的比较多。到了今天发工资居然有3788元,这是学习云客服以来,第一次有这么高的工资,挺开心。

对于这份兼职,做的好,很开心,做不好,压力大,而且需要一直“边做边学习”的状态,如果连续几天没上班,就很容易变得生疏,遇到无理取闹的人也会非常生气,但毕竟是服务行业,要懂得理性,懂得学会控制。

202512121409512422.jpg

  •  

垃圾分类与秸秆禁烧的思考

昨天下午去上班的时候,看到一个环卫师傅在收垃圾,把一包一包的垃圾往垃圾清运车里扔。忽然就想到,最近的这两年,垃圾分类是又少有人提起了。

之所以很少再提起,是因为现在我们垃圾焚烧发电了,而且垃圾根本就不够烧的。前两天还看到深圳要把以前的垃圾填埋场里的垃圾挖出来,当然,挖垃圾是次要的,主要的是要那片地。

其实就中国的国情来说,垃圾分类本身也是一个伪命题。能回收的垃圾,就算不分类也会被人捡走,然后剩余的垃圾被一股脑地堆进了垃圾车。

从垃圾分类又想到了禁烧秸秆,从环保的角度来说,可能是正确的,但是也不一定完全正确。传统的刀耕火种,流传了几千年,火能烧死草籽和虫卵,来年就不会用那么多的农药,现在农业的农药滥用,和这些不无关系。不打农药,庄稼根本就无法长成,早都被虫子吃光了。农药的滥用何尝不是对环境的另一种破坏呢。

随着经济的发展,其实农村的秸秆也越来越是一个问题了,以前拿来当作柴火用,现在富裕了,天然气也通到乡村,也就越来越少的人再用秸秆来烧锅做饭了,秸秆就堆积起来,靠自然的降解速度又很慢,只能越堆越多,从莫种意义上来说也是对环境的又一个污染。炊烟袅袅的乡村,终将会消失在一代人的记忆里。以后的孩子在看到"此木为柴山山出,因火成烟夕夕多"这类的对联时,又多了一份难以理解。

这些看似不相关的环保政策背后,其实都反映了我们在现代化进程中的一些深层次问题。我们在追求环保的同时,是否也应该考虑到传统智慧的价值?在推行新政策的时候,是否应该更加全面地评估其长远影响?

环保是一个复杂的系统工程,需要我们在保护环境和维持生态平衡之间找到最佳的平衡点。简单的"一刀切"政策,往往会在解决一个问题的同时,制造出新的问题。

或许,我们需要的是更加细致、更加因地制宜的环保策略,而不是简单粗暴的统一标准。毕竟,每个地区的情况不同,每种传统做法背后都有其存在的合理性。

  •  

别让你的烟,呛到无辜的人

最近发现公共场所抽烟的人越来越多了,楼道、电梯、路上,经常能碰到。那股烟味非常让人不太舒服。

我的店所在的这个写字楼楼道是一个密闭的空间,虽然物业也贴了楼道禁止吸烟的标语,但是也并没有什么实质性的作用,每当有人抽烟,屋里就会飘来一股烟味,有时候不得不把门关上,但是你又是在做生意,关上门又不合适,真实左右为难。

电梯里抽烟就更让人头疼了。很多次,进入电梯,里面都是一股浓浓的烟味,很多邻居也都在物业群里吐槽,这时候物业就是一只鸵鸟,不吭声,不吭声,逼急了,就说在电梯有禁烟的标语。其实他们也很无奈。还有一些年轻人也是,抽的电子烟,虽然没有那么难闻,但是危害是一样的。

电梯空间小,烟味散得慢。后面坐电梯的人还得闻这个味道。那些对烟味敏感的人,或者带着孩子的人,确实会不舒服。

路上抽烟的人也常见。走在他后面,风一吹,烟味就飘过来。有时候想超过去,他还走的挺快,闭着气赶紧穿过去,心里在骂他的娘。

我琢磨了一下,这些人大概有这么几种心态。第一种是觉得抽烟是自己的权利,想在哪抽就在哪抽。他们忘了自由的前提是不妨碍他人的自由。你的抽烟自由,不能建立在我吸二手烟的不自由上。

第二种是觉得抽几口没事,烟味一会儿就散了。他们也知道二手烟里的有害物质可以在空气中停留很久,但是,关我鸟事。

第三种是看到别人在公共场所抽烟,觉得自己也可以。典型的法不责众心理。问题是,错的事情不会因为做的人多就变成对的。

第四种是知道公共场所抽烟不对,但只要没人管,他们就照抽不误。说白了就是缺乏公德心。

有些人可能觉得,闻点烟味没什么大不了的。但二手烟确实有危害,特别是对孩子、孕妇、老人和有呼吸系统疾病的人。

其实我们国家早就出台了《公共场所控制吸烟条例》,明确规定室内公共场所、公共交通工具、电梯等地方禁止吸烟。问题是,规定是规定,执行是执行。很少看到有人因为公共场所抽烟被处罚。物业不管,保安不管,大家也都抱着"多一事不如少一事"的心态。

这就形成了一个恶性循环:没人管→更多人抽→更没人敢管。

说实话,作为一个普通市民,我们能做的有限。但至少可以从自己做起,如果家里有人抽烟,劝他们去专门的吸烟区,或者至少不要在密闭空间抽。遇到公共场所抽烟的人,可以礼貌地提醒。虽然可能没什么用,但至少表达了态度。

也可以支持公共场所设立明显的禁烟标志,支持物业加强管理。告诉孩子们吸烟的危害,特别是二手烟的危害。

抽烟是个人的选择,这个我理解。但如果在公共场所抽,确实会影响别人。公共场所是大家共用的,不是某个人的吸烟室。你的自由,不应该让别人不舒服。

那些在楼道、电梯、路上抽烟的朋友,可以换个角度想想:如果你的家人每天都要闻别人的烟味,你会怎么想?将心比心,其实大家都明白这个道理。

  •  

冬日杂记

这两天,气温又开始下降了。看着女儿因为脚伤在家里,晚上不开空调就有点不乐意,心里不免感慨。虽然今年集中供暖依然未能实现,但室内的温度保持在19度左右,体感上其实还算可以。都说今年会是一个寒冬,但我总感觉现在的冬天,已经远没有记忆中那么冷了。

小时候,对“冰冻三尺非一日之寒”这个成语,曾有过非常具体的、亲身的体会。在我们村子南边,有一个叫做“南坑”的水塘。那时候的南坑是终年有水,而每年冬天,它都会给我们带来一场盛大的冰雪游戏。特别是到了最冷的三九天,冰层会厚到我们一群小伙伴在上面尽情玩耍、奔跑跳跃,冰面都不会破裂。那厚厚的、结实的冰层,正是对“冰冻三尺”最生动的诠释。

然而,物是人非,现在的冬天,很多地方已经不结冰了,就算偶尔结了一层薄冰,也往往捱不过中午的日头,早早地融化。单从这一点来看,现在的冬天确实不如以前寒冷了。

想到那般彻骨寒冷的冬天,真的非常佩服那时候的河南人,竟然几乎是全靠着被窝熬过一整个季节。现在想来,那并非是不想取暖,而是生活条件所限,主要还是能源不足。有些人家连平常做饭的柴火都捉襟见肘,更别说拿来取暖了。那时候,河南农村主要的柴火来源是秸秆和树叶,这些燃料不耐烧,难以维持长久的温暖。那是一个物质匮乏的年代,是靠着坚韧和“硬扛”度过的冬天。

如今,时过境迁,村南的南坑虽然还在,但水面早已干涸见底。以前的南坑终年有水,正是因为我们那里的地下水位非常高。家家户户使用的压水井,往往只需一丈多深就能轻松出水,所以坑里常年水波荡漾也就不足为奇。可后来,水井越打越深,水位也越来越低。到了现在,打井必须依靠下潜水泵才能抽出水来,传统的一丈老井早已成为历史遗迹。冰冻三尺的南坑、充沛的地下水、还有全靠硬扛的童年冬季……这些记忆中的片段,都随着岁月的更迭和环境的变化,渐渐成为了历史。

  •  

EndeavourOS + Btrfs + Snapper + GRUB:完整的快照回滚系统配置指南

EndeavourOS由于使用的是滚动更新,系统存在着滚挂的可能性(尽管我已经使用了1个多月也没有问题),所以快照回滚是一个必须的选项。本文将详细介绍如何在 EndeavourOS 系统中配置完整的快照回滚系统,让您在系统出现问题时能够轻松恢复到之前的状态。

前言

为什么需要快照回滚系统?在日常使用中,我们难免会遇到以下情况:

  • 系统更新后出现兼容性问题
  • 安装某个软件导致系统不稳定
  • 配置文件修改错误导致系统无法启动
  • 恶意软件或误操作破坏系统

有了快照回滚功能,这些问题都可以通过简单的重启和菜单选择来解决。

系统要求

在开始之前,请确保您的系统满足以下条件:

  1. 已安装 EndeavourOS(或基于 Arch 的其他发行版)
  2. 使用 Btrfs 文件系统作为根分区
  3. 安装时选择 GRUB 作为引导加载程序

核心组件介绍

我们的快照回滚系统将由以下几个核心组件构成:

组件 作用 必要性
Snapper 快照管理核心程序,负责创建、删除和管理快照 必需
snap-pac 在 pacman 操作时自动创建 pre/post 快照 强烈推荐
grub-btrfs 将 Snapper 快照集成到 GRUB 启动菜单 必需
inotify-tools 文件系统监控工具,确保 GRUB 菜单及时更新 可选但推荐

安装步骤

步骤 1:安装核心软件包

打开终端,执行以下命令安装所需的软件包:

1
2
# 安装 snapper, snap-pac 和 grub-btrfs
sudo pacman -S snapper snap-pac grub-btrfs

软件包说明:

  • snapper:快照管理的核心程序,提供快照创建、删除、比较等功能
  • snap-pac:自动化工具,在每次 pacman 操作时自动创建"操作前"和"操作后"快照
  • grub-btrfs:GRUB 扩展模块,自动扫描 Snapper 快照并将其添加到启动菜单

步骤 2:配置 Snapper

安装完成后,我们需要创建 Snapper 配置:

1
2
3
4
5
# 创建根分区的 Snapper 配置
sudo snapper -c root create-config /

# 创建第一个手动快照作为基准
sudo snapper create --description "初始系统快照"

步骤 3:启用 GRUB 集成服务

grub-btrfsd 服务会监控快照变化并自动更新 GRUB 配置:

1
2
# 启用并启动 grub-btrfs 守护进程
sudo systemctl enable --now grub-btrfsd.service

步骤 4:生成初始 GRUB 配置

手动生成一次 GRUB 配置,确保现有快照出现在启动菜单中:

1
2
# 重新生成 GRUB 配置文件
sudo grub-mkconfig -o /boot/grub/grub.cfg

验证配置

检查服务状态

确认 grub-btrfsd 服务正常运行:

1
2
# 查看服务状态
sudo systemctl status grub-btrfsd

正常情况下,您应该看到类似以下的输出:

1
2
3
 grub-btrfsd.service - GRUB Btrfs snapshot detection daemon
   Loaded: loaded (/usr/lib/systemd/system/grub-btrfsd.service; enabled; vendor preset: disabled)
   Active: active (running) since ...

查看快照列表

检查 Snapper 是否正常工作:

1
2
# 列出所有快照
sudo snapper list

您应该能看到包含刚才创建的"初始系统快照"的列表。

测试自动快照功能

安装一个简单的软件包来测试自动快照功能:

1
2
3
4
5
# 安装测试软件包
sudo pacman -S neofetch

# 查看是否自动创建了快照
sudo snapper list

您应该能看到两个新的快照:一个在安装前(pre),一个在安装后(post)。

故障排除

问题 1:GRUB 菜单中没有显示快照

如果重启后 GRUB 菜单中没有显示快照选项,可能是因为缺少 inotify-tools

1
2
3
4
5
6
7
8
# 安装 inotify-tools
sudo pacman -S inotify-tools

# 重启 grub-btrfsd 服务
sudo systemctl restart grub-btrfsd.service

# 重新生成 GRUB 配置
sudo grub-mkconfig -o /boot/grub/grub.cfg

问题 2:服务启动失败

如果 grub-btrfsd 服务启动失败,检查以下内容:

1
2
3
4
5
# 检查服务日志
sudo journalctl -u grub-btrfsd.service -f

# 检查 Btrfs 子卷挂载情况
mount | grep btrfs

问题 3:快照无法启动

如果快照在 GRUB 菜单中显示但无法启动,可能是由于以下原因:

  1. 内核版本不匹配:确保快照中的内核版本与当前系统兼容
  2. initramfs 问题:重新生成 initramfs 镜像
  3. 子卷挂载问题:检查 /etc/fstab 配置

高级配置

自定义快照保留策略

编辑 Snapper 配置文件来自定义快照保留策略:

1
2
# 编辑配置文件
sudo nano /etc/snapper/configs/root

在文件中找到以下部分并根据自己的需求调整:

1
2
3
4
5
6
7
8
9
# 数量限制
TIMELINE_LIMIT_HOURLY="10"
TIMELINE_LIMIT_DAILY="7"
TIMELINE_LIMIT_WEEKLY="4"
TIMELINE_LIMIT_MONTHLY="12"
TIMELINE_LIMIT_YEARLY="0"

# 清理算法
TIMELINE_CLEANUP="true"

配置定时快照

启用定时快照功能,系统会定期自动创建快照:

1
2
3
4
5
# 启用 snapper-timeline.timer
sudo systemctl enable --now snapper-timeline.timer

# 启用 snapper-cleanup.timer
sudo systemctl enable --now snapper-cleanup.timer

使用指南

创建手动快照

1
2
3
4
5
# 创建描述性快照
sudo snapper create --description "安装显卡驱动前"

# 创建带类型和描述的快照
sudo snapper create --type single --description "系统优化完成"

删除快照

1
2
3
4
5
# 删除指定快照(替换 <ID> 为实际的快照编号)
sudo snapper delete <ID>

# 删除多个快照
sudo snapper delete <ID1> <ID2> <ID3>

比较快照

1
2
3
4
5
# 比较两个快照之间的差异
sudo snapper diff <ID1> <ID2>

# 比较特定文件的变化
sudo snapper diff <ID1> <ID2> /etc/fstab

回滚到快照

  1. 重启系统
  2. 在 GRUB 菜单中选择"Snapper snapshots"
  3. 选择要回滚的快照
  4. 按照屏幕提示完成回滚
  •  

电影《捕风追影》:老戏骨的港式动作片

还是暑假的时候,有次偶尔看到这部电影的信息,看到是成龙、梁家辉、张子枫主演的,还是有点期待的,但也不多,让我花上几十块钱去看还是有点舍不得的。如果是春节上映的话,还有这么点可能,最近在视频平台也上线了,昨天看了一下,感觉也还不错,是一部港味十足的动作片无疑。

老戏骨的精彩对决

成龙饰演的黄德忠是一位退休多年的跟踪专家,被请出山对付高科技犯罪团伙。虽然年事已高,但成龙依然展现了他标志性的"成龙式"动作喜剧风格——在洗衣房利用晾衣杆为武器,将反派塞进滚筒洗衣机,既规避了老年人硬拼体力的不合理,也延续了他独有的喜剧感。

而梁家辉则贡献了从影以来最凶猛的反派表演。一场在孤儿院走廊中手持短刃与30人近身缠斗的戏份,刀刀见血的暴力美学令人脊背发凉。67岁的他每一刀都精准狠辣,癫狂中透着末路枭雄的悲凉。

新老交替的传承主题

影片巧妙地融入了新老交替的主题。成龙与张子枫饰演的何秋果之间的师徒关系,既有《成龙历险记》中龙叔与小玉的感觉,又展现了传统跟踪术与现代高科技的碰撞。张子枫在片中的表现可圈可点,从最初被戏称为"吉祥物",到最后成为"团队王牌",展现了女性在警队中的成长与价值。

反派阵营中,梁家辉饰演的"影子"与他的"狼崽团"之间的关系同样复杂。从小收养的孤儿们长大后成为他的棋子,“父子"间互相猜疑中又带着一丝温情。这种矛盾的情感羁绊为影片增添了不少深度。

紧张刺激的动作场面

《捕风追影》的动作戏也很不错。从开场反派团伙的空港逃脱戏,到中段的各种跟踪与反跟踪技巧展示,再到最后的终极对决,每一场戏都设计得很好。

影片融合了跑酷、跳伞、枪战、爆破、近身肉搏等多种动作元素,展现了成家班的风采。特别是成龙在洗衣房的械斗场景,让人仿佛回到了他的黄金时代;而梁家辉的匕首戏则简洁狠辣,与成龙的风格形成鲜明对比。

剧情的亮点与不足

影片剧情紧凑,141分钟几乎无尿点。以"跟踪与反跟踪"为核心,融入AI、高科技犯罪等元素,对决不断层层反转。

当然,影片也有部分情节值得商榷。比如梁家辉饰演的"影子"如此心狠手辣,最后却对张子枫网开一面,如果影片能交代一下原因会更好。

此外,影片在技术细节上也存在一些硬伤。黑客几下就把警方的"天眼"系统搞瘫痪,这种情节过于简化了网络安全攻防的复杂性。现实中,像"天眼"这样的国家级监控系统应该有多重防护措施,不可能如此轻易被攻破。

另一个明显的技术硬伤是加密货币的处理方式。影片中加密货币被描绘得像普通文件夹一样可以直接拷贝,这与加密货币的实际工作原理大相径庭。真正的加密货币交易需要复杂的区块链验证过程,不可能简单地通过复制粘贴来完成转移。这种处理方式显然是为了剧情需要而牺牲了技术真实性。

不过,这些技术细节的简化也可能是为了照顾普通观众的理解,毕竟不是所有人都熟悉网络安全和区块链技术。作为商业动作片,《捕风追影》的主要卖点还是精彩的对决和紧凑的剧情,技术细节的准确性可能被放在了次要位置。

结语

《捕风追影》是一部诚意满满的商业动作片,它不仅让观众看到了成龙与梁家辉这两位老戏骨的精彩表演,也让我们看到了港式动作片的希望。在这个特效大片扎堆的时代,这种以拳拳到肉的动作爽感、实景拍摄诚意的作品,确实让人热血沸腾。

影片结尾那句"可能会后悔,但不会犯错,职责所在"道出了警察的职业精神,而"时代不同了,但规矩还是要有的"则反映了传统与现代的碰撞。这不仅仅是一部动作片,更是一部有深度、有温度的港式警匪片。

如果你是港片的爱好者,如果你想看看成龙和梁家辉这对老搭档时隔二十年的再次合作,《捕风追影》绝对值得一看。它不仅仅是一部动作片,更是一场关于传承、关于时代变迁的思考,也是对港式动作片黄金时代的一次致敬。中确实

  •  

《浪浪山小妖怪》:小人物的取经之路

自从关注到《浪浪山小妖怪》这部电影的信息后,就一直期待着。作为《中国奇谭》中《小妖怪的夏天》的衍生电影,我本以为只是简单的扩展,没想到在上映后在线上平台观看时,却被深深触动,打开了我内心深处那些久违的情感。

随着剧情的展开,我发现自己最初的期待还是太保守了,这部电影远比我想象的要深刻得多。这部电影讲述的是四个小妖怪——小猪妖、蛤蟆精、黄鼠狼精和猩猩怪,假扮唐僧师徒西天取经的故事。

最让我印象深刻的是这四个角色的设定。小猪妖成了团队的核心,蛤蟆精戴着大头娃娃假冒唐僧,口吃的猩猩怪被说服做了齐天大圣,黄鼠狼精则自己粘胡子、戴佛珠扮演沙师弟。这种"最不可能的师徒四人"组合,充满了荒诞的喜剧效果。

看着这些小妖怪笨拙地模仿着传说中的英雄形象,我不禁笑了出来。但笑着笑着,心里却涌起一阵酸楚。我们每个人不也常常是这样吗?在生活中扮演着各种角色,努力模仿着那些我们认为成功的人,却往往忘记了自己本来的样子。

电影中最打动我的,是这些小妖怪们踏上取经路的动机。它们不是为了普度众生,而是为了最朴素的愿望——“长生不老”,或者说,是为了改变自己作为底层小妖怪的命运。

这种动机让我想起了现实生活中的我们。多少人离开家乡来到大城市打拼,不也是为了改变命运吗?我们或许没有"取经成佛"这样宏大的目标,但我们都渴望通过自己的努力,过上更好的生活。

电影中有一个情节特别触动我:小妖怪们在取经路上时而被一眼识破、穷追猛打,时而被错认成真身,当作"唐僧肉"下锅。这种身份错位带来的荒诞感,不正是我们现实生活中常常遇到的困境吗?我们既想被认可,又害怕被看穿,在这种矛盾中挣扎前行。

电影的画面美学值得称道。制作团队采用了"笔墨入镜"的方法,将中国传统绘画的笔墨意境与现代电影镜头的光影空间完美融合。水墨氤氲的山川云气在银幕上舒展,工笔勾勒的精细角色在光影间跃然生动。

特别让我感动的是影片中那些自然景物的描绘。据说影片有大约80%的画面是自然景物,制作团队选择用手绘而非三维技术,正是为了更好地传达中国传统美学的意境。看着那些山峦、村落,我仿佛回到了儿时记忆中的乡村,那种朴素而真实的美感,在如今这个数字化的时代显得尤为珍贵。

影片的音乐也很出色。埙、洞箫、竹笛等中国传统乐器与西洋乐器的融合,为小妖怪们的旅途增添了妙趣。海浪声、虫鸣、鸟叫、风声共同构成的"声音蒙太奇",生动地再现了夏日场景,让人仿佛置身于那个充满奇幻色彩的世界。

电影中有一个情节让我深思:小妖怪们在小雷音寺与黄眉大王的斗争。在实力悬殊的对抗中,它们不再简单地模仿齐天大圣的外表,而是以行动与选择诠释了"踏平坎坷成大道"的精神。

这一情节重新定义了"取经"的含义。它不再是宿命式的任务,不是只有天赋异禀的人才能追寻的圣路,而是每个普通人都可以踏上的道路,都可以实现的转变。正如电影所展现的,“取经人"不再是唐僧师徒的专属称谓,每个想要改变命运的普通人,都可以成为取经人。

这种解读让我深有感触。我们常常觉得自己是平凡的小人物,不可能成就什么伟大的事业。但这部电影告诉我们,重要的不是我们是谁,而是我们选择成为谁,以及我们为此付出的努力。

看完电影,我忽然意识到,这部电影不仅仅是给孩子看的,更是给那些在生活中挣扎的成年人看的。

在这个充满压力和竞争的社会里,我们每个人都像是浪浪山中的小妖怪。我们或许没有显赫的背景,没有过人的才华,但我们都有一颗想要改变命运的心。我们或许会犯错,会迷茫,会走弯路,但只要我们不放弃,就总有希望。

《浪浪山小妖怪》用最荒诞的方式,讲述了一个最真实的故事。它告诉我们,无论我们多么渺小,多么不起眼,都有权利追求自己的梦想,都有可能成为自己生命中的主角。

看完后我一直在想,如果每个人都能像这些小妖怪那样,勇敢地踏上自己的取经路,这个世界会不会变得更美好一些呢?

也许会的。因为重要的不是起点在哪里,而是是否愿意迈出第一步;重要的不是有多少人相信你,而是你是否相信自己。

这大概就是《浪浪山小妖怪》想要告诉我们的道理吧。

  •  

体检、微恙与放下酒杯

日子在不经意间加速,转眼又到了做“身体年报”的时候。这几天在医院做了一系列检查,把身体各个部件都摸了一遍。总体而言,情况比想象中要好,这无疑是今年最让人松一口气的消息。

最让我欣慰的是一些老毛病正在逐渐清零。

  • 肝功能: 以前因为化疗的后遗症,我的胆红素指标一直偏高。这次复查,它终于回归了正常区间。这就像是在说,身体已经彻底走出了那段艰难的日子,开始稳步运行了。

  • 脂肪肝: 对比了以往的记录,脂肪肝的情况应该也在减轻。去年的 CT 报告还明确写着“脂肪肝”,而今年的结果,大夫给出的判断是程度已经比较轻了,甚至不再单独拿出来强调。这说明在日常的调整和控制上,方向是正确的。

  • 基础指标: 这个年纪,血脂和血压能够保持在正常水平,也算是给自己的健康管理打了一个合格分。

当然,时间的脚步不会因为谁而停止,身体机能的退化也是不可避免的。比如,报告单上清晰地写着:左心室舒张功能降低。这是年龄带来的必然印记,提醒着我要更珍惜和维护好现有的健康资本。

肠胃两年后的复查与新的治疗方案

前天又去做了两年多没做的肠胃镜。结果是好消息占了上风:无论是胃里还是肠里,都没有再长出息肉

但也检查出了老问题和一些新情况:

  • 新问题: B 级的反流性食管炎和浅表性胃炎。这大概是生活压力和饮食习惯累积的小小抗议。

  • 老问题: 结肠手术后的吻合口,依然有一如既往的溃疡,都快七年了,还没有完全长好。

过去,我一直是在肿瘤科复查,大夫通常没有针对这个溃疡给出特别的治疗建议。这次,我决定挂了消化科主任的号,听听更专业的意见。主任建议我服用四个月的美沙拉嗪,这是一种专门用于治疗溃疡性结肠炎的药物。希望这一次,能彻底让这个“七年之痒”的溃疡面愈合。

生活,从此放下酒杯

昨天和媳妇聊天时,做出了一个决定:以后酒不再喝了

其实我本身也不是一个嗜酒的人,主要是逢年过节、朋友聚会,以及遇到高兴的事情时,会小酌两杯。但从现在开始,能不喝就不喝了。毕竟身体已经过了可以随便挥霍的年纪,既然已经有食管炎和胃炎的苗头,那就应该更加彻底地避免任何刺激。

放下酒杯,不仅是对健康的负责,也是对生活态度的重新调整——很多快乐和庆祝,并不需要酒精的参与来放大。

说到酒,倒让我想起了一点童年旧事。

那时候酒的种类很少,在我们当地,最常见的可能就是鹿邑大曲宋河粮液。宋河粮液的酒瓶设计得特别好看,瓶型优雅,更重要的是,它的盖子是拧的,不是那种以前白酒和啤酒常用的,需要用起子撬开的金属皇冠盖。在那个年代,一个好看又结实的拧盖酒瓶,简直是小孩子心中的“高科技产品”。

我特别羡慕班里有这个酒瓶的同学,他们把酒瓶洗干净,用来带水到学校喝。那个瓶子不仅结实耐用,拧盖设计还能保证不漏水,在当时是一种象征,代表着家里有“好酒”喝。

现在回想,那段记忆简单又美好。而如今,我则要和手中的酒杯说声再见,转向更加朴素和健康的生活。

身体是革命的本钱,这次体检就像是身体给我交出的一份“年报”,有合格的成绩,也有需要改进的提示。接下来的日子,就是带着这些提示,更加认真地生活,做好健康的“减法”和“维护”。

  •  

独立思考,是抵抗所有现代焦虑的最终防线

你有没有过这样一种体验:自信满满地认为自己对某件事情了解透彻,直到你尝试向别人详细解释时,才发现原来自己并不如想象中那般了解。比如,试着解释一下你每天用的扫码支付是如何工作的,或者马桶是如何冲水的。突然间,你会发现自己只是会使用这些工具,却未必懂得它们的原理。 史蒂文·斯洛曼和菲利普·费恩巴赫在《知识的错觉:为什么我们从未独立思考》说,人类往往高估了自己的知识深度,误以为掌握了某些复杂事物的原理,然而我们其实只是知道如何操作这些事物,而非它们是如何运作的。这种现象作者称之为 “解释深度错觉”(Illusion of Explanatory Depth)

最后,作者得出结论说:你永远不会单独思考 (We Never Think Alone)。它呼吁我们对自己的知识保持谦逊,对社群的知识保持警惕,并在教育和政治中利用对这种错觉的理解,来促进更好的协作与决策。

书的作者一定没有看过《庄子》这本书。庄子在几千年前就说过:

“吾生也有涯,而知也无涯。以有涯随无涯,殆已!”

这本书给我的启示是一定要有独立思考的能力,特别是在如今这种信息爆炸的环境中——我们一方面生活在知识的洪流中,另一方面又无法真正掌握这些知识。我们把自己从不懂的事物中得到的片段信息,误认为是掌握了全局的理解。

焦虑背后的根本原因,在于我们对核心系统缺乏理解,丧失了“解释权”。无论是金融市场、公共卫生政策还是其他复杂的社会系统,普通个体常常无法真正理解这些系统如何运作。信息和规则只掌握在少数专家和机构手中,我们只能被动地接受结果。

当我们无法验证和理解这些系统的运行时,我们的知识焦虑就悄然滋生。焦虑的表现不再是基于对事物的理性分析,而是基于情感的“信不信”。我们被外部复杂的系统所支配,陷入了情绪化的决策和反应中。

这种缺乏独立思考的状态,使得我们容易被外界的声音带节奏,成为“知识节点”,把自己的决策权外包给简单且情绪化的答案。由此,集体焦虑的爆发成为不可避免的结果。

这也是这本书让我们对社群的知识保持警惕的原因。

独立思考,正是抵抗焦虑的最终防线。老子在《道德经》里说:知人者智,自知者明,明之后就不可能在有什么焦虑的情绪产生。而只有独立思考,才能自知。

独立思考的第一步,是承认自己的局限性,即认清自己的“有涯”。在面对复杂决策时,我们要质疑自己是否真的了解其运作原理,是否能够详细解释清楚。通过这种方式,我们能打破“知识的错觉”,将自信转化为理性。

独立思考并不是让我们脱离知识而是提高我们与他人合作的能力。 我们需要学会如何评估信息的来源、立场与专业性,筛选出真正的智慧,避免被噪音干扰。同时,我们还要能够批判性地整合不同的观点和信息,构建属于自己的认知框架。

只有具备独立思考的能力,我们才能在知识的海洋中保持清醒,不被情绪和集体焦虑所左右。

我们无法阻止知识的无限膨胀,也无法避免社会复杂性的增加,但我们可以改变自己在这个大系统中的角色。通过独立思考,我们不仅能应对信息时代的挑战,还能在集体智慧中保持自己的独立性和理性。

作为现代人,我们的使命是:以独立思考,成为知识社群中一个清醒、批判、高质量的合作者。只有这样,我们才能在理解世界复杂性的同时,不被任何形式的焦虑和节奏所支配。

  •  

以直报怨,怨未尽而心已定

《论语·宪问》中,有人问孔子:

“以德报怨,何如?” 孔子答:“何以报德?以直报怨,以德报德。”

我对这句话,之前一直理解为以牙还牙,昨天看书时候又看到这个词,觉得以牙还牙,爽是爽了,但不应该是这样一种情况,很多时候,我们也无法做到如此的酣畅淋漓。那么“以直报怨”究竟是什么意思?难道报了怨,心里就真的没有怨气了吗?


一、“以直报怨”,不是让怨消失,而是让怨归位

“怨”来自不平。 当你被误解、被伤害、被欺骗时,心里自然会生怨。 因此,与其把怨恨留在心心里,不如给它找到一个出口。 “以直报怨”的“直”,指的是公正、理性、合宜。 不是以牙还牙,也不是逆来顺受, 而是用正直的方式让怨发泄出来。 不久前我们小区发生的事情。小区的车位到现在还没有建好,前段时间,开发商说要建车位,并开始售卖剩余的车位,可是价格确实比几年前卖的价格低的多的多。所以,之前买车位的业主就很难受,去退也没有,开发商根本没钱给你。用一个业主的话说就是:

意难平

意难平,就是怨 虽然最终也不了了之了,但是把这个怨表达出来给了开发商,也算是有个出口,可能有时候还是会觉得窝囊,但是能有什么办法呢。当今的大环境就是如此,车位还好点,算是赔了几万块钱,想想同一个小区的房子呢,最高价的时候14000,现在只有不到一万,所以,想想还有别人比你惨,心里是不是好受点。当了韭菜就要有韭菜的觉悟。

所以,怨未必能尽,但若能“直面”它,怨就不会蔓延成恨。 这就是孔子所谓的“直”。


二、“直”的意义,在于止怨而非无怨

人若被怨气缠久了,容易迷失是非。 有时怨的不是别人,而是自己心里的不甘。 “直”让人不被情绪牵着走, 它像一条沟渠,让积怨之水有路可出。

你可以反击,可以申辩,可以拒绝, 但不必怀恨。

以直报怨,不是清除怨气,而是防止怨气滋生。

怨止于直,这一刻,心定了。


三、“以德报怨”,是怨止之后的更高境界

老子说:“报怨以德。” 那是更高的修养,是怨尽心清之后的平和。 但若怨尚未平,便谈以德相报, 那只是压抑,不是化解。

所以孔子说,先“直”后“德”。 以“直”立界,以“德”安心。

先止怨,后化怨。先明理,后谈仁。

两人讲的,不是冲突的两条路,而是修心的步骤。


四、怨未尽,而心已定

“以直报怨”的真正意义在于: 怨或许仍在,但它已不乱人心。 它变成了经验、成了界限、成了智慧。

怨,是人之常情; 直,是理之常道; 德,是心之常明。

当怨有界,德才有根。 怨未尽,心却已定—— 这,便是孔子的智慧。


怨若未报,会伤己; 怨若乱报,会伤人; 以直报怨,则两者皆安。

怨未必无,但心可以静; 怨未必尽,但人可以明。 “以直报怨”,正是这份有界的清醒。

  •  

把GotoSocial嵌入到Hugo

把博客重新换成Hugo后,我又把GotoSocial安装了起来,就是想发布自己有一些碎语之类的东西,在memos和GotoSocial中纠结了一会,最终选择了GotoSocial,主要原因还是看到memeos的作者随意改动API,为了以后不再有不必要的麻烦,还是选择一个更稳定的最好。整体完成后的效果可以参考:

我的微博

总体思路

由于 GoToSocial 默认开启了严格的 CORS 限制,获取内容的时候需要token,由于Hugo是静态博客,直接把token写在前端非常不安全,所以我们需要一个中转层。 Cloudflare Workers 可以完美胜任代理转发的功能,作用是:

  • 从 Hugo 前端发请求 → Cloudflare Worker
  • Worker 向 https://你的域名/api/v1/accounts/…/statuses 请求 GoToSocial 数据
  • Worker 再把 JSON 数据返回给 Hugo 前端
  • Hugo 构建时渲染

获取 GoToSocial 的 toot API 接口

目标概述

我们要:

  1. 向 https://你的域名/api/v1/apps 注册一个应用;
  2. 通过浏览器授权;
  3. 用授权码换取 access_token;
  4. 把这个 token 放入 Cloudflare Worker 的环境变量;
  5. 然后 Hugo 博客就能安全地从 Worker 获取嘟文数据。

详细步骤

注册一个新应用

在命令行执行以下命令(用 curl,别忘了改你的 app 名称):

1
2
3
4
5
6
7
8
curl -X POST \
  -H "Content-Type: application/json" \
  -d '{
        "client_name": "hugo-gts-proxy",
        "redirect_uris": "urn:ietf:wg:oauth:2.0:oob",
        "scopes": "read"
      }' \
  'https://你的域名/api/v1/apps'

成功后会返回类似:

1
2
3
4
5
6
7
{
  "id": "01J1CYJ4QRNFZD6WHQMZV7248G",
  "name": "hugo-gts-proxy",
  "redirect_uri": "urn:ietf:wg:oauth:2.0:oob",
  "client_id": "xxxxxxxxxxxxxxxx",
  "client_secret": "yyyyyyyyyyyyyyyy"
}

👉 复制并保存 client_id 与 client_secret。

获取授权码

打开浏览器访问以下链接(注意替换 YOUR_CLIENT_ID):

1
https://你的域名/oauth/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code&scope=read

系统会要求你登录并授权。 点击「允许」,你会看到页面上出现:

1
2
Here's your out-of-band token:
YOUR_AUTHORIZATION_CODE

👉 复制这个 YOUR_AUTHORIZATION_CODE。

用授权码换取访问令牌

然后在命令行执行:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
curl -X POST \
  -H "Content-Type: application/json" \
  -d '{
        "redirect_uri": "urn:ietf:wg:oauth:2.0:oob",
        "client_id": "YOUR_CLIENT_ID",
        "client_secret": "YOUR_CLIENT_SECRET",
        "grant_type": "authorization_code",
        "code": "YOUR_AUTHORIZATION_CODE"
      }' \
  'https://你的域名/oauth/token'

会返回类似:

1
2
3
4
5
6
{
  "access_token": "YOUR_ACCESS_TOKEN",
  "created_at": 1729436650,
  "scope": "read",
  "token_type": "Bearer"
}

🎉 这就是我们需要的 access_token!

验证 token 是否可用

试试看:

1
2
curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  'https://你的域名/api/v1/accounts/verify_credentials'

如果返回你的用户资料( username, id, url 等),说明 token 有效 。

Cloudflare Worker的设置

接下来打开 Cloudflare → Workers → 你的 Worker → 「Settings」→「Variables」→「Add Variable」

1
2
Name: GTS_TOKEN
Value: YOUR_ACCESS_TOKEN

保存。 Worker 代码示例如下 👇:

点击展开查看完整的配置代码(大约 160 行)
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160

export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    const headers = {
      "Access-Control-Allow-Origin": "*",
      "Access-Control-Allow-Methods": "GET, OPTIONS",
      "Access-Control-Allow-Headers": "*",
    };

    if (request.method === "OPTIONS") {
      return new Response(null, { headers });
    }

    const target = `https://你的域名${url.pathname}${url.search}`;
    const resp = await fetch(target, {
      headers: {
        "Authorization": "Bearer " + env.GTS_TOKEN,
        "User-Agent": "GTS-Proxy-Worker",
      },
    });

    if (!resp.ok) {
      return new Response(await resp.text(), {
        status: resp.status,
        headers: { ...headers, "Content-Type": "application/json" },
      });
    }

    const data = await resp.json();
细步骤
    // 并行拉取每条嘟文的回复
    const statuses = await Promise.all(data.map(async (status) => {
      let replies = [];
      try {
        const ctx = await fetch(`https://你的域名/api/v1/statuses/${status.id}/context`, {
          headers: { "Authorization": "Bearer " + env.GTS_TOKEN },
        });
        if (ctx.ok) {
          const contextData = await ctx.json();
          replies = contextData?.descendants?.map(r => ({
            id: r.id,
            content: r.content,
            account: {<details>
<summary>点击展开查看完整的配置代码大约 100 </summary>
              username: r.account?.username,
              display_name: r.account?.display_name,
              avatar完全正确 : r.account?.avatar,
            }
          })) || [];
        }
      } catch (err) {
        console.log("Reply fetch failed:", err);
      }

      return {
        id: status.id,
        created_at: status.created_at,
        content: status.content,
        url: status.url,
        account: {
          username: status.account?.username,
          display_name: statuexport default {
  async fetch(request, env) {
    const url = new URL(request.url);
    const headers = {
      "Access-Control-Allow-Origin": "*",
      "Access-Control-Allow-Methods": "GET, OPTIONS",
      "Access-Control-Allow-Headers": "*",
    };

    if (request.method === "OPTIONS") {
      return new Response(null, { headers });
    }

    const target = `https://l22.org${url.pathname}${url.search}`;
    const resp = await fetch(target, {
      headers: {
        "Authorization": "Bearer " + env.GTS_TOKEN,
        "User-Agent": "GTS-Proxy-Worker",
      },
    });

    if (!resp.ok) {
      return new Response(await resp.text(), {
        status: resp.status,
        headers: { ...headers, "Content-Type": "application/json" },
      });
    }

    const data = await resp.json();

    // 并行拉取每条嘟文的回复
    const statuses = await Promise.all(data.map(async (status) => {
      let replies = [];
      try {
        const ctx = await fetch(`https://l22.org/api/v1/statuses/${status.id}/context`, {
          headers: { "Authorization": "Bearer " + env.GTS_TOKEN },
        });
        if (ctx.ok) {
          const contextData = await ctx.json();
          replies = contextData?.descendants?.map(r => ({
            id: r.id,
            content: r.content,
            account: {
              username: r.account?.username,
              display_name: r.account?.display_name,
              avatar: r.account?.avatar,
            }
          })) || [];
        }
      } catch (err) {
        console.log("Reply fetch failed:", err);
      }

      return {
        id: status.id,
        created_at: status.created_at,
        content: status.content,
        url: status.url,
        account: {
          username: status.account?.username,
          display_name: status.account?.display_name,
          avatar: status.account?.avatar,
        },
        replies_count: status.replies_count || 0,
        reblogs_count: status.reblogs_count || 0,
        favourites_count: status.favourites_count || 0,
        media_attachments: (status.media_attachments || []).map(media => ({
          url: media.url?.startsWith("/") ? "https://域名" + media.url : media.url,
          preview_url: media.preview_url?.startsWith("/") ? "https://域名" + media.preview_url : media.preview_url,
        })),
        replies,
      };
    }));

    return new Response(JSON.stringify(statuses, null, 2), {
      headers: { ...headers, "Content-Type": "application/json" },
    });
  },
};</details>
s.account?.display_name,
          avatar: status.account?.avatar,
        },
        replies_count: status.replies_count || 0,
        reblogs_count: status.reblogs_count || 0,
        favourites_count: status.favourites_count || 0,
        media_attachments: (status.media_attachments || []).map(media => ({
          url: media.url?.startsWith("/") ? "https://你的域名" + media.url : media.url,
          preview_url: media.preview_url?.startsWith("/") ? "https://你的域名" + media.preview_url : media.preview_url,
        })),
        replies,
      };
    }));

    return new Response(JSON.stringify(statuses, null, 2), {
      headers: { ...headers, "Content-Type": "application/json" },
    });
  },
};

Hugo模板设置

在 Hugo 博客根目录下,新建:

1
2
content/toots/_index.md
layouts/_default/toots.html

📄 content/toots/_index.md

1
2
3
4
---
title: "我的嘟文"
description: "来自 GoToSocial 的最新动态"
---

🧩 layouts/_default/toots.html

点击展开查看完整的配置代码(大约 280 行)
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
{{ define "main" }}
<main class="main post-single" id="toots-page">
  <header class="page-header">
    <h1>{{ .Title }}</h1>
    {{ with .Description }}
      <p class="page-description">{{ . }}</p>
    {{ end }}
  </header>

  <div id="toots-container" class="toots"></div>

  <div class="load-more-wrapper">
    <button id="load-more-btn">加载更多嘟文</button>
  </div>

  <script>
  let tootsData = [];
  let displayedCount = 0;
  const pageSize = 5; // 每次加载条数

  // ✅ 加载嘟文
  async function loadToots(initial=false) {
    if (initial) {
      // 请注意:如果您要使用 Cloudflare Worker,这里的 URL 应该是您的 Worker URL,而不是原始 Mastodon/GoToSocial 实例的 URL。
      // 假设您的 Worker 地址是 https://worker.yourdomain.com/api/v1/accounts/01M4A5Q58VD6GJH97T2TE6W25J/statuses?exclude_reblogs=true
      const url = "https://toots.iliu.org/api/v1/accounts/01M4A5Q58VD6GJH97T2TE6W25J/statuses?exclude_reblogs=true"; 
      const res = await fetch(url);
      tootsData = await res.json();
    }

    const container = document.getElementById("toots-container");
    const nextToots = tootsData.slice(displayedCount, displayedCount + pageSize);

    for (const t of nextToots) {
      const date = new Date(t.created_at).toLocaleString();
      const username = t.account?.display_name || t.account?.username || "匿名";
      const avatar = t.account?.avatar || "https://l22.org/path-to-default-avatar.png";

      // ✅ 九宫格多图布局
      let mediaHTML = "";
      if (t.media_attachments && t.media_attachments.length > 0) {
        mediaHTML = `
          <div class="toot-media-grid">
            ${t.media_attachments.map(m => `
              <div class="toot-media-item">
                <img src="${m.preview_url || m.url}" alt="${m.description || ''}" loading="lazy" onclick="showLightbox('${m.url}')">
              </div>
            `).join('')}
          </div>
        `;
      }

      // 🚨 【修复点】直接使用 Worker 预取的 t.replies 数据来构建回复内容
      let repliesHTML = "";
      if (t.replies && t.replies.length > 0) {
        repliesHTML = `
          <div class="toot-replies">
            ${t.replies.map(r => {
              const avatar = r.account?.avatar || "https://l22.org/path-to-default-avatar.png";
              const name = r.account?.display_name || r.account?.username || "匿名";
              return `
                <div class="toot-reply">
                  <img src="${avatar}" class="toot-reply-avatar" alt="${name}">
                  <div class="toot-reply-body">
                    <strong>${name}</strong>:${r.content}
                  </div>
                </div>
              `;
            }).join('')}
          </div>
        `;
      } else if (t.replies_count > 0) {
        // 如果 Worker 没有返回 replies 但计数大于 0,可能是 Worker 拉取回复失败
        repliesHTML = `<div class="toot-replies"><p class='no-reply'>暂无回复(或Worker拉取失败)</p></div>`;
      }

      const tootHTML = `
        <article class="toot-card">
          <div class="toot-header">
            <img class="toot-avatar" src="${avatar}" alt="${username}">
            <span class="toot-username">${username}</span>
          </div>
          <div class="toot-date">
            <a href="${t.url}" target="_blank">${date}</a>
          </div>
          <div class="toot-content">${t.content}</div>
          ${mediaHTML}
          <div class="toot-footer">
            ❤️ ${t.favourites_count} 🔁 ${t.reblogs_count} 💬 ${t.replies_count}
          </div>
          ${repliesHTML}
        </article>
      `;

      container.insertAdjacentHTML("beforeend", tootHTML);
      
      // 🚨 【修复点】移除了原有的 loadReplies(t.id) 调用
    }

    displayedCount += pageSize;
    document.getElementById("load-more-btn").style.display = displayedCount >= tootsData.length ? "none" : "inline-block";
  }

  // 🚨 【修复点】移除了 loadReplies 函数

  // ✅ 初次加载
  document.getElementById("load-more-btn").onclick = () => loadToots();
  loadToots(true);

  // ✅ 简易图片灯箱
  function showLightbox(src) {
    let lightbox = document.getElementById("lightbox");
    if (!lightbox) {
      lightbox = document.createElement("div");
      lightbox.id = "lightbox";
      lightbox.innerHTML = `<img id="lightbox-img"><span id="lightbox-close">×</span>`;
      document.body.appendChild(lightbox);
      document.getElementById("lightbox-close").onclick = () => lightbox.classList.remove("show");
      lightbox.onclick = e => { if (e.target === lightbox) lightbox.classList.remove("show"); };
    }
    document.getElementById("lightbox-img").src = src;
    lightbox.classList.add("show");
  }
  </script>

  <style>
  /* 容器样式 */
  #toots-container {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
    margin-top: 2rem;
  }

  /* 嘟文卡片 */
  .toot-card {
    background: var(--entry);
    border-radius: var(--radius);
    padding: 1rem 1.5rem;
    box-shadow: var(--shadow);
    transition: transform .2s ease, box-shadow .2s ease;
  }
  .toot-card:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-hover);
  }

  .toot-header {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.5rem;
  }
  .toot-avatar {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    object-fit: cover;
  }
  .toot-username {
    font-weight: bold;
    color: var(--primary);
  }

  .toot-date {
    font-size: .85rem;
    color: var(--secondary);
    margin-bottom: .25rem;
  }

  .toot-content {
    font-size: 1rem;
    color: var(--primary);
    line-height: 1.6;
    overflow-wrap: break-word;
  }

  /* 九宫格多图 */
  .toot-media-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
    gap: 4px;
    margin-top: .5rem;
  }
  .toot-media-item img {
    width: 100%;
    height: 100px;
    object-fit: cover;
    border-radius: 6px;
    cursor: pointer;
    transition: transform .2s ease, opacity .3s ease;
  }
  .toot-media-item img:hover {
    transform: scale(1.05);
    opacity: .9;
  }

  /* 回复样式 */
  .toot-replies {
    margin-top: .75rem;
    border-left: 2px solid var(--border);
    padding-left: .75rem;
  }
  .toot-reply {
    display: flex;
    align-items: flex-start;
    gap: .5rem;
    margin-top: .5rem;
  }
  .toot-reply-avatar {
    width: 28px;
    height: 28px;
    border-radius: 50%;
  }
  .toot-reply-body {
    font-size: .9rem;
    line-height: 1.4;
  }
  .no-reply {
    color: var(--secondary);
    font-size: .85rem;
  }

  /* 加载更多按钮 */
  .load-more-wrapper {
    text-align: center;
    margin: 2rem 0;
  }
  #load-more-btn {
    padding: .6rem 1.5rem;
    border: none;
    border-radius: 9999px;
    background: linear-gradient(90deg, #1e90ff, #0066cc);
    color: #fff;
    font-size: 1rem;
    cursor: pointer;
    box-shadow: 0 3px 10px rgba(0,0,0,.1);
    transition: all .3s ease;
  }
  #load-more-btn:hover {
    transform: translateY(-2px);
    box-shadow: 0 5px 15px rgba(0,0,0,.2);
  }

  /* 灯箱样式 */
  #lightbox {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.8);
    display: none;
    justify-content: center;
    align-items: center;
    z-index: 9999;
  }
  #lightbox.show {
    display: flex;
  }
  #lightbox img {
    max-width: 90%;
    max-height: 85%;
    border-radius: 8px;
    box-shadow: 0 0 15px rgba(0,0,0,.5);
  }
  #lightbox-close {
    position: absolute;
    top: 20px;
    right: 30px;
    font-size: 2rem;
    color: #fff;
    cursor: pointer;
  }

  @media (prefers-color-scheme: dark) {
    .toot-card {
      background: #1c1c1c;
    }
  }
  </style>
</main>
{{ end }}

生成页面

运行:

1
hugo server

访问: 👉 http://localhost:1313/toots/ 即可看到自动加载的嘟文列表。 部署后访问 https://你的博客域名/toots/ 就能看到相同效果。 我是把CSS和模板写到了一起,有兴趣的可以把CSS单独弄一个文件,还会更简练。

  •  

禅让制度以及无为的再思考

最近阅读南怀瑾先生的《禅宗和道家》,书中关于上古史的一些观点引起了我深深的思考。他提到,帝尧是黄帝的曾孙,大禹则是黄帝的玄孙。 禹的儿子子启建立夏朝,开启了中国的“家天下”时代。 从这个角度来看,夏朝的建立,似乎也承继了黄帝的血脉和基业,在某种意义上,称之为黄帝家族的延续也未尝不可。

禅让制:实力与贤德的交织?

这就引出了一个关于古代禅让制度的疑问。传说中尧曾想将位子禅让给许由,但许由拒绝了,这种高洁的精神境界固然令人敬佩,但传说毕竟是传说。 古代的禅让,真的仅仅是“禅贤”吗?从尧、舜、禹的血缘关系和历史记载来看,禅让的对象往往是有实力的部落或部落联盟的首领。例如,舜在被禅让前,已是一位拥有四方部落支持的首领。因此,即使是在被推崇为“天下为公”的禅让时代,“贤德”固然是重要的衡量标准,但“实力”和“政治影响力”恐怕也是不可或缺的砝码。 贤德需要实力的支撑,才能真正实现治理天下的抱负。

历史课本对“无为”的误解与“消极”的标签

第一次接触“无为”,是在初中历史课本上。课本将老子的思想概括为“消极”,用“小国寡民”、“鸡犬之声相闻,老死不相往来”来论证其“退步”和“与世隔绝”。那时候,我对课本的观点深以为然。 然而,十几年过去了,令人遗憾的是,这种对老子思想的刻板化和标签化的误解似乎依然存在于某些教育体系中。前几天与女儿讨论古代史,她口中重述的,依然是老子思想“消极”的论调。 我深感,历史课本在这种误解的传播中,“功不可没”。

“无为”的真谛:非“躺平”,而是“有所不为”

“无为”的本意,绝非我们现在常说的“躺平”或“不作为”。 我认为,这里的“为”的真正内涵,应该是“妄为”或“刻意而为”,即:

  • 违反自然规律;
  • 勉强行事;
  • 出于私心或主观意愿的强行干预。

“无为”不是不行动,而是“无不当为”。它体现在行动上,就是“有所为,有所不为”。只做自己能做的、该做的,不强求能力范围之外的事,不进行过度焦虑或私欲驱动下的强行干预。

这种“妄为”在当今的教育领域尤其明显,“鸡娃”现象便是典型。父母过度焦虑,强行推动孩子做超出其年龄和兴趣范围的事情,便是典型的“刻意而为”与“强行干预”。

“无为”的智慧,在于顺应自然,尽己所能。

当你顺其自然地、尽心尽力地去努力,在各个方面都做到位了,不执着、不强求,最终自然而然会达到“无不为”的境界。这才是“无为而无不为”的真正含义——以不妄为的态度,最终成就一切该成就的事业。 老子的思想,远不是简单的“消极”二字可以概括的,它蕴含着深邃的治理智慧和人生哲理,值得我们每一个人重新去审视和体悟。

  •  

给Hugo PaperMod主题添加一个漂亮又简洁的友情链接页面

PaperMod 默认是极简风格,没有自带“友情链接(Friends / Links)”页,但是我们博主也不是互联网的孤岛,总有一些自己喜欢的左邻右舍,最简单的方法是用生成一个页面来作为友情链接页面,但是太丑了。老刘结合chatgpt,自己添加一个漂亮的友情链接页面,下面是 详细教程(以 Hugo + PaperMod 为例):

一、创建友情链接页面

在你的 Hugo 项目根目录执行:

1
hugo new friends/_index.md

这会在 content/friends/_index.md 生成文件。 打开该文件,修改为:

1
2
3
4
5
---
title: "友情链接"
layout: "friends"
summary: "那些值得一去的好地方"
---

( 注意: layout 是我们下一步要创建的模板文件名。)

二、创建页面模板

PaperMod 的页面模板位于:

1
themes/PaperMod/layouts/

但我们不直接改主题文件(避免主题升级覆盖),而是复制到你的项目中:

1
mkdir -p layouts/_default

然后创建一个新模板文件:

1
nano layouts/_default/friends.html

写入以下示例模板(简洁、与 PaperMod 风格一致):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
{{ define "main" }}
<main class="main-content" id="main-content">
  <article class="post-single">
    <header class="post-header">
     

      <h1 class="post-title">{{ .Title }}</h1>
      {{ with .Params.summary }}
        <p class="post-description">{{ . }}</p>
      {{ end }}
    </header>
<style>
.friend-links {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 1.2rem;
  margin-top: 1.5rem;
}
.friend-card {
  display: flex;
  align-items: center;
  padding: 1rem;
  border-radius: 0.75rem;
  background: var(--entry);
  box-shadow: 0 1px 3px rgba(0,0,0,0.1);
  transition: all 0.25s ease;
}
.friend-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 4px 10px rgba(0,0,0,0.15);
}
.friend-card img {
  width: 3rem;
  height: 3rem;
  border-radius: 9999px;
  margin-right: 1rem;
}
.friend-card .text-gray-600 {
  color: var(--secondary);
}
</style>

    <div class="post-content">
      {{ .Content }}

      <div class="friend-links grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4 mt-6">
        {{ range .Site.Data.friends }}
          <a href="{{ .url }}" target="_blank" rel="noopener" class="friend-card flex items-center p-4 rounded-xl shadow-sm hover:shadow-md transition">
            <img src="{{ .avatar }}" alt="{{ .name }}" class="w-12 h-12 rounded-full mr-4">
            <div>
              <div class="font-semibold">{{ .name }}</div>
              <div class="text-sm text-gray-600">{{ .desc }}</div>
            </div>
          </a>
        {{ end }}
      </div>
    </div>
  </article>
</main>
{{ end }}

三、创建数据文件(友情链接信息)

在项目根目录新建:

1
data/friends.yml

添加如下内容(你可以随意扩展):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
- name: "PaperMod 官方"
  url: "https://github.com/adityatelange/hugo-PaperMod"
  avatar: "https://avatars.githubusercontent.com/u/21258296?v=4"
  desc: "简洁优雅的 Hugo 主题"

- name: "Hugo 官网"
  url: "https://gohugo.io/"
  avatar: "https://gohugo.io/images/hugo-logo-wide.svg"
  desc: "世界上最快的静态网站生成器"

- name: "老刘博客"
  url: "https://iliu.org/"
  avatar: "https://iliu.org/img/apple-touch-icon.png/"
  desc: "分享我的思考与生活"

四、将“友情链接”加入导航栏

打开 config.yml 或 config.toml(根据你使用的格式),找到菜单配置部分:

1
2
3
4
5
6
menu:
  main:
    - identifier: friends
      name: 友情链接
      url: /friends/
      weight: 30

五、重新生成并预览

1
hugo server -D

打开浏览器访问:

1
http://localhost:1313/friends/

即可看到一个简洁、卡片式的友情链接页面,与 PaperMod 风格一致。 具体风格可以参考: 老刘博客

通过以上步骤,你就成功地为 Hugo PaperMod 主题添加了一个既美观又简洁的友情链接页面。这个页面不仅能增强你的站点互通性,还能提升用户体验。如果你喜欢,也可以根据自己的需求对样式和布局进行进一步的调整和优化。希望这篇文章对你有所帮助!

  •