阅读视图

发现新文章,点击刷新页面。

分享一下我构建的 图书元数据库 API

前言

自从国内图书界最大的【豆瓣读书】关闭公共 API 后,很多图书元数据削挂插件都失去了作用,所以我自己使用手上现有的资源制作了一个新的 API 服务,地址:https://book-db-v1.saltyleo.com/

本文的主题是分享一下我做出来的新玩意,欢迎各位大佬调试~

使用方法

端点URL: https://book-db-v1.saltyleo.com
请求方法: GET
响应格式: JSON

你直接点击这个链接,:https://book-db-v1.saltyleo.com/?keyword=刘慈欣 ,就可以得到与【刘慈欣】有关的前 10 本图书信息,对于开发者,直接解析 JSON 即可使用。

如果是非开发者,只想在网络上找到心仪的电子书,那直接去我的书架找更快些:SaltyLeo的书架

我做了什么?

我之前不是做了一个电子书查询网站嘛,在收集数据的过程中我发现,很多电子书网站的书籍信息都很少,往往就一个名字。手动去搜索引擎找也不是不行,就很低效,所以做出了这个 API 方便我了解书籍信息。

想着既然都做出来了,独乐乐不如众乐乐,索性就将其公开了,之所以提供 API 方式调用,也是为了方便其他人如果也想做自建书站,或者开发新的削刮插件的话,直接调取 API 获取数据即可,省去了很多收集数据,处理数据的时间,直接解析 JSON 即可放在项目上使用。

这只是第一版的 API,所以数据内容偏少。会逐渐补充。而且我对于大数据领域还是蛮感兴趣的,这个API 会稳定迭代,也会长期运营。

后端是基于 CloudFlare Worker 部署,费用几乎为零,当然为了避免高额的账单,我通过 CloudFlare 设置了最大 QPS,限制为 10,也就是说,每秒最多访问 10 次,这对于一般数量的电子书削刮来说已经够用了,1 分钟可以处理 600 本书呢,小规模数据稍等片刻就能处理完毕。如果你是有几十万本,或几百万本的,你可以使用 IP 池,或其他多线程爬虫技术。反正要是快被刷爆了,我会进一步限速的😏

后记

有了 AI 的加持,以前要深入了解学习后才能实现的事,现在变得很轻而易举了。学习的速度呈指数增加,像是 JS 我到现在对它还是一知半解,但不妨碍我能够让 AI 帮我写我所需要的功能,我觉得低代码和无代码还是不可靠的,AI 生成的代码片段总是有各种而样的BUG,需要手动修复。

最后,我只做了一些微小的工作,将散落在互联网上的数据略微做了整理和归纳,不值一提。

使用 Cloudflare Worker 部署一个简单的停靠页

前言

最近因为工作太忙了,脑海中有很多 idea 都没输出,先从简单的开始写吧。最近打算写一个新的网站,但在正式上线之前,我想要先将域名弄好,顺便弄了一个停靠页面,什么是停靠页呢?

就是像上面这张图片一样,内容你可以随意自定义。实际上功能你也可以随意自定义,只要你会写 JS。下面的内容就是如何使用 CloudFlare 的 Worker 服务部署停靠页。

创建 Wroker

注册和登录 Cloudflare 我就不赘述了,我们先创建个 Worker。在首页上,点击左边侧边栏的 Workers 和 Pages,就是下面这个按钮:

一进来,它会给你介绍,这个功能模块是干嘛的,略过,点击创建:

在进入创建应用程序页面,点击创建Worker:

cloudflare 会要求你为项目命名,你可以随意使用自己想要的名称,输入后点击保存后再点击右下角的完成:

会弹出个预览界面,直接点击完成即可:

编辑代码

上一步骤要等待几秒钟,就会弹出下面的界面:

此时点击右上角的编辑代码,我们将会进入一个类似 Vscode 的编辑器界面,如下图所示:

我的代码我放在这个链接了:Worker 代码,将里面的代码复制粘贴到 CloudFlare 的编辑器中,像是这样就可以了,参考下面的图片:

然后点击右上角的部署按钮即可。

设置自定义域

上述全部完成后,在 Worker 的设置> 自定义域 中设置一个你想要停靠的域名端点。我这里使用的是 https://book.tstrs.me,你可以使用任何你部署在 CloudFlare 中的域名。

后记

这个停靠页本来是计划使用在我自己的一个小项目上的,计划先启用域名,部署了一个停靠页警示自己,尽快完成。但稿子迟迟没写,网站都上线了,文章才发布。

网站就是上面自定义的域: https://book.tstrs.me,欢迎大家帮我找bug哈~

最近在学习 JS,无服务器部署真的是太爽了,不需要考虑用什么做后端基础设施,一次部署,全球访问,并且绝大部分地方访问速度都非常的快。而且 Cloudfalre 还有 D1 数据库、KV 键值对,任务队列,各种服务都是为了云原生设计的,真的是一把梭。

现在都2024年了,写博客的意义是什么?

引言

不少老观读者肯定发现,我把域名换掉了!没什么特别的原因,因为这是我的博客,用我最喜欢的昵称作为域名这很合适。之前的域名已经完成了它的历史任务,后续我也会继续付费直到它流量归零为止。

2017 年春,我开始写博客,一开始只是为了好玩,也很酷。不过后来懒散了,断断续续写了几年。虽然我不怎么更新文章,但我系统更新的勤啊,除去 Wordpress 和 Hexo 这已经是我第三版自己写的博客系统了。

谨以此文,纪念新域名的第一篇文章,也记下我理解的写博客的意义。

自我表达

2024 年了,人心愈加浮躁,生活也愈渐无聊,越来越难沉下心认真学习理解新鲜事物了,笔记软件中,idea 记录的越来越多,真正开始写的却没几个,像是本文,去年就新建了一直拖着没写。

如果天天只消费内容(例如刷抖音、小红书),而迟迟没有输出内容,大脑就会适应这样的回路,早晚会生锈。虽然有些迟滞,我还是慢慢的将这篇文章写完。技能是需要练习的,无论是生活、工作还是兴趣,都需要反复练习才能够持续精进。

对于我来说,这个博客可以看作是记录我学习成长的一本笔记。现在回过头看看以前写的文章不得不感叹,真的是太幼稚了。不过学习是一个循序渐进的过程,所有人都是从最简单基础的知识开始学起的,现在呢,各种杂七杂八的技术都学了一些,这就有了现在的这个博客。

