20240503

  • 使用 inotifywait + systemd 真正实现CICD 参考1 参考2

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    #!/bin/sh
    watchPath="/home/raccoon/blogs_rawRepo.git/"
    while inotifywait -r $watchPath -e create,modify,move,delete --timefmt '%d/%m/%y %H:%M' --format '%T %w %f %e'; do
    echo -e "\033[34m___________________"
    echo -e "___________NewDeployIsHere\033[0m"
    DeployPath="/var/www/blogs_remote/blogs_rawRepo/" #存放项目的文件夹位置
    cd $DeployPath
    echo "present dir $(pwd)"
    git add . -A && git stash
    git pull origin main
    echo "______npm install"
    npm install
    echo "______hexo g"
    hexo c && hexo g
    done
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #/etc/systemd/system/blogs_d.service
    [Unit]
    Description=DeployMyBlogs

    [Service]
    ExecStart=/bin/bash /home/raccoon/scrips/blog_d.sh

    [Install]
    WantedBy=multi-user.target
  • 配置git ssh秘钥 参考

  • raccoon.love解析到服务器,可以在命令行使用

20240430更新日志

加入ICP备案号

添加SSL证书

更改页面主题色, 需要刷新一下浏览器和服务器缓存

20240329更新日志

代码段采用light主题, 方便复制
加入搜索功能

20240225更新日志

使用了gitee和github双线部署

增加了autoDeploy脚本中的hx pull, 避免每次git pull的副作用

更新了timeParser的finddiff脚本, 用于在hx d之前判断即将更改的mtime文件是否符合预期

20240224更新日志

采用了permlink,见 使用crc校验生成permlink

会导致很多相对路径引用失效,慢慢修吧

20240220更新日志

史诗级更新:GithubAction

👉🏻指路牌

史诗级更新:GalleryIndex

很丑但是能用的代码,用于管理index页面下的各级标题

gallery语法div标签要写全!

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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import os
import hashlib

def folderParser(String):
#String = "aa"
count = String.split("_posts")[-1].count('/') - 1 # 1表示直属,2表示下一级目录,
String = String[0:String.rindex("/")]
dirname = String[String.rindex("/") + 1:len(String)]
return count, dirname

def head(String, head):
return "\n" + "#" * head + " " + String

def headWritter(headerList, w_file):
if not headerList == []:
sortedList = sorted(headerList, key=lambda x: x["date"], reverse=True)
w_file.write("\n<div class=\"gallery-group-main\">\n")
print("\n<div class=\"gallery-group-main\">\n", "has been written")
for header in sortedList:
galleryCmd = "\n{% galleryGroup '" + header["title"] + "' '" + header["description"] + "' '" + header["relpath"] + "' " + header["cover"] + " %}"
w_file.write(galleryCmd)
print(galleryCmd, "has been written to", index_file_path)
w_file.write("</div>\n\n")
print("div has been closed")

def randCover(string):
sha256_hash = hashlib.sha256()
# 将字符串转换为字节类型并进行哈希计算
sha256_hash.update(string.encode('utf-8'))
# 获取散列值(以十六进制字符串表示)
hash_value = sha256_hash.hexdigest()
# 将十六进制散列值转换为对应的十进制整数
hash_int = int(hash_value, 16)

coverList = [ "https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/default.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/calm_ocean_breeze.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/deep_space.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/dreamy_violet.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/evening_glow.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/fresh_meadow.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/frosty_morning.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/golden_beach.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/morning_dew.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/morning_glow.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/mysterious_night.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/mysterious_sea.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/prairie_sunset.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/romantic_pink.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/serene_forest.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/starry_galaxy.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/sunset_dusk.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/tranquil_blue_sky.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/tropical_rainforest.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/warm_sunshine.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/winter_aurora.png"
]
index = hash_int % len(coverList)
return coverList[index]



indexDict = {
"journey" : "旅途",
"edu" : "支教",
"letter" : "雲笺信语",
"other" : "其他",
"tech" : "纯纯寄术流",
"yoyo" : "悠悠"
}


for key, value in indexDict.items():

