跳转至

Welcome

A self-host blog - Status Page
- Email to Me


使用yt-dlp工具下载QQ音乐的MV

获取m3u8文件

  • Right click -> Inspect -> Network tab.
  • Enter m3u in the filter box.
  • Refresh the page, then click play on the video.
  • Several results will pop up in the network tab, in this case 15Mps.m3u8 was the 4k version. There's lower quality (10/5Mps) ones as well.
  • Right click on the 15Mps.m3u8 line, copy the url.

下载

yt-dlp  https://apd-e884a42ebcb1819c8e185bdd22d6b32d.v.smtcdns.com/mv.music.tc.qq.com/AI85i7JvkmyF4poFqhirDtuEnNIwyQjQKiMDd0TFbAjw/6371017979FE2EAD13F0216756673D8F64FF084085A30F1293F38C7A31471243BB1F9358EDD23833D48FCB2D2AC4B515ZZqqmusic_default/qmmv_0b6biyaaeaaapqaa3pcdpjrfirqaajdaaasa.f9944.m3u8

提取音频

-ss 14s 跳过了MV开头的剧情

ffmpeg -i video_audio.mp4  -map 0:1 -ss 14s   -c:a copy  audio.m4a
使用mediainfo查看音频质量,比特率192kbps,对比其它音乐文件,压缩率挺高的。
mediainfo output.m4a | grep "Bit rate" 
Bit rate mode                            : Constant
Bit rate                                 : 192 kb/s

参考

https://www.reddit.com/r/DataHoarder/comments/1ab8812/how_to_download_blob_embedded_video_on_a_website/

tailscale 使用记录

tailscale 免费最大提供10个节点,足够个人使用。在如今大内网的时代,非常方便组建子网,实现家中和公司互联互通。

添加DERP节点

如果两个节点有一个有公网IP, 或者能打洞(NAT1. NAT2),那么两个节点可以直连,速度很快。否则要通过DERP节点转发,但是tailscale在大陆没有DERP节点,HK的DERP节点都有300+的延迟,完全没法用。 所以只能自己搭建或租赁一个在大陆的私人搭建的节点。

出口节点

出口节点A是流量可以从这个节点出去,比如节点B可以从A查询IP地址时,显示的ip是节点A的公网ip 而不是B的。

转发到出口节点

在B节点上设置流量都从节点A出去 tailscale up --exit-node=

添加转发例外

启动转发后,所有流量都会从出口节点走。如果单机就没事,但是局域网多台电脑需要交互,例如从局域网主机C访问主机B, 由于主机B的流量都从节点A出去了,会导致主机C收不到请求答复。结果是C 无法ping B, C也不能ssh登录B。 所以要添加例外

将来自本地局域网主机C的流量不被转发到出口节点。例如路由器的子网是192.168.10.0/24,主机C是192.168.10.111, 本机ip是192.168.10.100

# ip rule add to <your-local-network> lookup main
ip rule add to 192.168.10.111/32 lookup main

连接安卓设备后,通过adb连接实现远程桌面

  1. 首先跳板机连接安卓,这里是wifi方式,adb connect 192.168.0.32:5555
  2. 启动隧道转发,ssh -vCN -L5038:localhost:5037 -L27183:localhost:27183 adb@SERVER -p PORT
  3. 在另一台设备上使用scrcpy远程安卓
    user@client:~$ export ADB_SERVER_SOCKET=tcp:localhost:5038
    user@client:~$ scrcpy --force-adb-forward -b2M -m800 --max-fps=15
    

对于不能有线连接设备的情况,通过下面命令开启无线adb

在adb shell中操作

# This line enables adbd to run as tcpip by default
root@device:~$ echo "service.adb.tcp.port=5555" >> /system/build.prop

# This line enables adbd to accept input from keyboard & mouse using scrcpy
root@device:~$ echo "persist.security.adbinput=1" >> /system/build.prop

# This line enables adbd
root@device:~$ echo "persist.service.adb.enable=1" >> /system/build.prop

# After that, just reboot the DEVICE
root@device:~$ reboot

参考

https://psabadac.medium.com/ssh-adb-9d92c676d8c0

吉他学习

最常用的10个和弦

