Fragments 用于存放不适合单独成文的碎片内容。
内容随心所欲,没有方向限制。本页内容独立于归档文章,单独设置 RSS 全文订阅
Fragments 用于存放不适合单独成文的碎片内容。
内容随心所欲,没有方向限制。本页内容独立于归档文章,单独设置 RSS 全文订阅
10:00 · 23 Mar, 2023
2022 年,我快乐地将博客迁移到了 Nuxt
2024 年,我记录了维护这个 Nuxt 博客遇过的事情
2025 年,我要跑路了
众所周知,Nuxt content 官网的文档都是语焉不详的,能参考文档完成的迁移只占很小一部分。剩下的只能在遇到问题时多翻 issue
这次更新最大也是最明显的改动就是查询底层的语法从类 MongoDB 变成了 SQL
因此需要自己写 schema 用于建表,启动时会扫描 /content
目录把符合要求的内容全部写到数据库里面
既然底层改了,那查询的 DSL 也要改,直接大改造
输出 Markdown 的 AST 也改了,那基于 v2 写的 body parser 怎么办,没办法搓了个 Wrapper 用来把 AST 改回原本 v2 时的输出
export const NuxtContentV3ASTWrapper = (body) => {
let _type = 'element'
if (Array.isArray(body[0])) {
_type = 'root'
} else if (typeof body === 'string') {
_type = 'text'
}
let tmpElement = {
type: _type
}
if (_type === 'text') {
tmpElement.value = body
} else if (_type === 'root') {
tmpElement.children = body.map((children) => NuxtContentV3ASTWrapper(children))
} else {
tmpElement.tag = body[0]
tmpElement.props = body[1]
if (_type === 'element') {
tmpElement.children = body.slice(2).map((children) => NuxtContentV3ASTWrapper(children))
}
}
return tmpElement
}
默认的时间戳变成了 z.date()
,别忘了旧版 Safari 不支持 ISO 8601
post.date.replaceAll('-', '/').replace('T', ' ')
用于 Server 的 serverQueryContent
直接被删了,要用只能 queryCollection(event, 'collection-name')
,然后看着 typescript 检查爆红
在我解决完这些问题以后,我还没意识到问题的严重性,当我随手检查开发者控制台的时候,我发现了 SQLite wasm 的请求……
这不对吧?在我费尽心思想要节省那丁点流量消耗的时候,一个 wasm 下场杀死了比赛
我一开始就看到缓存文件里面的数据库,我以为这个 SQLite 只是用于打包时的优化,用临时介质来优化处理速度是很正常的,我就没多想
但,我一个简简单单的博客,为什么要在前端跑这种重量级的东西?
也许有人会说几百 KB 并不多,现在谁会在乎那点流量。没错,没人在乎多消耗那一丁点,CDN 还会压缩优化。但跟 v2 相比呢?为了这点东西多消耗了多少倍?我做了个粗略的比较:
新旧两版同时打开首页,然后打开第一篇文章
# blog.nest.moe
58 requests | 488 kB transferred | 1.3 MB resources
# localhost
56 requests | 1.3 MB transferred | 2.7 MB resources
显然,社区里面被这个新特性苦恼的使用者不止我一个,Nuxt 官方的人员也有回复这么干的原因:
In Nuxt Content v1, we used LokiJS for the query builder which is now unmaintained for years.
In Nuxt Content v2, we used unstorage + our own query builder which was slower and making the server bundle bigger (was impossible to deploy on workers for instance).
冷静下来我的觉得是这是一个侧重程度的问题,究竟要重服务端,还是要客户端。作为开发者是很难实现完美平衡的
Nuxt content 的定位很尴尬,要作为 CMS 比它成熟的现成的方案多种多样,也没有选它的必要
这个博客一年都出不了几篇文章(那还不赶紧多写点?),自然就没有任何更新上去的理由
等到 v2 彻底被抛弃并且出现漏洞时(?),大概也是我跟 Nuxt 说拜拜的时候了
7:42 · 28 Apr, 2025
关于 vibe coding 的争论已经够多了,我无意加入,只是复盘一次修 bug 的过程
Tweet Listener的爬虫和主站通信使用的是一套运行在 WebRTC 上的内部 RPC,但在一次更新以后,爬虫因为无法从账号池获取到账号而停机
这问题挺好解决的对吧,找到哪里出问题修了就好了,但问题这时就出现了,前期我出于偷懒并没有打 log,导致根本不知道问题出在哪里,只能把 error log 打出来,然后继续跑直到下一次停机
等到第二次停机,我发现根本没有什么 error,log 非常干净:在一次常规的掉线重连以后爬虫就进入了神秘的单向通信的状态——能上报数据,但接收不到任何主站下发的配置和账号。数据进了 webrtc.DataChannel.Send()
以后就消失了,但 Send()
也没返回任何错误,然后就卡在这里好几个星期,期间我为爬虫加了一小段代码,用于检测来自主站的消息,当一定时间内接收不到消息时直接 os.exit(1)
,让守护程序去保证重启。然后还考虑了组网软件 zerotier 和 tailscale 的影响,停止使用组网的内网 ip,改成直接通过公网 ip 连接
但问题一直都在,并且还是捉摸不透,连稳定复现的办法都没有。不过还是有一点好消息的:停机越来越频繁,一般不超过 30 小时就能出现一次
我精简了整个项目的代码,整理出简单的 WebRTC 服务端和客户端,这两个端的工作就是不断连接,连上以后尝试互相发送消息,接收成功以后就断开重连……不断重复,希望能找到原因,期间还是一无所获,我还很迷惑 pion 没有 debug 级别的 log 吗,翻了 issue 都是直接贴代码,没看到几个会贴 log 的……好神奇的 debug 手法
终于,在一次偶然的机会,我重新查看 pion 仓库的 examples 目录,找到了一段打 log 的示例,修改了代码过了两天以后,最终于有好消息传来:
customLogger Warn: Failed to start manager: connecting canceled by caller
customLogger Warn: Failed to start SCTP: DTLS not established
customLogger Warn: undeclaredMediaProcessor failed to open SrtpSession: the DTLS transport has not started yet
customLogger Warn: undeclaredMediaProcessor failed to open SrtcpSession: the DTLS transport has not started yet
有了这几行文字,自然就能搞清楚问题所在,那么修复手法也就显而易见了:
- Peer.OnICEConnectionStateChange(func(state webrtc.ICEConnectionState) {
- log.Printf("Peer ICE Connection State Changed: %s [%s]\n", state, rtcContext.Addr)
+ Peer.OnConnectionStateChange(func(state webrtc.PeerConnectionState) {
+ log.Printf("Peer Connection State Changed: %s [%s]\n", state, rtcContext.Addr)
switch state {
- case webrtc.ICEConnectionStateConnected:
+ case webrtc.PeerConnectionStateConnected:
OnConnected()
- case webrtc.ICEConnectionStateDisconnected, webrtc.ICEConnectionStateClosed, webrtc.ICEConnectionStateFailed:
+ case webrtc.PeerConnectionStateFailed, webrtc.PeerConnectionStateClosed:
rtcContext.Close()
}
})
很简单的 bug 对吧,一下子就修好了
现在 bug 修完了,那么 vibe coding 在哪里?接下来就到 chatgpt 的聊天记录复盘了
去年 12 月想到这个需求的时候我对 WebRTC 一无所知,就一路顺着 chatgpt 的话来写——它给什么我用什么,顶多就简单改改,再经过简单测试一下就上线了
在 OnICEConnectionStateChange
这里我直接拷贝了代码粘贴上去运行,后面就没看了。其实我只需要往下拉大约 200vh
的网页内容,就能看到用 OnConnectionStateChange
的正解
但那时我连个概念都没有,怎么会思考两个事件之间会有什么异同呢。并且复现条件要求 ICE 连上但 DTLS 未连接……那么特殊的条件,webrtc.DataChannel.Send()
默认还不抛出 error,谁都不会第一时间想到这种原因,只能一点一点试。现在复盘可以站在上帝视角知晓一切,而在当时,就算我去提 issue,连稳定复现都做不到,又怎么描述呢,总不能 “各位别着急,可能下一秒复现,也可能要等几个星期。另外复现要求东京和洛杉矶各买一台服务器” 吧?
那么为什么在使用 WebRTC 后,那次更新前又不会停机呢?原因正好就在那次奇怪的更新为了配合特殊用户组自部署的特性,收紧了爬虫的权限:以前爬虫从主站获取账号池的地址和金钥自行连接获取,更新后只能通过主站获取这些配置。账号池跟爬虫位于同一台设备,所以可以非常可靠地直连,而爬虫在设计上只要有稳定的账号供应就能运作(先有爬虫,后来才有主站),所以连接到主站不是必须的;即使连接出现问题上报还是正常的,而启动后第一次连接基本都是正常的,没有任何问题——我连发现监听了不合适的事件的机会都没有
我也是老菜鸟了,也用过很长时间的 LLM 辅助编程,在无脑相信 LLM 的内容编程时还是翻车了——面对不熟悉的地方连有错有漏都不知道,更别说发现问题在哪了。那么那些时间线上各种零基础管杀不管埋的补光灯,是怎么回事就不用多说了……
2025-05-02 补充
半个月前写的,然而现在时间线好像见不到这些怪人了,另外爬虫也正常运行已经一百多个小时了(修了别的导致崩溃的 bug 重启过)
16:00 · 13 Apr, 2025
用 Golang 和 Nuxt 重写了一个 PHP 软件,到插件系统时懵了,最后花了点时间折腾出来了,这里记录一下思路
// /plugins/hooks.go
type PluginInfo struct {
Name string
// ...other data or func
}
var PluginList = make(map[string]PluginInfo)
func RegisterPlugin(name string, plugin PluginInfo) {
PluginList[name] = plugin
}
/plugins/
,通过 init()
调用 RegisterPlugin()
自动将插件信息注入到 PluginList
// /plugins/example.go
func init() {
RegisterPlugin(ExamplePlugin.Name, ExamplePlugin)
}
type ExamplePluginType struct {
PluginInfo
}
var ExamplePlugin = ExamplePluginType{
Name: "example1"
//...
}
<!--/pages/some-page.vue-->
<script setup>
definePageMeta({
plugin_name: 'example1'
// ...
})
</script>
<!--/pages/another-page.vue-->
<script setup>
definePageMeta({
plugin_name: 'example2'
// ...
})
const router = useRouter()
console.log(router.currentRoute.value.meta.plugin_name)// example2
console.log(router.getRoutes().find(route => route.name === 'some-page')?.meta.plugin_name) // example1
</script>
9:16 · 10 Oct, 2024
万恶起源是有一天发现屏幕冒了条绿线,手机是21年1月买的,上官网找了一下保外物料的价格:¥1150……还是凑合着继续用好了,然后就这么用了差不多一年。
直到昨晚吃过饭又有点受不了十几条绿线,去搜才发现一年前一加就已经针对这事提供以无修无摔无进水为前提的保外免费换屏,但官方从来都没有公开宣传过(印度那边的换屏政策也是通过媒体宣布的,一加官方对于这政策没有留下任何记录),于是今天爬起来做完备份就直接跑去本地的 OPPO 售后换屏,顺便自费换块电池。
一套流程(检测->拆盖->拆机->换屏/电池->组装->清胶打胶封盖->下载 H2OS 刷机->校准指纹传感器)下来大概耗时 2 小时,前 1 小时修机,后 1 小时刷机,我使用的 PixelExperience 没有一加的工程模式,要校准就只能刷回官方的系统,选择 ColorOS 是不可能的,我又不可能让中国售后给我刷 OxygenOS ……那只能折中一下刷大氢了……
下面是工单节选:
序号 | 收费类型 | 物料名称 | 零售价 | 数量 | 优惠金额 | 理赔金额 |
---|---|---|---|---|---|---|
1 | 维修 | 电池组件 | ¥119.00 | 1 | ¥0.00 | ¥0.00 |
2 | 维修 | 屏幕上盖组件 | ¥1150.00 | 1 | ¥1150.00 | ¥0.00 |
物料原价合计:¥1269.00,单项优惠金额合计:¥1150.00,理赔金额合计:¥0.00
刷机期间有一台 9R 来送修,一看屏幕又是熟悉的绿线……
再后续是刷氧刷 PE 折腾到两三点:自从网页不再发布完整卡刷包以后,一加发了很多 OTA 完整包,我又没有这些包只能每次都下载安装一步一步更新上去,费了很多时间。恢复备份弄到四五点
希望这玩意能再战三年
8:29 · 5 Aug, 2024
折腾某个 DePIN 项目(互联网是一个圈,早年的挂机网赚玩法换个皮又出来了)要用到 Chromium 插件挂机,拿我自己的笔记本挂怕是到最后连电费都交不起……最后翻箱倒柜找出当年的树莓派3B+
系统是 Ubuntu 22.04.4 LTS,装上 KDE 、 xrdp(我主要用 Windows 系统自带的 RDP 客户端,如果是其它系统可以用 VNC 代替) 和 Chromium 挂机就完事了
apt install kde-standard xrdp chromium-browser
这篇应该会在发币后公开(看看能有多少收益 :))
You’ve Successfully Claimed 55.04 GRASS
也太抠了
啊?怎么就四倍了???
3:00 · 3 Aug, 2024
虽然可能没什么用,不过既然花了点时间研究就顺便发出来吧
首先我要说的是这玩意没什么用,因为它并不开源,用户只能通过 npm 拿到混淆后的版本,其次文档也等于没有,参数给了也不一定会用到,不论是 官方demo 还是 用户自己实际体验 都跟 官网demo(注:官网需要登录 Google 帐号) 的体验不一致
官方似乎就没考虑过给 Node.js 等非浏览器运行时使用,硬是塞了一个完全没用上的 canvas API
进代码,最后导致其他运行时用不了
所以要用就得改改文件,由于 npm 包内的文件内容会被压缩到一行,所以要修改的部分基本都是在同一行的,需要单独搜索找到并修改
同样是因为被压缩到一行,所以我懒得放出特别大的 patch 包……尤其是在这个一次会加载全部内容的碎片栏目
# node_modules/@mediapipe/tasks-text/wasm/text_wasm_internal.js
## begin
#### note: esm only
+ import fs from "fs";
+ import path from "path";
+ import crypto from "crypto";
+
+ import { fileURLToPath } from "url";
+ import { dirname } from "path";
+ const __filename = fileURLToPath(import.meta.url);
+ const __dirname = dirname(__filename);
+
+ const nodePath = path;
+ const crypto_module = crypto;
#### ---
#### note: esm only
- var fs=require("fs");var nodePath=require("path");
- var crypto_module=require("crypto");
#### ---
### replace
- if(typeof custom_dbg==="undefined"){function custom_dbg(text){console.warn.apply(console,arguments)}}
+ function custom_dbg(text){console.warn.apply(console,arguments)}
#### ---
## end
### replace
#### note: esm only
- if (typeof exports === 'object' && typeof module === 'object')
- module.exports = ModuleFactory;
- else if (typeof define === 'function' && define['amd'])
- define([], () => ModuleFactory);
+ export default ModuleFactory
# node_modules/@mediapipe/tasks-text/text_bundle.mjs
### replace
- void 0!==e?this.h.canvas=e:Ui()?this.h.canvas=new OffscreenCanvas(1,1):(console.warn("OffscreenCanvas not supported and GraphRunner constructor glCanvas parameter is undefined. Creating backup canvas."),this.h.canvas=document.createElement("canvas"))
+ this.h.canvas=null
### replace
- if(e&&await Oi(e),!self.ModuleFactory)throw Error("ModuleFactory not set.");if(n&&(await Oi(n),!self.ModuleFactory))throw Error("ModuleFactory not set.");return self.Module&&r&&((e=self.Module).locateFile=r.locateFile,r.mainScriptUrlOrBlob&&(e.mainScriptUrlOrBlob=r.mainScriptUrlOrBlob)),
#### note: next line is ending with a space " "
+ return
然后就是很不优雅的使用,需要提前将模型下载到本地
import { LanguageDetector,FilesetResolver } from "@mediapipe/tasks-text";
import ModuleFactory from "./node_modules/@mediapipe/tasks-text/wasm/text_wasm_internal.js";
import { readFileSync } from "fs";
globalThis.ModuleFactory = ModuleFactory;
global.self = globalThis;
const buf = readFileSync(`./language_detector.tflite`);
const wasmFileSet = await FilesetResolver.forTextTasks('./node_modules/@mediapipe/tasks-text/wasm')
const languageDetector = await LanguageDetector.createFromOptions(wasmFileSet, {
baseOptions: {
modelAssetBuffer: new Uint8Array(buf),
maxResults: -1
},
});
const textData = "hello";
const result = languageDetector.detect(textData);
console.log(result);
// Graph successfully started running.
// INFO: Created TensorFlow Lite XNNPACK delegate for CPU.
// WARNING: Attempting to use a delegate that only supports static-sized tensors with a graph that has dynamic-sized tensors (tensor#15 is a dynamic-sized tensor).
// W0714 11:12:40.749000 678624 inference_feedback_manager.cc:121] Feedback manager requires a model with a single signature inference. Disabling support for feedback tensors.
// {
// languages: [ { languageCode: 'en', probability: 0.5111953616142273 } ]
// }
我也不知道为什么只能返回一种语言,鉴于 官方demo 其实也只会返回一种语言,我也无话可说了
10:27 · 14 Jul, 2024
我一直在用中文写作的原因其实很简单……外语没学好,与其写出非中文和中文使用者都看不懂的奇怪表达,不如用中文写明白写清楚,写到即使机翻也能轻松转换
不过,我还是进行了新的尝试,前两天我上传了一篇拿 GPT-4o 翻译的库存文章,未来可能还会上传这种机翻润色的文章来帮助到非中文的读者。
现在归档页面是全语言的文章混合的,未来可能会按照语言来拆分不同的栏目,并且做好其他仅中文的组件的翻译工作
The following part is translated using GPT-4o.
The reason I've been writing in Chinese all along is quite simple: I haven't mastered foreign languages. Instead of producing strange expressions that neither Chinese nor non-Chinese speakers can understand, it's better to write clearly and intelligibly in Chinese, so that even machine translation can easily convert it.
However, I've tried something new recently. A few days ago, I uploaded a previously written article translated by GPT-4o. In the future, I might upload more machine-translated and polished articles to help non-Chinese readers.
Currently, the archive page mixes articles in all languages. In the future, I might split it into different sections based on language and ensure proper translation for other Chinese-only components.
16:30 · 10 Jul, 2024
最近在折腾贴吧列表,为了方便处理数据,我把数据库转成 json
再进行处理
7:20 · 13 Feb, 2024
年初我就想着去更新我那个早在 2018 年就过期的护照,结果一路拖到年末才去,前后10分钟就搞定了,之前在网上看的一大堆“教程”似乎也没什么用
在移民局小程序预约最大的作用是提早填好一大堆琐碎的东西,不必到现场再填,现场并没有多少人,所以不看预约,直接去也是可以的
拍照可以现场用自助机拍照,至于要穿有衣领的衣服什么的古早规定早就不用在意了……
然后就是经典的提交相片回执和身份证,签名,交钱,然后就没了
邮寄 18CNY 每本
旧护照/通行证也不管,不回收也不剪角,所以可以不带
最后战绩:
后续补充:
移民局小程序查到待取证状态就可以带身份证直接去自助机取了,那张写着要带的回执并没有用上
另外自助机真的很慢很慢……
11:07 · 14 Dec, 2023
Some twitter api endpoints location
* I made a mistake, NOT ALL verified accounts send tweets to Atlanta
3:16 · 21 Oct, 2023
最近学习了一番怎么写高并发的爬虫
首先丢掉的是用了很久的 Node.js,类型转过来倒过去时间就被浪费掉了,想了半天我还记得又便于部署的语言,就剩下 golang 了
然后到了各种被各种“教程”写到烂的优化办法,我就不细讲了
Transport
的连接池保留多少连接
超时肯定要设置的,不然等着卡死吧json.NewDecoder(..).Decode(...) / json.NewEncoder(..).Encode(...)
替代更慢的 json.Marshal() / json.Unmarshal()
,同时关掉 json.NewEncoder(..)
的转义 html 选项然而还是有个一个奇奇怪怪的接口,它的反爬手法是限制单个 tcp 连接的总请求数…… stackoverflow 的回答说 http.Client
没有这个方法,得自己手操 tcp 连接池(net.Dial()
),GPT 只会跟我说要 response.Body.Close()
,手操连接池什么的还是饶了我吧……经过几天的现场学习,我暂且算是想到了一个解决办法,丢在这里算是抛砖引玉吧
package main
import (
"io"
"log"
"net/http"
"time"
)
func initClient() *http.Client {
var transport = http.DefaultTransport.(*http.Transport).Clone()
return &http.Client{
Timeout: time.Second,
Transport: transport,
}
}
var sequence = 0
var client *http.Client
var maxConnection = 100
func main() {
client = initClient()
var requestTicker = time.NewTicker(time.Millisecond * 100)
for {
select {
case <-requestTicker.C:
if sequence%maxConnection == 0 {
client = initClient()
}
go func() {
req, _ := http.NewRequest("GET", "http://example.com", nil)
response, err := client.Do(req)
if err != nil {
log.Fatal(err)
return
}
defer response.Body.Close()
str, _ := io.ReadAll(response.Body)
log.Println(string(str[:]))
}()
sequence++
}
}
}
大概思路就是次数够了就创建一个新的 http.Client()
,再用指针 client
指向它,原来的 http.Client()
会继续执行到结束,然后被 GC 回收 <- 不知道 GPT 有没有坑我
8:15 · 15 Oct, 2023
最近 Twitter 费尽心思在阻止用户和开发者匿名访问推文内容,尽管我在 nitter 的 issue 提出取得访客帐号并签名请求的方案,但在本篇我也提到过要运行这玩意需要大量的访客帐号,所以单打独斗可能不是一个好的办法。
压力大时我就会胡思乱想,想着能不能构建一个分布式的帐号池,由于 Twitter 客户端的请求统一采用 OAuth 签名,这一套方案甚至能在访客帐号彻底失效后继续由人工录入 userbot 的各种信息的方式延续下去。
架构我就参考 ZeroTier,总共分成三级:
Planet 可以开放 API 供外部调用,发号顺序应该是 本机的访客帐号 > 同步来的访客帐号 > 本机的 userbot 帐号(如果开放)
这只是一个想法,还有很多不完善的地方,暂时想到的:
当然啦,这只是我的一点想法,目前我还没有时间和精力去完善那些问题,甚至还没新建文件夹。
也许只是又一个在我的胡思乱想下的无用产物。
19:38 · 21 Aug, 2023
在两个月前的某一天,我就想到了我这个 blog 的标题栏的那个 の 很适合拿来替换成各种各样的元素,于是这个组件的雏形就出来了:
至于怎么引入 svg,我试了好几种,目前的方案是 @iconify-json + @unocss,这并不是最优解,我还需要自己在 uno.config.ts
加 safelist
动画用了点奇技淫巧,本来我想像轮播图那样滚动,js 控制当前要显示的元素,css 控制动画,于是不同步的计时器就会导致动画跑完了图还没切最后一闪而过的问题,最后选择用 position: absolute
+ display: none
来让所有元素都堆在同一位置,再把进出的动画拆分,当下一个元素显示时当前元素会淡出,最后不透明度变 0
,从视觉上消失
19:45 · 15 Aug, 2023
前段时间心血来潮写 chāo 了个类似 Twitter 生日气球的组件,因为是 vue 组件所以这边也能玩,点卡片右下角的气球标就会放气球,鼠标移上去就可以戳爆了,气球跑完以后再点再放
跟原版有小改动以适应博客环境,未来会加入好玩的组件大包中。
17:27 · 5 Aug, 2023
最近用 GitHub Actions 来更新静态资产,由于涉及到爬虫,需要跟第三方网站交互,我感觉用官方实例来跑有可能会像那些跑签到脚本的仓库那样被封,终究还是自托管一个实例。
吐槽几句:
npm i
直接跑挂了,不知什么问题known_hosts
,最后自己换上去就好了,没有用 KNOWN_HOSTS_FILE
是因为文档也没细讲干脆一改了之ci/cd + cron
的方案(主要是简单了解一下市面上的那些 ci/cd 占内存都是以 GB
为单位的,而我的小鸡的内存 1GB
都不到16:12 · 5 Aug, 2023
怎么说呢……体验就是很难受:
BIGINT
转成 TEXT
,只能自己想办法,找了半天找到一个 CAST(<AA> AS text) AS <AA>
,然后就是很苦逼地挨个去拷贝粘贴 attributes: [
[Sequelize.options.dialect === 'sqlite' ? Sequelize.literal('CAST(value AS text)') : 'value', 'value'],
]
MATCH...AGAINST
,MATCH
还在研究怎么搞,REGEXP
那个耗时看着就头疼,最后只能回归 LIKE%%
大法WAL
模式也救不了,写都写不进去;高 I/O
的查询直接歇菜,动不动就是几十秒的耗时吐槽归吐槽,最后还要继续折腾……
18:50 · 24 Jul, 2023
一直都有听说 B2 桶,但注册以后用不上只能摆在一边吃灰,最近准备将跑了三年半的 bing 每日图片丢上云,于是这玩意就成了省钱利器。
什么注册账号配置代理这些烂大街的内容就不说了,看 如有乐享的文章 就好。
这里就补充一个,应该是前人写文章时还没出的功能:Redirect Rules。
(http.host eq "b2.example.com" and http.request.uri.query ne "")
Type | Expression | Status code |
---|---|---|
Dynamic | concat("https://b2.example.com", http.request.uri.path) | 301 |
其中那个 b2.example.com
改成自己的 host
这样做主要是防止被有心人无限改查询字符串刷调用次数,毕竟 2500
次动动手指就刷完了。
17:20 · 20 Jul, 2023
先把证书导出来得到一个 FiddlerRoot.cer
,
openssl x509 -inform der -in FiddlerRoot.cer -out fiddler.pem
file1=$(openssl x509 -inform PEM -subject_hash_old -in fiddler.pem | head -1)
cat fiddler.pem > "$file1.0"
openssl x509 -inform PEM -text -in fiddler.pem -out /dev/null >>"$file1.0"
file2=$(openssl x509 -inform PEM -subject_hash -in fiddler.pem | head -1)
cat fiddler.pem > "$file2.0"
openssl x509 -inform PEM -text -in fiddler.pem -out /dev/null >>"$file2.0"
然后将生成的这两个文件拷贝到 /system/etc/security/cacerts/
目录下,重启设备。
4:20 · 7 Jul, 2023
拿 Svelte 来重构了一下blog,虽然最后没完成,不过还是挺有意思的,处理 Markdown 的生态一般,有种 戴着镣铐跳舞的感觉。
留下了一个本来用来替换掉右下角 NuxtJS
标的玩意。
9:14 · 30 May, 2023