69 lines
2.3 KiB
Go
69 lines
2.3 KiB
Go
// 长文的自动摘要与自动封面:站主没填这两项时从正文派生——
|
|
// 摘要取正文开头的一段纯文本,封面取正文第一张图。
|
|
// 更新路径只在「新值与旧值都为空」时才生成,站主主动清空的要保得住。
|
|
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 ""
|
|
}
|