Em
食指放在5弦的第二品上,中指放在4弦的第二品上, 或用中指放在5弦的第二品上,无名指放在4弦的第二品上

D
食指放在3弦的第二品上,中指放在1弦的第二品上,无名指放在2弦的第三品上

C
食指放在2弦的第一品上,中指放在4弦的第二品上,无名指放在5弦的第三品上

G
食指放在5弦的第二品上,中指放在6弦的第三品上,无名指放在1弦的第三品上, 或中指放在5弦的第二品上,无名指放在6弦的第三品上,小指放在1弦的第三品上

Am
食指放在2弦的第一品上,中指放在4弦的第二品上,无名指放在3弦的第二品上

F
食指大横按在一品上,中指放在3弦的第二品上,无名指放在5弦第三品上,小指放在4弦第三品上
F
F

E
食指指放在3弦的第一品上,中指放在5弦第二品上,无名指放在4弦第二品上

Dm
食指放在1弦第一品上,中指放在3弦第二品上,无名指放在2弦第三品上

A
食指放在4弦第二品上,中指放在3弦第二品上,无名指放在2弦第二品上

Bm
食指大横按放在第二品上,中指放在2弦第三品上,无名指放在4弦第四品上,小指放在3弦第四品上
Bm

八个实用的吉他和弦转换技巧

1.压熟要转换的和絃,确保没有杂音 2.找出共通的手指 C-Am 3.练习手指移动的速度,先从练习移动低音的手指开始 C-F 4.相同指型的手指可以一起移动

引用

https://www.zhihu.com/tardis/bd/ans/1797295715

ways of generating compile command json file

clangd is programming language server of clang, requires a compile_commands.json file located in source code directory for the best. I recommend intercept-build for generating the file, because it is included in clang-tools package when compiling via make and makefile.

  • intercept-build make -B
  • bear make -B
  • compiledb make -B
  • meson, cmake
  • codechecker

or use bash script

make --always-make --dry-run \
 | grep -wE 'gcc|g\+\+' \
 | grep -w '\-c' \
 | jq -nR '[inputs|{directory:".", command:., file: match(" [^ ]+$").string[1:]}]' \
 > compile_commands.json

reference

https://releases.llvm.org/11.0.1/tools/clang/docs/JSONCompilationDatabase.html https://gist.github.com/gtors/effe8eef7dbe7052b22a009f3c7fc434 https://stackoverflow.com/questions/21134120/how-to-turn-makefile-into-json-compilation-database

difference of lxc container and docker container

  • creating a lxc container will alloc a new partition from lvm(a new logic partition), create a root-fs and copy image into it, and the image is a zip file.
  • creating a docker container will mount docker image layers one by one into the host's fs

best way

best way of running docker in pve is probably install docker inner a lxc container

speed up docker installation

https://mirrors.tuna.tsinghua.edu.cn/help/docker-ce/

remove old

for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do apt-get remove $pkg; done

setup repository

