About Mumulhl

00后,分享编程、技巧、生活

The RSS's url is : https://mumulhl.eu.org/index.xml

Please copy to your reader or subscribe it with :

Preview of RSS feed of Mumulhl

给 Android 换个配色

2024-08-15 15:25:12

介绍

Material You 加入到 Android 12 中,其中包括了动态配色。

用户可以直接在系统层面上很方便地改变系统配色和支持动态配色的软件的配色。开发者也不需要再开发配色功能。

设置

(因为不同厂商把选项名改得不一样,所以很难明确写出选项的名称)

  1. 打开设置
  2. 点击一个名称大致包含了 桌面壁纸 的选项
  3. 点击名称像 系统风格 的选项,就可以选择颜色了。

可以单独选择配色,也可以从壁纸上提取出颜色。

结语

用了 Android 13 一整年了,都不知道有这个功能 😂 最近用 Flutter 开发词典的时候才了解到。

将 Android 作为 Linux 的麦克风

2024-08-11 12:40:00

你的电脑可能没有麦克风,需要的时候,又不想买一个麦克风,这时候就可以把你的 Android 当作麦克风来用。

Audio Source 是一个用 ADB 将 Android 麦克风的输入转发到 PulseAudio 进程的工具。

准备

使用

Android 端

可在 Releases 页面下载,或在 IzzyOnDroid F-Droid Repository 下载。

安装后,点开软件,如果没看到 UI 很正常,这个软件就是没有 UI 的… 然后要授权软件麦克风和通知权限,如果授权权限的弹窗闪退,可以在 设置 里面授权软件权限。

Linux 端

下载 audiosource 脚本并授权可执行权限。

1
curl -O https://raw.githubusercontent.com/gdzx/audiosource/master/audiosource && chmod +x audiosource

用 USB 数据线连接手机和电脑,在 开发者选项 里开启 USB 调试模式

用 adb 查看一下连接的 Android 设备,这时手机会弹出授权窗口,点授权就完事了。授权完再运行一下这个命令,看看是否正常。

1
adb devices

运行 audiosource 脚本,你的 Linux 就有麦克风啦 :)

1
./audiosource run

结语

Audio Source 是我意外在 F-Droid 找到的,F-Droid 上的宝藏很多 :)

yt-dlp 教程

2024-08-10 20:59:35

yt-dlp 是一个功能强大的命令行音频、视频下载器。yt-dlp fork 自基于 youtube-dl 的已不维护的 youtube-dlc,具有额外的功能和问题修复。

yt-dlp 不仅支持 YouTube,还支持一千多个网站。除了下载音频、视频,还能下载封面。

安装

可以通过 pip 安装,也可以通过你所用的系统的包管理器安装,还可以到 release 页面下载可执行文件。

1
2
3
pip install yt-dlp
# or
pipx install yt-dlp

使用

视频

直接加链接即可。

1
yt-dlp "https://www.youtube.com/watch?v=dQw4w9WgXcQ"

可以下载一整个播放列表的视频。

1
yt-dlp "https://www.youtube.com/playlist?list=PLp8YAQVH95dwCMvzkxUhFy4KWRAtp_awf"

还可以下载 m3u8。

1
yt-dlp "https://example.com/index.m3u8"

列出视频可以下载的格式,也列出了传输协议、格式、分辨率、帧率、大小等信息。

1
2
3
yt-dlp -F "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
# 与下面的命令等价
yt-dlp --list-formats "https://www.youtube.com/watch?v=dQw4w9WgXcQ"

yt-dlp 默认会下载分辨率、帧率等最好的视频,如果要指定相应的分辨率、帧率,要用 --format-sort/-S 参数。

下载分辨率不优于 720p 的视频,也就是下载 720p 的视频。

1
yt-dlp -S "res:720" "https://www.youtube.com/watch?v=dQw4w9WgXcQ"

指定视频的容器格式。

1
yt-dlp -S "ext:webm" "https://www.youtube.com/watch?v=dQw4w9WgXcQ"

, 连接多个限制条件。

1
yt-dlp -S "ext:webm,res:720" "https://www.youtube.com/watch?v=dQw4w9WgXcQ"

