From bf623eaea42f9e75da58e87a6d75d75582cfd210 Mon Sep 17 00:00:00 2001 From: fish Date: Wed, 11 Nov 2026 17:21:04 +0800 Subject: [PATCH] =?UTF-8?q?=E7=9F=AD=E5=89=A7=20SEO=20=E6=8F=8F=E8=BF=B0?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E3=80=8C=E8=87=AA=E5=AE=9A=E4=B9=89=20+=20?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E6=A8=A1=E6=9D=BF=E3=80=8D=E6=8B=BC=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SeoInfo.Description 现在只存管理员纯自定义文本(不再被覆盖) - Playlet.Description 存合并后的展示值: {自定义} + 黄豆短剧《X》全集在线观看, 已更新至第N集,免费高清持续更新。前台 buildPlayletDetailSeoInfo 读这个。 - mergePlayletSeoDescription 处理重复、历史尾部剥离、空值回退 - stripPlayletSeoAutoTemplate 用于把 merged 字符串回写成纯自定义,保证 老库里把模板当自定义存的记录在下次保存时自动迁移到新结构。 Co-Authored-By: Claude Opus 4.7 --- web/service/srv_playlet/playlet.go | 68 ++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 8 deletions(-) diff --git a/web/service/srv_playlet/playlet.go b/web/service/srv_playlet/playlet.go index 024d3e4..70a4f59 100644 --- a/web/service/srv_playlet/playlet.go +++ b/web/service/srv_playlet/playlet.go @@ -1613,16 +1613,66 @@ func normalizeSeoValue(seo pubdef.SeoValue) pubdef.SeoValue { return seo } +// mergePlayletSeoDescription 把管理员自定义的 SEO 描述和自动模板拼在一起。 +// 规则: +// - custom 为空 → 返回 autoDesc +// - custom 已经包含当前版本的 autoDesc → 直接返回 custom,不重复追加 +// - custom 结尾带有旧版本的「黄豆短剧《…》…免费高清持续更新。」模板 +// (集数/剧名变更后产生的历史尾部) → 剥离旧尾部再拼接新模板 +// - 其它情况 → custom + autoDesc +func mergePlayletSeoDescription(custom, autoDesc string) string { + custom = strings.TrimSpace(custom) + autoDesc = strings.TrimSpace(autoDesc) + if custom == "" { + return autoDesc + } + if autoDesc == "" { + return custom + } + if strings.Contains(custom, autoDesc) { + return custom + } + if idx := strings.LastIndex(custom, "黄豆短剧《"); idx >= 0 && strings.HasSuffix(custom, "免费高清持续更新。") { + prefix := strings.TrimSpace(custom[:idx]) + if prefix == "" { + return autoDesc + } + return prefix + autoDesc + } + return custom + autoDesc +} + +// stripPlayletSeoAutoTemplate 从 SeoInfo.Description 中剥离自动模板部分,只保留管理员自定义。 +// 用于把展示用的 merged 字符串回写成「纯自定义」存库。 +func stripPlayletSeoAutoTemplate(merged, autoDesc string) string { + merged = strings.TrimSpace(merged) + autoDesc = strings.TrimSpace(autoDesc) + if merged == "" || autoDesc == "" { + return merged + } + if merged == autoDesc { + return "" + } + if strings.HasSuffix(merged, autoDesc) { + return strings.TrimSpace(strings.TrimSuffix(merged, autoDesc)) + } + if idx := strings.LastIndex(merged, "黄豆短剧《"); idx >= 0 && strings.HasSuffix(merged, "免费高清持续更新。") { + return strings.TrimSpace(merged[:idx]) + } + return merged +} + func applyPlayletDescription(doc *playletmod.Playlet) { if doc == nil { return } - description := playletmod.BuildPlayletDescription(doc.PlayName, doc.Title, doc.TotalEpisode) - if description == "" { + autoDesc := playletmod.BuildPlayletDescription(doc.PlayName, doc.Title, doc.TotalEpisode) + if autoDesc == "" { return } - doc.Description = description - doc.SeoInfo.Description = description + // SeoInfo.Description 存纯自定义(用户没传时为空);Playlet.Description 存合并后的展示值。 + doc.SeoInfo.Description = stripPlayletSeoAutoTemplate(doc.SeoInfo.Description, autoDesc) + doc.Description = mergePlayletSeoDescription(doc.SeoInfo.Description, autoDesc) } func applyPlayletDescriptionOnUpdate(exist *playletmod.Playlet, req *proto.PlayletUpdateReq, setDoc bson.M) { @@ -1641,11 +1691,10 @@ func applyPlayletDescriptionOnUpdate(exist *playletmod.Playlet, req *proto.Playl if req.TotalEpisode != nil { totalEpisode = *req.TotalEpisode } - description := playletmod.BuildPlayletDescription(playName, title, totalEpisode) - if description == "" { + autoDesc := playletmod.BuildPlayletDescription(playName, title, totalEpisode) + if autoDesc == "" { return } - setDoc[playletmod.FN.Playlet.Description] = description seo := exist.SeoInfo if req.SeoInfo != nil { if current, ok := setDoc["seoInfo"].(pubdef.SeoValue); ok { @@ -1655,8 +1704,11 @@ func applyPlayletDescriptionOnUpdate(exist *playletmod.Playlet, req *proto.Playl } } seo = normalizeSeoValue(seo) - seo.Description = description + // 剥离历史/当前版本的自动模板,仅保留纯自定义部分落到 SeoInfo.Description。 + seo.Description = stripPlayletSeoAutoTemplate(seo.Description, autoDesc) setDoc["seoInfo"] = seo + // Playlet.Description = 自定义 + 自动模板,供前台 SEO 页面渲染。 + setDoc[playletmod.FN.Playlet.Description] = mergePlayletSeoDescription(seo.Description, autoDesc) } func playletToWebResp(item *playletmod.Playlet, themeNameMap map[int64]string, tagNameMap map[int64]string, categoryId *int64) *proto.PlayletListResp {