tonglin0325的个人主页

各平台账号登录对接文档

当我们开发的系统想要使用第三方账号系统(比如微信,微博,facebook)进行登录的时候,就需要使用第三方平台的登录能力,下面是各第三方平台的对接文档

关于oauth和oauth2.0:理解OAuth 2.0

關於OAuth 2.0-以Facebook為例

1.微信

https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html

2.微信小程序

https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html

3.微博

web端

app移动端,可以使用refresh token

https://open.weibo.com/wiki/%E6%8E%88%E6%9D%83%E6%9C%BA%E5%88%B6

4.哔哩哔哩

https://openhome.bilibili.com/doc/4/eaf0e2b5-bde9-b9a0-9be1-019bb455701c

全文 >>

Goland中config.go文件无法被正常识别

在使用Goland开发go项目的时候,突然有一次遇到有些包下面的类无法被引用的情况,排查下来发现是这些包下面的config.go文件无法被正常识别成go代码文件

从而导致下面无法引用其他包中的所有config.go文件中的类

kratos无法正常引用

gorm的gen无法正常引用

解决方法是去File Type下面的File type auto-detected by file content下面将config.go配置删除,就可以解决这个问题

全文 >>

go学习笔记——配置

1.读取命令行参数

1
2
3
4
func main() {
println("Hello ", os.Args[1])
}

配置arg

输出

1
2
Hello World

注意arg[0]是go程序的运行目录

2.使用flag加载环境变量

golang内置的标准库flag,可以用来读取配置文件的路径

1
2
3
4
5
6
7
func main() {

var configFilePath = flag.String("conf", "./", "config file path") // flag也支持flag.Bool,flag.Int等用法
flag.Parse()
println(*configFilePath)
}

配置

输出

1
2
./configs

如果找不到-conf配置的话,才会输出 ./

3.使用toml或者multiconfig加载toml配置文件

1.使用toml

1
2
go get github.com/BurntSushi/toml@latest

参考:https://github.com/BurntSushi/toml

config.toml配置

1
2
3
4
5
6
Age = 25
Cats = [ "Cauchy", "Plato" ]
Pi = 3.14
Perfection = [ 6, 28, 496, 8128 ]
DOB = 1987-07-05T05:45:00Z

读取配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
type Config struct {
Age int
Cats []string
Pi float64
Perfection []int
DOB time.Time // requires `import time`
}

func main() {

buf, err := os.ReadFile("./configs/config.toml")
tomlData := string(buf)
if err != nil {
panic(err)
}
var conf Config
if _, err := toml.Decode(tomlData, &conf); err != nil {
fmt.Println(err.Error())
}
fmt.Println(conf)

}

输出

1
2
{25 [Cauchy Plato] 3.14 [6 28 496 8128] 1987-07-05 05:45:00 +0000 UTC}

2.使用multiconfig

1
2
go get github.com/koding/multiconfig

参考:https://github.com/koding/multiconfig

读取配置

