230731更新后,三端全面支持 瀑布流、图片灯箱、图片灯箱、外部链接、自定标识、快速评论、音乐模块、视频模块、说说置顶 功能。除了社交平台,即刻说也可成为你的下一个“朋友圈”。

250103更新的版本里,结合了在此前多位喵友的反馈和提醒下,重新修正了本篇内容,至此,可以说是大大优化了上手的难度,和减少教程的上手难度。

如果没有服务器可以搭建memos,可以使用iCat自用的memos服务

效果预览

创建数据

小节开始前,提醒事项。
对于初次魔改新手,建议先过一遍:魔改前置教程:添加自定义css和js文件

  • 创建[博客根目录]/source/essay/index.md页面,并配置以下内容。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
---
title: 即刻短文
date: 2023-01-17 13:38:17
type: essay
top_img: false
aside: false
top_page: true
top_bg: https://img.meuicat.com/banner
top_item: 即刻短文
top_title: 封の碎碎念
top_tips: 使用 即刻短文动态部署版 构建
top_link: /about/
top_text: 关于博主
---

<!-- 页面内容 -->
  • 创建[主题目录]/layout/includes/page/essay.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
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
mixin renderArticle(item)
.item
.bber-content
if item.content
p.datacont= item.content

if item.image
.bber-image
each iten, indey in item.image
- const image = item.image[indey].split('||')
img(src=image[0] alt=image[1] ? image[1] : '' title=image[1] ? '' : '即刻短文配图' )

if item.video
.bber-video
if item.video.bilibili
- const autoplay = item.video.autoplay ? '&autoplay=1' : '&autoplay=0'
- const biliurl = '//player.bilibili.com/player.html?bvid=' + item.video.bilibili.match(/(BV\w+)/)[1] + autoplay