# 该文件夹下的所有文件(以便日期排序)
file_paths = []

# 要遍历的文件夹路径
folder_path = "./source/_posts/" + value
# 打开文件,准备写入绝对路径的文件
index_file_path = "./source/index/" + key + "/index.md"

with open(index_file_path, "r") as r_file:
lines = r_file.readlines()

with open(index_file_path, "w") as w_file:
for i in range(0, 6):
w_file.write(lines[i])

# 遍历文件夹下的所有文件
for root, dirs, files in os.walk(folder_path):
dirs.sort()
for file_name in sorted(files):
file_path = os.path.join(root, file_name)
if file_path.endswith(".md"):
file_paths.append(file_path)

last_head_weight = 0
last_parent = ""
# 头部索引的列表,用于排序和暂存
headerList = []
for path in file_paths:
curr_head_weight, curr_parent = folderParser(path)
headMkd = head(curr_parent, curr_head_weight)
if not curr_head_weight == last_head_weight: # 标题级别不等
headWritter(headerList, w_file)
w_file.write(headMkd)
print(headMkd, "has been written to", index_file_path, "\n")
headerList = []
elif not last_parent == curr_parent: # 标题级别等但是标题内容不等
headWritter(headerList, w_file)
w_file.write(headMkd)
print(headMkd, "has been written to", index_file_path, "\n")
headerList = []
last_head_weight = curr_head_weight
last_parent = curr_parent
with open(path, "r") as file:
lines = file.readlines()[0:15]
headDict = {"relpath" : path.split("_posts")[-1].replace(".md", "").strip(), "path" : path}
for line in lines:
if line.strip().startswith("hidden"):
headDict["hidden"] = line.replace("hidden:", "").strip()
if line.strip().startswith("description"):
headDict["description"] = line.replace("description:", "").strip()
if line.strip().startswith("cover"):
headDict["cover"] = line.replace("cover:", "").strip()
if line.strip().startswith("title"):
headDict["title"] = line.replace("title:", "").strip()
if line.strip().startswith("date"):
headDict["date"] = line.replace("date:", "").strip()
# 特殊情况处理
if not "description" in headDict or headDict["description"] == "" or headDict["description"] == "null":
headDict["description"] = "description"
if not "hidden" in headDict or headDict["hidden"] == "" or headDict["hidden"] == "null":
headDict["hidden"] = "false"
if not "cover" in headDict or headDict["cover"] == "" or headDict["cover"] == "null" or headDict["cover"].startswith("'linear-gradient"):
headDict["cover"] = randCover(headDict["date"])

if headDict["hidden"] == "false":
headerList.append(headDict)
headWritter(headerList, w_file)

史诗级更新:抄了butterfly页面的外挂标签

👉🏻指路牌

史诗级更新:用updated字段避免action文件mtime雷同

👉🏻指路牌

勇者级更新:AutoDeploy脚本实现hx new 避免hexo assert文件夹的副作用

1
2
3
4
5
6
7
8
9
10
11
elif [ "$input" = "new" ]; then 
cd ~/blogs/source/_posts
read -p "Present working dir: $(pwd), sure to continue?y/n" continueNew
if [ "$continueNew" = "n" ]; then
echo "Bye!"
else
hexo new -p "$filename"
echo "____"
echo "$filename"
rmdir "$(pwd)/$filename"
fi

重构文件夹

在技术流下,新增毕设,博客相关文件夹,可能导致某些相对路径引用失效

//TODO

  • permlink是否可以有效解决这个问题?

  • permlink和asset文件夹是否冲突?

20240219更新日志

开启asset资源文件夹

使用不太方便的外挂标签引用, 对pdf等文件支持不错, 直接引用, 不要加相对路径, 缺点是对markdown的支持又变少了

在markdown中也无法显示, 因此尽量对文件使用标签, 对图片使用图床

坏处是,同一个文件夹内,如果有直属的md文件,就会有同名的文件夹,也可能会有子文件夹,这样会搞不清楚资源文件夹和子文件夹

