红米Note9Pro5G安卓最干净刷机指南

记得玩安卓刷机还是11年的事,都十年过去了,后来试着玩过,发现太费时间就没有坚持,这次花了两天好好折腾了一番,之所用时如此之久全因为内网的混淆信息太多了。 大概记录几个坑和信息点,希望能帮你闭坑。

  1. 站点https://miuiver.com/ 非常有帮助的站点,它帮我了解了目前刷机的流程和几个基本工具,同时可以找到大陆小米历史固件,所以降级就不用担心了。
  2. 小米在刷机领域包括国外很火的原因就是它低廉的价格,成本很大部分从广告收回去,所以往往也是刷机资源最丰富的品牌。如果是以刷机为目的的可以考虑购买小米性价比最高的机型。
  3. 刷机型号,不同机子刷机会有不同的问题,这里最好看好机子的开发代码,所谓的开发代码指的是虽然卖的是两台不同的机器,但是内在是一样的,只不过用于不同的消费产品线而已,这里关注开发代码是因为你需要根据代码来找到合适的固件和twrp,当然这里也就能搜到这台机子刷机的坑了。
  4. 我的机子代码是gauguin ,机子红米Note 9 Pro 5G / 小米10T Lite,在刷机前搞清楚代码,有的机子不能刷机可以早点止损。查代码:https://miuiver.com/xiaomi-device-codename/ 或者 https://xiaomi.eu/community/threads/miui-13-stable-release.64441/
  5. 需要recovery,其实也不是必须,从12开始可以直接从fastboot刷入,这里必须要说的是我的代码对应的官方twrp是坏的,很多bug,比如mtp就挂载不了,最后我是使用的orangefox来代替。这里要提一下https://forum.xda-developers.com/ 这个站点,比如twrp也有人尝试修复,但是修复包我还是用不了。
  6. 官方recovery带有启动校验,需要刷入twrp后第一时间安装Magisk来patch boot img防止recovery回滚。
  7. 忘了也是最最重要的是解锁,没解锁都是扯淡,这里吐槽一下,小米的解锁可以工作,但是如果尝试失败就来个十几天不能动也是够恶心一壶的了。

最后推荐一下eu版本的xiaomi rom,没有广告,还是合法的,欧洲真是好呀。对了不是欧洲国际版,而是叫eu版,真鸡儿别扭。https://xiaomi.eu/community/threads/miui-13-stable-release.64441/ 刷入后需要跳过wifi设置,装好科学工具后才能正常使用

MAC Apple sillicon M1 Pro 中使用Pyenv安装Python的几个坑

开始使用M1 Pro后就陆续碰到几个坑,然后知道为了兼容有时候需要再x86_x64兼容模式来切换一些过度的软件,所以今天在使用pyinstaller打包时发现报错了,一查m1从21年开始就有各种错误,然后发现原来mac下安装python其实会有各种坑,只不过大神还没放到pyenv上吧。

  1. 首先请尝试一下几个临近的版本,比如3.9.11不行那么就试下3.9.10,众多版本的适配就是可能运气好就没问题,因为它涉及到了多个组件和mac系统适配的问题,解决之前换一个版本是一个省事的办法。这里不得不说,3.9才开始支持apple sillicon所以没升级的就别去折腾低版本了。

  2. pyinstaller依赖的python需要env PYTHON_CONFIGURE_OPTS="--enable-shared" pyenv install 3.9.10,如果不是这么安装的,重新安装即可。

  3. 重新安装常用的几个组件:brew reinstall zlib bzip2 readline openssl sqlite3 xz gcc gettext,这里要说明的是多种尝试后我的问题在安装了gettext组件后解决。如果还未解决的,请尝试看一下环境变量是否已经设置

    1
    2
    CFLAGS="-I$(brew --prefix openssl)/include -I$(brew --prefix bzip2)/include -I$(brew --prefix readline)/include -I$(xcrun --show-sdk-path)/usr/include"
    LDFLAGS="-L$(brew --prefix openssl)/lib -L$(brew --prefix readline)/lib -L$(brew --prefix zlib)/lib -L$(brew --prefix bzip2)/lib"
  4. 关于几个误区,因为m1的适配没多久,目前充斥着很多使用x86的方案,python目前arm源生的没有问题可以先试一下,转译可能会出其他的问题,xcode需要更新到最新版这应该是基本操作了。本来我的环境没有问题,更新到12.3后才发现pyenv安装的python如此不靠谱还真的应了它的全称“simple python env”,brew安装的python非常靠谱!

iPhone 后台无痛同步照片-iCloudPD

file

一直都买较大的iphone内存就是因为图片太多了,也一直没有找到比较好的导出所有图片的办法,用过群辉的photos也买过appstore上流行的几款同步软件,结果都以失败告终,我想其他人用的舒服难道是因为他们的图片没我多?