iframe(src=biliurl scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true")
else if item.video.player
video(src=item.video.player controls="controls" style="object-fit: cover")

if item.aplayer
.bber-music
.aplayer(data-id=item.aplayer.id data-server=item.aplayer.server data-type="song" data-autoplay="false" data-mutex="true" data-theme='var(--icat-theme)')

hr

.bber-bottom
.bber-info
.bber-info-time
i.MeuiCat.icon-calendar-todo-fill
time.datatime(datetime=item.date)= 'Loading'

if item.from
.bber-info-from
span= item.from

if item.link
- const link = item.link.split('||')
a.bber-content-link(target="_blank" href=link[0] title=link[1] ? link[1] : '跳转到短文指引的链接')
i.MeuiCat.icon-link-m-line
| 链接

if item.top
.bber-info-top
i.MeuiCat.icon-hot-top-fill
| 置顶

if item.content
.bber-reply(onclick="commentText(" + `'${item.content}'` + ")")
i.MeuiCat.icon-chat-fill

- const {strip, mode, mode_link} = theme.essay

if theme.essay.enable
section#bber
case mode.trim()
when 'local'
- const essaydata = site.data.essay.essay_list

if essaydata && essaydata.length > 0
#waterfall.list
- const limitedList = strip === -1 ? essaydata : essaydata.slice(0, strip)
each item in essaydata.filter(item => item.top)
+renderArticle(item)
each item in limitedList.filter(item => !item.top)
+renderArticle(item)

#bber-tips
if strip === -1 || Math.abs(strip) >= essaydata.length
| - 已展开所有短文 -
else
| - 只展示最近 #{strip} 条短文 -

when 'json'
#page-load
img(src="https://img.meuicat.com/blog/loading.svg")
script.
async function essayFormat(data) {
const renderArticle = async (item) => {
let image = '', video = '', type = ''

if (item.image) item.image.map(e => image += `<img src="${e.split(' || ')[0]}" ${e.split(' || ').length > 1 ? `alt='${e.split(' || ')[1]}'` : `title="即刻短文配图"`} />`).join('')
let aplayer = item.aplayer ? `<div class="bber-music"><div class="aplayer" data-server="${item.aplayer.server}" data-type="song" data-id="${item.aplayer.id}" data-autoplay="false" data-mutex="true" data-theme="var(--icat-theme)"></div></div>` : ''
if (item.video) video = item.video.player ? `<div class="bber-video"><video src="${item.video.player}" controls="controls" style="object-fit: cover;"></video></div>` : item.video.bilibili ? `<div class="bber-video"><iframe src="//player.bilibili.com/player.html?bvid=${item.video.bilibili.match(/(BV\w+)/)[1]}${item.video.autoplay ? '&autoplay=1' : '&autoplay=0'}" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe></div>` : ''
const time = changeTime(item.date)
let link = item.link ? ((type = item.link.split(' || ')), `<a class="bber-content-link" href='${type[0].startsWith('/') ? type[0] : (type[0].startsWith('http') ? type[0] : 'https://' + type[0])}' title="${type.length > 1 ? type[1] : '跳转到短文指引的链接' }" target="_blank"><i class="MeuiCat icon-link-m-line"></i>链接</a>`) : '';

return `<div class="item"><div class="bber-content">${item.content ? `<p class="datacont">${item.content}</p>` : ''}${image ? `<div class="bber-image">${image}</div>` : ''}${aplayer}${video}</div><hr><div class="bber-bottom"><div class="bber-info"><div class="bber-info-time"><i class="MeuiCat icon-calendar-todo-fill"></i><time datetime="${item.date}">${time}</time></div>${link}${item.from ? `<div class="bber-info-from"><span>${item.from}</span></div>` : ''}${item.top ? `<div class="bber-info-top"><i class="MeuiCat icon-hot-top-fill"></i>置顶</div>` : ''}</div>${item.content ? `<div class="bber-reply" onclick="commentText('${item.content}')"><i class="MeuiCat icon-chat-fill"></i></div>` : ''}</div></div>`
}

const { strip } = GLOBAL_CONFIG.essay
let essayTips, items = [], topitem = []

const processedData = await Promise.all(data[0].essay_list.map(async (item) => {
const formatdata = await renderArticle(item)
if (!formatdata) return null
if (item.top) {
topitem.push(formatdata)
} else {
items.push(formatdata)
}
return formatdata
}))
essayTips = strip === -1 || strip >= items.length ? `<div id="bber-tips">- 已展开所有短文 -</div>` : (items = items.slice(0, (strip - topitem.length)), `<div id="bber-tips">- 只展示最近 ${strip} 条短文 -</div>`)

return `<div id="waterfall" class="list">${topitem.concat(items).filter(item => item !== null).join('')}</div>${essayTips}`
}

when 'memos'
#page-load
img(src="https://img.meuicat.com/blog/loading.svg")
script.
async function essayFormat(data) {
const renderArticle = async (item) => {
const contentRegex = /#(.*?)\s|\n/g, imageRegex = /\!\[(.*?)\]\((.*?)\)/g, playerRegex = /{\s*player\s*(.*)\s*}/g, linkRegex = /(?<!\!)\[(.*?)\]\((.*?)\)/g, topRegex = /#top/g, fromRegex = /(?<![\w\/])(?<!\{)\{([^{}\s]+)\}(?!\})(?![\w\/])/g
let time = new Date((item.createdTs - (new Date().getTimezoneOffset() * 60)) * 1000).toISOString(), content = item.content, image = '', img = content.match(imageRegex), aplayer = content.match(/{\s*music\s*(.*?)\s*(.*?)\s*}/g), video = content.match(playerRegex), link = content.match(linkRegex), type = '', from = content.match(fromRegex)

if (item.resourceList.length) {
if (!img) img = []
item.resourceList.forEach(e => {
if (e.externalLink) img.push(e.externalLink)
else img.push(`${baseUrl}/o/r/${e.uid}`)
})
}

if (img) image += img.map(e => `<img src="${e.replace(imageRegex, '$2')}" ${e.replace(imageRegex, '$1') ? `alt="${e.replace(imageRegex, '$1')}"` : `title="即刻短文配图"`} />`).join('')
aplayer = aplayer ? `<div class="bber-music"><div class="aplayer" data-server="${aplayer[0].match(/\{\s*music\s*(.*?)\s*\d+\s*\}/)[1]}" data-type="song" data-id="${aplayer[0].match(/\d+/)[0]}" data-mutex="true" data-autoplay="false" data-theme="var(--icat-theme)"></div></div>` : ''
video = video ? `<div class="bber-video"><video src="${video[0].replace(playerRegex, '$1').trim()}" controls="controls" style="object-fit: cover;"></video></div>` : content.match(/{\s*bilibili\s*(.*?)\s*}/g)
video = Array.isArray(video) ? `<div class="bber-video"><iframe src="//player.bilibili.com/player.html?bvid=${video[0].match(/(BV\w+)/)[1]}${video[0].match(/{\s*bilibili\s*(.*?)\s*true\s*}/g) ? '&autoplay=1' : '&autoplay=0'}" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe></div>` : ''
const timeFormat = changeTime(time)
link = link ? ((type = link[0].replace(linkRegex, '$2')), `<a class="bber-content-link" href='${type.startsWith('/') ? type : (type.startsWith('http') ? type : 'https://' + type)}' title="${link[0].replace(linkRegex, '$1') ? link[0].replace(linkRegex, '$1') : '跳转到短文指引的链接' }" target="_blank"><i class="MeuiCat icon-link-m-line"></i>链接</a>`) : ''
from = from ? `<div class="bber-info-from"><span>${from[0].replace(fromRegex, '$1')}</span></div>` : ''
content = content.replace(contentRegex, '').replace(imageRegex, '').replace(/\{(.*?)\}/g, '').replace(linkRegex, '').trim()

return `<div class="item"><div class="bber-content">${content ? `<p class="datacont">${content}</p>` : ''}${image ? `<div class="bber-image">${image}</div>` : ''}${aplayer}${video}</div><hr><div class="bber-bottom"><div class="bber-info"><div class="bber-info-time"><i class="MeuiCat icon-calendar-todo-fill"></i><time class="datatime" datetime="${time}">${timeFormat}</time></div>${link}${from}${item.content.includes('#top') ? `<div class="bber-info-top"><i class="MeuiCat icon-hot-top-fill"></i>置顶</div>` : ''}</div>${content ? `<div class="bber-reply" onclick="commentText('${content}')"><i class="MeuiCat icon-chat-fill"></i></div>` : ''}</div></div>`
}

const { strip, mode_link } = GLOBAL_CONFIG.essay
const baseUrl = mode_link.substring(0, mode_link.indexOf("/", mode_link.indexOf("//") + 2))
let essayTips, items = [], topitem = []

const processedData = await Promise.all(data.map(async (item) => {
const formatdata = await renderArticle(item,baseUrl)
if (!formatdata) return null
if (item.content.includes('#top')) {
topitem.push(formatdata)
} else {
items.push(formatdata)
}
return formatdata
}))
essayTips = strip === -1 || strip >= items.length ? `<div id="bber-tips">- 已展开所有短文 -</div>` : (items = items.slice(0, (strip - topitem.length)), `<div id="bber-tips">- 只展示最近 ${strip} 条短文 -</div>`)

return `<div id="waterfall" class="list">${topitem.concat(items).filter(item => item !== null).join('')}</div>${essayTips}`
}
  • 修改[主题目录]/layout/page.pug来使页面匹配。
1
2
3
4
5
6
7
8
      when 'shuoshuo'
include includes/page/shuoshuo.pug
+ when 'essay'
+ include includes/page/essay.pug
+ +commentLoad
default
include includes/page/default-page.pug
+commentLoad
  • 打开[主题目录]/layout/includes/head/config.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
  if (highlightEnable) {
const { copy, language, height_limit, fullpage, macStyle } = theme.code_blocks
highlight = JSON.stringify({
plugin: syntaxHighlighter ? syntaxHighlighter : config.highlight.enable ? 'highlight.js' : 'prismjs',
highlightCopy: copy,
highlightLang: language,
highlightHeightLimit: height_limit,
highlightFullpage: fullpage,
highlightMacStyle: macStyle
})
}

+ let essay = 'undefined'
+ if (theme.essay && theme.essay.enable && theme.essay.mode !== 'local') {
+ const { strip, mode, mode_link, mini } = theme.essay
+ essay = JSON.stringify({
+ strip: strip,
+ mode: mode,
+ mode_link: mode_link,
+ mini_strip: mini.strip
+ })
+ }

···

percent: {
rightside: !{theme.rightside_scroll_percent},
},
- autoDarkmode: !{theme.darkmode.enable && theme.darkmode.autoChangeMode === 1}
+ autoDarkmode: !{theme.darkmode.enable && theme.darkmode.autoChangeMode === 1},
+ essay: !{essay}
}
  • _config.butterfly.yml主题配置文件中,新增以下配置项。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# essay 即刻短文