嵌入元数据,默认不嵌入。

1
yt-dlp --embed-metadata "https://www.youtube.com/watch?v=dQw4w9WgXcQ"

嵌入封面,默认不嵌入。

1
yt-dlp --embed-thumbnail "https://www.youtube.com/watch?v=dQw4w9WgXcQ"

嵌入字幕,默认不嵌入。仅支持 mp4mkvwebm 容器的视频

1
yt-dlp --embed-subs "https://www.youtube.com/watch?v=dQw4w9WgXcQ"

音频

分离出视频中的音频。

1
2
3
yt-dlp -x "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
# 与下面的命令等价
yt-dlp --extract-audio "https://www.youtube.com/watch?v=dQw4w9WgXcQ"

指定音频的格式和品质,品质取值 0-10,0 最佳,10 最差,默认为 5。

1
yt-dlp -x --audio-format opus --audio-quality 0 "https://www.youtube.com/watch?v=dQw4w9WgXcQ"

嵌入元数据。

1
yt-dlp -x --embed-metadata "https://www.youtube.com/watch?v=dQw4w9WgXcQ"

封面

列出所有封面。

1
yt-dlp --list-thumbnails "https://www.youtube.com/watch?v=dQw4w9WgXcQ"

下载封面,同时会下载视频。

1
yt-dlp --write-thumbnail "https://www.youtube.com/watch?v=dQw4w9WgXcQ"

下载所有封面,不会下载视频。

1
yt-dlp --write-all-thumbnails "https://www.youtube.com/watch?v=dQw4w9WgXcQ"

结语

