标签外挂是 Hexo 独有的功能,并不是标准的 Markdown 格式。

以下的写法,只适用于 Butterfly 主题,用在其它主题上不会有效果,甚至可能会报错。使用前请留意

Butterfly主题 自带的标签外挂

More info

推荐添加的标签外挂

哔哩哔哩卡片标签外挂

效果

添加方法

bilibili.js

[blogroot]\themes\butterfly\scripts\tag下新建文件bilibili.js并粘贴如下代码:

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
'use strict'
let playIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none" class="icon"><path fill-rule="evenodd" clip-rule="evenodd" d="M4.67735 4.2798C5.98983 4.1725 7.85812 4.0625 10 4.0625C12.1421 4.0625 14.0105 4.17252 15.323 4.27983C16.2216 4.3533 16.9184 5.04049 16.9989 5.9318C17.0962 7.00837 17.1875 8.43614 17.1875 10C17.1875 11.5639 17.0962 12.9916 16.9989 14.0682C16.9184 14.9595 16.2216 15.6467 15.323 15.7202C14.0105 15.8275 12.1421 15.9375 10 15.9375C7.85812 15.9375 5.98983 15.8275 4.67735 15.7202C3.77861 15.6467 3.08174 14.9593 3.00119 14.0678C2.90388 12.9908 2.8125 11.5627 2.8125 10C2.8125 8.43727 2.90388 7.00924 3.00119 5.93221C3.08174 5.04067 3.77861 4.35327 4.67735 4.2798ZM10 2.8125C7.81674 2.8125 5.9136 2.92456 4.5755 3.03395C3.07738 3.15643 1.8921 4.31616 1.75626 5.81973C1.65651 6.92379 1.5625 8.39058 1.5625 10C1.5625 11.6094 1.65651 13.0762 1.75626 14.1803C1.8921 15.6838 3.07738 16.8436 4.5755 16.966C5.9136 17.0754 7.81674 17.1875 10 17.1875C12.1835 17.1875 14.0868 17.0754 15.4249 16.966C16.9228 16.8436 18.108 15.6841 18.2438 14.1807C18.3435 13.077 18.4375 11.6105 18.4375 10C18.4375 8.38948 18.3435 6.92296 18.2438 5.81931C18.108 4.31588 16.9228 3.15645 15.4249 3.03398C14.0868 2.92458 12.1835 2.8125 10 2.8125ZM12.1876 10.722C12.7431 10.4013 12.7431 9.59941 12.1876 9.27866L9.06133 7.47373C8.50577 7.15298 7.81133 7.55392 7.81133 8.19542V11.8053C7.81133 12.4468 8.50577 12.8477 9.06133 12.527L12.1876 10.722Z" fill="#9499A0"/></svg>`
let likeIcon = `<svg width="36" height="36" viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg" class="icon"><path fill-rule="evenodd" clip-rule="evenodd" d="M9.77234 30.8573V11.7471H7.54573C5.50932 11.7471 3.85742 13.3931 3.85742 15.425V27.1794C3.85742 29.2112 5.50932 30.8573 7.54573 30.8573H9.77234ZM11.9902 30.8573V11.7054C14.9897 10.627 16.6942 7.8853 17.1055 3.33591C17.2666 1.55463 18.9633 0.814421 20.5803 1.59505C22.1847 2.36964 23.243 4.32583 23.243 6.93947C23.243 8.50265 23.0478 10.1054 22.6582 11.7471H29.7324C31.7739 11.7471 33.4289 13.402 33.4289 15.4435C33.4289 15.7416 33.3928 16.0386 33.3215 16.328L30.9883 25.7957C30.2558 28.7683 27.5894 30.8573 24.528 30.8573H11.9911H11.9902Z"></path></svg>`
let coinIcon = `<svg width="28" height="28" viewBox="0 0 28 28" xmlns="http://www.w3.org/2000/svg" class="icon" style="fill:;"><path fill-rule="evenodd" clip-rule="evenodd" d="M14.045 25.5454C7.69377 25.5454 2.54504 20.3967 2.54504 14.0454C2.54504 7.69413 7.69377 2.54541 14.045 2.54541C20.3963 2.54541 25.545 7.69413 25.545 14.0454C25.545 17.0954 24.3334 20.0205 22.1768 22.1771C20.0201 24.3338 17.095 25.5454 14.045 25.5454ZM9.66202 6.81624H18.2761C18.825 6.81624 19.27 7.22183 19.27 7.72216C19.27 8.22248 18.825 8.62807 18.2761 8.62807H14.95V10.2903C17.989 10.4444 20.3766 12.9487 20.3855 15.9916V17.1995C20.3854 17.6997 19.9799 18.1052 19.4796 18.1052C18.9793 18.1052 18.5738 17.6997 18.5737 17.1995V15.9916C18.5667 13.9478 16.9882 12.2535 14.95 12.1022V20.5574C14.95 21.0577 14.5444 21.4633 14.0441 21.4633C13.5437 21.4633 13.1382 21.0577 13.1382 20.5574V12.1022C11.1 12.2535 9.52148 13.9478 9.51448 15.9916V17.1995C9.5144 17.6997 9.10883 18.1052 8.60856 18.1052C8.1083 18.1052 7.70273 17.6997 7.70265 17.1995V15.9916C7.71158 12.9487 10.0992 10.4444 13.1382 10.2903V8.62807H9.66202C9.11309 8.62807 8.66809 8.22248 8.66809 7.72216C8.66809 7.22183 9.11309 6.81624 9.66202 6.81624Z"></path></svg>`