# modify by MeuiCat (yife.Liang)
# https://meuicat.com/posts/1cdf15f7.html
# --------------------------------------

essay:
enable: true
# 即刻短文仅展示前n条
# Jike short text only shows the first n
strip: 30
# local:本地静态 / json:动态json / memos:动态Memos
mode: memos
mode_link: https://memos.meuicat.com/api/v1/memo?creatorId=1&tag=说说 #动态模式地址
mini:
enable: false
strip: 10
# 主页即刻mini点击的跳转链接
link: /essay/
  • 【可选】在_config.butterfly.yml主题配置文件中开启站点的pjax
1
2
3
4
5
6
7
8
9
10
# Pjax
# https://github.com/MoOx/pjax
# 当用户点击链接,通过ajax更新页面需要变化的部分,然后使用HTML5的pushState修改浏览器的URL地址;这样可以不用重复加载相同的资源(css/js), 从而提升网页的加载速度
# 使用pjax后,一些自己DIY的js可能会无效,跳转页面时需要重新调用;使用pjax后,一些个别页面加载的js/css,将会改为所有页面都加载
# --------------------------------------
pjax:
enable: true
exclude:
# - xxxx
# - xxxx
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
if hexo-config('essay.enable')
#bber
width 100%

#waterfall
transition 0.3s
opacity 0