同步命令: docker exec -it icloud-jz /usr/local/bin/sync-icloud.sh

如果是第一次运行,需要保存密码: docker exec -it icloud-jz /usr/local/bin/sync-icloud.sh --Initialise

Dockerfile 变量解释:

user:container里新建的用户名称,建议与你宿主机的用户名相同,所有下载的照片的owner也都是这个user

user_id: 用户的id,默认为1000,与你宿主机用户的id相同就可以了。

group: container里新建的用户组名称,建议与你宿主机的用户组相同,所有下载的照片的owner group也都是这个group。

group_id:用户所在组的id,默认为100.0,与你宿主机的用户组id相同就可以了。

apple_id: 你的要同步的AppleID填进去。

apple_password(弃用不需要配置):默认为usekeyring,保持默认就可以了。

authentication_type: 鉴权方式。如果启用了两步验证就填2FA,没有就填Web。

TZ: 时区,国内的话设置为Asia/Shanghai。

synchronisation_interval:多长时间同步一次,单位秒,默认12小时(43200)。

convert_heic_to_jpeg: 是否把HEIC的照片自动转换为JPEG,填true或false.

folder_structure: 文件夹结构,默认为年/月/日({:%Y/%m/%d}),但我感觉如果那么多文件夹不太容易翻找,因此只设了按年份分类{:%Y}。

关于两步验证:如果启用了两步验证,运行配置脚本后icloudpd会模拟网页方式访问iCloud,需要在输入密码以后接收两步验证的信息(第一次运行脚本时需要输入AppleID的密码,密码会保存在keyring中,以后只输入验证码就可以了)。把手机接收到的两步验证的验证码输入就可以得到一个有效期为90天的cookie,到期后需要重新运行脚本,接收验证码生成新的cookie,90一天个循环,生成的cookie文件存放在/config中。

关于防呆措施:icloudpd中有一项防呆措施,用于防止错误的把下载照片的文件夹设置到错误的地方导致container被占满无法启动。因此,设置的用于下载的照片的文件夹需要手动在里边新建一个文件,文件名为.mounted(包装前边那个点)。

引用:https://zhuanlan.zhihu.com/p/234748179

memory align/内存对齐 golang和csharp

file

为什么要内存对齐

总线读取总是32位的倍数读取的,对齐算法有助于提升程序的运行效率,大部分的语言都在底层实现了这部分的支持,只是实现有所不同。

golang的对齐和c#的对齐

两者比较不太公平,毕竟csharp要先转一次IL。他们的底层数据类型为了内存对齐都会采用padding的方式,但是又有不同,比如bool类型,csharp中是4个字节,而golang是一个字节。理论上bool只需要一个bit来表示true和false,但是对齐理论告诉我们你起码得是一个字节为最小的单位,所以八个bool也是一个字节的大小,然后这里csharp居然占用了4个字节,查找不少资料,给了很多理由和借口,总之csharp的哲学就是保证底层运行的可靠和原子性。所以在csharp中用uint16反倒比bool省空间。

在使用Map这种数据类型时需要注意的几个问题

file

  • 因为性能的原因map一般实现不支持写的并发,如果是并发场景需要确认map的实现是否支持或者更换为支持的实现。
  • map的值类型一般不需要关心,但是键很重要,涉及到hash的原理和实现的算法,所以键的特殊类型会影响性能。
  • 触发扩容,一般实现中扩容并不会影响性能,大部分算法都是在插入和删除时进行,但是有的算法会主动进行迁移,比如redis,内存也会产生波动,对于生产环境特别需要注意。
  • 各种实现之间的差异除了架构上,算法也会有,主要体现在冲突key的解决方法上,但是各种方法各有利弊,所以能分成多个map就不要塞到一起去。

Openmediavault 6的安装和升级

file

因为OMV5在SMB限制Quota大小的问题时发现omv已经发布了6版本,于是想到可能升级后可以解决这个问题,事实上设置中已经可以更新了,效果还未测试。

如果你的OMV版本 < 6那么可以用下面的命令升级:

1
2
3
4
apt update
apt upgrade -y
omv-update
omv-upgrade

如果你已经是最新版的omv,那么需要使用最新版的Debian11才可以安装,因为它依赖PHP7.4,其他系统同理,那么在运行前面的命令前需要先升级debian的大版本到11后再执行即可。