function bilibili(args) {
const id = args[0].replace(/.*video\/(.*)\/?.*/, '$1')
const time = args[1]
const hidden_desc = args[2]
return `
<a href="https://www.bilibili.com/video/${id}/" class="bilibili_box" id="${id}"></a>

<script>
bilibili()
function bilibili() {
let dom = document.getElementById('${id}')
fetch('https://bilibili.o0w0b.top/api/b?id=${id}').then(res=>res.json()).then(data=>{
dom.innerHTML = \`
<div class="bilibili_cover">
<img src="https://s1.hdslb.com/bfs/static/player/img/play.svg" class="play_icon no-lazyload">
<img src="\${data.pic + '&h=300'}" class="no-lazyload">
${time ? `<span>${time}</span>` : ''}
</div>
<div class="bilibili_info">
<div class="title">\${data.title}</div>
${hidden_desc == 'true' ? '' : '<div class="desc">\${data.desc}</div>'}
<div class="stat">
<span>${playIcon}\${data.view}</span>
<span>${likeIcon}\${data.like}</span>
<span>${coinIcon}\${data.coin}</span>
</div>
<div class="owner">
<span class="tip">视频</span>
<img src="\${data.face + '&h=100'}" class="no-lazyload">
<span>\${data.owner}</span>
</div>
</div>
\`
})
}
</script>
`
}

hexo.extend.tag.register('bilibili', bilibili, { ends: false })

bilibili.styl

[blogroot]\themes\butterfly\source\css\_tags下新建文件bilbili.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
.bilibili_box
display: flex
background: var(--card-bg)
border: 1px solid #e0e3ed
border-radius: 10px
overflow: hidden
color: var(--font-color) !important
text-decoration: none !important
transition: .3s
&:hover
border-color: #4976f5
+maxWidth768()
flex-direction: column
.bilibili_cover
width: 234px
position relative
+maxWidth768()
width: 100%
img
width: 100%
filter: none
margin: 0 !important
border-radius: 0 !important
.play_icon
position: absolute
width 45px
height 45px
opacity .8
top: 50%
left 50%
transform: translate(-50%,-50%)
span
position: absolute
bottom: 0px
right: 5px
color: white
text-shadow: 0 1px 3px #7a7a7a
.bilibili_info
padding: 10px 10px 10px 18px
line-height: 1
width: calc(100% - 200px)
display: flex
flex-direction: column
justify-content: space-around
+maxWidth768()
width: 100%
padding-bottom: 25px
line-height: 1.5
.title
font-size: 1.2rem
font-weight: bold
white-space: nowrap
overflow: hidden
text-overflow: ellipsis
line-height: 1.5
.desc
font-size: 15px
margin: 2px 0 4px
white-space: nowrap
overflow: hidden
text-overflow: ellipsis
+maxWidth768()
// word-break: break-all
white-space: normal
display:-webkit-box;
-webkit-box-orient:vertical;
-webkit-line-clamp:2;
.stat
font-size: 15px
svg
margin-right: 3px
font-size: 18px
width: 1em
height: 1em
path
fill: var(--font-color)
span
margin-right: 10px
display: inline-flex
align-items: center
.owner
display: flex
align-items: center
line-height: 1
font-size: 15px
.tip
color: #FF6699
border: 1px solid
padding: 3px 6px
font-size: 12px
border-radius: 5px
margin-right: 10px
img
width 22px
height: 22px
border-radius: 50% !important
object-fit: cover
margin 0 5px 0 0 !important