&.list
display flex
flex-direction column

&.show
opacity 1

if hexo-config('enter_transitions')
.item
animation slide-in .6s .2s backwards

.item
position relative
display flex
flex-direction column
padding 1rem 1rem 0.9rem
width calc(100% / 3 - 1rem / 3)
transition all .3s, width 0s
@extend .cardHovers

+maxWidth1024()
width 49%
margin-right 1%

+maxWidth768()
width 100%

&:hover
box-shadow var(--icat-shadow-border)

.bber-content
display flex
flex-flow wrap
width 100%
height 100%

> *
margin-bottom .5rem !important

p.datacont
margin 0
font-size 15px
font-weight 700
color var(--icat-fontcolor)
line-height 1.38

.bber-image
display flex
gap .3rem
width 100%
flex-wrap wrap

> *
width calc(100% / 4 - .9rem / 4)
aspect-ratio 1 / 1
overflow hidden
border-radius 6px

a img
width 100%
height 100%
object-fit cover

.bber-video
position relative
padding 30% 50%

video, iframe
position absolute
width 100%
height 100%
left 0
top 0
margin 0
border-radius 6px
border var(--icat-border-always)
cursor pointer

.bber-music
width 100%
height 90px

.aplayer
margin 0
border-radius 6px

hr
margin .5rem 0 1rem
width 100%
border var(--icat-border-dashed)

.bber-bottom
display flex
justify-content space-between
width 100%

.bber-info
display flex
flex-wrap wrap
align-items center

> *
display flex
align-items baseline
padding 8px
background var(--icat-gray-op)
color var(--icat-fontcolor)
font-size .7rem
line-height 1
border-radius 99px