写不出什么结语了(liao) :(

Dart 中读取 mdict 词典教程

2024-08-09 17:56:10

Dict_reader 是一个用于读取 mdict 词典的 Dart 语言库,支持 MDX/MDD 格式。

README 提供了几个示例,本文提供更适合生产环境的示例。

安装

1
dart pub add dict_reader

使用

在生产环境中,会用到搜索单词、查看单词的功能,而且必须要高效,这时候轮到 SQLite 数据库出场了。在第一次读取词典时,用 Drift 存储少量数据,用于之后快速地搜索和查看。

安装 Drift

1
dart pub add drift drift_flutter dev:drift_dev dev:build_runner

示例

 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
// database.dart
import "package:dict_reader/dict_reader.dart";
import "package:drift/drift.dart";
import "package:drift/native.dart";
import "dart:io";

part 'database.g.dart';

@TableIndex(name: 'idx_keyText', columns: {#keyText})
class Dictionary extends Table {
 TextColumn get keyText => text()();
 IntColumn get recordBlockOffset => integer()();
 IntColumn get startOffset => integer()();
 IntColumn get endOffset => integer()();
 IntColumn get compressedSize => integer()();
}

@DriftDatabase(tables: [Dictionary])
class AppDatabase extends _$AppDatabase {
 // After generating code, this class needs to define a `schemaVersion` getter
 // and a constructor telling drift where the database should be stored.
 // These are described in the getting started guide: https://drift.simonbinder.eu/getting-started/#open
 AppDatabase() : super(_openConnection());

 @override
 int get schemaVersion => 1;

 Future<void> insertUsers(List<DictionaryCompanion> dictionary) async {
 await batch((batch) {
 batch.insertAll(this.dictionary, dictionary);
 });
 }

 Future<List<DictionaryData>> searchWord(String word) {
 return (select(dictionary)..where((u) => u.keyText.like('$word%'))).get();
 }

 static QueryExecutor _openConnection() {
 return NativeDatabase(File('dictionary.db'));
 }
}

void main() async {
 final database = AppDatabase();
 final dictReader = DictReader("MDX FILE PATH");

 // 不用获取 keyText 和 offset 存入数据库时,可以传入 false 参数
 await dictReader.init();

 // 将 keyText 和 offset 存入数据库,只需一次
 var queue = <DictionaryCompanion>[];
 await for (final (
 keyText,
 (recordBlockOffset, startOffset, endOffset, compressedSize)
 ) in dictReader.read()) {
 queue.add(DictionaryCompanion(
 keyText: Value(keyText),
 recordBlockOffset: Value(recordBlockOffset),
 startOffset: Value(startOffset),
 endOffset: Value(endOffset),
 compressedSize: Value(compressedSize)));
 }

 await database.insertUsers(queue);

 // 通过数据库搜索单词
 final result = (await database.searchWord("go"))[0];
 // 获取单词数据
 print(await dictReader.readOne(result.recordBlockOffset, result.startOffset,
 result.endOffset, result.compressedSize));

 await database.close();
}

然后生成 database.g.dart 文件:

1
dart run build_runner build

这个示例不适合直接放到生产环境中,稍微改一下就可以了。

结语

Dict_reader 主要是翻译 mdict-analysis。我对 Dart 不是很熟,在翻译过程中经常去问 gpt-4o-mini 以及 SearchGPTool,有帮助也有捣乱,最终还是花了四天时间完成。

Dict_reader 并没有完全翻译,而且挑选了最重要、有意义的部分翻译,也基于我自身考虑(我手头没有 mdict 格式 3.0 版本的词库),例如没有校验、不支持 lzo 压缩、不支持 mdict 格式的 3.0 版本,但不影响一般使用。

上手美科2089电子琴

2024-08-05 21:23:30

最近趁着暑假学钢琴,但家里没有钢琴,于是舅舅送了我一台电子琴。

这台电子琴型号是 MK-2089,61 键,255 种音色,255 种伴奏,24 首示范曲。

小故事

1

收到的这台电子琴有两个白键翘起来,按照 B 站上的教程,拧了十几个螺丝放回去,又拧了十几个螺丝装好,还有两个拧不回去了,而且手都快拧成麻花了,肯定很香。

2

看了电子琴架拼装示范图半天,都不知道怎么装电子琴架,毕竟我连劳动课上简单的小东西看说明书也做不出来。最后我对着孔的间距装好了,然后我发现电子琴可以直接放桌子上,把椅子升高一下就能弹了…

图片

电子琴 其他东西

评测

这些仅是我个人的看法,我不是专业的。

优点:

缺点:

dig 的现代替代品 doggo

2024-08-04 15:36:46

dig 是用来查询 DNS 的工具,doggo 则是它现代的增强品。

有个叫作 dog 的 dig 替代品,但是已经多年没更新了,doggo 的灵感就是来自 dog。写这篇文章时,doggo 依然保持更新。

doggo 不仅是一个命令行工具,还有个网页版

特点

安装

脚本

1
curl -sS https://raw.githubusercontent.com/mr-karan/doggo/main/install.sh | sh

包管理

二进制文件

https://github.com/mr-karan/doggo/releases

Go Install

1
go install github.com/mr-karan/doggo/cmd/doggo@latest

快速上手

不想打五个字的话,可以 alias dig="doggo",把 dig 设置为 doggo 的别名,这样就只用打三个字了。

1
2
3
4
5
doggo example.com # 查询 A 记录

doggo example.com AAAA # 查询 AAAA 记录

doggo example.com A NS # 查询多个记录

输出结果非常简洁,而且带有颜色。

结语

文本所介绍的内容已经可以满足大部分需求了,想要更深入使用,可以观光下文档 https://doggo.mrkaran.dev/docs/

JavaScript/TypeScript 免费调用 gpt-4o-mini

2024-08-01 16:12:35

Duckduckgo AI Chat 提供了免费的 gpt-4o-mini,我开发了一个小库 duckduckgo-ai-chat 用来调用 Duckduckgo AI Chat 的 API。

注意事项

Duckduckgo AI Chat 是有针对 IP 的额度限制的,不要滥用

小故事

在 jsr.io 上的 duckduckgo-ai-chat 之所以第一个版本是 2.0.0,是因为 1.0.0 基于 Bun 编写发布在 npm 上,发完才发现 bun 不符合我的 all-in-one 需求,所以就换 Deno 了…

顺便发到了 Deno 团队新搞的 jsr.io 上,不仅支持用不同包管理器安装,而且还支持在任何运行时上跑。

兼容性

除了 Bun,其他运行时都没问题。

安装

1
2
3
4
5
6
7
npx jsr add @mumulhl/duckduckgo-ai-chat
# or
pnpm dlx jsr add @mumulhl/duckduckgo-ai-chat
# or
yarn dlx jsr add @mumulhl/duckduckgo-ai-chat
# or
deno add @mumulhl/duckduckgo-ai-chat

使用示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import { initChat } from "@mumulhl/duckduckgo-ai-chat";

// 初始化,可选模型有 gpt-4o-mini, claude-3-haiku-20240307, meta-llama/Llama-3-70b-chat-hf, mistralai/Mixtral-8x7B-Instruct-v0.1
const chat = await initChat("gpt-4o-mini");

// 一次性获取完整的回复
let message = await chat.fetchFull("Hello");
console.log(message)

// 重新回复
chat.redo()
message = await chat.fetchFull("Hello");
console.log(message)

// 获取流式回复
const stream = chat.fetchStream("Hello");
for await (let data of stream) {
 console.log(data)
}

简易友链朋友圈搭建教程

2024-07-30 11:41:16

Simple Friend Circle 是我偶然想到的一个超简单的友链朋友圈,它不需要后端,只需要 CI 去定时拉取博文,然后生成静态页面,再在自己的博客上用 <iframe> 引入这个静态页面。

搭建

Fork 这个项目,在 Actions 中开启 workflows,然后开启叫作 Friend Circle 的 workflow,关闭叫作 Lint Commit Messages 的 workflow,之后在 Settings 的 Pages 中将 Branch 选为 gh-pages。

(是不是很简单?:))

配置

links 文件用于配置各个博客的 RSS 链接和头像,像这样:

1
https://mumulhl.eu.org/index.xml https://mumulhl.eu.org/img/avatar_hub440208ea63c4061633255bf6046ed7b_104338_300x0_resize_q75_h2_box_2.webp

插入博客

在想要插入友链朋友圈的网页加入这段 HTML:

1
<iframe src="https://YOUR GITHUB NAME.github.io/simple-friend-circle/" width="100%" height="600rem" style="border:none;"></iframe>

样式

像颜色之类的可以到 public/main.css 自行调整,默认的颜色来自我用的 Stack 主题。

存档 Youtube Music ID 批量下载音乐

2024-07-27 22:02:28

yt-music-archive 是我写的一个小脚本,用于将 Youtube Music 上的音乐下载到本地,并将其 ID 存入一个存档文件中,也可以从存档文件中还原出音乐。

(我在花了几个小时写完后,才想起用 yt-dlp 下载播放列表也可以做到同样的功能,算了,写了都写了,就写篇教程吧…)

安装

1
2
3
git clone https://github.com/mumu-lhl/yt-music-archive
cd yt-music-archive
sudo make

或者从 AUR 安装:

1
2
3
yay -S yt-music-archive
# or
paru -S yt-music-archive

使用

1
2
3
4
5
6
yt-music-archive save <ID> # 下载音乐并将 ID 存入存档文件,默认音乐保存在 ~/Music

yt-music-archive save <ID> -p <PATH> # 指定音乐保存到哪个路径下

yt-music-archive fetch # 根据存档的 ID 拉取音乐,默认音乐保存在 ~/Music
yt-music-archive fetch -p <PATH> # 指定音乐保存到哪个路径下

配置

目前可配置的选项不多,可以编辑 /etc/yt-music-archive/yt-music-archive.conf~/.config/yt-music-archive/yt-music-archive.conf

1
2
3
archive_file=~/.local/share/yt-music-archive/archive
 # 存储 id 的存档文件
#default_path=~/Music # 默认保存音乐的路径

结语

I’m a 🤡.

PKGBUILD 编写、发布、自动更新教程

2024-07-25 19:54:02

概念

PKGBUILD

PKGBUILD 文件采用 Bash 语法,用于 Archlinux 及其衍生发行版构建软件包,用户可以将自己编写的 PKGBUILD 发布到 AUR(Arch User Repository),让其他用户构建并安装软件包(通常由工具完成,如 yay、paru)。

编写 PKGBUILD 只需要 Bash 的 创建变量读取变量声明函数创建数组 等少量知识即可,可以到 网道 WangDoc 学习。

makepkg

读取 PKGBUILD 构建软件包的工具。

辅助工具

这些工具在后文会介绍具体,请先用 pacman 安装,可以简化 PKGBUILD 的维护:

1
sudo pacman -S devtools nvchecker namcap

这些工具你可能需要(不要的话关系也不大),使用自行看其文档:

基本格式

你可以在 /usr/share/pacman 目录下找到三个没有注释的 PKGBUILD 示例文件,其中 PKGBUILD.pro 应该是最有用的。

 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
# https://wiki.archlinux.org/title/Arch_package_guidelines
# Maintainer: Your Name <[email protected]>
pkgname=NAME # 名称
pkgver=VERSION # 版本
pkgrel=1 # 通常为 1,不需要更改,当版本不变需要让用户重新安装软件包时
 #(如 PKGBUILD 增加补丁、修复 bug),需要加 1。
pkgdesc="" # 介绍
arch=() # 适用的架构,如 x86_64、aarch64、i386,也可以是 any,表示软件不受架构限制
url="" # 软件主页链接
license=("GPL") # 许可证
groups=() # 归属的软件包组,基本用不到
depends=() # 软件运行所需的依赖
makedepends=() # 构建软件所需的依赖
optdepends=("package_name: description")
 # 软件运行可选的依赖
provides=() # 提供的功能
conflicts=() # 与什么功能冲突,通常与 provides 的值相同
replaces=() # 该包安装时替换什么包,基本用不到
backup=() # 该包安装或卸载时,要备份的文件的路径,
 # 使用相对路径(如 etc/pacman.conf),通常是配置文件。
 # 小知识:
 # 升级时包自带的要备份的文件将会以 .pacnew 后缀保存,不覆盖本地的;
 # 卸载时本地的要备份的文件会以 .pacsave 后缀重新命名
options=() # makepkg 选项,具体参数在
 # https://man.archlinux.org/man/PKGBUILD.5#OPTIONS_AND_DIRECTIVES
changelog= # 软件更新日志,基本都不写的
source=(FILENAME::URL)
 # 不定构架,软件来源(可以是压缩文件,也可以是 git 仓库地址,写法见下面的 git 示例),
 # FILENAME 用于将下载到的文件命名为它,
 # 可以用上面定义的变量组成,如 $pkgname-$pkgver.tar.gz
 # makepkg 会自动解压,解压后的目录存于变量 srcdir
 # URL 则是指向文件的链接
#source=(URL) # FILENAME 也可以省略
#source_x86_64 # 相应架构的软件来源
noextract=() # 需要其他解压工具时,不解压的软件来源,填写这一项需要在 prepare 函数中解压文件
 # 还要在 makedepends 填写解压工具
sha256sums=() # 不定架构的软件来源的 hash,下文将介绍用 updpkgsums 自动填写,也可以用其他的 hash,如 sha512
#sha256sums_x86_64
 # 特定架构的软件来源的 hash

# pkgver 函数用于获取软件版本,替代 pkgver 变量,通常用于打包直接用 git 拉取仓库进行构建的软件包
#pkgver() {}

# prepare 函数准备软件构建,在 build 函数前执行
#prepare() {}

# build 函数构建软件,在 package 函数前执行
#build() {}

# package 函数安装软件
package() {
 # 安装二进制文件
 # 工作步骤:
 # 1. 将一个文件复制到另一个文件
 # 2. 赋予复制后的文件可执行权限
 install -Dm755 ${srcdir}/binary ${pkgdir}/usr/bin/binary # srcdir 变量是软件来源解压后的目录
 # pkgdir 变量是一个存放被打包的文件的目录
}

自动填写 hash

1
updpkgsums

示例

请根据自己要打包的软件选择示例,也可以直接跳到 如何发布

二进制

基本格式

git 从仓库拉取构建

只写出一些与打包二进制的不同的地方。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
pkgname=NAME-git # 名称应该以 -git 结尾
pkgver=1 # 先随便填个版本进去,等下构建时 makepkg 会自动填写 pkgver 函数生成的版本
sha256sums=("SKIP") # 因为拉取最新的仓库所以无法指定 hash,直接跳过检查 hash
source=("git+https://URL")

pkgver {
 # 从 git 仓库生成软件版本
 # 其他实现见: https://wiki.archlinux.org/title/VCS_package_guidelines#Git
 cd "$pkgname"
 ( set -o pipefail
 git describe --long --abbrev=7 2>/dev/null | sed 's/\([^-]*-g\)/r\1/;s/-/./g' ||
 printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short=7 HEAD)"
 )
}

其他

如 pip、npm、cargo 等编程语言的软件包的打包是不需要手写 PKGBUILD 的,用脚本生成就可以了,见 Arch Wiki

测试

构建

写完 PKGBUILD 最好测试一下能否正常构建软件。

1
makepkg

这是最简单的测试方法,但有个问题,因为安装了很多包,系统是不“干净”的,如果 PKGBUILD 中有依赖没写上去,也会正常构建,为了避免这种情况,可以用 pkgctl 构建。

1
pkgctl build

pkgctl 会自动在一个“干净”的 chroot 里下载安装依赖并构建软件。而且还会生成 .SRCINFO 文件,这是发布至 AUR 必须要有的文件。

安装

1
makepkg --install

发布

如果测试没问题的话就可以发布了。首先的首先,你需要一个 AUR 账号,这个步骤很简单,就不写了。

验证

创建 AUR 专用的 SSH 密钥。

1
ssh-keygen -f ~/.ssh/aur

~/.ssh/config 中加入这些内容:

1
2
3
Host aur.archlinux.org
 IdentityFile ~/.ssh/aur
 User aur

最后在 AUR 账号的设置页面加入 ~/.ssh/aur.pub 里的公钥就好了。

生成 .SRCINFO 文件

如果不是用 pkgctl 测试构建软件包,那么需要这条命令生成 .SRCINFO 文件:

1
makepkg --printsrcinfo > .SRCINFO

创建包仓库

AUR 只接受 master 分支的推送。

1
2
3
4
5
6
7
# 如果还没有 git 仓库
git -c init.defaultbranch=master clone ssh://[email protected]/pkgbase.git

# 如果已有 git 仓库
git switch -c master
## 如果有了提交
git branch -d

推送

这一步不用我多说吧 :)