1
2
3
4
5
6
7
8
9
10
11
12
func main() {

m := multiconfig.NewWithPath("./configs/config.toml") // supports TOML and JSON

// Get an empty struct for your configuration
conf := new(Config)

// Populated the serverConf struct
m.MustLoad(conf) // Check for error

fmt.Printf("%+v\n", conf)

输出

1
2
&{Age:25 Cats:[Cauchy Plato] Pi:3.14 Perfection:[6 28 496 8128] DOB:1987-07-05 05:45:00 +0000 UTC}

4.使用viper加载配置文件

安装viper

1
2
go get github.com/spf13/viper

在config目录下添加viper.go文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package config

import "github.com/spf13/viper"

// 全局Viper变量
var Viper = viper.New()

func Load(configFilePath string) error {
Viper.SetConfigName("config") // config file name without file type
Viper.SetConfigType("yaml") // config file type
Viper.AddConfigPath(configFilePath) // config file path
return Viper.ReadInConfig()
}

配置文件

1
2
3
4
db:
mysql:
dsn: root:123456@tcp(127.0.0.1:55000)/test?charset=utf8mb4&parseTime=True

读取配置

1
2
3
4
5
6
7
8
9
10
11
12
func main() {

var configFilePath = flag.String("conf", "./", "config file path")
flag.Parse()

if err := config.Load(*configFilePath); err != nil {
panic(err)
}

println(config.Viper.GetString("db.mysql.dsn"))
}

全文 >>

sublime插件使用

sublime软件支持安装插件来增强功能

Tool->Command Palette->install package

1.sqlbeautifier SQL格式化

command+L,然后command+F,格式化SQL

2.添加行号或者递增的数字

先选中对应的文本,然后按command+shift+L,并command+左箭头 把光标移动行首,如下

再按command+option+N

1:1表示从1开始,每次递增+1,也可以修改成1:2

全文 >>

Python爬虫学习——使用selenium和chrome爬取js动态加载的网页

1.使用docker镜像运行selenium+chrome环境

官方镜像仓库selenium/standalone-chrome,只支持amd64

拉取镜像

1
2
docker pull selenium/standalone-chrome:120.0

启动

1
2
docker run -d -p 4444:4444 -p 15900:5900 selenium/standalone-chrome:120.0

其他参数

1
2
docker run -d -p 4444:4444 -p 15900:5900 -e SE_NODE_MAX_SESSIONS=5 --shm-size=2g selenium/standalone-chrome:120.0

参考:https://hub.docker.com/r/selenium/standalone-chrome

访问 localhost:4444/ui 可以查看selenium的运行状态

可以使用mac自带的屏幕共享功能连接pod的vnc

输入 vnc://localhost:15900,默认密码是secret

界面

2.安装依赖

ubuntu/debian换源

1
2
3
4
sudo -s
sed -i s@/archive.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list
apt-get update

安装pip3

1
2
apt-get install python3-pip

安装selenium和webdriver-manager

1
2
3
pip3 install selenium
pip3 install webdriver-manager

3.运行selenium

查看chrome和driver version

1
2
3
4
5
root@ced974ac3394:/# google-chrome --version
Google Chrome 120.0.6099.224
root@ced974ac3394:/# chromedriver --version
ChromeDriver 120.0.6099.109 (3419140ab665596f21b385ce136419fde0924272-refs/branch-heads/6099@{#1483})

1.不启用chrome gui

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
root@ced974ac3394:/# python3
Python 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
options = Options()
options.add_argument('--headless')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)
driver.get("https://python.org")
print(driver.title)

Welcome to Python.org

exit()

参考:https://github.com/password123456/setup-selenium-with-chrome-driver-on-ubuntu_debian

2.启用chrome gui

1
2
3
4
5
6
7
8
9
10
11
12
13
14
root@fce0fc2def31:/# python3
Python 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
options = Options()
options.add_argument('--disable-dev-shm-usage')
options.add_argument("--remote-debugging-port=9222") # 不加的话会报session not created: DevToolsActivePort file doesn't exist
options.add_argument('--no-sandbox') # 不加的话会报chrome not reachable
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)

此时vnc界面会弹出浏览器

1
2
3
4
>>> driver.get("https://python.org")
>>> print(driver.title)
Welcome to Python.org

打开了python的网页

4.cloudflare人机校验

如果语言cloudflare的人机校验,可以尝试使用 undetected_chromedriver 这个包来代替selenium的webdriver

安装 undetected_chromedriver

1
2
pip3 install undetected_chromedriver

替换seleniuim的web driver

1
2
3
4
5
6
import undetected_chromedriver as uc

driver = uc.Chrome(headless=True,use_subprocess=False)
driver.get('https://nowsecure.nl')
driver.save_screenshot('nowsecure.png')

参考:https://github.com/ultrafunkamsterdam/undetected-chromedriver

5.M1芯片环境运行selenium docker

由于selenium/standalone-chrome镜像只支持amd64架构,如果是M1芯片的话,需要使用支持arm64架构的镜像 seleniarm/standalone-chromium

拉取镜像

1
2
docker pull seleniarm/standalone-chromium:120.0

启动,需要指定运行平台是linux/arm64

1
2
docker run -d -p 4444:4444 -p 15900:5900 -e SE_NODE_MAX_SESSIONS=5 --shm-size=2g --platform linux/arm64 selenium/standalone-chrome:120.0

运行selenium

seleniarm/standalone-chromium镜像中的浏览器是chromium,和chrome浏览器一些区别,需要指定webdriver的路径为/usr/bin/chromedriver

1
2
3
4
5
6
7
8
9
10
11
12
13
14
root@fce0fc2def31:/# python3
Python 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
options = Options()
options.add_argument('--disable-dev-shm-usage')
options.add_argument("--remote-debugging-port=9222") # 不加的话会报session not created: DevToolsActivePort file doesn't exist
options.add_argument('--no-sandbox') # 不加的话会报chrome not reachable
driver = webdriver.Chrome(service=Service("/usr/bin/chromedriver"), options=options)

如果使用m1芯片想 undetected_chromedriver 来绕过cloudflare的人机校验的话

1
2
3
4
5
6
import undetected_chromedriver as uc

driver = uc.Chrome(executable_path="/usr/bin/chromedriver",headless=True,use_subprocess=False)
driver.get('https://nowsecure.nl')
driver.save_screenshot('nowsecure.png')

默认的下载路径在/root/Downloads

全文 >>

unblock netease music配置

yaml配置

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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
port: 7890
socks-port: 7891
allow-lan: false
mode: Rule
log-level: silent
external-controller: 127.0.0.1:9090
secret: ""
dns:
enable: true
ipv6: false
nameserver:
- https://dns.rubyfish.cn/dns-query
- https://223.5.5.5/dns-query
- https://dns.pub/dns-query
- https://119.29.29.29/dns-query
fallback:
- https://1.0.0.1/dns-query
- https://public.dns.iij.jp/dns-query
- https://dns.twnic.tw/dns-query
fallback-filter:
geoip: true
ipcidr:
- 240.0.0.0/4
- 0.0.0.0/32
- 127.0.0.1/32
domain:
- +.google.com
- +.facebook.com
- +.youtube.com
- +.xn--ngstr-lra8j.com
- +.google.cn
- +.googleapis.cn
- +.gvt1.com
proxies:
- name: "UnblockMusic"
type: http
server: localhost
port: xx
proxy-groups:
-
name: "Netease Music"
type: select
proxies:
- UnblockMusic
- DIRECT
rules:
# Unblock Netease Music
- DOMAIN,api.iplay.163.com,Netease Music
- DOMAIN,apm3.music.163.com,Netease Music
- DOMAIN,apm.music.163.com,Netease Music
- DOMAIN,interface3.music.163.com,Netease Music
- DOMAIN,interface.music.163.com,Netease Music
- DOMAIN,music.163.com,Netease Music
- DOMAIN,interface.music.163.com.163jiasu.com,Netease Music
- DOMAIN,interface3.music.163.com.163jiasu.com,Netease Music
- DOMAIN,music.126.net,Netease Music
- DOMAIN-SUFFIX,163yun.com,Netease Music
- DOMAIN-SUFFIX,mam.netease.com,Netease Music
- DOMAIN-SUFFIX,hz.netease.com,Netease Music

# CIDR规则
- IP-CIDR,39.105.63.80/32,Netease Music
- IP-CIDR,45.254.48.1/32,Netease Music
- IP-CIDR,47.100.127.239/32,Netease Music
- IP-CIDR,59.111.160.195/32,Netease Music
- IP-CIDR,59.111.160.197/32,Netease Music
- IP-CIDR,59.111.181.35/32,Netease Music
- IP-CIDR,59.111.181.38/32,Netease Music
- IP-CIDR,59.111.181.60/32,Netease Music
- IP-CIDR,101.71.154.241/32,Netease Music
- IP-CIDR,103.126.92.132/32,Netease Music
- IP-CIDR,103.126.92.133/32,Netease Music
- IP-CIDR,112.13.119.17/32,Netease Music
- IP-CIDR,112.13.122.1/32,Netease Music
- IP-CIDR,115.236.118.33/32,Netease Music
- IP-CIDR,115.236.121.1/32,Netease Music
- IP-CIDR,118.24.63.156/32,Netease Music
- IP-CIDR,193.112.159.225/32,Netease Music
- IP-CIDR,223.252.199.66/32,Netease Music
- IP-CIDR,223.252.199.67/32,Netease Music
- IP-CIDR,59.111.21.14/31,Netease Music
- IP-CIDR,59.111.179.214/32,Netease Music
- IP-CIDR,59.111.238.29/32,Netease Music

# Advertising
- DOMAIN,admusicpic.music.126.net,REJECT
- DOMAIN,iadmat.nosdn.127.net,REJECT
- DOMAIN,iadmusicmat.music.126.net,REJECT
- DOMAIN,iadmusicmatvideo.music.126.net,REJECT

- DOMAIN-SUFFIX,local,DIRECT
- IP-CIDR,127.0.0.0/8,DIRECT
- IP-CIDR,172.16.0.0/12,DIRECT
- IP-CIDR,192.168.0.0/16,DIRECT
- IP-CIDR,10.0.0.0/8,DIRECT
- IP-CIDR,17.0.0.0/8,DIRECT
- IP-CIDR,100.64.0.0/10,DIRECT
- GEOIP,CN,DIRECT
- MATCH,DIRECT

如果使用yt-dlp音源需要额外安装

R3300L电视盒子刷机

1.先线刷当贝安卓系统到EMMC

  1. 打开USB_Burning_Tool, 打开img文件, Erase flash 和 Erase bootloader 默认勾选. 等着
  2. R3300L断开电源, 开关关上(弹出状态), 顶住AV口内的小开关, 连上USB线,
  3. 等待几秒, 会看到USB_Burning_Tool界面显示Connect success, 然后点击Start
  4. 然后就等进度条一直写到100%
  5. 完成后点击Stop, 关闭USB_Burning_Tool

拔掉USB线, 重新连上HDMI, 加电, 系统开机就是新的安卓系统了

使用的系统是20180123-S905L-R3300L-V12C-root-qlzy

参考:R3300L运行CoreELEC, EmuELEC和Armbia

2.再刷armbian系统到TF卡

双系统不用把armbian系统刷进emmc,需要在安卓系统中安装Reboot to LibreELEC的apk来启动TF卡系统,装上TF卡就自动进行armbian系统

参考:魔百盒R3300L、CM101H以及中兴ZX10 B860AV1.2刷armbian跑甜糖

使用的系统版本是Armbian_20.10_Arm-64_buster_current_5.9.0.img

3.armbian换源

1
2
cp /etc/apt/sources.list /etc/apt/sources.list.bak

换成清华源

1
2
3
4
5
6
7
8
9
10
11
12
deb https://mirrors.tuna.tsinghua.edu.cn/debian buster main contrib non-free
#deb-src https://mirrors.tuna.tsinghua.edu.cn/debian buster main contrib non-free

deb https://mirrors.tuna.tsinghua.edu.cn/debian buster-updates main contrib non-free
#deb-src https://mirrors.tuna.tsinghua.edu.cn/debian buster-updates main contrib non-free

deb https://mirrors.tuna.tsinghua.edu.cn/debian buster-backports main contrib non-free
#deb-src https://mirrors.tuna.tsinghua.edu.cn/debian buster-backports main contrib non-free

deb https://mirrors.tuna.tsinghua.edu.cn/debian-security/ buster/updates main contrib non-free
#deb-src https://mirrors.tuna.tsinghua.edu.cn/debian-security/ buster/updates main contrib non-free

然后

1
2
apt-get update

如果遇到NO_PUBKEY的报错

1
2
3
Err:4 https://mirrors.tuna.tsinghua.edu.cn/debian buster-backports InRelease
The following signatures couldn't be verified because the public key is not available: NO_PUBKEY XXXXXXXXX NO_PUBKEY XXXXXXXXX

执行下面命令

1
2
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys XXXXXXX

4.安装docker

1
2
armbian-config

1
2
3
root@arm-64:~# docker -v
Docker version 25.0.3, build 4debf41

5.docker部署openwrt

1.部署openwrt

假设armbian的ip是192.168.0.xx

创建network

1
2
docker network create -d macvlan --subnet=192.168.0.0/24 --gateway=192.168.0.1 -o parent=eth0 macnet

启动pod,其中192.168.0.11是openwrt后面会使用的ip

1
2
3
4
5
6
7
8
9
docker run \
-d \
--name=unifreq-openwrt-aarch64 \
--restart=unless-stopped \
--network=macnet \
--privileged \
--ip=192.168.0.11 \
unifreq/openwrt-aarch64:latest

打开网卡混杂模式

1
2
sudo ip link set eth0 promisc on

将pod中/etc/config/network的192.168.0.1或者修改成192.168.0.11

1
2
docker exec unifreq-openwrt-aarch64 sed -e "s/192.168.0.1/192.168.0.11/" -i /etc/config/network

重启pod

1
2
docker restart unifreq-openwrt-aarch64

参考:M401a系列:armbian下docker安装openwrt做旁路由

2.登录openwrt

登录192.168.0.11访问openwrt的管理页面,注意是http的浏览器访问的时候需要接受风险,默认账号密码是root和password

3.设置openwrt

这时候openwrt需要进行一些设置

1.关闭 DHCP

网络 => 接口 => LAN => DHCP 服务器 => 基本设置

操作: 勾选忽略此接口

2.关闭ipv6

网络 => 接口 => LAN => DHCP 服务器 => IPv6 设置

操作: 禁用 路由通告服务, DHCPv6 服务, NDP 代理

3.配置 网关 和 DNS,这样在pod中才能访问网络

网络 => 接口 => LAN => 一般设置 => 基本设置
操作:

  1. IPv4 网关 改为 192.168.0.1
    2. IPv4 广播 改为 192.168.0.255
    3. 使用自定义的 DNS 服务器 改为 114.114.114.114

这时候pod中就可以访问外网了

4.armbian访问openwrt

其中192.168.0.116是armbian机器的ip,192.168.0.11是openwrt的ip

1
2
3
4
5
root@arm-64:~# ip addr add 192.168.0.116 dev mynet
root@arm-64:~# ip link set mynet up
root@arm-64:~# ip route add 192.168.0.11 dev mynet
root@arm-64:~# ping 192.168.0.11<br /><br />PING 192.168.0.11 (192.168.0.11) 56(84) bytes of data.<br />64 bytes from 192.168.0.11: icmp_seq=1 ttl=64 time=1.02 ms<br />64 bytes from 192.168.0.11: icmp_seq=2 ttl=64 time=0.415 ms<br />64 bytes from 192.168.0.11: icmp_seq=3 ttl=64 time=0.426 ms<br />64 bytes from 192.168.0.11: icmp_seq=4 ttl=64 time=0.413 ms

参考:N1 通过 Docker 安装 Openwrt 为旁路由

5.设置软路由ss kx上网

注意需要把软路由接到主路器上

如果不想修改主路由的DNS地址,那么可以通过修改手机的路由器地址到openwrt的ip地址+修改DNS地址到openwrt的ip地址的方式

参考:软路由(operwrt)通过ss Plus+ kx上网教程

全文 >>

各开放平台账号登录API对接文档

当我们开发的系统想要使用第三方账号系统(比如微信,微博,facebook)进行登录的时候,就需要使用第三方平台的登录能力,下面是各第三方平台的对接文档

关于oauth和oauth2.0:理解OAuth 2.0

關於OAuth 2.0-以Facebook為例

1.微信

https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html

2.微信小程序

https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html

3.微博

web端

app移动端,可以使用refresh token

https://open.weibo.com/wiki/%E6%8E%88%E6%9D%83%E6%9C%BA%E5%88%B6

4.哔哩哔哩

https://openhome.bilibili.com/doc/4/eaf0e2b5-bde9-b9a0-9be1-019bb455701c

全文 >>

MySQL学习笔记——多表连接和子查询

多表连接查询

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
# 返回的是两张表的乘积
SELECT * FROM tb_emp,tb_dept
SELECT COUNT(*) FROM tb_emp,tb_dept

# 标准写法,每个数据库都能这么写
SELECT * FROM tb_emp CROSS JOIN tb_dept

# 内连接 只列出这些连接表中与连接条件相匹配的数据行
SELECT * FROM tb_emp e,tb_dept d WHERE e.NAME = d.NAME

SELECT * FROM tb_emp INNER JOIN tb_dept
ON tb_emp.NAME = tb_dept.NAME

# 外链接 不仅列出与连接条件相匹配的行,还列出左表(左外连接),右表(右外连接)或两个表(全外连接)中所有符合where过滤条件的数据行
# 左外连接 在外连接中,某些不满足条件的列也会显示出来,也就是说,只限制其中一个表的行,而不限制另一个表的行
# 左边的表作为主表,左边的表会全部显示
SELECT * FROM tb_emp LEFT JOIN tb_dept
ON tb_emp.NAME = tb_dept.NAME

#oracle语法,左连接加号在左边
SELECT * FROM tb_emp e,tb_dept d WHERE e.NAME=d.NAME(+)

#右外连接
SELECT * FROM tb_emp RIGHT JOIN tb_dept
ON tb_emp.NAME = tb_dept.NAME

#全外连接 MySQL不支持 OUTER

#自连接
SELECT c.NAME '部门名字',c2.NAME '其他部门'
FROM tb_dept c LEFT JOIN tb_dept c2
ON c.description=c2.id

全文 >>