Files
rootandClaude Opus 5 acb9a34520 [AI] fix: 修复短剧剧集重复显示
两处原因,分别处理:

1. contentsync 只按 _id 水位线插新增,源库事后打上的 isDelete 传不过来,
   源站删掉的重复集在目标库一直留着。每轮同步后补扫一次 media /
   media_content / video_info,把源库的软删除标记同步过去,并按
   web/service/mediacontentser 的同一口径重算父级 currentEpisode /
   freeEpisode。只做「源库删了→目标也删」一个方向,不与本地下架保护冲突。

2. 各站 skd 的媒资库同步会为同一集(mediaId+hashId 相同)另插一条自己的 _id,
   与 contentsync 带过来的源库那条并存。媒资库那条在 SaleCoin=0 时
   listenPermission=2,本该收费的集可以白看。插入时若发现本地已有同一集,
   把本地那条 isActive:false 下架;并新增 skd 配置开关
   switch.mediaSyncDisabled,非源站可直接关掉这条同步链。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-29 20:18:36 +08:00

78 lines
2.7 KiB
Go

package main
// CollSpec 描述一个集合怎么同步。
//
// localFields 是「站点本地字段」:目标库自己产生、源库无权覆盖的字段。
// 判定依据有三类,改动前请先确认属于哪一类:
// 1. 运行时计数器 —— 各站点自己累积的播放/点赞/收藏/购买数
// 2. 本地定时任务写入 —— 如 skd/job/hotvalue 会重算并写回 hot
// 3. 后台运营编排 —— 如 web/service/vidser 写的 happinessPlazaTop、liaoBaTopSort
//
// 这些字段走 $setOnInsert:新文档插入时给初值,之后永不再覆盖。
// 其余字段走 $set。
//
// 注意:常规同步只按 _id 水位线取新增,不比对存量修改,所以 $set 实际只在
// 新文档插入、或手动 --full 重扫时才起作用。
type CollSpec struct {
Name string
// LocalFields 走 $setOnInsert,只在首次插入时写入,之后永不覆盖。
LocalFields []string
}
// 各集合的本地字段清单,来自对源库与目标库 400/300 条抽样的逐字段比对,
// 并交叉核对了 web/ 与 skd/ 中的写入点。
var specs = []CollSpec{
{
Name: "video_info",
LocalFields: []string{
// 运行时计数器
"playCount", "fakePlayCount", "effectivePlayCount", "pageViewCount",
"likeCount", "fakeLikeCount", "collectCount", "forwardCount",
"shareCount", "fakeShareCount", "commentCount", "fakeCommentCount",
"validCommentCount", "purchaseCount", "rewarded", "fakeRewarded",
// 本地 skd 重算:skd/job/hotvalue/video.go
"hot", "hotCommentExposureUntil", "lastHotTriggerAt",
// 后台运营编排:web/service/vidser/vid.go
"happinessPlazaTop", "liaoBaTop", "liaoBaTopSort",
"isTopping", "isRecommend", "chosen", "chosenDate",
"sortCode", "tagSort", "recoWeight", "upTag", "shareSort", "worksSort",
// 本地修改时间戳
"updatedAt",
},
},
{
Name: "media",
LocalFields: []string{
"countBrowse", "countCollect", "countComment", "countContentPurchases",
"countDisLike", "countLike", "countPurchases", "countView",
"hot",
// 短剧在各站点的编排位
"choice", "choiceSort", "general", "generalSort", "sectionSort",
"updateTime", "updatedAt", "updatedAct", "updatedDesc",
},
},
{
Name: "media_content",
LocalFields: []string{
"countBrowse", "countLike", "countPurchases", "fakeCountBrowse",
"updateTime", "updatedAt", "updatedAct",
},
},
{
Name: "media_tag",
LocalFields: []string{"updatedAt"},
},
{
Name: "media_tag_dimension",
LocalFields: []string{"updatedAt"},
},
{
Name: "tag",
LocalFields: []string{
"collCount", "fakeCollCount", "fakePlayCount", "likeCount",
"playRating", "tPlayCount", "vPlayCount", "videoCount", "hotMark",
"updatedAt",
},
},
}