自动更新

根据 PKGBUILD 生成自动更新的配置 .nvchecker.toml

1
pkgctl version setup

更新 PKGBUILD 中的 pkgver:

1
pkgctl version upgrade

再用 updpkgsums 自动填写 hash,非常的完美!

日常维护

当你维护一大堆包的时候,显然一个个去更新太慢了。可以把所有包的仓库放在一个目录下,再在这个目录下执行这条命令一次性更新所有包:

1
pkgctl version $(ls)

如果哪个包被更新了,要手动去构建一下,然后提交推送,避免出问题。这个任务不算很难,毕竟一下子也不会有很多包更新。

结语

这篇文章写起来超费时间,比写三篇小短文的总时间还要多 :(

因为找不到 PKGBUILD 编写、发布、自动更新一体化的教程,所以就自己写啰。

这篇文章介绍编写的 PKGBUILD 比较简单,不是很完整,剩下就是下一篇文章的事了 :)

用 RSS 订阅本站的所有文章或按标签、分类订阅文章

2024-07-23 09:57:30

本站所用的主题没有直接把 RSS 链接显示在网页上,而是放在了 HTML <link> 标签里,但是要怎么订阅本站的所有或部分文章呢?

HowTo

如果要订阅本站所有文章,在 RSS 阅读器里直接订阅 https://mumulhl.eu.org。如果要根据标签、分类订阅,直接订阅相应的链接就可以了,如 https://mumulhl.eu.org/categories/skill/

