君不密则失臣,臣不密则失身,几事不密则害成。是以君子慎密而不出也。
人生第一次获得这么多的赞
读远方青木的文章,随手留了个言,没想到这么的点赞,mark一下。
Hexo保留链接隐藏文章
Hexo生成的一些文章,默认是全部被主页和标签索引的,那么有些文章不希望被索引,而且有希望通过链接直接分享给别人看,就可以利用hexo-hide-posts插件。
- 先安装hexo-hide-posts
1
npm install hexo-hide-posts --save
- 在想要隐藏的文章里添加hidden标记。
1
2
3
4
5
6
7
8
9
layout: post
title: "Hexo保留链接隐藏文章"
date: 2024-01-02 13:04:38 +0800
hidden: true
tags:
- Hexo
categories: Tech
只需简单这两部就可以了,虽然可以在_config.yml做一些更详细的配置,但是没必要。
重新生成文章,就可以看到隐藏的文章不在主页和标签页里了。但是可以通过链接访问,链接可以在生成文章的日志里找到。
在centos上安装immich
一直在研究怎么把自己的上万张照片找一个合适的地方放置,目前还没有定论,但是比较倾向于immich.app.
记录在centos上的安装过程。
安装docker-ce
enable 阿里云里的docker-ce的repo
1
2yum install -y yum-utils
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repoyum安装docker-ce
1
yum install -y docker-ce docker-ce-cli --nobest --skip-broken
启动docker-ce
1
2
3systemctl enable docker
systemctl start docker
systemctl status docker # 检查是不是启动成功
通过docker compose安装immich.app
创建目录
如果挂载了多个磁盘,建议选择一个合适的目录,immich启动后会挂载全部的所在目录。1
2mkdir ./immich-app
cd ./immich-app准备 docker-compose.yml 和 example.env
下载文件:1
2wget https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
wget -O .env https://github.com/immich-app/immich/releases/latest/download/example.env下载后docker-compose.yml需要改动一下镜像的地址,换成国内的源。
github的镜像源ghcr.io可以换成南京大学的ghcr.nju.edu.cn,默认dockerhub的源换成docker.nju.edu.cn,国内访问速度比较快。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
98version: "3.8"
services:
immich-server:
container_name: immich_server
image: ghcr.nju.edu.cn/immich-app/immich-server:${IMMICH_VERSION:-release}
command: [ "start.sh", "immich" ]
volumes:
- ${UPLOAD_LOCATION}:/usr/src/app/upload
env_file:
- .env
depends_on:
- redis
- database
- typesense
restart: always
immich-microservices:
container_name: immich_microservices
image: ghcr.nju.edu.cn/immich-app/immich-server:${IMMICH_VERSION:-release}
# extends:
# file: hwaccel.yml
# service: hwaccel
command: [ "start.sh", "microservices" ]
volumes:
- ${UPLOAD_LOCATION}:/usr/src/app/upload
env_file:
- .env
depends_on:
- redis
- database
- typesense
restart: always
immich-machine-learning:
container_name: immich_machine_learning
image: ghcr.nju.edu.cn/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}
volumes:
- model-cache:/cache
env_file:
- .env
restart: always
immich-web:
container_name: immich_web
image: ghcr.nju.edu.cn/immich-app/immich-web:${IMMICH_VERSION:-release}
env_file:
- .env
restart: always
typesense:
container_name: immich_typesense
image: docker.nju.edu.cn/typesense/typesense:0.24.1@sha256:9bcff2b829f12074426ca044b56160ca9d777a0c488303469143dd9f8259d4dd
environment:
- TYPESENSE_API_KEY=${TYPESENSE_API_KEY}
- TYPESENSE_DATA_DIR=/data
# remove this to get debug messages
- GLOG_minloglevel=1
volumes:
- tsdata:/data
restart: always
redis:
container_name: immich_redis
image: docker.nju.edu.cn/redis:6.2-alpine@sha256:70a7a5b641117670beae0d80658430853896b5ef269ccf00d1827427e3263fa3
restart: always
database:
container_name: immich_postgres
image: docker.nju.edu.cn/postgres:14-alpine@sha256:28407a9961e76f2d285dc6991e8e48893503cc3836a4755bbc2d40bcc272a441
env_file:
- .env
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_DB: ${DB_DATABASE_NAME}
volumes:
- pgdata:/var/lib/postgresql/data
restart: always
immich-proxy:
container_name: immich_proxy
image: ghcr.nju.edu.cn/immich-app/immich-proxy:${IMMICH_VERSION:-release}
environment:
# Make sure these values get passed through from the env file
- IMMICH_SERVER_URL
- IMMICH_WEB_URL
ports:
- 5003:8080
depends_on:
- immich-server
- immich-web
restart: always
volumes:
pgdata:
model-cache:
tsdata:
.env不需要改
1 | # You can find documentation for all the supported env variables at https://immich.app/docs/install/environment-variables |
确认docker-compose.yml文件中immich-proxy段落里的ports端口没有问题,启动immich。
1
docker compose up -d
访问 http://{ip}:{port}
根据照片的拍摄时间重新命名照片文件名
这几天一直想给照片搞个备份,在寻找一个性价比比较高而且又比较稳定的方案,现在还没找到,先进行图片整理工作。
整理过程中想把所有的文件名给改一下,于是总结了这个脚本。
需要提前从这里https://exiftool.org/ 下载一个exiftool.exe用于操作图片或者视频的exif信息。
1 |
|
百度网盘读取全部文件列表
代码来源于网上,很遗憾找不到从哪里找到的了。
安装百度云盘的PC版本,BaiduYunCacheFileV0.db这个文件一般放置在百度网盘的安装目录下的user目录下。
这个目录类似于单文件数据SQLite,直接调用sqlite3的python库把数据读取出来,然后转成txt文件就可以了。
1 | #!/usr/bin/env python3 |
flask全局的@app.errorhandler(Exception)无法起效
正常情况下,在能查到的所有文档都会这样表达如何给falsk设置全局的Excepition拦截器。
1 |
|
但是无论如何,在我的项目中就是无法使用,后来看了一下报出的异常,是从flask_restx打出来的,总是返回internal server error。
于是怀疑是使用了flask_restx或者flask_restful的原因,是这个架构提前抓住了异常没有往上抛出,导致flask根本无法接到异常。
看了一flask_restx的源码,尤其是flask_restx.api.Api.handle_error方法,最后发现在一种判断条件是,flask_restx就会把异常给抛出去了。
于是发现,只需要加个配置就可以了。
1 | app.config['PROPAGATE_EXCEPTIONS'] = True |
这样问题就解决了。
在多个文件中搜索汉字
之前写代码的过程,用中文加了很多的注释,现在需要找出来,改掉。
可以利用正则表达式来进行搜索, 匹配中文汉字的编码就可以了。
1 | ^((?!(\*|//)).)+[\u4e00-\u9fa5] |
将某市医师服务协会网站上的定考模拟测评试题导出PDF
给朋友帮忙,想将某市医师服务协会网站上的定考模拟测评试题导出成为PDF,方便在手机上进行学习。
经过操作分析后,网页是每一道试题都是一个json数据,需要想办法直接获取所有的数据,代码没有混淆和加密,可以直接尝试调用已经存在的方法。
在console口直接执行下面的代码,在bbresult中就可以获得所有试题的数据。
1 | var bbresult = []; |
取到的结果示例:
1 | [ |
将得到的500条数据直接存在一个json文件中,命名为data.json。
利用下面的代码,就可以将这个json文件里的数据,成功的转换成带有格式的PDF文件。
1 | import json |
PDF效果非常不错,放在手机上查看清晰可读,收获范主任稀有的赞一次!
声明:代码不会对任何系统产生危害,所有的操作都是在正规注册付费账号里合规合法完成,未传播任何带有版权数据。如有侵权,请联系删除。
在Python Flask程序中发起request请求时卡死的问题
当前的Python Flask程序部署到包含三个pod的一个deployment中,业务中需要一个消息通知到三个pod,目前不想引入消息队列组件,所以调用现有的kubernetes python库,直接取出三个pod的IP,直接访问三遍。方法略显粗糙,虽然不优雅,但是轻量级的解决了问题。
1 | resp = requests.post(url, |
但是在调试中发现,在一个API代码中一旦发起新的request请求,系统直接卡住,甚至所有的POD IP都无法支持访问了。
这个问题,一开始的研究思路是以为循环调用一个API导致的无限循环,但是加入debug log以后并没有打出log来,看起来并不是。
最后突然想起,之前把flask的app启动方式换成了gevent.pywsgi.WSGIServer, 会不会是线程无法启动的问题。
最后查到了如下内容:
1 | gevent is a coroutine -based Python networking library that uses greenlet to provide a high-level synchronous API on top of the libev or libuv event loop. |
所以,gevent是协程级别的,那么自然就阻塞了IO,那如何解决呢?
https://www.gevent.org/api/gevent.monkey.html#module-gevent.monkey
官方提供了一个patch库。总结起来就是这样:
gevent 是一个基于协程的 Python 网络库,它使用 Greenlet 库提供了一种高效的协程实现。协程是一种轻量级的线程,允许并发执行,但没有真正的并行性。协程可 以在遇到 I/O 操作时自动地切换到其他任务,从而提高程序的并发能力。
然而,在标准的 Python 线程模型中,当一个线程遇到 I/O 操作时,它会被阻塞,直到 I/O 操作完成。这意味着在传统的多线程模型下,一个线程在等待 I/O 完成时 会占用一个线程资源,而其他线程则无法被调度执行。
monkey.patch_all() 是 gevent 提供的一个函数,用于实现对标准库的自动补丁,以便与协程一起使用。这个函数会对一些常见的阻塞式 I/O 操作进行替换,使其在 遇到阻塞时能够自动地切换到其他协程任务。
当你在执行 monkey.patch_all() 后,gevent 会修改 Python 的内置库,例如 socket、threading、time 等,以便在这些库中的 I/O 操作发生时进行协程切换。 这样一来,当使用 gevent 的 WSGIServer 启动一个服务器时,它会在遇到阻塞的 I/O 操作时自动切换到其他协程,而不会阻塞整个服务器。
总结起来,执行 monkey.patch_all() 会对 Python 的内置库进行补丁,使得在使用 gevent 的 WSGIServer 启动服务器时,能够自动地在 I/O 操作发生时切换到其 他协程,从而实现多线程的并发处理能力。这使得 gevent.pywsgi.WSGIServer 能够更高效地处理并发请求。
所以在整个flask最开始的地方加上这样一段,问题就解决了。
1 | # noinspection PyUnresolvedReferences |
同时,借这个机会,再次重温了一些线程(Process),进程(Thread)和协程(Coroutine)。这篇文章讲的挺好。
https://juejin.cn/post/7027998293351202853
有两个重要的的点:
- 线程是程序执行中一个单一的顺序控制流程,是程序执行流的最小单元,是处理器调度和分派的基本单位。
- 协程进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序。