package video import ( "context" "encoding/json" "sort" "strconv" "strings" "time" dto "media/model/dto/video" entity "media/model/entity/video" "gitea.redpowerfuture.com/red-future/common/db/gfdb" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/util/gconv" ) var SceneSplitTask = new(sceneSplitTaskDao) type sceneSplitTaskDao struct{} const sceneSplitTaskTable = "scene_split_task" // Insert 创建任务(排除 id 字段,让数据库自增) func (d *sceneSplitTaskDao) Insert(ctx context.Context, data *entity.SceneSplitTask) (id int64, err error) { r, err := gfdb.DB(ctx).Model(ctx, sceneSplitTaskTable). Data(data). FieldsEx(entity.SceneSplitTaskCols.Id). Insert() if err != nil { return 0, err } return r.LastInsertId() } // GetByTaskID 根据taskId查询任务 func (d *sceneSplitTaskDao) GetByTaskID(ctx context.Context, taskID string) (res *entity.SceneSplitTask, err error) { r, err := gfdb.DB(ctx).Model(ctx, sceneSplitTaskTable). Where(entity.SceneSplitTaskCols.TaskID, taskID). One() if err != nil { return nil, err } if r == nil { return nil, nil } err = r.Struct(&res) return } // UpdateRunning 更新为运行中 func (d *sceneSplitTaskDao) UpdateRunning(ctx context.Context, taskID string) error { _, err := gfdb.DB(ctx).Model(ctx, sceneSplitTaskTable). Data(g.Map{ entity.SceneSplitTaskCols.Status: "running", }). Where(entity.SceneSplitTaskCols.TaskID, taskID). Update() return err } // UpdateSuccess 更新为成功 func (d *sceneSplitTaskDao) UpdateSuccess(ctx context.Context, taskID string, segmentURLs, audioURL string, sceneCount int, audioDuration float64, videoDuration float64) error { _, err := gfdb.DB(ctx).Model(ctx, sceneSplitTaskTable). Data(g.Map{ entity.SceneSplitTaskCols.Status: "success", entity.SceneSplitTaskCols.SegmentURLs: segmentURLs, entity.SceneSplitTaskCols.AudioURL: audioURL, entity.SceneSplitTaskCols.SceneCount: sceneCount, entity.SceneSplitTaskCols.AudioDuration: audioDuration, entity.SceneSplitTaskCols.VideoDuration: videoDuration, entity.SceneSplitTaskCols.ErrorMessage: "", }). Where(entity.SceneSplitTaskCols.TaskID, taskID). Update() return err } // UpdateError 更新为失败 func (d *sceneSplitTaskDao) UpdateError(ctx context.Context, taskID string, errMsg string) error { _, err := gfdb.DB(ctx).Model(ctx, sceneSplitTaskTable). Data(g.Map{ entity.SceneSplitTaskCols.Status: "failed", entity.SceneSplitTaskCols.ErrorMessage: errMsg, }). Where(entity.SceneSplitTaskCols.TaskID, taskID). Update() return err } // EntityToSceneSplitTaskRes 实体转DTO func EntityToSceneSplitTaskRes(e *entity.SceneSplitTask) *dto.GetSceneSplitTaskRes { res := &dto.GetSceneSplitTaskRes{ TaskID: e.TaskID, Status: e.Status, SceneCount: e.SceneCount, AudioDuration: e.AudioDuration, VideoDuration: e.VideoDuration, } if e.CreatedAt != nil { res.CreatedAt = gconv.Int64(e.CreatedAt.Timestamp()) } else { res.CreatedAt = time.Now().UnixMilli() } if e.Status == "success" { res.AudioURL = e.AudioURL res.Segments = ParseSegmentEntries(e.SegmentURLs) res.SceneCount = e.SceneCount res.AudioDuration = e.AudioDuration res.VideoDuration = e.VideoDuration } if e.Status == "failed" { res.ErrorMessage = e.ErrorMessage } return res } // ParseSegmentEntries 将 JSON 数组解析为按时间线排序的 SegmentEntry 切片 // JSON 格式: [{"timeline":"0.0-7.2","url":"..."}, ...] func ParseSegmentEntries(jsonStr string) []dto.SegmentEntry { if jsonStr == "" { return nil } // 先尝试解析为数组格式 var entries []dto.SegmentEntry if err := json.Unmarshal([]byte(jsonStr), &entries); err == nil && len(entries) > 0 { // 按起始时间排序确保有序 sort.Slice(entries, func(i, j int) bool { return extractStartTime(entries[i].Timeline) < extractStartTime(entries[j].Timeline) }) return entries } // 兼容旧的 map 格式 {"0.0-7.2":"url", ...} var m map[string]string if err := json.Unmarshal([]byte(jsonStr), &m); err != nil { return nil } entries = make([]dto.SegmentEntry, 0, len(m)) for timeline, url := range m { entries = append(entries, dto.SegmentEntry{Timeline: timeline, URL: url}) } sort.Slice(entries, func(i, j int) bool { return extractStartTime(entries[i].Timeline) < extractStartTime(entries[j].Timeline) }) return entries } // extractStartTime 从时间线 key(如 "0.0-7.2")提取起始秒数用于排序 func extractStartTime(timeline string) float64 { idx := strings.Index(timeline, "-") if idx < 0 { return 0 } v, _ := strconv.ParseFloat(timeline[:idx], 64) return v }