同样的, 要想使得资源能够正常访问,就得保持asset属性开启,那么就尽量避免用hexo new来新建文件,这样会使得文件夹变乱

可以考虑复制粘贴,或者也集成到autoDeploy中,用hx命令解决

使用脚本可将旧的笔记转移到这里

迁移记录

开启butterfly page页的toc功能

TODO

  • 使用脚本管理index页面(yml树状结构存储?)

  • 测试多端部署能力

20240216更新日志

Twikoo的数据库由netlify转为huggingface,解决墙问题,增加自动化

这里遇到一个很大的问题就是,netlify被墙了,至于为什么会被墙,我也很难理解。

据说huggingface,不能发SMTP,这下进退两难了。

今天凌晨在解决Twikoo不能评论的问题的时候,怎么也没想到是被墙了,跑去官方群问,问出njuse同行🐴同志,🤡

但很遗憾hugginface无法自动发邮件

动态分类导航磁贴

教程

主页双栏

教程

更新shell脚本

  • cd 根目录
  • 询问是否继续
  • 询问commit message

themes 文件夹 diff

1
2
3
4
5
6
Files butterfly/layout/category.pug and /node_modules/butterfly/layout/category.pug differ
Files butterfly/layout/includes/categoryBar.pug and /node_modules/butterfly/layout/includes/categoryBar.pug differ
Files butterfly/layout/index.pug and /node_modules/butterfly/layout/index.pug differ
Files butterfly/layout/page.pug and /node_modules/butterfly/layout/page.pug differ
Files butterfly/layout/tag.pug and /node_modules/butterfly/layout/tag.pug differ 以上文件均在实现导航磁贴,见github
Files butterfly/plugins.yml and /node_modules/butterfly/plugins.yml differ 将twikoo的插件版本号更改

文章置顶

1
sticky: 1 # 添加在front-matter

20240217更新日志

解决了评论系统问题

见另一篇文文章:hexo评论系统

解决了py脚本自动更新时间问题

判断一下是否需要写入即可。index页面依然是强制写入,但使用hash使得每个gallery对应的图片固定,使得git记录不再每次都显示6个index页面

1
2
3
4
needChange = 1
for line in lines:
if line.startswith("categories:") and line.strip() == rel_path:
needChange = 0

202402170016104

关闭随机top_cover,使得主页显示更紧密

分类页图标更改

跟简单,跟window manager配置时候的问题是一样的,字体引入了才能读取unicode,人在困的时候果然思维是呆滞的

小风车特效

小风车特效忘了从哪里学来的,反正很简单,其实对应的还有熊佬的自动加标题功能。但是butterfly自动带目录,所以不如小风车旋转。否则,带数字标题的小风车旋转也太奇怪了。

html 标签使用

见这篇文章

二级域名的使用

凌晨把raccoon.love解绑,给了netlify,结果github.io在朋友圈又被墙了,

买了个新域名xuebao.site,准备给github.io

突然想到raccoon.love还有二级域名可以用。。。。

🤡

遂把github.io重新绑到raccoon.love,netlify给了一个二级域名

并在此兜售xuebao.site域名

TODO

还是想把首页卡片改小一点,并显示description,因为双栏显示不了description

暂时关闭双栏

神奇的是,关闭双栏要先npm uninstall 双栏插件,hx clean还不起效果

20240215 基线发布

倒腾一周,终于有个还像样的基线可以发布了。最大的感受就是前端知识实在太少了,完全不足以覆盖问题,所以出了很多看起来匪夷所思的现象,使人夜不能寐。

hexo使用

基本使用见hexo文档和butterfly文档,不多赘述

详细解释组织博客的一些逻辑概念

post

博客的核心,推送到主页的文章,默认新建的页面类型,可加tag,category

page

功能性的页面,不会作为一篇文章在主页展示,也不可加tag, category,不会被标签页归档页和分类页收录(标签页归档页和分类页本身就是page)

例如标签页,分类页,归档页,主页,关于我页,以及自定义的各种专栏页面

draft

草稿,基本不用,用hidden更方便些

以上三个页面类型的基本模板在scaffolds文件夹下定义

category