(RSS 还能这样订阅以前都不知道,最近才意外知道)

如何实现?

HTML <link> 最常见的用法就是为网页引入 CSS 文件,它的作用是标志网页和外部资源的关系。

1
<link href="main.css" rel="stylesheet">

href 属性的值是文件路径,rel 则是 relationship 的缩写,表示网页和外部资源的关系。relstylesheet,就表示 main.css 是该网页的 CSS。

引入 RSS 的 <link> 是长这样的:

1
<link href="index.xml" rel="alternate" type="application/rss+xml">

type 的值为 application/rss+xml 标志了 index.xml 的类型是 RSS,rel 的值为 alternate 根据 MDN 意思是当前网页的替代。

RSS 阅读器通常支持这种方式订阅,以前我只知道输入 RSS 文件的链接订阅…

检测 Python 代码所需的最低版本

2024-07-22 14:56:53

以后也会写像这样的工具类文章,写得特快…不会写得很啰唆,简单利落。

Vermin

Vermin 是一个检测 Python 代码所需的最低版本的工具,在本文写时已经有一段时间没有更新了。

安装

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# pip
pip install vermin

# pipx
pipx install vermin

# AUR
yay -S python-vermin
# or
paru -S python-vermin

使用

1
2
# 检测目录下的所有 Python 代码,这条命令可以满足大部分需求,不需要怎样配置
vermin .