所以我觉得,写博客的主要意义就是【自我表达】:将自己的所思所想用文字的方式记录下来,输出内容才是最好的学习。

知识分享

我在自学的路上,总是会遇到各种各样的问题,绝大部分的问题都可以通过 Google 找到解决方法。这是为什么呢?因为这个世界上绝大部分的问题,从前有人已经遇到过了,并且在网上分享过他们的解决方法,所以我们可以轻而易举的参照资料解决当下的问题。

这样解决问题,不过是站在巨人的肩膀上罢了。但有的时候,通过翻阅大量资料都没找到答案的问题呢?我就会将其记录下来,以备我日后可能的查阅,并且我会将其分享到我的博客中,让后来的人可以参照我之前的解决方法。

最近了解到一个概念:流体智力、晶体智力。流体智力是指在混沌状态中发现意义、解决问题的能力,一般会在 20 岁到达顶峰。晶体智力是指在成长过程中接触到的各种知识技能沉淀结晶变成属于你自己的能力,一般会持续增长到 65 岁。

现在生成式 AI 越来越厉害,国产 AI 更是百花争鸣,经过一年多的追赶,我觉得使用上已经和 ChatGPT 没有太大的差别了。把问题丢给 AI 去解决就是流体智力,当我们下次遇到这个问题能够自己独立思考并解决就是晶体智力。

我认为存在于大脑之外的知识都不属于自己的,虽然 AI 知道这个世界上所有的知识,但它并不能解决所有的问题,所以我们要不断地打磨自己的晶体智力。将学习会的知识再传授给其他人,这样会让我们的对于知识的掌握和理解更加深刻。

篆刻印记

之所以将域名切换到现在这个就是因为我觉得,一个网站,它的域名必须和它的主题契合。博客的名字从 2021 年开始就叫做《SaltyLeo的博客》了,可域名还是长得跟乱码一样,越看越糟心,所以 23 年底买了现在的域名。

当我写的文章越多,那么我在互联网上的印记就越深,之前一直迟迟不迁移,是因为对于流量、反向链接、引荐等,有很深的执念,但我现在不那么在乎了,因为我认为博客是写给未来的自己看的。对于搜索引擎,有索引更好,不索引我也无所谓。

现在我认为啊,博客就像是我们在互联网上的家一样,有的人家里炫酷无比、有的很温馨、有的很文艺,这没有任何的好坏之分,只是风格不同。我将 Google 的广告全部撤下了,这点流量带来的广告费连杯咖啡都付不起,可对于读者来说,就像是牛皮藓一样恶心。谁会想在家门口和家里贴广告呢。

后记

很早以前老家的门口因为修马路抬高了路基,抬高了快有2层楼,沿着路边的房子如果不跟着抬高,就会像是住在地下室一样。当时家里重建了房子,可门前的柚子树却没办法抬高了,因为它太大了,所以当时是直接用土将宅地基的地面堆高到和路面齐平。我还记得那年秋天,当地基的打好后,我站在地上摘柚子,以前那可是要站在梯子上才能够得到的啊。

因为树被埋在土里了,家门口没有了树荫,长辈就重新种了一棵树苗,那树苗瘦的根竹竿似的,为了防止它被人撞倒,还用了一个水泥管保护它。每次回老家的时候,都会觉得它长高了,最近一次看到它已经长到快三层楼了。

总结一下吧,我觉得写博客呢,和种树很像。

🌱 首先,要选择一个小树苗,先种下去。

学习搭建博客相关的知识,尝试搭建部署博客。

🌞 接着,必须需要给它足够多的营养和阳光,让它能够破土而出。

在重试第 N 次后,终于博客成功上线了。

💧 当它开始慢慢长大的时候,要时不时为这颗树苗浇水施肥和除虫。

我们再一点点写文章充实它,当出现 bug 的时候修复它,要有足够的耐心和恒心。

渐渐的培养它、照顾它,随着时间的流逝,你将得到一颗枝繁叶茂的大树🌳。想做一件事,但不知道应该什么时候开始做的时候,那就现在就做,哪怕磕磕绊绊也要开始做起来。

为 V2ray 启用定时重启,避免内存溢出错误

接前文,我家里不是搭建了一个 V2ray 的全局代理么,要是持续运行太久,内存估计会吃不消,所以我在网上找到了一个小脚本,定时重启它。

系统要求

本脚本必须要系统支持 systemd,我用的是Ubuntu,自带 systemd。

教程

首先使用命令 nano /usr/local/restart 创建一个脚本文件,输入:

#!/bin/sh
systemctl restart v2ray

再创建一个服务,使用命令 nano /etc/systemd/system/restart.service,输入:

[Unit]
Description=Restart V2Ray
[Service]
Type=simple
ExecStart=/bin/sh /usr/local/restart

然后再创建一个定时器,使用命令 nano /etc/systemd/system/restart.timer,输入:

[Unit]
Description=Retart
[Timer]
OnBootSec=24h
#首次启动后多少小时执行
OnUnitActiveSec=24h
#每隔多少小时执行
Unit=restart.service
[Install]
WantedBy=multi-user.target

最后一步执行以下命令激活这个定时器即可:

systemctl start restart.timer && systemctl enable restart.timer

联通腾讯大王卡 - 个人 V2ray 免流方案的一些研究与探索

本文撰写于2023年12月5日,已经稳定使用半年有余,好东西当然要分享啦,所以写出来给大家参考参考。

前言

对于手机重度使用者(我)来说,流量就像是空气,没有流量就不能活,但我用的又特别多。

我两年前写的那篇文章 《使用 V2ray 与小火箭实现联通移动网络下免流翻墙~》 介绍的联通手厅免流 host 已经不好用了,后来年中特别忙,懒得折腾就买了个29包月的流量卡先顶着,但两张卡对于我来说还是不方便,所以我又继续研究我的大王卡了。

原理

为了照顾到不怎么太懂的网友,我简单讲讲免流的原理。免流是运营商和一些平台方合作的产物,当用户使用移动网络访问这些平台的时候,运营商会根据访问的域名进行筛选,符合免流政策的访问流量就计入到免费流量中,不收取用户的通用流量费用。

