长文自动摘要与自动封面:未填时从正文派生——摘要剥语法取开头 110 字(标题行/代码块/图链接剔除),封面取正文第一张图;更新只在「新旧都空」时补,站主主动清空的保得住;保存响应回写编辑器可见
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
// 长文的自动摘要与自动封面:站主没填这两项时从正文派生——
|
||||
// 摘要取正文开头的一段纯文本,封面取正文第一张图。
|
||||
// 更新路径只在「新值与旧值都为空」时才生成,站主主动清空的要保得住。
|
||||
package admin
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"oneblog/internal/model"
|
||||
)
|
||||
|
||||
const autoSummaryLen = 110
|
||||
|
||||
var (
|
||||
mdImageRe = regexp.MustCompile(`!\[[^\]]*\]\(([^)\s]+)[^)]*\)`)
|
||||
mdCodeFence = regexp.MustCompile("(?s)```.*?```")
|
||||
mdLinkRe = regexp.MustCompile(`\[([^\]]*)\]\([^)]*\)`)
|
||||
mdHeadingRe = regexp.MustCompile(`(?m)^#{1,6}\s+.*$`) // 标题行整行不进摘要(与文章标题重复)
|
||||
mdNoiseRe = regexp.MustCompile(`(?m)^([>\s*-]+|\d+\.\s)+`)
|
||||
mdEmphasis = strings.NewReplacer("**", "", "__", "", "~~", "", "*", "", "_", "")
|
||||
wsRe = regexp.MustCompile(`\s+`)
|
||||
)
|
||||
|
||||
// autoMeta 按需填充 in.Summary / in.CoverURL。
|
||||
// cur 为更新前的旧文章(新建时传 nil)。
|
||||
func autoMeta(in *model.PostInput, cur *model.Post) {
|
||||
if in.Kind != model.KindLong || strings.TrimSpace(in.ContentMd) == "" {
|
||||
return
|
||||
}
|
||||
if strings.TrimSpace(in.Summary) == "" && (cur == nil || strings.TrimSpace(cur.Summary) == "") {
|
||||
in.Summary = summarizeMarkdown(in.ContentMd, autoSummaryLen)
|
||||
}
|
||||
if strings.TrimSpace(in.CoverURL) == "" && (cur == nil || strings.TrimSpace(cur.CoverURL) == "") {
|
||||
in.CoverURL = firstImage(in.ContentMd)
|
||||
}
|
||||
}
|
||||
|
||||
// summarizeMarkdown 剥掉 markdown 语法后取正文开头一段纯文本
|
||||
func summarizeMarkdown(md string, maxRunes int) string {
|
||||
s := mdCodeFence.ReplaceAllString(md, " ") // 代码块整段不进摘要
|
||||
s = mdHeadingRe.ReplaceAllString(s, " ")
|
||||
s = mdImageRe.ReplaceAllString(s, " ")
|
||||
s = mdLinkRe.ReplaceAllString(s, "$1")
|
||||
s = mdNoiseRe.ReplaceAllString(s, " ")
|
||||
s = mdEmphasis.Replace(s)
|
||||
s = strings.ReplaceAll(s, "`", "")
|
||||
s = wsRe.ReplaceAllString(s, " ")
|
||||
s = strings.TrimSpace(s)
|
||||
runes := []rune(s)
|
||||
if len(runes) > maxRunes {
|
||||
return string(runes[:maxRunes]) + "…"
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// firstImage 取正文第一张图片的地址(markdown 图;http/站内路径均可)
|
||||
func firstImage(md string) string {
|
||||
m := mdImageRe.FindStringSubmatch(md)
|
||||
if m == nil {
|
||||
return ""
|
||||
}
|
||||
u := m[1]
|
||||
if strings.HasPrefix(u, "http://") || strings.HasPrefix(u, "https://") || strings.HasPrefix(u, "/uploads/") {
|
||||
return u
|
||||
}
|
||||
return ""
|
||||
}
|
||||
Reference in New Issue
Block a user