&:not(:first-child)
margin-left 0.5rem

i
padding-right 4px
font-size .8rem

a:hover
background var(--icat-theme)
color var(--icat-with)

.bber-content-link
background-color rgba(103, 194, 58, 0.13)
color rgb(103, 194, 58)

.bber-info-top
background-color rgba(245, 108, 108, 0.13)
color rgb(245, 108, 108)

.bber-reply
cursor pointer
transition 0.3s

&:hover
color var(--icat-theme)

#bber-tips
display flex
justify-content center
margin-bottom 2rem
padding-top 2rem
color var(--icat-secondtext)
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
let essayData

const initwaterfall = () => {
const waterfallElement = document.querySelector('#waterfall')
if (!waterfallElement) return
const init = () => {
const rootStyle = parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--global-font-size').trim()) * 0.5

const waterfall = new InfiniteGrid.MasonryInfiniteGrid(waterfallElement, {
gap: { horizontal: rootStyle - 2, vertical: rootStyle },
useTransform: true,
useResizeObserver: true
})
waterfall.renderItems()
setTimeout(() => {
btf.addGlobalFn('pjaxCompleteOnce', () => { waterfall.destroy(); }, 'removeWaterfall')
typeof loadMeting === 'function' && document.getElementsByClassName('aplayer').length && loadMeting()
btf.loadLightbox(waterfallElement.querySelectorAll('img'))
waterfallElement.classList.add('show')
}, 300)
}

typeof InfiniteGrid === 'function' ? init() : btf.getScript(`${GLOBAL_CONFIG.infinitegrid.js}`).then(init)
}

const essay = {
swiper: () => {
const essayElement = document.querySelector('#essay')
if (!essayElement) return

const swiperFn = () => {
const swiper = new Swiper(essayElement, {
direction: 'vertical',
autoplay: {
delay: 3000,
disableOnInteraction: false
},
loop: true
})
essayElement.addEventListener('mouseenter', () => {
swiper.autoplay.stop()
})
essayElement.addEventListener('mouseleave', () => {
swiper.autoplay.start()
})
btf.addGlobalFn('pjaxCompleteOnce', () => { swiper.destroy(); }, 'removEessay')
}

typeof Swiper === 'object' ? swiperFn() : btf.getScript('https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/Swiper/8.0.6/swiper-bundle.min.js').then(swiperFn)
},
init: async () => {
const essayElement = document.getElementById('bber') || document.getElementById('essay-mini')
if (!essayElement) return

if (GLOBAL_CONFIG.essay !== 'undefined') {
if (!essayData) essayData = await fetch(GLOBAL_CONFIG.essay.mode_link).then(res => res.json())
const html = await essayFormat(essayData)
essayElement.innerHTML = html
}
initwaterfall(), essay.swiper()
}
}
btf.addGlobalFn('pjaxComplete', essay.init(), 'removEessay')

部署数据文件

  • 创建 [blogRoot]/source/_data/essay.yml 文件,并新增以下内容
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
essay_list:
- content: 即刻短文测试
date: 2023/07/31 15:30:50
from: iPhone XR
video:
player: /video/1.mp4

- content: 测试bilibili视频
date: 2023/07/31 15:30:50
video:
bilibili: //player.bilibili.com/player.html?aid=913951276&bvid=BV1RM4y1p75T&cid=1211165267&page=1

- content: bilibili网页链接
date: 2023/07/31 15:30:50
video:
bilibili: https://www.bilibili.com/video/BV17T4y1A7eW/?spm_id_from=333.1007.tianma.1-3-3.click

- content: bilibili单bv号
date: 2023/07/31 15:30:50
video:
bilibili: BV17T4y1A7eW
autoplay: true

- content: 完噜 还剩一天让我咋准备 😭
date: 2023/05/11 20:35:42
from: iPhone XR
image:
- https://s11.ax1x.com/2023/05/11/p9sKEh8.jpg

- content: 如果要定义 那就是下班后的日落和在家等我下班的她~
date: 2023/05/10 16:16:15
aplayer:
server: netease
id: 1949516216
top: true

