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