追踪音乐播放记录

2024-07-21 21:57:29

上次写博客还是在上次呸,上次写博客在一年前了…

概念

Scrobbler

Scrobbler 的意思是是向音乐社区平台提交音乐播放记录的程序。

音乐社区平台

音乐社区平台,往往不直接提供音乐,允许用户评论音乐,记录 Scrobbler 向其提交的 不同音乐播放器 上音乐播放记录,根据记录的数据推荐音乐总结听歌报告

选择音乐社区平台

Last.fm 是一个音乐社区平台用户量应该是最多的,部分功能收费。

ListenBrainz 是我目前正在使用的音乐社区平台,是开源项目,可以自行部署,完全免费。

为了节省打字时间,还有一些可以自行部署的音乐社区平台就自行去找啦~

选择 Scrobbler

搜一下一大把的。

Pano Scrobbler 是自由软件,支持多种音乐社区平台,界面采用 Material You。鉴于我只在 Android 上听歌,所以只能推荐在 Android 上的 Scrobbler 了。

下一步

搞好音乐社区平台和 Scrobbler,然后正常听音乐就可以了。

过去一年

2023-06-30 20:17:32

这是新博客的第一篇文章, 是对过去一年的总结。

这篇文章的缘由

各位看官可能感到奇怪, 对过去一年的总结应该写在年初或者年末才对啊, 这篇怎么写在年中呢?