[data-theme='light'] .bilibili_box .bilibili_info .stat svg,
[data-theme='dark'] .bilibili_cover
opacity .8

使用方法

使用此标签外挂只需要填写视频链接,填写后将会自动获取信息
视频时长因为不容易通过 api 获取,所以设置成了手动填写

1
{% bilibili 视频链接 视频时长 是否隐藏简介 %}

若需要隐藏简介,在后面添加 true,默认不隐藏简介

1
2
3
{% bilibili https://www.bilibili.com/video/BV1NT411C7wS 25:01 %}
<!-- 如果想要隐藏简介,添加true即可(注意,要隐藏简介则必须填写视频时间!),如下 -->
{% bilibili https://www.bilibili.com/video/BV1NT411C7wS 25:01 true %}

同一个视频的卡片不能同时显示, 如果同时设置多个同一个视频的卡片,

只会在第一个位置显示,且会根据最后一个的设置决定是否隐藏简介

隐藏简介后的效果

关于用到的API

API地址:https://bilibili.o0w0b.top/api/b

该API由Vercel托管,强烈建议自建API

  • id

    bilibili 视频ID

  • t

    请求单个数据的类型,可选值如下

备注
owner 视频作者名
face 视频作者头像
title 视频标题
desc 视频简介
pic 视频封面
view 观看数量
like 点赞数
coin 投币数
danmaku 弹幕数
favorite 收藏数
reply 评论数量
share 分享数量

示例:

  1. https://bilibili.o0w0b.top/api/b?id=BV1h84y1Y7nn
    会返回视频的所有数据
  2. https://bilibili.o0w0b.top/api/b?id=BV1h84y1Y7nn&t=view
    会返回视频的观看数量

自建API

安装Vercel CLI

打开终端,运行如下命令

1
npm i -g vercel

初始化项目

新建一个文件夹,然后在此文件夹中打开终端

运行如下命令,然后重复按回车

1
npm init

安装axios

运行如下命令

1
npm i axios

创建文件

创建完成后的结构

新建 api 目录,然后在 api 目录下创建如下两个文件

创建的文件名字对应你后期的 api 路径名,如 b.js 对应 xxx.top/api/b
另外,index.js 文件对应的是 xxx.top/api

b.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const axios = require('axios')
module.exports = async (req, res) => {
if (req.method === 'GET') {
if (req.query.id) {
let { data } = await axios.get('https://api.bilibili.com/x/web-interface/view?bvid=' + req.query.id)
data = data.data
let ls = {
owner: data.owner.name,
face: "https://images.weserv.nl/?url=" + data.owner.face,
title: data.title,
desc: data.desc,
pic: "https://images.weserv.nl/?url=" + data.pic,
coin: data.stat.coin,
danmaku: data.stat.danmaku,
favorite: data.stat.favorite,
like: data.stat.like,
reply: data.stat.reply,
share: data.stat.share,
view: data.stat.view,
}
if (req.query.t) { return res.send(ls[req.query.t]) } else return res.send(JSON.stringify(ls))
} else { return res.send('Hi Bilibili') }
}
}

index.js

为了避免访问 xxx.top/api 报错,我们给它也添加一个内容使其返回 Hi Bilibili

1
2
3
module.exports = (req, res) => {
return res.status(200).send('Hi Bilibili')
}

在根目录下创建 vercel.json 文件并粘贴如下代码:
(这一步是为了防止跨域)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
"headers": [
{
"source": "/api/(.*)",
"headers": [
{
"key": "Access-Control-Allow-Origin",
"value": "*"
},
{
"key": "Access-Control-Allow-Headers",
"value": "X-Requested-With, Content-Type, Authorization"
},
{
"key": "Access-Control-Allow-Credentials",
"value": "true"
}
]
}
]
}

部署

在部署前先运行如下命令来测试代码是否生效

第一次运行会让登录和创建项目,登录的话选择你平时登录的方式,例如:github ,在浏览器完成授权就登录成功了。创建项目就重复按回车即可。

运行如下命令,然后重复按回车

1
vercel dev

测试index.js:浏览器打开http://localhost:3000/api ,页面正常会显示 Hi Bilibili

测试b.js:http://localhost:3000/api/b?id=BV1h84y1Y7nn ,页面正常会显示相应数据

本地测试没问题了就可以运行如下命令进行线上部署了

1
vercel --prod

vercel提供的网址在国内无法访问,需要绑定一个自己的域名


链接卡片标签外挂

效果

添加方法

link.js

[blogroot]\themes\butterfly\scripts\tag下新建文件link.js并粘贴如下代码:

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
/**
* link
* {% link title,desc,url %}
* {% link 标题,介绍,链接 %}
*/

'use strict'

let defaultIcon = "https://imgbed.o0w0b.top/file/1764343661265_image.png";

function link(args) {
args = args.join(' ').split(',');

// 获取参数
let title = (args[0] || '点击直达链接').trim(),
desc = (args[1] || '').trim(),
url = (args[2] || '').trim(),
urlNoProtocol = url.replace(/^https?\:\/\//i, ""),
imgUrl = (args[0] ? "https://www.faviconextractor.com/favicon/" + urlNoProtocol : defaultIcon).trim();

// 使用 <img> 标签,但添加 onerror,如果获取不到图标就显示 defaultIcon
let favicon = `<img src="${imgUrl}" class="no-lightbox" onerror="this.src='${defaultIcon}'">`;

return `<a href="${url}" ${url.includes('http') ? 'target="_blank"' : ''} title="${title}" referrerPolicy="no-referrer" class="link_card">
<div class="link_icon">${favicon}</div>
<div class="link_content">
<div class="link_title">${title}</div>
${desc ? `<div class="link_desc">${desc}</div>` : ''}
</div>
</a>`;
}

hexo.extend.tag.register('link', link, { ends: false })

link.styl

[blogroot]\themes\butterfly\source\css\_tags下新建文件link.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
.link_card
display: flex
margin: 10px 0
color: var(--font-color) !important
text-decoration: none !important
background: var(--reward-pop)
border-radius: 10px
padding: 12px
&:hover
background: #9370DB /* 鼠标悬浮时的颜色, 可自定义修改 */
color: white !important
.link_icon,.link_content
height: 4rem
.link_icon
img,svg
height: 4rem
width: 4rem
.link_content
margin-left: 1rem
width: calc(100% - 6rem)
overflow: hidden
line-height: 1.5
display: flex
flex-direction: column
justify-content: center
.link_title
font-weight: bold
font-size: 1.2rem
.link_title,.link_desc
word-break: break-all
overflow:hidden
text-overflow: ellipsis
&:not(:has(.link_desc)) .link_title
display:-webkit-box
-webkit-box-orient:vertical
-webkit-line-clamp:2
.link_desc
opacity: .6
.link_desc,&:has(.link_desc) .link_title
white-space: nowrap

使用方法

使用此标签外挂不需要写网站图标的链接,填写网站链接后将会自动获取
如果未能获取,会显示默认图标 ( https://imgbed.o0w0b.top/file/1764343661265_image.png )

1
{% link 标题, 描述,链接 %}

链接的开头需要加https,例如:https://o0w0b.top

不加https的效果请自行尝试

使用时,这三个参数虽然不需要全写,但位置一定要留出来

  • 只添加链接

该方式的标题默认为 “点击直达链接”,图标为未能获取网站图标时的默认图标

1
{% link ,,https://o0w0b.top %}

效果:

  • 不添加描述
1
{% link o0w0b的主页,, https://o0w0b.top %}

效果: