From 92e2fd13864105463b5af8079e6dfaeae5554631 Mon Sep 17 00:00:00 2001 From: fish Date: Wed, 11 Nov 2026 17:36:06 +0800 Subject: [PATCH] =?UTF-8?q?=E7=9F=AD=E5=89=A7=E6=8F=8F=E8=BF=B0=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E6=8B=BC=E6=8E=A5=20+=20SEO=20=E6=A0=87=E9=A2=98/?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Playlet.Description = Playlet.SeoInfo.Description = 简介(Desc) + 自动模板 - 自动模板 = 黄豆短剧《{playName}》全集在线观看,已更新至第{N}集,免费高清持续更新。 - 每次保存时 SeoInfo.Title 同步覆盖为 Playlet.Title - 去掉 strip/merge 辅助: Desc 作为源每次重算,不读取被存储的 SeoInfo.Description, 避免重复保存导致模板堆叠 Co-Authored-By: Claude Opus 4.7 --- web/service/srv_playlet/playlet.go | 79 ++++++++---------------------- 1 file changed, 21 insertions(+), 58 deletions(-) diff --git a/web/service/srv_playlet/playlet.go b/web/service/srv_playlet/playlet.go index 9eb8f6e..6ba9a58 100644 --- a/web/service/srv_playlet/playlet.go +++ b/web/service/srv_playlet/playlet.go @@ -1613,69 +1613,22 @@ 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 } autoDesc := playletmod.BuildPlayletDescription(doc.PlayName, doc.Title, doc.TotalEpisode) - if autoDesc == "" { + // Description = 简介(Desc) + 自动模板,Playlet.Description 与 SeoInfo.Description 始终一致。 + merged := strings.TrimSpace(doc.Desc) + autoDesc + if merged == "" { return } - // 先剥离历史模板,得到纯自定义,再拼接当前模板,同一份合并值同时写入 - // Playlet.Description 和 SeoInfo.Description,保证两个字段始终一致。 - custom := stripPlayletSeoAutoTemplate(doc.SeoInfo.Description, autoDesc) - merged := mergePlayletSeoDescription(custom, autoDesc) doc.Description = merged doc.SeoInfo.Description = merged + // SEO 标题跟随 Playlet.Title 同步。 + if title := strings.TrimSpace(doc.Title); title != "" { + doc.SeoInfo.Title = title + } } func applyPlayletDescriptionOnUpdate(exist *playletmod.Playlet, req *proto.PlayletUpdateReq, setDoc bson.M) { @@ -1695,9 +1648,18 @@ func applyPlayletDescriptionOnUpdate(exist *playletmod.Playlet, req *proto.Playl totalEpisode = *req.TotalEpisode } autoDesc := playletmod.BuildPlayletDescription(playName, title, totalEpisode) - if autoDesc == "" { + + // 简介(Desc) 作为自定义描述的唯一源,取请求值或历史值,不读取被存储的 SeoInfo.Description, + // 避免多次保存堆叠。 + desc := strings.TrimSpace(exist.Desc) + if req.Desc != nil { + desc = strings.TrimSpace(*req.Desc) + } + merged := desc + autoDesc + if merged == "" { return } + seo := exist.SeoInfo if req.SeoInfo != nil { if current, ok := setDoc["seoInfo"].(pubdef.SeoValue); ok { @@ -1707,10 +1669,11 @@ func applyPlayletDescriptionOnUpdate(exist *playletmod.Playlet, req *proto.Playl } } seo = normalizeSeoValue(seo) - // 先剥离历史/当前模板得到纯自定义,再拼接当前模板,同一份合并值写入两个字段。 - custom := stripPlayletSeoAutoTemplate(seo.Description, autoDesc) - merged := mergePlayletSeoDescription(custom, autoDesc) + // 每次 description 更新 → SEO 描述、SEO 标题同步。 seo.Description = merged + if title != "" { + seo.Title = title + } setDoc["seoInfo"] = seo setDoc[playletmod.FN.Playlet.Description] = merged }