而 V2ray 呢,可以通过使用混淆的功能在通过运营商网络到达节点服务器之间,伪装成符合免流政策的域名,进而实现免流的效果。

但最近联通正在逐渐收紧免流政策,针对公免已经几乎没有多少挣扎空间了,还是定向流量比较稳妥些。

最新的解决方案

截至2023-12-13,稳定使用中。

手机套餐

首先先讲讲我的套餐政策吧,我使用的是腾讯大王卡月租:19/月,它套餐内有 3GB 的通用流量,我这个是最早办的那一批,所有腾讯系 App 可以免费使用40GB流量,因为免流的关系,我又开了虎牙的 12 元 12G 的定向免流包,本文的重点就是这 52GB 流量的利用。

宽带

我家的宽带是联通 1000M下行/200M上行,有公网 IP 地址。这里的 200M 上行对于出门在外的移动设备来说就是 200M 下行,这个速度已经非常顶了,下载速度可以达到30M/s,完全能够满足我的使用需求。

服务器动态端口

不确定是 GFW 还是运营商,在我的使用中会如果长时间保持一个连接,就会被莫名其妙阻断,而且这个阻断也不是持续的,就一小会一小会的。

为了解决这个问题,我之前的文章写过《动态端口》但是,那是针对单用户使用的,现在我的副卡也在使用这个免流,之前的方案也就不适用了。

我最新的方案是在路由器上放通了一批端口进入中转机:

然后,在中转机器上使用 iptables 把这些端口呢,全部转发到 v2ray 的入站端口上,相当于这 5000 个端口任意一个都可以连接到 v2ray。

移动端自动切换端口

在我的 iPhone 上呢,我使用快捷指令设置了每半个小时自动切换端口,本身端口数量这么多,所以哪怕阻断了几个也无所谓。

切换端口倒是和之前《文章》中没什么区别,只不过没有了开关端口的指令了,直接随机几个端口出来使用,以下是生成小火箭订阅的两个函数,仅供参考。

免流Host

目前我使用的最新的免流 Host 是这个,非常的稳定,而且可以叠加虎牙免流包直接使用。

tx.flv.huya.com

后记

最终的效果就是手机在使用流量并开启小火箭全局代理的情况下,下行也能实现 200M 的速度,并且免流在达到 52GB 之前都不会收取我任何的额外费用。只不过上传只有 75M 了,这个是由联通5G基站限制的。

我就通勤的时候用用,家和公司都有 WIFI,52GB 完全够用了,这套配置只要腾讯系免流不改变验证机制,我应该是不会再调整了,毕竟太方便了。

使用 Cloudflare 作为动态域名解析服务 (DDNS) 并持久运行

前言

我家里的联通宽带虽然有公网 IP,但时不时的还是会给我换一下,我使用的TPlink的路由器自带DDNS 功能,由于更新的频率并不高,实时性并不强。有的时候掉线了也不知道。

解决方案

所以呢,我在网络上搜索了一下,发现可以使用 Cloudflare 作为动态域名解析服务,为我的公网IP做解析,并且可以设置较短的时间间隔以保证实时性。

Cloudflare 上的操作

首先要获取 Global API Key,前往这个地址:https://dash.cloudflare.com/profile,获取你的key:

然后设置一个计划要设置 DDNS 的域名,这里填写 IP 可以随便填写,反正马上要更新掉的,关键是必须云朵是灰色的。

我这里以 test.tstrs.me 举例:

到这里,Cloudflare 上的操作就完成了。

家里服务器上的操作

首先下载脚本文件:

wget https://raw.githubusercontent.com/SaltyLeo/cloudflare-api-v4-ddns/master/cf-v4-ddns.sh

然后编辑它:

nano cf-v4-ddns.sh

对这几个字段补充完整,括号部分需要删除:

CFKEY=【填写 Global API Key】

CFUSER=【填写 CloudFlare 的登陆邮箱】

CFZONE_NAME=【你的一级域名,比如 tstrs.me】

CFRECORD_NAME=【你的二级域名,比如 test.tstrs.me】

授予可执行权限:

chmod 755 cf-v4-ddns.sh

最后运行一下:

./cf-v4-ddns.sh

如果一切正常,输出应该如下图所示:

设置定时更新

我之所以不用TPlink自带的DDNS就是因为它更新太慢了,不知道什么时候才能更新好,这个脚本呢,可以自由设置更新频率,我这边设置的是2分钟运行一次,这样哪怕出现网络波动,也就只会掉线2分钟,并不算太严重。

我这里使用 crontab 来操作定时任务使用命令 crontab -e 打开定时任务编辑器,填写以下命令,根据你的目录自行修改路径:

*/2 * * * * /root/cloudflare_ddns/cf-v4-ddns.sh >/dev/null 2>&1

后记

到这里DDNS 服务的配置和自动化就已经完成了,系统会每2分钟查询DNS数据,如果IP和当前IP一致,就不会更新,如果不一致,就会更新。

如何在 Windows 上挂载 Linux 系统的目录?

前言

因为在 Windows 下远程连接到服务器上编辑文件不方便,所以我现在使用的是:winscp,但它有个缺单就是挺卡顿的,要是不它和 putty 配合能够替代 termius,我早就把它换掉了。 我有的时候编写代码,是在线修改的,所以通过 winscp 的话,如果发生了数据丢失或者其他的故障,恢复起来很麻烦。 本文将介绍一个简单的在 Windows 下挂载 Linux 服务器目录的方法。

实现

我在网上找到一个非常简单的挂载方法,使用 SSHFS-Win 就可以了。首先需要依次安装以下软件:

1、WinFsp : 下载地址:WinFsp Github:GitHub/winfsp

2、SSHFS-Win : 下载地址:SSHFS-Win Github:GitHub/sshfs-win

3、SSHFS-Win-Manager: 下载地址:SSHFS-Win-Manager Github:GitHub/sshfs-win-manager

然后打开 SSHFS-Win-Manager,点击右上角的 add connection:

在弹出的页面按照提示依次填写你的 Linux 服务器相关信息,最后点击 SAVE 保存:

如果需要持久连接的话,还需要在 ADVANCED 中勾选以下选项:

最后如果要开机自启动的话,在设置界面打开第一个选项即可:

后记

这样挂载好了之后,后续的所有文件操作就只在 Windows 下完成,最大的特点就是方便了,唯一有点遗憾的就是速度会有点慢,不过这个也是本地网络的问题,和软件无关。