去年年初时我写过一篇《年记》, 里边承诺今年按时再写一篇《年记》, 好巧不巧的是, 我把生成博客的文件夹删了, 以至于我无法发那篇文章。 实际上这些都是借口, 博客可以花时间在搞, 但是那篇文章我写都没写。 年初过去了, 接下来要等年末发, 但是我是在有些等不及了, 于是选择现在发这篇文章。

好, 接下来正式开始回忆过去一年。

使用的软件

操作系统

刚好一年前, 我装了 Arch Linux, 这时还是双系统, 我保留了 Windows。 前几天我用 Manjaro Linux 替代了 Windows 的位置, 装 Manjaro Linux 的原因是 Arch Linux 出了点问题, 启动速度很慢, 但找不到问题在哪, 想去重装, 不过 Arch Linux 装起来了有点麻烦, 有些东西还得自己手动配置, 于是我选择了 Manjaro Linux。 Manjaro Linux 装起来就是简单, 鼠标点几下就装好了。

桌面环境

换成 Arch Linux 后就有了桌面环境一说。 最开始按照看的教程安装了 KDE, 用起来还行。

直到今天一月份, 我感觉 KDE 有许多功能我都用不上, 于是想要去找一个非常简单的桌面环境, 在看 B 站的时候看到了 Hyprland, 我就去找了个配置去用。 Hyprland 需要自己去装很多需要的软件, 例如通知、 软件启动器等等, 给用户极大的自定义空间。

之后我用上了 EAF, 我给 EAF 提交了很多优化 Hyprland 上的体验的补丁, 但是还不能用得顺手, 于是我换用了 Gnome, 现在我使用的桌面环境就是它。 在 Gnome 上, EAF 用得顺手多了。

编辑器

