利用 Termux 和 Termux-API 在 Android 手机上定时自动更新壁纸

缘起

这个事情的需求,其实……就是闲得。

开个玩笑。我其实之前用 Tasker 这个 APP 做过类似的事情,见之前文章:分享一些自己DIY的task的profile,但是有一阵遇到了 android 手机的壁纸 bug,我的 pixel 给干挂了两回,其中有一回甚至给重制了才救回来,救回来之后就没起过自动更换壁纸的任务了。

这次是看到 V 站上有个大佬,展示自己极少的 APP 时,截图里展示了一个桌面,上面的壁纸上有格言,还有英文单词。于是我就自然而然的想要不要把毒鸡汤也写到壁纸上呢?:)

环境准备

Termux 和 Termux-API

我这里环境(Termux 和 Termux-API)是现成的,但如果没有需要安装的话,请记住,不要装 google play 上的 Termux 和 Termux-API,而是要装 F-Droid 这个市场上的 Termux 和 Termux-API!

注意:要给 Termux 足够的权限(也许 Termux-API 也需要):

  • 后台运行的权限(不要被节电模式给干掉)
  • 要设置为随机启动

最后,还要打开 Termux,输入:

1
2
apt install termux-api;
# pkg install termux-api; # 也可以用命令 pkg

ImageMagick 及其他软件

打开 Termux,继续输入:

1
2
apt install ImageMagick;
apt install wget curl grep sed;

具体实现

抓取毒鸡汤

毒鸡汤 也是我自己 fork 了某个大佬的代码,自己搭建的服务。本身没提供 API 服务,这里也没想再开发一个 API 接口,所以直接模拟 web 访问,然后把需要的数据抓出来即可。不过我们还需要手工折行。

定时抓取壁纸并处理(用 ImageMagick)

我自己有个壁纸服务:壁纸,会定时更新输出的壁纸,后台爬虫是用 go 实现的。

这里我就直接用了自己的这个壁纸服务,定时(每小时)去抓一个壁纸回来。接着做如下处理:

  • 如果宽小于 1080 或者高小于 2400 的话,会首先被按原比例放大,直到宽达到 1080 或高达到 2400(具体看哪种放大的比率小)。
  • 再接着在壁纸正中截取一个 1080x2400 的图片出来
  • 最后在这个截取出来的 1080x2400 的图片的合适位置写上毒鸡汤服务中抓取出来的文本数据,把最终结果保存为文件

设置壁纸

最后自然是把上一步保留的文件用 termux-wallpaper 命令(来自于软件包 Termux-API)设置成新壁纸。

把整个工作自动化

把上面的流程写成代码(假设存为文件 $HOME/bin/change_wallpaper.sh),再用 termux-job-scheduler(来自于软件包 Termux-API)将这个代码设置为定时运行。我的例子里我是这样用的。打开 Termux,输入命令:

1
2
3
4
5
6
termux-job-scheduler \
--persisted true \
--period-ms 3600000 \
-s $HOME/bin/change_wallpaper.sh;
# persisted 是指重启后保持有效
# period-ms 3600000 是指一小时跑一次

几个坑

中文字体

在图片上写中文(含全角标点)时需要用中文的字体,因为普通字体里没有中文字符呀!

所以,要在所有可用字体里选出有中文字符且全角标点位置不在中间的,其实还有个想法,就是想找一个酷一点的中文字体,我把所有可用字体做了个循环,测试写中文字符以及全角标点,结果保存到文件里,代码大概如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
for i in $(\
magick -list font | \
grep "Font:" | \
awk '{print $2}' \
)
do
echo $i
convert \
-font $i \
-pointsize 72 \
label:测,。试test \
x.jpg x-${i}.jpg
done

我先在我的 Mac 里跑的,找到一堆合适的字体以后,再去找 Termux 里 magick -list font | grep "Fonts:" | awk '{print $2}' 的结果来做对比,结果发现,匹配上的只有一种字体:Noto-Serif-CJK-SC。:(

当然,也可以再单独在 Termux 里安装新的好看的可用字体。但我没这么做,看以后需求吧。

crond vs termux-job-scheduler

其实最早这个方案我是打算用 crond 来做定时任务的,软件都安装设置好了。

打开 Termux,

1
apt install cronie termux-services;

关闭并重新打开 Termux

1
sv-enable crond;

但是发现用 crond 跑其他任务都没问题,但是跑 termux-API 里的命令总会报 Selinux 的错误!实在是搞不定啊,于是才转向 termux-job-scheduler 方案。

其实刚用 termux-job-scheduler 时日志里也出跟 crond 一样的信息,当时心就哇凉了,但没想到后来自己居然就好了?!:)

ImageMagick 的 -crop 跟 -gravity Center 一起用的问题

ImageMagick 软件包里的命令:convert 有个参数:*-crop*,功能是用来从图片上截取一部分,这个参数还需要提供 x、y 两个参数,这两个可以理解为横坐标(x)和纵坐标(y),这个时候学过一点点编程基础的小可爱们是不是自然而然都会以为 -crop 参数(其实是操作参数,可以理解为命令)截取的长方形图片是以这个横坐标 x、纵坐标y 为顶点的呢?

我一开始也是这么认为的,所以当我用 -gravity Center 将坐标零点设置为图片中心之后,我将参数 x 和 y 分别设置成了 -540 和 -1200,结果就悲催了,最后经过调试,才知道当有 -gravity Center 时,x 和 y 是指截取长方形的中心的坐标!!!!

所以,这里的 x 和 y 都应该是 0 才对!!

change_wallpaper.sh 代码

最后,show you the code:

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
#!/data/data/com.termux/files/usr/bin/bash

TMP_IMG="$(mktemp $HOME/tmp/tmpimg.XXXXXX)"
sublen=8 # 每行显示的字符个数
DJT_TXT="$(
curl -s https://djt.theyan.gs | \
grep -Po '(xxxxxxxxxx)' | \
sed -r 's/.{'"$sublen"'}/&\n/g' \
)"

wget -q -O - https://wallpaper.theyan.gs/wp | \
convert - \
-resize '1080x2400^<' \
- | \
convert - -gravity Center \
-crop 1080x2400+0+0 \
+repage \
- | \
magick - -font Noto-Serif-CJK-SC \
-pointsize 128 \
-fill DarkViolet \
-annotate +5+500 \
"$DJT_TXT" \
$TMP_IMG

termux-wallpaper -f $TMP_IMG

rm $TMP_IMG
# 抓毒鸡汤那一段 grep 的正则需要自己调整这个程序才能正常跑
# 不要来抓我的毒鸡汤的数据呀:(,这个项目程序、数据都是开源的,可以直接下载的,地址毒鸡汤上有。

最后,附壁纸截图一张:

手机壁纸截图