[AI] fix: 剧集去重键补上 videoUrl
媒资库会给同一集重新发 hashId(「JK学姐不为人知的秘密」源库那条 hashId 6aa23652…、本地那条 6acaf74c…,videoUrl 一模一样), 只比 hashId 会漏掉这一类重复,前端仍显示「1 1 2 2」。 改成 mediaId 下 hashId 或 videoUrl 任一相同即认定是同一集。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+42
-24
@@ -261,8 +261,8 @@ func runPass(ctx context.Context, srcDB *mongo.Database, t target, spec CollSpec
|
||||
return out, c.Err()
|
||||
}
|
||||
|
||||
// localTwins 查出这批源文档在目标库的「同一集另一条」:
|
||||
// (mediaId, hashId) 相同但 _id 不同。
|
||||
// localTwins 查出这批源文档在目标库的「同一集另一条」:同属一个 mediaId,
|
||||
// 且 hashId 或 videoUrl 相同,但 _id 不同。
|
||||
//
|
||||
// 各站点自己也在跑媒资库同步(common/media/syncMedia.go),它按
|
||||
// (mediaId, hashId) 去重、用自己的 _id 为同一集插一条;本同步再把源库那条
|
||||
@@ -270,29 +270,40 @@ func runPass(ctx context.Context, srcDB *mongo.Database, t target, spec CollSpec
|
||||
// 更要紧的是媒资库那条在 SaleCoin=0 时 listenPermission=2(免费),
|
||||
// 等于用户可以白看本该收费的集。
|
||||
//
|
||||
// 必须同时认 videoUrl:媒资库会给同一集重新发 hashId(实测
|
||||
// 「JK学姐不为人知的秘密」源库那条 hashId 6aa23652…、本地那条
|
||||
// 6acaf74c…,videoUrl 却一模一样),只比 hashId 会漏掉这一类。
|
||||
//
|
||||
// 以源库那条为准(购买记录都挂在它上面),把本地那条下架 isActive:false,
|
||||
// 不删除,便于事后回查。
|
||||
localTwins := func(docs []bson.M) (map[any]any, error) {
|
||||
hashes := make([]any, 0, len(docs))
|
||||
want := map[string]any{} // mediaId|hashId -> 源库 _id
|
||||
for _, d := range docs {
|
||||
h, ok := d["hashId"].(string)
|
||||
if !ok || h == "" {
|
||||
continue
|
||||
keys := make([]any, 0, len(docs)*2) // 待查的 hashId 与 videoUrl
|
||||
want := map[string]any{} // mediaId|key -> 源库 _id
|
||||
add := func(mid primitive.ObjectID, v string, id any) {
|
||||
if v == "" {
|
||||
return
|
||||
}
|
||||
keys = append(keys, v)
|
||||
want[mid.Hex()+"|"+v] = id
|
||||
}
|
||||
for _, d := range docs {
|
||||
mid, ok := d["mediaId"].(primitive.ObjectID)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
hashes = append(hashes, h)
|
||||
want[mid.Hex()+"|"+h] = d["_id"]
|
||||
h, _ := d["hashId"].(string)
|
||||
u, _ := d["videoUrl"].(string)
|
||||
add(mid, h, d["_id"])
|
||||
add(mid, u, d["_id"])
|
||||
}
|
||||
if len(hashes) == 0 {
|
||||
if len(keys) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
// hashId 上有索引,按它捞再在内存里配 mediaId
|
||||
c, e := dst.Find(ctx, bson.M{"hashId": bson.M{"$in": hashes}, "isActive": true},
|
||||
options.Find().SetProjection(bson.M{"_id": 1, "mediaId": 1, "hashId": 1}))
|
||||
// hashId 上有索引;videoUrl 没有,所以放在同一个 $or 里一次查完
|
||||
c, e := dst.Find(ctx, bson.M{"isActive": true, "$or": []bson.M{
|
||||
{"hashId": bson.M{"$in": keys}},
|
||||
{"videoUrl": bson.M{"$in": keys}},
|
||||
}}, options.Find().SetProjection(bson.M{"_id": 1, "mediaId": 1, "hashId": 1, "videoUrl": 1}))
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
@@ -300,21 +311,28 @@ func runPass(ctx context.Context, srcDB *mongo.Database, t target, spec CollSpec
|
||||
out := map[any]any{}
|
||||
for c.Next(ctx) {
|
||||
var row struct {
|
||||
ID primitive.ObjectID `bson:"_id"`
|
||||
MediaID primitive.ObjectID `bson:"mediaId"`
|
||||
HashID string `bson:"hashId"`
|
||||
ID primitive.ObjectID `bson:"_id"`
|
||||
MediaID primitive.ObjectID `bson:"mediaId"`
|
||||
HashID string `bson:"hashId"`
|
||||
VideoURL string `bson:"videoUrl"`
|
||||
}
|
||||
if e := c.Decode(&row); e != nil {
|
||||
return nil, e
|
||||
}
|
||||
srcID, ok := want[row.MediaID.Hex()+"|"+row.HashID]
|
||||
if !ok {
|
||||
continue
|
||||
for _, k := range []string{row.HashID, row.VideoURL} {
|
||||
if k == "" {
|
||||
continue
|
||||
}
|
||||
srcID, ok := want[row.MediaID.Hex()+"|"+k]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if sid, ok := srcID.(primitive.ObjectID); ok && sid == row.ID {
|
||||
continue // 就是源库那条自己,不是重复
|
||||
}
|
||||
out[srcID] = row.ID
|
||||
break
|
||||
}
|
||||
if sid, ok := srcID.(primitive.ObjectID); ok && sid == row.ID {
|
||||
continue // 就是源库那条自己,不是重复
|
||||
}
|
||||
out[srcID] = row.ID
|
||||
}
|
||||
return out, c.Err()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user