如果是初次安装,或者打算手动安装可以参考下面的代码:

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
cat <> /etc/apt/sources.list.d/openmediavault.list
deb http://packages.openmediavault.org/public shaitan main
# deb http://downloads.sourceforge.net/project/openmediavault/packages shaitan main
## Uncomment the following line to add software from the proposed repository.
# deb http://packages.openmediavault.org/public shaitan-proposed main
# deb http://downloads.sourceforge.net/project/openmediavault/packages shaitan-proposed main
## This software is not part of OpenMediaVault, but is offered by third-party
## developers as a service to OpenMediaVault users.
# deb http://packages.openmediavault.org/public shaitan partner
# deb http://downloads.sourceforge.net/project/openmediavault/packages shaitan partner
EOF

export LANG=C.UTF-8
export DEBIAN_FRONTEND=noninteractive
export APT_LISTCHANGES_FRONTEND=none
apt-get install --yes gnupg
wget -O "/etc/apt/trusted.gpg.d/openmediavault-archive-keyring.asc" https://packages.openmediavault.org/public/archive.key
apt-key add "/etc/apt/trusted.gpg.d/openmediavault-archive-keyring.asc"
apt-get update
apt-get --yes --auto-remove --show-upgraded \
--allow-downgrades --allow-change-held-packages \
--no-install-recommends \
--option DPkg::Options::="--force-confdef" \
--option DPkg::Options::="--force-confold" \
install openmediavault-keyring openmediavault

# Populate the database.
omv-confdbadm populate

# Display the login information.
cat /etc/issue

Openmediavault 6解除了SMB共享被Quota限制为4TB的限制

file

SMB中用Quota来限制分享目录的最大空间,但是omv5只支持4TB以下,超过4TB就不行了,正好我的MBP有2TB大小,需要至少5TB才能正常每日备份,更新好omv6后控制台上可以正确的设置到5TB,明天测试一下备份效果。

Nginx防盗链,珍惜你的流量

防盗链

关于盗链

上图很好的解释了盗链的原理,只要是给人看的图片就不可避免的被人盗用,最气的莫过于还要盗用你的流量,毕竟网页文本并不需要多少带宽,带宽消耗的主要是多媒体文件,所以做好多媒体的防盗链即可。

防盗链的方法

  1. 轻度过滤,利用referer参数,在nginx中设置valid_referers none block *.jinzhao.me jinzhao.me;{:.apacheconf},none和block的设置使得图片 可以单独打开;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # Directives to send expires headers and turn off 404 error logging.
    location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
    valid_referers none block *.jinzhao.me jinzhao.me;
    if ($invalid_referer) {
    return 403;
    }
    access_log off;
    log_not_found off;
    expires 180d;
    }
  2. 中度过滤,现在前端可以设置不让浏览器带上referer参数,表现为图片的referer_policy设置为none。可恶的是目前大多人似乎都这么干,所以如果盗链压力大可以将上面的block和none去掉,那么非许可域名的请求都会被拒绝,坏处是如果有人分享了你的多媒体地址它是无法单独打开的。

  3. 重度过滤,其实2已经足够使用了,但是还是无法避免一些iframe这种变态的手法,这时候就要利用nginx的httpaccesskey mould来给站点的请求都加上临时的秘药,这无疑会给服务器增加负担,不推荐使用。

Typora配置Python脚本上传到用Golang配置的自建图床

Python+Golang的好处

  1. 上传的脚本很自然的想到用python,似乎没有更好的选择了,速度取决于服务器带宽
  2. 图床用golang,早就想试一下golang写服务端了,gogs的性能给我很深的印象,部署后居然常驻只用了3.966MB,以后服务端还会考虑其他语言么,不可能的。

为什么不用Picgo

大部分攻略用的都是Picgo,试了一下除了上传外还有其他小功能,几百兆的体积只是干几句python干的事似乎有点浪费,于是有了下面这个脚本,一共3kb,还不用常驻。

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
import os
import sys
import json
import requests
import mimetypes
import argparse
import time

APP_DESC = """
upload pictures automatically
"""
print(APP_DESC)
if len(sys.argv) == 1:
sys.argv.append('--help')

parser = argparse.ArgumentParser()
parser.add_argument('-s', '--source', type=str, nargs='+', help="", required=True)
# parser.add_argument('-c', '--config', default="./config.json", help="读取配置文件", required=True)
args = parser.parse_args()

# 从参数中获取要上传的文件列表
img_list = args.source

# print(img_list)
Auth_Code = 'abcdef123456'
Image_Host = 'https://demo.com'

def uploadImage(filePath):
fileName = os.path.basename(filePath)
fileName = bytes(fileName, "utf-8").decode("unicode_escape")
files = {'file': (fileName, open(filePath, 'rb'), mimetypes.guess_type(fileName)[0])}

# Convert all non ASCII characters to UTF-8 escape sequence

res = requests.post(url=Image_Host + '/upload',
files=files,
headers={'Authorization': Auth_Code, 'Uri': time.strftime("/%Y/%m/"), 'Image_Host': Image_Host})
return json.loads(res.text)