分类属性,写在post类页面的头部,用于标识此文件属于哪一个或者多个分类

tag

分类属性,写在post类页面的头部,用于标识此文件属于哪一个或者多个标签

category和tag的区别

tag只能并列,没有树状从属关系。一篇文章可以打100个tag, 这一百个标签都会并列显示在标签页,地位等同

categoriy是有从属关系的,而且是树状,也就是说可以从属多个分类,hexo会默认将这些分类按照从前到后的顺序变成从属关系,像文件夹一样

image-20240214223825097

因此我的使用方式是,将所有文章强制加category,用分类页代替文件夹浏览,可以实现通过分类页快速定位任何一篇文章

有个bug,hidden插件隐藏掉的文章,不会计入文章综述,但是会计入分类页显示的文章数量。因此如果一个分类下的所有文章都是隐藏的,即使在分类页看起来有文章,点进去也会页面丢失

在hidden的github仓库, 作者给了我一个解决方案, 对应4.12版本

archive

时间轴,排列所有文章,稍微丑一点的主页?

hidden&password

依赖于hexo-hide-postshexo-blog-encrypt

hidden可以将post在主页、tag页、分类页面都隐藏,只可通过链接访问

password可以给文章加密

四种使用情况

  • no hidden & no password:正常公开的文章
  • hidden & no password:不想直接出现在主页被点击访问,但需要所有人通过链接可访问,如404页面,或者草稿页面
  • no hidden & password:不想让别人看,但希望可以通过主页标签页分类页访问的文章,也就是给持有密码的人看的文章
  • hidden & password:含私密信息的草稿,或者希望通过按钮导航给固定人看的且但防止其他人误点的文章。

图床

见另一篇文章typora+piclist+aliyunoss图床

这里不做导航,因为另一篇文章的地址时刻都在变化,如何实现自动更改链接?这也是一个问题

Butterfly魔改

由于css样式十分复杂,导致更改分类页面icon的想法一直未能实现,而现在我又要准备练球,练完球吃烧烤,因此本部分内容暂且告一段落,css文件夹依然保留,(而且大概率就是前面那几行导致的字体识别问题),但inject属性注释掉,主页的魔改也暂时告一段落,待我拥有了充足的css知识,再来更改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#article-container h1:before,
#article-container h2:before,
#article-container h3:before,
#article-container h4:before,
#article-container h5:before,
#article-container h6:before,
#post .post-outdate-notice:before,
.fontawesomeIcon,
.note:not(.no-icon)::before,
hr:before {
display: inline-block;
font-weight: 600;
font-style: normal;
font-variant: normal;
font-family: 'Font Awesome 5 Free';
text-rendering: auto;
-webkit-font-smoothing: antialiased
}

自动化

本来想用github流水线,但是鉴于blog规模较小,暂未使用

当前在本地实现了两个自动化功能:

  • 将每一篇post相对于source的路径添加到categories属性,这样分类页就是文件夹视图
  • 将每个分类下的文章以gallery外挂标签的形式,添加到对应文件夹的index中

其实还有一个就是写了个小脚本将以上过程和hexo三件套结合起来

依赖:npm install,python3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
hexo-site@0.0.0
├── hexo-blog-encrypt@3.1.9
├── hexo-deployer-git@4.0.0
├── hexo-generator-archive@2.0.0
├── hexo-generator-category@2.0.0
├── hexo-generator-index@3.0.0
├── hexo-generator-tag@2.0.0
├── hexo-hide-posts@0.4.0
├── hexo-lazyload-image@1.0.13
├── hexo-renderer-ejs@2.0.0
├── hexo-renderer-marked@6.2.0
├── hexo-renderer-pug@3.0.0
├── hexo-renderer-stylus@3.0.1
├── hexo-server@3.0.0
├── hexo-theme-butterfly@4.12.0
├── hexo-theme-fluid@1.9.7
├── hexo-theme-landscape@1.0.0
├── hexo-wordcount@6.0.1
└── hexo@7.1.0

1. categoryParser

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
import os