apt-get update apt-get install ca-certificates curl gnupg install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod a+r /etc/apt/keyrings/docker.gpg echo \ "deb [arch=\((dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/debian \ "\)(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \ tee /etc/apt/sources.list.d/docker.list > /dev/null

install

apt-get update apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

copy image to another host

docker save | bzip2 | ssh user@host docker load

fix problem 'modprobe: FATAL: Module fuse not found in directory /lib/modules/6.1.10-1-pve'

enable the Options of your container (Select the container on the left-hand side > Options > Features) and then enable FUSE

warn Just be aware that FUSE in LXC containers can cause some problems (no snapshots, no suspend backup, lower security since there is less containment).

convert docker image to lxc image

https://www.reddit.com/r/Proxmox/comments/u9ru5c/comment/i640ixf/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button

https://gist.github.com/flaki/9a6c58447e50219a9b77a7cd15433896

文本处理

sed 将vmstat的输出转成csv

vmstat的输出如下,空格分割的。sed命令sed 's/^ *//;s/ */,/g' vmstat.dat > vmstat.02.csv做了两件事: 1. 将行首的空格去掉 2. 将其他空格转成','符合csv的格式

多个sed命令用';'分隔,且共用/g命令

procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu-------
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st gu
 1  0 999208 3603968 353020 8258580    0    0    22   166 1016    2  4  1 94  0  0  0
处理后
procs,-----------memory----------,---swap--,-----io----,-system--,-------cpu-------
r,b,swpd,free,buff,cache,si,so,bi,bo,in,cs,us,sy,id,wa,st,gu
1,0,999208,3603968,353020,8258580,0,0,22,166,1016,2,4,1,94,0,0,0

awk 遍历

我之前的awk通常用来打印某一列的内容,例如cat vmstat.dat | awk -F' ' '{print $1}' 打印$1第一列, -F设定分隔符。除此之外还能遍历查找。 例如查找'TARGET'

awk '{for(i=1;i<=NF;i++)if($i=="TARGET"){print "TARGET located at row: " NR " col: " i }}' 

这里NR表示当前的, NF代表当前的。 NR还可以用来指定要处理的行号,例如vmstat中有两个header。例如 1. 只打印第二行的命令是awk '(NR==2){print $0}' 2. 要知道'id'在哪一列,则遍历第二行的每一列数据 awk '(NR==2){for(i=1;i<NF;i++) if($i=="id"){print i}' 会打印'15' 3. 要打印id这列的第一行的值, awk '(NR==2){for(i=1;i<NF;i++) if($i=="id"){getline; print $i}' 会打印'94'

要打印id这列的第N行的值时,就循环调用getline N次。

使用python库openpyxl 处理excel

体验了 openpyxl, 接口设计非常自然, 功能也非常全, 包括合并格子、字体、颜色。典型用法如下

import openpyxl


workbook = openpyxl.load_workbook('output.xlsx')
print(workbook.sheetnames)

sheet = workbook['Sheet']
print(sheet.max_row) #总行数
print(sheet.max_column) #总列数
print(sheet.dimensions) #左上角:右下角

cell1 = sheet['A1']
print(cell1.row) #1
print(cell1.column) #A
print(cell1.coordinate) #A1

# 单元格的内容
print(cell1.value)

# 遍历
#先行后列
for row in sheet.iter_rows():
  for c in row:
    print(f"[{c.row}][{c.column}] = {c.value}")

#先列后行
for col in sheet.iter_cols():
  for r in col:
    print(f"[{r.row}][{r.column}] = {r.value}")

# 保存
workbook.save('test.xlsx')

连词和复合句

英语中,句子(sentence)通常由好个子句子组成,这叫复合句(compound sentense), 由连词和子语句(Clause)、短语(Phase)、单词(Word)组成。

子句和短语

子句包含完整的主谓, 但短语没有主和谓, 有好多个phase组成。比较长度 Clause > Phase > Word, word很好区别。 短语是不完整的, 而子语句包含了完整的主谓(宾)。

Phrase: Meows so loudly
Clause: That cat meows so loudly

子句当名词

  • She completely understood everything he said. 拆成主谓宾'She understood XXX', 'everything he said' 是宾语XXX, 是一个名词
  • They remembered what the keynote speaker covered. 同上

子句当副词

  • She fixed the sink without facing difficulty. 拆成主谓宾'She fixed XXX'。'without facing difficulty'修饰动词'fix', 是副词
  • The pool was installed after they built the deck. 拆成主谓 'The poll was adj'。 'after they built the deck'是修饰形容词(或was), 是副词

子句当形容词

  • My friend who rides a motorcycle said it’s a great weekend to ride. 拆成主谓宾'XXX said XXX'。 'who rides a motorcycle' 形容词,形容'My Friend'
  • No matter what time of day we visit, we always run into the dog that barks. 同上, 形容'dog'

子句当名词和形容词时,比较好看出子句的主谓(宾), 而当副词

短句是几个单词组成,可以当很多成分

  • She runs every Sunday. 当副词
  • She was taller than all of her classmates. 当形容词
  • My small dog barks at ducks. 名词

连接词

连接词用来连接子句和短语

一致关系

for, and, nor, but, or, yet, so

FANBOYS

配对关系, 搭配用

both/and, either/or, neither/nor, not only/but, whether/or

主从关系

after, although, as, as if, as long as, as much as, as soon as, as though, because, before, by the time, even if, even though, if, in order that, in case, in the event that, lest, now that, once, only, only if, provided that, since, so, supposing, that, than, though, till, unless, until, when, whenever, where, whereas, wherever, whether or not, while

按功能分连接词

表示强调

indeed

表示递进

what's more, furthermore

表示转折

however, but

表示原因结果

because, as a result

yet 相关

yet 一直让我脑子转不过弯, 不知道怎么翻译成中文。例如歌名'Are you bored yet?', 没yet是‘你无聊吗?’。 当有yet时我以为翻译成’你还无聊吗?‘, 而结果翻译成‘你觉得无聊了吗?’

gptchat解释“yet表示提问者预期如此,也就是提问者预期被提问者无聊了。”, 所以正确理解应该是: “你应该无聊了吧?” 显然这里yet是副词,修饰bored。

当副词, 修饰形容词和动词

any yet 但是 nor yet 也不 ; 又不 ; 也没有 but yet 但还是 not yet 还没 why is there yet another problem

当连词, 连接子句和短语

Yet she 而她已经 Yet Moralistic 但注重道德

参考

https://www.grammarly.com/blog/parts-of-speech/conjunctions/ https://www.grammarly.com/blog/sentences/phrases/ https://www.grammarly.com/blog/grammar/clauses/

linux子进程

Linux的exec(3)是一系列函数。之前总是稀里糊涂地用,这次搞清楚了。

       #include <unistd.h>

       extern char **environ;

       int execl(const char *pathname, const char *arg, ...
                       /*, (char *) NULL */);
       int execlp(const char *file, const char *arg, ...
                       /*, (char *) NULL */);
       int execle(const char *pathname, const char *arg, ...
                       /*, (char *) NULL, char *const envp[] */);
       int execv(const char *pathname, char *const argv[]);
       int execvp(const char *file, char *const argv[]);
       int execvpe(const char *file, char *const argv[], char *const envp[]);

规律

这6个函数可以分为两组'execl组'和'execv组'。 后缀p表示从$PATH中查找程序, 后缀e表示最后一个参数是数组,里面是环境变量。

验证

这里通过c语言和python调用命令cat hello.txt, 验证每个函数。

#include <unistd.h>

int main(){
  int pid=-1;
  pid=fork();
  if(pid == 0)
  execl("/usr/bin/cat", "cat", "hello-execl.txt", NULL);

  pid=fork();
  if(pid == 0)
  execlp("cat", "cat", "hello-execlp.txt", NULL);

  pid=fork();
  if(pid == 0)
  execle("/usr/bin/cat", "cat", "hello-execle.txt", NULL, (char*[]){NULL});

  pid=fork();
  if(pid == 0)
  execv("/usr/bin/cat",  (char*[]){"cat", "hello-execv.txt", NULL});

  pid=fork();
  if(pid == 0)
  execvp("cat",  (char*[]){"cat", "hello-execvp.txt", NULL});

  pid=fork();
  if(pid == 0)
  execve("/usr/bin/cat",  (char*[]){"cat", "hello-execve.txt", NULL}, (char*[]){NULL});
}
注意当使用选项参数时,选项和参数需要分开成两个字符串。例如grep -n 10 "target" file命令, 调用方法是
execlp("grep", "grep", "-n", "10",  "target", "file", NULL);

使用环境变量,要用sh来拓展ENV1符号

execle("/usr/bin/sh", "sh","-c" ,"echo $ENV1", NULL, (char*[]){"ENV1=HELLO", NULL});

python 的os库的方法更全,且不需要带NULL

>>> [method for method in dir(os) if method.startswith("exec")]
['execl', 'execle', 'execlp', 'execlpe', 'execv', 'execve', 'execvp', 'execvpe']

实现cat hello.txt

import os
os.execlp("cat", "cat", "hello.txt")

使用环境变量, 同样要用sh来拓展ENV1符号

import os

env = os.environ.copy()
env["ENV1"]="hello"
os.execlpe("sh", "sh", "-c", "echo $ENV1", env)

实用替代方法

exec族的函数都会替换当前进程的堆栈,所以需要用fork生成新的进程。更方便的方法是在c中用system, python中用subprocess