def parse_response_url(json, img_path):
# 从返回的json中解析字段
if json['status_code'] != 200:
print("{}\tweb端返回失败,可能是APIKey不对. status_code {} .".format(
img_path, json['status_code'])
)
else:
img_url = Image_Host + json["data"]["url"]
print(img_url)

def uploadImageList(img_list):
# 获得本地图片路径后,上传至图床并记录返回的json字段
for img in img_list:
# 先判断传过来的是本地路径还是远程图片地址
if "http" == img[:4]:
# 非本地图片的话可以考虑下载到本地再上传,但是没这个必要
print(img)
try:
filename = img.split('/')[-1]
r = requests.get(img, allow_redirects=True)
filepath = r'~/srv/tmp/' + filename
if os.path.isfile(filepath):
os.remove(filepath)
open(filepath, 'wb').write(r.content)
uploadImage(filepath)
os.remove(filepath)
print(img)
except:
print(img + "\t上传失败")
continue
else:
try:
res_json = uploadImage(img)
parse_response_url(res_json, img)
except:
print(img + "\t上传失败")

uploadImageList(img_list)

为什么要自建图床?而不是使用本地相对路径的目录或者是github/gittee免费图床

本地相对路径限制太大,不好分享,也不方便文档的在组织。 各种免费图床,这个世界变化这么快,我宁可自己花钱靠得住一些,也没有容量大小限制等问题。 自建会不会麻烦,其实自用的简单图床只需要很少的代码比如下面:

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
package main

import (
"io"
"log"
"net/http"
"os"
)

var (
// 文件 key
uploadFileKey = "file"
// 上传的图片保存根路径
filePath = "/images/"
)

func main() {
http.HandleFunc("/upload", uploadHandler)
if err := http.ListenAndServe(":8081", nil); err != nil {
log.Fatalf("error to start http server:%s", err.Error())
}
}

func uploadHandler(w http.ResponseWriter, r *http.Request) {
// 接受文件
file, header, err := r.FormFile(uploadFileKey)
if err != nil {
// ignore the error handler
}
log.Printf("selected file name is %s", header.Filename)
authValue := r.Header.Get("Authorization")
authCode := "abcdef123456"
authCodeEnv, exists := os.LookupEnv("Authorization_Code")
if exists {
authCode = authCodeEnv
}

if authValue != authCode {
log.Printf("auth fail")
return
}
path := filePath + r.Header.Get("Uri")
createFile(path)
imgPath := path + header.Filename
log.Printf("path is %s", path)

// 将文件拷贝到指定路径下,或者其他文件操作
dst, err := os.Create(imgPath)
if err != nil {
log.Fatalf("create file error :%s", err.Error())
// ignore
}
_, err = io.Copy(dst, file)
if err != nil {
log.Fatalf("copy file error :%s", err.Error())
// ignore
}
log.Printf("upload success")
io.WriteString(w, "{\"status_code\": 200, \"data\": {\"url\": \""+(r.Header.Get("Image_Host")+r.Header.Get("Uri")+header.Filename)+"\"}}")
}

//调用os.MkdirAll递归创建文件夹
func createFile(filePath string) error {
if !isExist(filePath) {
err := os.MkdirAll(filePath, os.ModePerm)
return err
}
return nil
}

// 判断所给路径文件/文件夹是否存在(返回true是存在)
func isExist(path string) bool {
_, err := os.Stat(path) //os.Stat获取文件信息
if err != nil {
if os.IsExist(err) {
return true
}
return false
}
return true
}

上面的图床自用问题不大,如果多人多博客使用还需要完善以下几点

  1. 只有auth code鉴权,一个泄露就挂了
  2. 路径没有安全检测,如果泄露了auth code就有隐患 服务端建议放在docker中。

最新微软远程桌面 mac版(Microsoft Remote Desktop for mac)

苹果Transporter、微软远程桌面已原生适配支持M1 Mac\_腾讯新闻

微软的远程桌面一直是办公不可缺少的必需品,是在装PD这样的虚拟机太麻烦也很重。

可惜微软的远程桌面锁定在美国区,无法直接使用,找的分离版不久就会有cpu占用高等的问题出现,而每次找分离版很痛苦,幸运的是老外做了一个分享所有mac最新微软软件的站点,链接也都是微软官方的,这里真的要吐槽,既然都有下载地址了为啥不公开呢。

微软软件for mac地址:https://macadmins.software/

里面Office等全家桶都有,如果你是下载Microsoft Remote Desktop远程桌面那么直接用地址,会一直指向最新版:https://go.microsoft.com/fwlink/?linkid=868963

You need to set client_id and slot_id to show this AD unit. Please set it in _config.yml.