每天学习一点新东西,再将其整理输出,让日渐浮躁的脑子平静一些。

为了支持WebP格式,写了一个图片上传小插件

前言

我之前写文章的时候,为了解决插入图片麻烦的问题,我使用了腾讯云的对象储存 (COS) 储存我的图片,使用 PicGo 在 Windows 平台上传文件。

在我网站流量不大的时候一点问题都没有,但流量渐渐起来了后,我发现对象储存每个月的免费流量都会超,虽然超的不多,但这也是一笔额外的开销。而且随着时间的增长,这部分的支出会越来越大,所以我打算将文件储存到我自己服务器上。

而且在Google Search Console里,它说我的图片内容都未经压缩,应该使用更加先进的webP格式,可以更加节省储存空间和带宽。

分析需求

虽然上述的需求在 PicGo 中都有对应的插件可以实现。但是呢,在 PicGo 中操作都非常的不便,我折腾了半天也没实现使用 sftp 传输文件到我的服务器的需求,而压缩功能呢,根本就不能用,插件市场中的两个插件都是调用云端服务来实现的,云端服务更新了api就直接挂了。

所以我打算自己实现一个简单的图片上传小工具,嵌入在我的博客系统中,它的功能非常简单,就只需要实现上传和转换格式的功能即可。

简单实现

这里我就使用了最简单的方式,搭建了一个页面,这个页面只有一个功能:上传图片到服务器,返回 markdown 格式的链接。下图就是最终效果。

tstrs.me_img

它的前端代码太冗长了,我放在 simplenote 了:html_code 前端的功能非常简单,支持选择、拖放与直接 ctrl+v 粘贴图片,后台将会自动处理上传,如果有错误会在控制台报错,一切正常上传成功后,会将后端返回的链接输出在页面上并提供复制按钮。

后端代码:

if 'image' not in request.files:
            return 'No file uploaded!', 400
        file = request.files['image']
        if file.filename == '':
            return 'No file selected!', 400
        try:
            timestamp = datetime.datetime.now().strftime("%d%H%M%S%f")
            filename = timestamp + '.webp'
            now = datetime.datetime.now()
            folder_name = now.strftime("%Y/%m")
            folder_path = os.path.join('/home/wwwroot/img.learn2.cn/new_img/', folder_name)
            os.makedirs(folder_path, exist_ok=True)
            save_path = folder_path +"/"+ filename
            image = Image.open(file)
            image = image.convert('RGB')
            image.save(save_path, 'WEBP')
            return f'![tstrs.me_img](https://img.learn2.cn/new_img/{folder_name}/{filename})', 200
        except Exception as e:
            return str(e), 500

上面代码中的工作逻辑是这样的:检查来自request中的文件,是否为图片文件。如果是就继续下一步,生成新的文件名根据日期生成储存它的文件夹。接着使用 PIL 将图片转换为 WebP 格式,最后将 markdown 格式的链接返回到前端页面以供复制。

上面的代码只是一个思路,并不是可以实际运行的脚本,这种定制化的插件想来也不是所有的人都能够使用。你可以将上述代码稍加修改后移植到自己的程序中。

后记

自己动手才能丰衣足食,很多现成的工具确实不错,但太臃肿了,根本用不到这么多功能。对了,这里面的JS代码绝大部分都是ChatGPT写的,我只是修改了api部分~

最近两个月工作太忙了,这博客都快变成月更了。累积的稿子已经非常多了,后面会慢慢更新。

使用 Python 配合 Shadowrocket 为 V2ray 启用真·动态端口!

前言

我在日常使用中发现移动网络运营商或者 GFW 会对长期与某一个固定境外 IP 端口的连接进行干扰,严重的时候直接无法访问启用了 V2ray 服务的端口。那么如何应对呢?

分析

首先简单介绍下我的设备和网络环境,我的移动设备是一台 iPhone,上面安装了 Shadowrocket,当我长时间使用某一个节点后,会间歇性的无法连接,这个过程会持续好几个小时然后又突然恢复。

我的 V2ray 节点是自己部署在韩国节点的,使用的加密方式是 Websocket+TLS,本身的速度虽然不是特别快,但绝对不会卡顿成这样,每次卡顿的时候我手动更改端口后就可以立即恢复正常,所以应该是 GFW 在从中作梗。

解决思路&方案

我简单讲一下我的解决思路吧,花了点时间研究了一下 V2ray 自带的动态端口功能,虽然可以解决我的需求,但这还是需要一个主端口用来通讯,这样情况下主端口被干扰的话,也会无法使用。

动态端口-V2ray

而服务器上自动定时更换端口不现实,因为我的移动设备并不知道当前最新的端口是什么。那么要如何才能让服务器更换端口后,移动设备又能知道当前的端口号呢?

Python伪代码

下面是我写的一个小脚本,使用了 Python 的 Flask 框架,下面的代码主要是写个思路,并不能直接拿来用的。它的功能就是来了一个请求,将之前使用的端口弃用,随机一个新的端口号,并将这个端口转发到本地的 443 端口。最后将新的端口号码生成新的 vmess 订阅链接。

with open('port_nums', 'r', encoding='utf-8') as f:
    old_port = f.read()
del_cmd = f'''sudo iptables -t nat -D PREROUTING -p tcp --dport {old_port} -j REDIRECT --to-port 443'''
os.system(del_cmd)
new_port = random.randint(40000, 50000)
add_cmd = f'''sudo iptables -t nat -A PREROUTING -p tcp --dport {new_port} -j REDIRECT --to-port 443'''
os.system(add_cmd)
with open('port_nums', 'w', encoding='utf-8') as k:
    k.write(str(new_port))
r1 = f'auto:318d18d5-4b00-43ba-abf5-60f3f4312345@1.2.3.4:{new_port}'
r2 = str(base64.b64encode(r1.encode("utf-8"))).replace("b'","").replace("'","")    
r3=f'''vmess://{r2}?emarks=baidu.com&obfsParam=baidu.com&path=/v2ray&obfs=websocket&tls=1&tfo=1&mux=1&alterId=0'''
r4 = base64.b64encode(r3.encode("utf-8"))
return r4

Shadowrocket 订阅功能