我试过不少的编辑器, 比如 VSCodium、 Neovim、 Emacs 等等, 最终使用了 Emacs + Helix, Emacs 是主力, Helix 很少用, 只在终端下使用。

选择 Emacs 也有个来由, 我觉得编码的时候, 把手在键盘和鼠标之间换来换去, 严重干扰了编码时的思维, 所以我尝试取用全键盘的编辑器。

最开始用的是 VSCodeium 配上 Neovim 插件, 但是一装好就感觉极大的不适应(原因记不清了, 随便编一个 ), 故此放弃。

之后我又尝试了 Neovim, 我抄配置抄得很厉害, 整个配置几百行代码, 没几行出自自己之手。

后来我看了陈斌大佬的一年成为 Emacs 高手 (像神一样使用编辑器)后, 了解 Emacs 的一些优势, 决心去用用 Emacs, 开始去安装不同大佬的配置来用, 最终尝试失败, 换回了 Neovim。 今年年初不知咋的, 我又想去试试 Emacs, 这次我不去抄配置了, 开始自己动手去写, 这次成功用上了 Emacs, 现在用着很顺手, 想抛弃都做不到。 现在我用的配置是经过多次大规模改写后的, 最开始用 straight + use-package 管理插件, 在参考了懒猫大佬的配置后, 改用了 submodule 管理插件。

我现在的配置用 lsp-bridge 作为补全插件, 最初我是在看 B 站的时候, 看到了一个关于 lsp-bridge 的视频, 想着试一试没想到上了瘾, 又用上了 EAF、 blink-search、 popweb 等插件, 懒猫大佬开发的插件实在是太好用了, 真是爱不释手, 平时大部分操作依赖他开发的插件。

开源贡献

在过去一年(2022)我可以肯定的说, 我没有贡献任何代码, 但我从今年(2023)的一月份在 GitHub 上开始开源贡献。 最初我是在用 lsp-bridge 的时候发了一个 =fix typo= 的 PR, 自此开启了每周开源贡献之旅。

我发的 PR 都是对软件的改进, 例如修复 bug、 拓展功能等等, 这既方便了我的使用, 也方便了其他人的使用。 虽然有些 PR 我已经不用了, 但我仍觉得它依旧有价值。

开源贡献加强了我的能力, 尤其是代码阅读能力, 最开始给 EAF 添加 Hyprland 的支持时, 代码读起来很不顺, 现在看一个陌生项目, 读得很快。

开源贡献中有着许多大佬的帮助, 让我知道了代码该怎样写可读性高, 维护成本低。 我主要发 PR 给懒猫大佬的项目, 他对我的 PR 处理很仔细, review 有时处理起来比较麻烦, 但是让我也学到了一些东西。 懒猫大佬还有其他的大佬对我的代码进行过改良, 我都看了那些改进的 commit, 学到了不少。

我开发了 EAF PyQterminal, 这是一个基于 EAF 开发的终端模拟器, 我原本想要自己去宣传宣传, 但是懒猫大佬抢先我一步, 不仅在 Emacs China 论坛上发了, 还在他的推特上发了, 懒猫大佬人是真的好! 这个软件开发出来还是有许多问题的, 懒猫大佬不断给我提 issue、 PR, 处理起来要费一点时间, 但是真的好开心, 以前的项目都是无人问津(已经被我删了), 现在有人来关注我的项目, 多好啊。 这些 issue 和 PR 使得它更加完善, 感谢懒猫大佬!!!

新博客

新博客与原来的旧博客不同, 换用 Hugo 作为静态网站生成器, 如果以后文章多了, 速度不会像 Hexo 那样慢, 现在还不知道以后文章会不会多起来。

新博客采用 Hugo BearBlog 作为主题, 我很喜欢这种极简风格的主题, 以前用的主题现在看来有些花哨。

归档

2022-03-06 08:00:00

朋友圈

0001-01-01 08:00:00

搜索

0001-01-01 08:00:00

项目

0001-01-01 08:00:00

App

库 Cool

自部署

Emacs

🤡

友链

0001-01-01 08:00:00

你可以 email/comment 我加友链,也可以等我 email/comment 你加友链 :)