- content: Melancholia - | 一款纯记录写作类Hexo主题 ✍️
date: 2023/04/23 22:27:22
from: Macbook Pro
link: https://github.com/yife68/Hexo-Theme-Melancholia || Melancholia

- content: 爱看 但还是得吃我一拳
date: 2023/04/22 15:10:30
from: iPhone XR
image:
- https://s11.ax1x.com/2023/05/03/p9JqGXd.jpg
- https://s11.ax1x.com/2023/05/03/p9Jq86H.jpg

- content: iCat 新启程
date: 2023/03/24 16:54:25
from: iPhone XR
link: https://meuicat.com/blog/14/
image:
- https://s11.ax1x.com/2023/05/02/p9GosYQ.jpg

- content: 各种观影史集于一体!人生足迹页诞生咯~
date: 2023/02/19 14:50:17
from: Macbook Pro
link: /collect/ || 链接描述
  • JSON文件可参照以下格式
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
[
{
"class_name": "即刻短文",
"essay_list": [
{
"content": "园长新造型!爱死",
"date": "2023/08/01 17:12:30",
"video": {
"bilibili": "//player.bilibili.com/player.html?aid=701381935&bvid=BV1dm4y1L7vj&cid=1212026428&page=1",
"autoplay": true
}
},
{
"content": "这辈子都不想完善项目了 😭 两点了 一看才搓完三分之一..",
"date": "2023/08/01 02:02:44",
"video": {
"player": "https://meuicat.com/video/1.mp4"
}
},
{
"content": "让我看看是谁在路上都还在敲键盘 噢 原来是我自己啊..",
"date": "2023/07/31 15:54:26",
"from": "iPhone XR"
},
{
"content": "落班 烧个排骨778~",
"date": "2023/07/26 17:55:36",
"from": "iPhone XR",
"image": [
"https://s11.ax1x.com/2023/07/26/pCjWbY4.jpg || 图片描述",
"https://s11.ax1x.com/2023/07/26/pCjWqfJ.jpg"
]
},
{
"content": "嘘..听歌..睡觉...",
"date": "2023/07/20 00:38:41",
"aplayer": {
"server": "netease",
"id": "1430702919"
},
"top": true
},
{
"content": "人生应该是一个轴对称的形状,最后失去的,也就是最开始拥有的。现在没人记得你的生日,有好处也有坏处,至少我是这么理解的。但无论是好还是坏,忍一忍,都会很快过去的",
"date": "2023/07/19 01:48:36",
"from": "iPhone XR",
"link": "/blog/64 || 链接描述"
},
{
"content": "用堆AI重绘一下我最爱的头像(图一 👉 图二)",
"date": "2023/07/06 16:30:32",
"from": "iPhone XR",
"link": "/blog/61",
"image": [
"https://img.meuicat.com/posts/2023/7/10.webp",
"https://img.meuicat.com/posts/2023/7/11.webp"
]
},
{
"content": "",
"date": "2023/06/30 08:26:22",
"aplayer": {
"server": "netease",
"id": "2009974513"
}
}
]
}
]
参数 释义 注意事项
content 【选填】说说内容 /
date 【必填】说说发布的时间 /
image 【可选】说说图片 图片的描述可在链接后以“||”分割开。如:”https://img.meuicat.com/posts/2023/7/11.webp || 亦小封”
aplayer 【可选】音乐播放器 /
aplayer.server 【必填】音乐播放器的服务器 目前仅支持填写:netease、tencent
aplayer.id 【必填】音乐ID 只能填写单曲id
video 【可选】视频 /
video.player 【选填】video视频播放器 /
video.bilibili 【选填】bilibili视频 必须是b站带BV号的视频链接
video.autoplay 【选填】bilibili视频是否自动播放 如需自动播放,请填写true
from 【可选】标识符,无实际意义 /
link 【可选】外部链接 链接描述可在链接后以“||”分割开。如:”https://meuicat.com/ || MeuiCat”