最后我使用 Shadowrocket 的订阅功能,定时向服务器获取最新的端口号,服务器收到订阅更新的请求后,关闭之前的通讯端口,随机启用一个端口号,再将新端口加入到订阅链接中返回给移动端设备。

这样移动端设备就可以通过更新订阅来使用最新的端口连接到服务器了。

因为我的移动设备是 iPhone,所以我理所当然的使用了快捷指令!如果你也是iPhone,并且你也安装了快捷指令和 Shadowrocket 那么可以点击这个链接获取这个快捷指令,就如同它的名字一样,它只有一个功能:更新订阅

将其添加到快捷指令后,接下来就是有趣的部分了,我们可以为iPhone 设置自动化,然后每2个小时自动向服务器请求新的端口。根据我用了大约一周的测试下来,几乎没有任何可以感知的干扰发生了。

后记

最近工作很忙,没时间学习和提升自己,抽出空解决了一个困扰我很久的小问题还是挺有意思的。如果这个小脚本有人需要的话,欢迎可以评论告诉我。

简单快速为树莓派写入系统

几年前阴差阳错,买了一块树莓派4B,没曾想竟然成了理财产品,要不是当时看着性能羸弱,我铁定买它四个八个的。

从箱子里把它翻出来的时候还嘎嘎新,接上电也正常闪灯运行,但我忘记了ssh的账户密码,所以重新为sd卡写入了一遍系统,出乎意料的非常简单,只需要下载一个软件就能完成。本文主要内容就是介绍如何简单快速为树莓派写入系统。

下载烧录器

在这个页面 Raspberry Pi OS 下载镜像烧录软件,并安装。

烧录系统

到这里准备工作就完成了,让我带你一步步烧录树莓派系统。双击打开软件。

选择烧录系统

选择储存卡

高级设置配置SSH

勾选以启用SSH 功能。

接下来配置用户名和密码

烧录

然后点击烧录即可。

点击继续就开始刷写系统了。

后记

不得不感慨时过境迁,我上一篇写如何为树莓派刷系统的文章还是 2017 年,技术进步的太快了,一下就这么方便,让人有点不适应了😂

Windows RDP 远程桌面如何提高传输帧率?流畅玩游戏!

前言

虽然默认设置下 RDP 远程桌面已经可以流畅使用办公软件以及一般的应用了,但由于帧率只有30,所以想要稳定 60 帧游戏是根本不可能,我在网上找到了一个非常简单的小技巧可以为远程桌面开启 60 帧传输。

修改帧率

首先要打开注册表编辑器,直接再Windows自带的搜索框中搜索即可。

在红色圈圈处填写以下字符串HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations

在空白处右键 > 新建 ‘DWORD(32位)值’,命名为:DWMFRAMEINTERVAL:

最后双击刚刚新建好的字段,将基数改为十进制,然后数值数据填写15保存,然后重启即可生效。

后记

实际效果取决于客户端设置、网络环境等等因素。我有的时候可以使用 RDP 在公司远程到家里的电脑打打游戏,但有的时候可以60帧,有的时候又不行,有点随机,可能跟分辨率与色阶有关系。

为了一键翻译写好的文章,我又为网站添加了一个自动翻译功能!

前言

本站,从设计之初,就是要作为多语言站点设计的,但第一版本的使用的是 Azure 的翻译 API,好用是好用,但是有些翻译会很奇怪,例如代码块内的内容也会被翻译。

绝大部分情况下,代码块内的文本都是需要复制粘贴到命令行界面运行的,哪怕是多个空格都会出错,更何况是字符都不对了。为此我尝试了 5 中不同的翻译 API,只能说虽然各有千秋,但出错的点都惊人的一致,所以还是得在后端代码中做出优化才行。

API们

我用过的翻译 API 有这几个:ChatGPTtext-davinci-003AzureTranslatorGoogleTranslator腾讯云机器翻译。下面是我试用这几款翻译 API 过程中遇到的问题与坑,如果各位也有需要用到,可以参考一下。

ChatGPT

其中不得不说,ChatGPT 翻译出来的文本是最好的,而且语法通顺,markdown语法都能保留(prompt强制必须保留)。但是它有一个致命问题,就是速度比较慢,这里的速度并不是指的响应慢,返回速度还是很快的,但是比如一篇文章5000字,ChatGPT 3.5最大能够一次性接收的token只有 4096 ,而且一个中文字符算作1.6个 token,很明显我需要将一篇文章拆分成多个请求进行翻译。

text-davinci-003

text-davinci-003 和 ChatGPT 几乎一摸一样,只不过自由发挥的幅度会更小些,更加像是个翻译工具。但他们有一个共同的缺点,就是无法在国内简单使用,必须要使用特殊的网络工具才行。

GoogleTranslator

其次是 Google,用了这么多年网页版本,这次用的API 付费和免费的感觉没什么差,一如既往的好,但是日文翻译会将markdown标记语言中包围代码行的重音符替换成括号,这样就完全不美观了。

AzureTranslator

至于 AzureTranslator,它什么都好,就是容易封账号,要是有稳定的账号,那么选它准没错。

腾讯云机器翻译

最后我试用了腾讯云的 【腾讯云机器翻译】 ,感觉虽然翻译准确度和符号转换和Google一样有问题,最后就是速度嘎嘎快,这肯定是因为服务器部署在大陆境内的原因。

后记

因为翻译的代码写的太狗屎了,所以我这里就不贴了,主要是记录一下各种不同的翻译平台的区别。 当系统成型后,想要为网站再添加新功能就是比较费时费力的事情,所以以后还是多规划规划,留好接口以备不时之需。

在 Python Flask 中 request 的属性简单解释

因为写代码的时候经常会需要用到,但又记不住,只能靠写下来了,可能并不全,等下次遇到再做添加。

以下就是一些在 python 的Flask 中常用到的 request 对象中的常用属性。

获取请求地址

path = request.path 

request.path 返回的是客户端请求的路径部分,即不包括协议、主机名、端口号和查询参数的 URL 路径。

获取请求方法

method = request.method 

获取当前请求的 HTTP 方法,例如 GET、POST、PUT、DELETE 等。

请求来源的ip

ip = request.remote_addr 