# 获取_posts目录的绝对路径
posts_dir = "./source/_posts"
posts_dir_abs = os.path.abspath(posts_dir)

# 遍历_posts目录及其子目录下的所有文件
for root, _, files in os.walk(posts_dir):
for file in files:
file_path = os.path.join(root, file)

# 计算当前文件相对于_posts目录的路径
rel_path = os.path.relpath(file_path, start=posts_dir_abs)
rel_path = rel_path[:rel_path.rfind('/')].replace("/", ", ")
rel_path = "categories: [" + rel_path + "]"

with open(file_path, 'r') as file:
lines = file.readlines()

index = 0
catindex = 0
with open(file_path, 'w') as file:
for line in lines:
index += 1
if line.strip().startswith("categories:"):
file.write(rel_path + "\n")
catindex = index
else:
file.write(line)

print(rel_path, "has been written to", file_path, "line:", catindex)

起因是,不想每次新建post文件时,都手动将两层或者三层分类都输入到头部,另外总会有忘记输入的时候,这就需要自动化的检查了

<!DOCTYPE html>

源文件目录
文件头部属性
部署后的分类页面

代码实现逻辑就是遍历目录,用os.walk很方便,找到文件,记录相对路径,字符串替换,打开文件,按行读取,如果行首是categories,则写入,否则写入原来行内容。

相当于是把文件重写,但是git并不会将重写的行识别为已更改,所以应该不会给push带来压力。

2. galleryParser

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
import os
import random

def randCover():
coverList = [ "https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/default.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/calm_ocean_breeze.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/deep_space.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/dreamy_violet.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/evening_glow.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/fresh_meadow.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/frosty_morning.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/golden_beach.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/morning_dew.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/morning_glow.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/mysterious_night.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/mysterious_sea.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/prairie_sunset.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/romantic_pink.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/serene_forest.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/starry_galaxy.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/sunset_dusk.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/tranquil_blue_sky.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/tropical_rainforest.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/warm_sunshine.png",
"https://picturebed-raccoon.oss-cn-hangzhou.aliyuncs.com/wallpapers/colorful/400x400/winter_aurora.png"
]
return random.choice(coverList)

indexDict = {
"journey" : "旅途",
"edu" : "支教",
"letter" : "雲笺信语",
"other" : "其他",
"tech" : "纯纯寄术流",
"yoyo" : "悠悠"
}

for key, value in indexDict.items():
# 该文件夹下的所有文件(以便日期排序)
file_paths = []
# 头部索引的列表,用于排序
headerList = []
# 要遍历的文件夹路径
folder_path = "./source/_posts/" + value
# 打开文件,准备写入绝对路径的文件
index_file_path = "./source/index/" + key + "/index.md"

# 遍历文件夹下的所有文件
for root, _, files in os.walk(folder_path):
for file_name in files:
file_path = os.path.join(root, file_name)
file_paths.append(file_path)

for path in file_paths:
with open(path, "r") as file:
lines = file.readlines()[0:10]
headDict = {"relpath" : path.split("_posts")[-1].replace(".md", "").strip(), "path" : path}
for line in lines:
if line.strip().startswith("hidden"):
headDict["hidden"] = line.replace("hidden:", "").strip()
if line.strip().startswith("description"):
headDict["description"] = line.replace("description:", "").strip()
if line.strip().startswith("cover"):
headDict["cover"] = line.replace("cover:", "").strip()
if line.strip().startswith("title"):
headDict["title"] = line.replace("title:", "").strip()
if line.strip().startswith("date"):
headDict["date"] = line.replace("date:", "").strip()
# 特殊情况处理
if not "description" in headDict or headDict["description"] == "" or headDict["description"] == "null":
headDict["description"] = "description"
if not "hidden" in headDict or headDict["hidden"] == "" or headDict["hidden"] == "null":
headDict["hidden"] = "false"
if not "cover" in headDict or headDict["cover"] == "" or headDict["cover"] == "null" or headDict["cover"].startswith("'linear-gradient"):
headDict["cover"] = randCover()

if headDict["hidden"] == "false":
headerList.append(headDict)

