114 lines
4.0 KiB
Go
114 lines
4.0 KiB
Go
package service
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/google/uuid"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type deletionMediaRow struct {
|
|
ID uuid.UUID
|
|
ObjectKey string
|
|
}
|
|
|
|
type deletionMediaSet struct {
|
|
rows map[uuid.UUID]string
|
|
}
|
|
|
|
func newDeletionMediaSet() *deletionMediaSet {
|
|
return &deletionMediaSet{rows: make(map[uuid.UUID]string)}
|
|
}
|
|
|
|
func (set *deletionMediaSet) addQuery(query *gorm.DB) error {
|
|
var rows []deletionMediaRow
|
|
if err := query.Scan(&rows).Error; err != nil {
|
|
return err
|
|
}
|
|
for _, row := range rows {
|
|
if row.ID != uuid.Nil {
|
|
set.rows[row.ID] = row.ObjectKey
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (set *deletionMediaSet) objectKeys() []string {
|
|
keys := make([]string, 0, len(set.rows))
|
|
seen := make(map[string]struct{}, len(set.rows))
|
|
for _, key := range set.rows {
|
|
if key == "" {
|
|
continue
|
|
}
|
|
if _, exists := seen[key]; exists {
|
|
continue
|
|
}
|
|
seen[key] = struct{}{}
|
|
keys = append(keys, key)
|
|
}
|
|
return keys
|
|
}
|
|
|
|
func (set *deletionMediaSet) deleteRows(tx *gorm.DB) error {
|
|
if len(set.rows) == 0 {
|
|
return nil
|
|
}
|
|
ids := make([]uuid.UUID, 0, len(set.rows))
|
|
for id := range set.rows {
|
|
ids = append(ids, id)
|
|
}
|
|
if err := tx.Exec("DELETE FROM channel_asset_cache WHERE media_asset_id IN ?", ids).Error; err != nil {
|
|
return err
|
|
}
|
|
return tx.Exec("DELETE FROM media_assets WHERE id IN ?", ids).Error
|
|
}
|
|
|
|
func collectMediaByObjectKey(tx *gorm.DB, set *deletionMediaSet, pattern string) error {
|
|
return set.addQuery(tx.Table("media_assets").Select("id,object_key").Where("object_key LIKE ?", pattern))
|
|
}
|
|
|
|
// removeEpisodeDerivedContent removes everything produced from an episode analysis.
|
|
// It intentionally keeps the episode source/subtitle and all project assets.
|
|
func removeEpisodeDerivedContent(tx *gorm.DB, projectID, episodeID uuid.UUID, media *deletionMediaSet) error {
|
|
// 封面来自本剧集的首帧,删除反推结果前先清理外键引用,避免随后删除媒体对象时产生约束错误。
|
|
if err := tx.Exec(`UPDATE creative_projects SET cover_asset_id=NULL
|
|
WHERE id=? AND cover_asset_id=(SELECT cover_asset_id FROM project_episodes WHERE id=?)`, projectID, episodeID).Error; err != nil {
|
|
return err
|
|
}
|
|
if err := tx.Exec("UPDATE project_episodes SET cover_asset_id=NULL WHERE id=?", episodeID).Error; err != nil {
|
|
return err
|
|
}
|
|
taskScope := `(task_type IN ('prompt_reverse','video_generation')
|
|
OR (task_type='image_generation' AND input_data->>'target_type'='storyboard')) AND
|
|
(episode_id=? OR storyboard_id IN (SELECT id FROM episode_storyboards WHERE episode_id=?))`
|
|
if err := media.addQuery(tx.Table("media_assets media").Select("DISTINCT media.id,media.object_key").
|
|
Joins("JOIN generation_outputs output ON output.media_asset_id=media.id").
|
|
Joins("JOIN generation_tasks task ON task.id=output.task_id").
|
|
Where(taskScope, episodeID, episodeID)); err != nil {
|
|
return err
|
|
}
|
|
if err := media.addQuery(tx.Table("media_assets media").Select("DISTINCT media.id,media.object_key").
|
|
Joins("JOIN episode_storyboards storyboard ON storyboard.thumbnail_asset_id=media.id").
|
|
Where("storyboard.episode_id=?", episodeID)); err != nil {
|
|
return err
|
|
}
|
|
derivedPrefix := fmt.Sprintf("juyou_ran/video-redraw/projects/%s/episodes/%s/storyboards/%%", projectID, episodeID)
|
|
if err := collectMediaByObjectKey(tx, media, derivedPrefix); err != nil {
|
|
return err
|
|
}
|
|
if err := tx.Exec("UPDATE episode_storyboards SET active_output_id=NULL WHERE episode_id=?", episodeID).Error; err != nil {
|
|
return err
|
|
}
|
|
if err := tx.Exec("DELETE FROM generation_outputs WHERE task_id IN (SELECT id FROM generation_tasks WHERE "+taskScope+")", episodeID, episodeID).Error; err != nil {
|
|
return err
|
|
}
|
|
if err := tx.Exec("DELETE FROM generation_tasks WHERE "+taskScope, episodeID, episodeID).Error; err != nil {
|
|
return err
|
|
}
|
|
if err := tx.Exec(`UPDATE generation_tasks SET storyboard_id=NULL
|
|
WHERE storyboard_id IN (SELECT id FROM episode_storyboards WHERE episode_id=?)`, episodeID).Error; err != nil {
|
|
return err
|
|
}
|
|
return tx.Exec("DELETE FROM episode_storyboards WHERE episode_id=?", episodeID).Error
|
|
}
|