获取客户端的 IP 地址,将获取到的 IP 地址赋值给变量 ip,以便后续使用。需要注意的是,有些代理服务器可能会改变客户端的 IP 地址,因此在使用时需要谨慎。如果你需要获取真实的客户端 IP 地址,可以使用 Flask 的扩展 Flask-HTTPAuth。

获取form表单的数据

form = request.form 

返回的是客户端提交的包含表单数据的字典。它只会返回提交方式为 POST 的请求中的表单数据,如果请求方式为 GET,则返回空字典。

需要注意的是,如果客户端提交的是一个空表单,那么 request.form 也会返回一个空字典。如果你需要判断客户端是否提交了表单数据,可以使用 request.method 来判断请求方式是否为 POST,然后再使用 Python 的 len() 函数来判断字典中是否有数据。

获取查询字符串/表单数据

value = request.values 

返回的是客户端提交的所有数据,包括表单数据和查询参数。它会返回一个字典,其中包含了客户端提交的所有数据,包括 GET 请求中的查询参数和 POST 请求中的表单数据。

获取头部信息

headers = request.headers 

返回的是客户端发送的请求头部信息,它会返回一个字典,其中包含了所有的请求头部信息。

HTTP 请求头部包含了客户端发送请求时的一些附加信息,例如浏览器类型、所使用的操作系统、请求的语言、请求的时间、请求的来源等等。服务器可以使用这些信息来判断客户端的身份、优化响应、记录日志等等。

获取发起请求的浏览器的信息

User_Agent = request.headers['User-Agent'] 

User-Agent 是 HTTP 请求头部中的一个字段,它用来标识客户端所使用的浏览器、操作系统、设备等信息。

主机

host = request.headers['Host'] 

Host 是 HTTP 请求头部中的一个字段,它用来标识客户端请求的主机名或 IP 地址。

获取指定参数

name = request.args.get('name', "没有获取到name") 

获取客户端请求中的查询参数,其中 name 是查询参数的名称,"没有获取到name" 是默认值,如果客户端请求中没有包含 name 参数,则会返回默认值。

环境

environ = request.environ 

environ 是一个字典,它包含了客户端请求的所有相关信息,例如客户端的 IP 地址、请求的方法、协议类型、请求头部信息等等。

完整路径

full_path = request.full_path 

返回的是一个字符串,包含了客户端请求的完整路径。

获取完整 URL 地址

url = request.url

获取客户端请求的完整 URL 地址,包括协议类型、主机名、路径和查询参数。

获取基础 URL 地址

base_url = request.base_url

获取客户端请求的基础 URL 地址,包括协议类型、主机名和路径,但不包括查询参数。

获取根 URL 地址

url_root = request.url_root

获取客户端请求的根 URL 地址,包括协议类型、主机名和应用程序路径,但不包括查询参数。

是否为XMLHTTPRequest请求

si_xhr = request.is_xhr 

返回一个布尔值,用于表示当前请求是否是通过 XMLHttpRequest 发起的异步请求,如果是,则返回 True,否则返回 False。

当前的蓝图名

blueprint = request.blueprint 

返回一个字符串,表示当前请求所属的蓝图名称。如果当前请求不属于任何蓝图,则返回 None。

根节点, 当前执行的函数

endpoint = request.endpoint 

返回一个字符串,表示当前请求所对应的视图函数名称。如果当前请求没有匹配到任何视图函数,则返回 None。

视图参数

view_args = request.view_args 

返回一个字典,表示当前请求所匹配的动态路由参数。如果当前请求没有匹配到任何路由,则返回一个空字典。

与 ChatGPT 结对编程!让它为文章目录增加动态效果!

效果

现在我已经为我的博客详情页面增加了动态目录功能,效果如下动图所示,右侧的目录栏目可以随着页面的滚动自动高亮当前篇幅进度。这样看起来会更加美观一些。

【视频在YouTube,如果无法观看直接看右边的目录变化也是一样的】

这可不是我写的代码,我可不会写 JS,这部分代码我完全是让 ChatGPT 完成的,我只是调整了一下最终的CSS 显示效果。

对话

因为原文比较多,ChatGPT 输出真的是又臭又长。所以我将其共享在这个链接内,有兴趣可以点击阅读: 对话原文

后记

从对话中可以看出来,我是真的一点都不会 JS,连控制台输出都不会的那种,但这不影响我想要实现这个功能,ChatGPT 能够做的事情真的非常的多,但我们要有一双善于使用它的双手。

在 OpenCat 中使用 Azure 的文本转语音功能!

引言

在使用 OpenCat 的时候,我发现它有一个朗读功能,默认调用 iPhone 手机的朗读语音,虽然说不是不能用,就听起来很呆,傻里傻气的声音。

但我在设置里找到了 Azure TTS 的设置,在这里,你可以配置 Azure TTS 功能,它的文本转语音效果不能说和人一模一样,也八九不离十了。用它来朗读来自 ChatGPT 的回复非常的好用。

接下来我将教你如何配置这个小功能!

使用 Azure 文本转语音

首先你需要有 Azure 的订阅账户,如果你没有的话,那么接下来的步骤就只能看看了,关于如何创建 Azure 订阅账户,以后单独开一篇文章写。

在 Azure 中创建资源

1、登录你的 Azure 账号。 2、然后点击这个链接进入创建 TTS 资源的页面: https://portal.azure.com/#create/Microsoft.CognitiveServicesSpeechServices

填写以下信息: 区域:选择 East Asia 名称:随便一个名字 定价层:选择免费试用(Free F0)

3、填写完毕后,点击「审阅并创建」 4、点击「创建」

转到资源

在这个页面稍等一会儿,等待部署完成后,就可以点击转到资源。

前往获取密钥

在这个页面的左侧,找到【密钥和终结点】点击过去。

获取密钥

复制密钥1,填写到 opencat 的 设置》集成》Azure TTS 中,区域选择你之前填写的区域,最后点击验证并保存即可。

如何使用 Python 调用 Google 翻译无限制免费 API 接口 ?

前言

在我构建新版本的网站后端的时候,我一开始使用的是 Google 翻译付费API,但我翻译了一部分我的文章后,Google 跟我说要找我收费 200 多刀。我就立马更换了隔壁家 Microsoft Azure 的翻译服务,他们家可以每月可以免费使用 200 万字符,对于我的用量来说,完全用不完。然而好景不长,今天收到邮件:

