修复跳屏问题

This commit is contained in:
2025-06-03 00:44:35 +08:00
parent 728ba79eb6
commit 90c8df4ceb
5 changed files with 441 additions and 277 deletions

View File

@@ -146,7 +146,7 @@ func MovieList(c *gin.Context) {
sortBy := c.Query("sort")
order := c.Query("order")
if sortBy == "" {
sortBy = "created_time" // 默认按创建时间排序
sortBy = "duration" // 默认按创建时间排序
}
// 应用排序

View File

@@ -13,6 +13,7 @@ import (
"strconv"
"strings"
"sync"
"time"
)
// Movie 电影信息结构
@@ -74,7 +75,7 @@ var Movies []*Movie // 存储所有电影信息的全局切
var MovieDict = make(map[string]*Movie) // 存储需要处理缩略图的视频字典
var MovieDictLock sync.Mutex // 保护MovieDict的并发访问
var IsRemakePNG = false // 是否重新生成所有PNG缩略图
var IsRemakePNG = true // 是否重新生成所有PNG缩略图
var Categories = []string{ // 分类
"15min", "30min", "60min", "大于60min", "最新添加"}
@@ -223,38 +224,55 @@ func generateThumbnail(movie *Movie) {
baseName := strings.TrimSuffix(movie.FileName, filepath.Ext(movie.FileName))
outputPath := filepath.Join("movie", baseName+".png")
// 根据时长选择不同的采样策略
var filter string
switch {
case movie.Duration <= 2:
filter = "select='isnan(prev_selected_t)+gte(t-prev_selected_t\\,5)',scale=320:180,tile=3x3"
case movie.Duration <= 5:
filter = "select='isnan(prev_selected_t)+gte(t-prev_selected_t\\,10)',scale=320:180,tile=3x3"
case movie.Duration <= 30:
filter = "select='isnan(prev_selected_t)+gte(t-prev_selected_t\\,20)',scale=320:180,tile=3x3"
case movie.Duration <= 60:
filter = "select='isnan(prev_selected_t)+gte(t-prev_selected_t\\,35)',scale=320:180,tile=3x3"
default:
filter = "select='isnan(prev_selected_t)+gte(t-prev_selected_t\\,60)',scale=320:180,tile=3x3"
}
// --- Start of improved logic ---
// 执行ffmpeg命令生成缩略图
// Fixed skip for the beginning of the video, as per original code's ffmpeg args
const skipStartSeconds = 10.0
// Number of frames we want in the tile (for a 3x3 grid)
const numFramesInTile = 9.0 // Use float for calculations
durationAfterSkip := float64(movie.Duration) - skipStartSeconds
var intervalSeconds float64
if durationAfterSkip <= 0.1 { // Use a small threshold like 0.1s
intervalSeconds = 0.05 // A very small interval to grab whatever is there.
} else {
if numFramesInTile > 1 {
intervalSeconds = durationAfterSkip / (numFramesInTile - 1.0)
} else {
intervalSeconds = durationAfterSkip
}
if intervalSeconds <= 0 {
intervalSeconds = 0.05 // Fallback to a tiny interval
}
}
filter := fmt.Sprintf("select='isnan(prev_selected_t)+gte(t-prev_selected_t\\,%.3f)',scale=320:180,tile=3x3", intervalSeconds)
log.Printf("Movie: %s, OriginalDuration: %ds, SkipStart: %.1fs, DurationForSampling: %.2fs, CalculatedInterval: %.3fs",
movie.FileName, movie.Duration, skipStartSeconds, durationAfterSkip, intervalSeconds)
// Execute ffmpeg command
cmd := exec.Command("ffmpeg",
"-ss", fmt.Sprintf("%.0f", skipStartSeconds), // Using the defined skipStartSeconds
"-i", movie.VideoPath,
"-vf", filter,
"-frames:v", "1",
"-q:v", "3",
"-y", // 覆盖已存在文件
"-frames:v", "1", // Crucial for outputting a single tiled image
"-q:v", "3", // Quality for the frames before tiling/PNG compression
"-y", // Overwrite output file if it exists
outputPath,
)
var stderr bytes.Buffer
cmd.Stderr = &stderr
startTime := time.Now()
if err := cmd.Run(); err != nil {
log.Printf("生成缩略图失败: %s (%d min): %v\n错误输出: %s",
// Assuming movie.Duration is in seconds, adjusted log from (%d min) to (%d s)
log.Printf("生成缩略图失败: %s (%d s): %v\n错误输出: %s",
movie.VideoPath, movie.Duration, err, stderr.String())
} else {
log.Printf("成功生成缩略图: %s", outputPath)
log.Printf("成功生成缩略图: %s (耗时: %v)", outputPath, time.Since(startTime))
}
}