sortedList = sorted(headerList, key=lambda x: x["date"], reverse=True)

with open(index_file_path, "r") as file:
lines = file.readlines()

with open(index_file_path, "w") as file:
for i in range(0, 6):
file.write(lines[i])
for header in headerList:
galleryCmd = "\n{% galleryGroup '" + header["title"] + "' '" + header["description"] + "' '" + header["relpath"] + "' " + header["cover"] + " %}"
file.write(galleryCmd)
print(galleryCmd, "has been written to", index_file_path)

基本逻辑是,用dict存储_post的子文件夹和index的子文件夹的对应关系,此dict需要维护,如果post目录有新增或重命名,需要新建index对应page,并修改此dict和yml文件中的专栏属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
menu:
首页: / || fas fa-home
关于我: /about/ || fa-regular fa-address-card
目录||fa fa-indent:
时间轴: /archives/ || fas fa-archive
标签: /tags/ || fas fa-tags
分类: /categories/ || fas fa-folder-open
专栏||far fa-compass:
旅程: /index/journey/ || fas fa-earth-americas
🪀 悠悠: /index/yoyo/
支教: /index/edu/ || fas fa-graduation-cap
纯纯寄术流: /index/tech/ || fab fa-ubuntu
雲笺信语: /index/letter || fas fa-envelope
其他: /index/other || fas fa-link

对每一个key和value,读取对应的post文件夹下的所有文件,加入到file_paths, 同时读取相应index文件夹下的index.md文件,

<!DOCTYPE html>

post文件目录
index文件目录

对于file_paths里的每一个文件,读取头部信息,存储为dict,并在内存中生成一个list存放hidden为false的dict。

读取header时候要做特殊判断,cover可能为渐变线性函数表达,这种是不能直接写入gallery外挂标签的语法里的,调用一个randomCover返回一个随机cover

然后打开相应的index文件,前6行不动,后面按照时间近到远按照外挂标签语法强制写入即可,源post文件更新头部信息也可以强制同步

3. autoDeploy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/bin/bash
input=$1
pwd
if [ "$input" = "s" ]; then
hexo clean && hexo g && hexo s
elif [ "$input" = "d" ]; then
/usr/bin/python3 /Users/raccoon/blogs/auto/categoryParser/parser.py
/usr/bin/python3 /Users/raccoon/blogs/auto/galleryParser_py/main.py
hexo clean && hexo g && hexo d
git add .
git commit -m 'update blog'
git push
elif [ "$input" = "category" ]; then
/usr/bin/python3 /Users/raccoon/blogs/auto/categoryParser/parser.py
elif [ "$input" = "gallery" ]; then
/usr/bin/python3 /Users/raccoon/blogs/auto/galleryParser_py/main.py
else
echo "error input"
fi

很简单的一个脚本,在blog根目录执行,s命令集成了hexo三件套,d命令部署完还会将blog源码也push,便于多端协同

在deploy之前也会运行两个py脚本保证文章结构

自己还在本地放了一个alias,方便

1
alias hx=/Users/raccoon/blogs/auto/autoDeploy.sh

4. 硬编码点

  • post头部信息行数

  • index头部信息行数

  • 专栏文件夹数量
  • index文件夹数量
  • 以上两者的对应关系的dict,yml中的导航菜单

5. bugs

文章更新时间为文件修改时间,使用py脚本相当于每个文件都被touch一次,导致文章更新时间一模一样

使用Github Action也会导致一样的情况

Twikoo

https://libertysea.github.io/posts/3ac55f45.html

https://sheerkvc.top/2024/01/22/62.commentUpdate/

前端就是好啊,直接薄纱Valine

Netlify+MongoDB也薄纱LeanCloud(尤其是国内版)

前端数据项配置见auto文件夹

参考博客:

spricoder.github.io

eaglebear2002.github.io

aomanhao.top (私密评论,typecho动态博客,handsome主题)

bankyin.github.io

https://beaumon.github.io/

https://zfe.space

https://kaiboshi.gitee.io/

https://youngjuning.js.org/871db46757c2/

https://benpaodewoniu.github.io/categories/

TODO