我们检测到可疑活动或违反使用条款的行为,因此禁用了订阅以保护付款方式的所有者和 Microsoft。 如果你认为这是一个错误,请继续向安全团队提交支持票证以查看决定。

后来我看应该是我切换账号的时候,误操作导致微软判定我薅羊毛,所以把我 Ban 了。在经过一小段时间的搜索后,我发现 GitHub 上有一个现成的轮子可以直接使用。

GitHub : BaseMax/UnlimitedAutoTranslate

它可以调用 Google 的免费 API,并且自动截断大于 4500 字符的部分,然后将其分段翻译,就绕开了免费版API 单次只允许翻译 4500 字符的限制。本文以下部分是如何使用这个轮子,以及将其优化与应用。

安装

请根据你的python版本使用对应的 pip 安装:

pip install googletrans
# OR
pip3 install googletrans

使用

因为我是要将其集成在我的网站翻译模块内的,所以我对其进行了删改,简化后的代码如下:

import re
import sys
from deep_translator import GoogleTranslator
def split_text(text, max_len=4500):
    lines = text.split("\n")
    chunks = []
    chunk = ""
    for line in lines:
        if len(chunk + line) > max_len:
            chunks.append(chunk)
            chunk = ""
        chunk += line + "\n"
    if chunk:
        chunks.append(chunk)
    return chunks

def translate(text, target):
    chunks = split_text(text)
    translated_text = ''
    for chunk in chunks:
        translated = GoogleTranslator(source='auto', target=target).translate(text=chunk)
        translated_text += translated + "\n"
    translated_text = re.sub(r'[\n]{3,}', '\n\n', translated_text.strip())
    translated_text = translated_text.strip()
    return translated_text

translated = translate('你好,我是saltyleo,来自中国。','en')    
print(translated)

直接将上述代码粘贴到服务器上,运行后即可得到返回:

Hello, I'm saltyleo, from China.

至此,你就已经得到了一个可以无限量翻译文本的python脚本了,如果你需要翻译整个文件,请移步原作者的github,原始代码是根据文件翻译的。

如果你不知道你想要翻译到的语言缩写是什么,可以在这个链接内查找你想要翻译到的语言名称对应的缩写:googletrans.LANGUAGES

这个链接这个库的文档:Googletrans: Free and Unlimited Google translate API for Python

后记

看到 Google 账单的那一刻,我才知道:免费的才是最贵的,Google的计费规则太过于复杂,还是直接薅它免费 API 的羊毛算了。

ChatGPT iOS 官方APP 上线 AppStore !免费无广告!功能特性大解析!

前言

在今天林凌晨 OpenAi 在 AppStore 商家了官方 iOS 应用,虽然没有上架国区,但如果你拥有美区或者其他地区的apple id 账号,那么你是可以正常下载体验的。

我简单体验了一下,感觉非常的有趣,下面我将简单介绍一下它的特性,以及一些小问题,还有对比市面上如此众多的第三方app 有什么优势。对了Android 应用很快也会到来。

AppStore 下载地址:OpenAI ChatGPT

特性

这里的特性是指对比网页版有何不一样。

新的 plus 订阅方式

提供了新的订阅途径!可以使用 AppStore 中的订阅了!如果你的 Apple ID 是美区账号,并且已经拥有了可以正常购买 app 的能力,那么你是可以直接在软件内订阅plus 的。价格依旧是19.99$/月。这解决了很多以前无法开通plus 服务的朋友们。

语音输入

可以使用内置的语音输入功能提出问题,会使用OpenAi自己的语音转文字工具 whisper 将你的话转换成文字向ChatGPT 提问,使用体验相当不错。

绕开网页版被封禁的问题

看过我之前文章的朋友一定知道,我使用的网络节点是被屏蔽了openai的网页版使用权的,但api访问是可以的,现在使用同样的网络节点,iOS app 却可以正常使用。

可以使用插件集

虽然无法选择插件集,但你可以在网页版上新建好会话,并选好插件,然后可以在app 中的历史记录中点击这个会话就可以继续使用联网功能和插件进行对话。这个小问题应该在后续的更新中很快的更新完善。

对比第三方App

这里的对比主要是和opencat 做对比。

发热问题

这是目前最大的问题,我不清楚是否是我个人原因,我的设备是iPhone 13 pro ,在打开界面无任何操作的情况下,温度会直线上升,直至烫手的地步。

基础功能

基础功能还比较少,只有文本输入与语音输入,可以使用插件集,还有一个简单的history 功能。除此之外就乏善可陈了,无法调节字体、语音返回等。不过官方下场,新功能的加入只是时间问题。

依旧需要特殊的网络工具才能访问

当然,作为Openai 的亲儿子,当然还是要使用特殊的网络工具才能访问它!

为什么需要重构网站代码?网站升级改造!

前言

啊哈,当你看到这篇文章的时候,新的网站应该已经上线了!

虽然界面外观没有太大的变化,但是内在却是处处不同。几乎全部的代码都删改了一遍,重新规范了所有的类和函数的命名规则,并完善了注释,尽可能地优化了性能,修复了无数的bug。

最最最重要的更新就是本站的多语言功能升级到8种语言了!

这八种语言分别是:简体中文、英语、法语、德语、日语、韩语、俄语和西班牙语,这样来自不同语言的搜索引擎都会收录我的网站啦。

本文的主要内容是关于:我需不需要要重构代码?以及重构代码中可能遇到的问题以及注意事项。

我为什么要重构?

1、提升访客停留时间

在我自己搭建的 umami 访客统计中,我看到很多来自欧洲和非洲的访客停留时间都非常的短,除了文章内容没有吸引力的原因外,另一个很显而易见的原因是因为语言不通所导致的。

根据我我在网络上查询到的资料,绝大部分来自小语种国家的人一般都使用英语作为第二语言。所以目前这八种语言至少可以应对全球80%的访客。

在可以预见的未来,本站支持的多语言数量并不会再增加。

2、清除冗余代码

我在将网站迁移到Flask 的那篇文章中已经说明了,这整个前后端并不是为了博客特意开发的,而是一个失败项目的回收再利用,这也是我迫切想要重构网站系统的原因之一。

在将其修改为博客前后端程序的时候,因为编码技能的不熟练以及编码水平有限,很多的逻辑写的比较凌乱和零散。可能会发生a引用b,b又引用c,c有的时候又会引用a,造成这套系统冗余代码非常多,而且还不能一删了之,因为有些逻辑链我都理不清了。

