惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
WordPress大学
WordPress大学
宝玉的分享
宝玉的分享
人人都是产品经理
人人都是产品经理
博客园 - 聂微东
IT之家
IT之家
V
V2EX
Jina AI
Jina AI
V
Visual Studio Blog
有赞技术团队
有赞技术团队
博客园 - 司徒正美
博客园 - 叶小钗
The Cloudflare Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
小众软件
小众软件
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 三生石上(FineUI控件)
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Google DeepMind News
Google DeepMind News
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
腾讯CDC
Google Online Security Blog
Google Online Security Blog
博客园 - 【当耐特】
Apple Machine Learning Research
Apple Machine Learning Research
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
N
News and Events Feed by Topic
N
News and Events Feed by Topic
The Last Watchdog
The Last Watchdog
W
WeLiveSecurity
月光博客
月光博客
Security Archives - TechRepublic
Security Archives - TechRepublic
Webroot Blog
Webroot Blog
SecWiki News
SecWiki News
博客园_首页
罗磊的独立博客
量子位
Latest news
Latest news
I
Intezer
V
Vulnerabilities – Threatpost
A
Arctic Wolf
Last Week in AI
Last Week in AI
Recent Commits to openclaw:main
Recent Commits to openclaw:main
S
SegmentFault 最新的问题
S
Security Affairs
阮一峰的网络日志
阮一峰的网络日志
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
酷 壳 – CoolShell
酷 壳 – CoolShell
P
Palo Alto Networks Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
N
News | PayPal Newsroom

山岳库博

自建虚拟局域网实现文明六稳定联机 追光者 快手面经(二〇二四年五月九日) 一文搞懂伪代码 2023 级新生周赛第二周题解 Swpp Backends 官方文档 在 MavenCentral 上发布你的项目 控制台游戏引擎开发文档 MI——高级合成表模块 人狼羊菜过河详细题解 蓝桥杯 2023 训练四 Java 全解 蓝桥杯 2023 训练三 Java 全解 蓝桥杯 2023 训练二 Java 全解 全自动博客部署方案 小白也能用的 SW 构建插件 MI—电力系统工作原理 MI文档——自动化GUI绘制 给博客添加追番页面 网站加载速度优化方案总结 给博客添加自定义的通知悬浮窗
Butterfly 友链魔改教程
空梦 · 2023-04-23 · via 山岳库博

发表于更新于

字数总计1.6k阅读时长7分钟阅读量

更新日志
  • 更新精灵图生成器,修改缺省的本地文件库的位置,修复db.json异常膨胀的 BUG
  • 窄屏不再添加 css 动画
  • 精灵图支持拆分
  • 改进精灵图生成器
  • 发布初代版本

  该教程不适合小白食用,需要有一定的基本功!

  教程中没有支持配置项,如果你希望支持配置项的话可以自行修改。

魔改

  首先需要修改 pug,修改\layout\includes\page\flink.pug为:

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
#article-container
.flink
if site.data.link
-
let index = 0 // 计数器,不要修改
let group = 0 // 分组计数器,不要修改
// 头像文件名,按需修改
const avatarRoot = './sprites/avatar-'
const ext = 'jpg' // 头像拓展名,按需修改
const limit = 0 // 每张图片头像数量限制,按需修改,需要和精灵图保持一致
// 样式表,不要修改
let rootStyle = `.group-0{background:url(${avatarRoot}0.${ext})}`
-
each list in site.data.link
if list.class_name
h2!= list.class_name
if list.class_desc
.flink-desc!= list.class_desc
- let className = list.beautify ? 'beautify' : 'terse'
- if (list.deprecated) className += ' deprecated'
.flink-list(class = className)
each item in list.link_list
a.flink-item(href = url_for(item.link), target = '_blank')
if list.beautify
if item.tag
span.card-tag!= item.tag
img.card-bg.no-lightbox(src = url_for(item.siteshot))
.info
if list.deprecated
.text
span.name!= item.name
else
- const styleStr = index === 0 ? '' : `background-position-y:-${(index) * 100}px`
.avatar.no-lightbox(class=`group-${group.toString(16)}`, style=styleStr)
.text
span.name!= item.name
span.descr!= item.descr
-
if (++index === limit) {
index = 0
++group
rootStyle += `.group-${group.toString(16)}{background:url(${avatarRoot}${group}.${ext})}`
};
-
style!= rootStyle
!= page.content

  然后添加样式,修改\source\css\_page\flink.styl为:

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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
maxWidth(value)
@media screen and (max-width: unit(value, px))
{block}

minWidth(value)
@media screen and (min-width: unit(value, px))
{block}

.flink-list
display flex
flex-wrap wrap

.flink-item
position relative
border-radius 8px
overflow hidden
border var(--km-button-border)
background var(--hl-bg)

&:hover
text-decoration none !important
box-shadow var(--km-subt-shadow)
border var(--km-light-border)

.avatar
transition all .6s
border-radius 50%
background-size cover
width 100px
height 100px

.card-tag
position absolute
color white
font-size 10px
left 0
top 0
padding 4px 8px
background #0084FF
z-index 1
border-bottom-right-radius 12px
transition all .6s

.text
display flex
flex-direction column
padding-right 10px

.name
max-width 100%
font-weight bold
text-overflow ellipsis
white-space nowrap
overflow hidden

.descr
margin-bottom 10px
font-size small
overflow hidden
max-height 52px