memos api地址格式如下所示:
https://memos地址/api/v1/memo?creatorId=用户UID&tag=标签名

memos地址就是首页地址,如:memos.meuicat.com

Memos 0.20.1以下版本UID的获取方式:

  • 点击个人头像,然后点击 RSS

  • 根据浏览器链接获取ID

如url是:https://memos.meuicat.com/u/1/rss.xml
则creatorId就是1
最后完整链接如下:
https://memos.meuicat.com/api/v1/memo?creatorId=1&tag=说说
能看到数据则为正确链接

Memos 0.21.0版本UID获取方式:

  • 点击设置 - 我的账号 - 编辑

  • 用户名上显示的数字即是你的UID

  • Memos用法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#说说 {标识符} 我是内容 [我是链接](https://meuicat.com) ![](https://img.meuicat.cn/blog/8.png)
<!-- 常规写法 -->

#说说 网易云音乐 {music netease 29947420 }
#说说 腾讯音乐 {music tencent 330977131 }
<!-- 音乐写法 -->

#说说 普通视频 { player https://v.meuicat.com/video/1.mp4 }
#说说 哔哩哔哩手机视频 { bilibili https://m.bilibili.com/video/BV17T4y1A7eW }
#说说 哔哩哔哩网页视频 { bilibili https://www.bilibili.com/video/BV17T4y1A7eW/?spm_id_from=333.1007.tianma.1-3-3.click }
<!-- 视频写法 -->