而且为了让它能够更加适合我的使用习惯以及新增更多的功能,在这基础上,不断的叠加代码导致系统越来越臃肿,最终变成了一座屎山,而现在想要新增功能,特别是针对底层逻辑的修改,几乎就是不可能的任务。

3、优化性能

最初设计的时候是为了应对以万为单位的数据量设计的,所以是用的是ES。但我觉得目前以及可以看到的未来我的文章数也不会以万为单位。哪怕我天天写,一年才三百多篇,算上多语言版本也就才两千多篇,五年才能破万。

所以我打算使用 Sqlite 作为网站的数据库,这样对于性能的需求应该能大幅下降。

4、增加新功能

本站一开始就支持了多语言,但这个多也就只是两种:中文和英文。

但我在后台看到我甚至有来自 yandex 的引荐,那我就在想了,也许我可以直接提供俄语版本的博客内容,这样可以让yandex 收录更多的文章,并因此来带更多的流量,Google了一下,干脆提供所有主要语言的版本得了,免得以后还要增加其他的语言。

有的时候啊,想法一出来,就想立马把它给实现,要不然会在心里一直念念不忘。我立即着手准备新增功能。

不到一个小时后,我就放弃了想要在原有代码上新增功能的想法,因为我一开始在数据库结构设计上就写死了两种语言,这不仅仅是要改数据库结构,搜索模块、缓存模块、甚至RSS生成器都要重新设计😭。

稍稍一计算工作量,与其在旧的代码上修修改改,还不如完全重新开发一个呢。说搞就搞,我真的是一刻也停不下来,立刻在电脑上新建了一个项目目录,开始重构代码。

我是如何做的?

这里简单讲讲我是如何做的,具体的各种实现,我会后面再单独开一篇讲讲。

1、备份数据

各位,备份数据真的是重中之重,丢失了数据真的让人难以接受。在做任何重要操作前,务必备份数据。

我讲讲我在五一节期间遇到的真实案例吧。因为大家都要出游,我也不例外。当我在等待换乘列车的时候,拿出笔记本远程连接到家里的 Windows 使用 VScode remote 连接到 Linux 虚拟机上写代码。可能路径很绕,但 VScode remote 真的救了我的数据。

当时的情况是我对某个 .json 测试文件测试完毕了,需要将它从项目目录删除,不知道怎么回事同时选择到了 app.py 文件,然后 Delete + Enter 操作行云流水。屏幕一闪发现刚刚在写的代码页面怎么没了,反应过来的时候人都傻了。

最后找回文件的方法是:在同目录新建一个同名文件,使用时间线功能恢复到之前的版本。

2、重新设计数据库结构

我对数据库进行了彻头彻尾的改造,首先是加入了每一篇文章的语言标识,以及对应的其它语言的文章ID,这样当访客在访问某一篇文章的时候就可以使用多语言切换按钮跳转到不同的语言。

当然还是因为我的旧博客,我还是兼容了之前的链接格式。

3、编码

这部分可以讲的太多了,为了支持多语言,我翻译了网站上的所有显性文本,并根据访客的语言自动使用最合适的。

为了更好的翻译文章,在后端内置了azure 的翻译器,写完中文后,点击即可全文翻译,然后人工校对以下格式就可以发布了,节省了我大量的时间。

为了让我更好的管理文章,搞了个类似聚合的功能,对于我只看得到中文的文章,而其他语言的文章都在这篇文章的子页面下。

为了 SEO ,新版博客的每一个页面都是静态页面,移除了所有的 Ajax 异步加载页面元素功能,这样对于爬虫也更加友好。

为了......

更多的新功能和技术细节后续我会在新文章里单独详细介绍。

后记

距离上一次更新过去了差不多三周多,打破了我之前为自己顶的目标【周更博客】,但我认为这是值得的,不仅仅满足了自己的成就感,还让我的各种技能得到了充分的锻炼。ps:后续更新就不会影响博客文章发布了。

哦,对了,这次更新中,ChatGPT 功不可没,有大约一半的代码我都让它进行过优化,以提升可读性和性能,可能再现实问题上 ChatGPT 经常胡编乱造,但在写代码这部分能力上,它的可靠性还算可以,而且哪怕出了错,也可以将错误直接丢给它,让它继续debug。

如何编译安装带有FTS5扩展的Sqlite3?

引言

最近无聊想要捣鼓一下Sqlite,打算使用它来重构一下博客的后台,想要尽可能地降低博客站点对服务器性能的消耗,也想挑战一下自己,学习一些新的东西。

目前重构还只是在技术验证阶段,还在努力学习消化 Sqlite3 中。本文主要内容为编译安装带有FTS5扩展的Sqlite3。

编译Sqlite3

编译带FTS5的 SQLite3 需要以下步骤:

1、下载最新版本的 SQLite3 源代码 下载链接在 SQLite3 官网:https://sqlite.org/download.html

目前最新版本为:https://sqlite.org/2023/sqlite-src-3410200.zip

2、解压源代码文件,并进入解压后的目录,先安装 tclsh 否则编译会失败。

sudo apt-get install tclsh
sudo apt-get install build-essential

3、然后在终端中输入以下命令,开启 FTS5 支持:

./configure --enable-fts5

4、输入以下命令,开始编译:

make

5、编译完成后,输入以下命令进行安装:

make install

检查当前的Sqlite3 是否支持 FTS5

要检查 SQLite3 是否支持 FTS5,可以使用下面 Python 语言的测试 demo 测试一下:

import sqlite3

try:
    # 尝试创建一个 FTS5 表
    conn = sqlite3.connect(':memory:')
    conn.execute('CREATE VIRTUAL TABLE test USING fts5(name, content)')
    print('FTS5 supported')
except sqlite3.OperationalError:
    print('FTS5 not supported')
finally:
    conn.close()

这段代码会尝试在内存中创建一个 FTS5 表。如果 FTS5 可用,返回“FTS5 supported”;如果不可用,返回“FTS5 not supported”。

后记

需要注意的是,SQLite3 对 FTS5 的支持是在编译时确定的,所以必须编译时启用 FTS5 才能在 Python 中使用 FTS5。如果你使用的是标准发行版的 SQLite3,可能无法使用 FTS5。

❌