&.beautify .flink-item
width calc(25% - 16px)
height 210px
margin 8px
transition all .6s

+maxWidth(1000)
width calc(33% - 16px)

+maxWidth900()
width calc(25% - 16px)

+maxWidth(700)
width calc(33% - 16px)

+maxWidth(500)
width calc(50% - 16px)

+maxWidth(350)
width calc(100% - 16px)

.card-bg
position relative
height 60%
min-width 100%
object-fit cover
margin 0 !important
transition all .6s !important
filter blur(0)

.info
position relative
height 40%
transition background .6s, height .6s

.avatar
position absolute
left -32px
top -32px
transform scale(.2)

.text
position relative
top 0
margin-left 30px
transition all .6s

+minWidth(500)
&:hover
.card-bg
height 35%
filter blur(3px)

.info
height 66%
background #F2B94B
color white

.avatar
left -10px
top -50px
transform rotateZ(-35deg) rotateX(360deg) rotateY(360deg) scale(.6)

.text
top 26px
margin-left 10px

.descr
max-height 78px

.card-tag
left -100%

&.terse
&:not(.deprecated)
.flink-item
height 100px

.flink-item
width calc(25% - 12px)
padding 6px
margin 6px

+maxWidth1024()
width calc(33% - 12px)

+maxWidth(1000)
width calc(50% - 12px)

+maxWidth900()
width calc(33% - 12px)

+maxWidth(700)
width calc(50% - 12px)

+maxWidth(450)
width calc(100% - 12px)

.info
position relative
height 100%
width 100%

.avatar
position absolute
transform scale(.7)
left -10px
top -6px

.text
position relative
left 85px
width calc(100% - 80px)
transition all .6s

+minWidth(600)
&:hover
.avatar
transform rotateX(180deg) rotateY(180deg) scale(.01)
left -100px
opacity 0

.text
left 10px
width calc(100% - 20px)

.text:first-child
left 10px
width calc(100% - 20px)

编写 YML

  然后我们还需要编写友链的 YML 文件,格式要求如下:

1
2
3
4
5
6
7
8
9
10
- class_name: name        # 分类名,任意字符串
beautify: true # 是否使用美化格式(缺省为 false)
deprecated: false # 是否标记为失联友链(缺省为 false)
link_list: # 友链列表
- name: name # 友链名称,任意字符串
link: url # 友链地址
descr: text # 简介,不要太长
siteshot: url # 美化格式的卡片上方的图片链接
# ......
# ......

生成精灵图

  接下来我们需要生成一个精灵图,有两种选择:

  1. 手动拼接
  2. 使用工具自动生成

  前者的话找一个图片编辑软件自己一个一个按顺序拼接起来就可以了,每个头像必须为正方形且大小相同、纵向排列。

  我写了一个自动化生成的工具,可以供小伙伴们使用:

  该软件使用 Kotlin 编写,运行环境的最低要求为 JRE8,使用时通过命令启动即可:

1
java -jar ./SpriteBuilder.jar [args]

  目前支持的参数有:

参数名值类型解释(缺省值)
ymlString友链文件的路径(./source/_data/link.yml
outputString输出文件的路径,不带拓展名(./sprites/avatar
sizeInt单个头像的大小(120
retryInt网络拉取重试次数(2
limitInt每张精灵图的头像数量限制,填 <= 0 的数表明无限制(0
formatString输出的图像格式,支持 jpg 和 png(jpg
localString本地图像库地址(./.sprite_data/
timeoutInt网络拉取超时时间,单位 ms(10000

  该工具支持解析友链 YML 的信息,然后拼接出图片,只支持导出 jpg 格式。

  YML 的格式要求如下:

1
2
3
4
5
6
7
8
9
10
11
- deprecated: false     # 为 true 时该分类不生成头像,缺省为 false
link_list:
- link: url # 友链地址
avatar: url0 # 头像的地址,以`file://`开头时会从本地读取(例如:file//D:/a.jpg)
- link: url # 友链地址
avatar: url1
# ......
- deprecated: false
link_list:
# ......
# ......

  工具支持解析ImageIO.read支持的所有图像格式,同时附加webp格式支持,基本覆盖常用格式,解析图像时使用图像的二进制数据判断图像格式。

  本地图像库用于自动替换友链的头像,比如有如下 yaml:

1
2
3
- link_list:
- link: https://kmar.top/
avatar: https://image.xxx.top/qq.jpg

  工具会在本地图像库中检查目录中是否存在名为kmar.*的文件,如果有的话会直接使用本地图像库中的图片,不会发起网络请求。

  在本地库中查找时,会使用link的域名(不带二级域名和顶级域名)作为文件名称,比如:

  • https://kmar.top/ - kmar
  • https://www.kmar.top/ - kmar
  • https://abc.github.io/ - github

  如果本地图像库中存在多个文件名一致但拓展名不一致的文件,会选择最后一个。

  工具在拉取文件时的请求头设置如下:

1
2
3
referer: 'https://sprite-builder.kmar.top/'
user-agent: 'sprite-builder'
accept: 'image/webp, image/*'

  当拉取文件遇到 403 错误时,会尝试将referer设置为空,然后重新进行拉取(如果没有超出重试次数限制的话)。


创作不易,扫描下方打赏二维码支持一下吧ヾ(≧▽≦*)o

avatar

Butterfly 友链魔改教程空 梦 | 山岳库博

更新于 2023-10-18

发布于 2023-04-23