#说说 #top
我是内容 ![我是图片描述](https://img.meuicat.cn/blog/8.png)![](https://img.meuicat.cn/blog/8.png)
<!-- 置顶写法 -->
参数 释义 注意事项
#标签 【必填】标签,用于区分说说 标签内前缀为#,至少需要有一个
#top 【可选】置顶,用于置顶说说。置顶的说说会排在最前面,不受数量显示限制 /
{自定义标识符} 【可选】标识符,无实际意义,选填 {}内容前后不能有空格和换行
music 【可选】音乐,写法注意规范,以空格隔开每个项。 /
music.service 【必选】music第一项数据,音乐服务商 目前仅支持填写:netease、tencent
music.id 【必选】music第二项数据,音乐id 仅可以是封面id/单曲id/歌单id
bilibili 【可选】bilibili,写法注意规范,以空格隔开每个项。 /
bilibili.link 【必选】bilibili第一项数据,bilibili视频链接 必须是b站带BV号的视频链接
bilibili.autoplay 【可选】bilibili第二项布尔值,bilibili视频是否自动播放。默认不自动播放 如需自动播放,请填写true

关于更多写法问题可以访问iCat - Memos查看

即刻Mini

上面已经集成了即刻mini的js操作,只需要在配置文件里,将mini.enable设置为true即可。

  • 新增[主题目录]/layout/includes/mixins/indexPostUI.pug页面内容。
1
2
3
4
  #recent-posts.recent-posts.nc
+ if theme.essay.enable && theme.essay.mini.enable
+ include ./essay_mini.pug
.recent-post-items
  • 创建[主题目录]/layout/includes/mixins/essay_mini.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
- const { strip, link } = theme.essay.mini

.essay-mini(onclick=`pjax.loadUrl('${link}')`)
i.MeuiCat.icon-bblogo(title="即刻短文" style="font-size: 2.5rem")
.swiper-container#essay
.swiper-wrapper#essay-mini
case theme.essay.mode
when 'local'
- const essaydata = site.data.essay
if essaydata && essaydata.essay_list.length > 0
each item, i in essaydata.essay_list.slice(0, strip)
.li-style.swiper-slide
| #{item.content}
if item.image
| 【图片】
else if item.aplayer
| 【音乐】
else if item.video || item.bilibili
| 【视频】
when 'json'
.li-style.essay-loading(style="text-align: center") 正在加载...
script.
async function essayFormat(data) {
const list = data[0].essay_list.slice(0, GLOBAL_CONFIG.essay.strip).map(item => {
const type = item.image ? '【图片】' : item.aplayer ? '【音乐】' : item.video ? '【视频】' : ''
return `<div class="li-style swiper-slide">${item.content + type}</div>`
})
return list.join(' ')
}
when 'memos'
.li-style.essay-loading(style="text-align: center") 正在加载...
script.
async function essayFormat(data) {
const list = data.slice(0, GLOBAL_CONFIG.essay.strip).map(item => {
let data = item.content, content = data.replace(/#(.*?)\s|\n/g, '').replace(/\!\[(.*?)\]\((.*?)\)/g, '').replace(/\{(.*?)\}/g, '').replace(/(?<!\!)\[(.*?)\]\((.*?)\)/g, '').trim()
const type = data.match(/\!\[(.*?)\]\((.*?)\)/g) ? '【图片】' : data.match(/{\s*music\s*(.*?)\s*(.*?)\s*}/g) ? '【音乐】' : data.match(/{\s*player\s*(.*)\s*}/g) || data.match(/{\s*bilibili\s*(.*?)\s*}/g) ? '【视频】' : ''
return `<div class="li-style swiper-slide">${content + type}</div>`
})
return list.join(' ')
}
i.MeuiCat.icon-bb-btn-s-line(title="查看全文")
  • 在上面创建过的[主题目录]/source/css/_page/essay.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
    #bber-tips
display flex
justify-content center
margin-bottom 2rem
padding-top 2rem
color var(--icat-secondtext)

+ if hexo-config('essay.mini.enable')
+ .essay-mini
+ display: flex
+ align-items: center
+ padding: .5rem 1rem
+ height: 50px
+ gap: 1rem
+ @extend .cardHovers
+ if hexo-config('enter_transitions')
+ animation: slide-in 0.6s 0.4s backwards
+
+ #essay
+ width: 100%
+ overflow: hidden
+
+ #essay-mini
+ display: flex
+ flex-direction: column
+ width: 100%
+ height: 25px
+ line-height: 25px
+ will-change: transform
+
+ .li-style
+ margin: auto
+ width: auto
+ max-width: 100%
+ height: 25px
+ font-weight: 700
+ text-align: center
+ overflow: hidden
+ text-overflow: ellipsis
+ white-space: nowrap
+
+ i, .li-style
+ transition .3s
+ cursor: pointer
+
+ &:hover
+ color: var(--icat-theme)
  • _config.butterfly.yml主题配置文件中inject下的headbottom分别引入swiper-bundle.min.css以及swiper-bundle.min.js
1
2
3
4
5
6
7
8
9
  ···

inject:
head:
- <script src="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/Swiper/8.0.6/swiper-bundle.min.js"></script> # Swiper - 轮播动画库CSS样式
bottom:
- <script src="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/Swiper/8.0.6/swiper-bundle.min.js"></script> # Swiper - 轮播动画库JS

···

Meting说明

如遇到音乐模块无法显示,请将查看meting的js资源文件链接是否为butterfly资源。

如果为butterfly,请将链接改为第三方meting最新资源链接。

譬如:
https://unpkg.com/meting@2.0.1/dist/Meting.min.js
https://cdn.staticfile.net/meting/2.0.1/Meting.min.js

以及检查主题配置是否已经开启aplayerInject.enable

魔改适配

已适配Solitude主题,具体魔改教程可前往下方文章查看

旧版教程

更新历史

  • 240423 更新:三端功能全适配;优化使用体验,异步化处理;修复一些已知问题

  • 240411 更新:新增置顶功能;修复Memos版本时区错误、多余转义符等问题

  • 230808 更新:新增适配Memos动态部署功能

  • 230804 更新:新增显示短文数量的设置功能

  • 230802 更新:修复JSON加载导致的音乐功能错误;修复JSON载入导致时间戳混乱

  • 230731 更新:新增静态部署版的视频说,适配bilibili以及video链接

  • 250103 更新:显著优化新逻辑,减少渲染时间以及报错率