2023-07-08 19:00:29 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2023-07-09 00:25:39 +00:00
|
|
|
"fmt"
|
2023-07-08 19:00:29 +00:00
|
|
|
"io/fs"
|
|
|
|
"log"
|
|
|
|
"os/exec"
|
|
|
|
"path/filepath"
|
|
|
|
"sort"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Category 电影分类结构
|
|
|
|
type Category struct {
|
|
|
|
Name string `json:"name"`
|
|
|
|
Movies []Movie `json:"movies"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// Movie 电影结构
|
|
|
|
type Movie struct {
|
|
|
|
Name string `json:"filename"`
|
|
|
|
Image string `json:"image"`
|
|
|
|
Duration int `json:"duration"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// var movies []Movie
|
|
|
|
var categories []Category
|
|
|
|
|
2023-07-09 00:25:39 +00:00
|
|
|
var IsRemakePNG = false
|
|
|
|
|
2023-07-08 19:00:29 +00:00
|
|
|
func initMovie() {
|
|
|
|
// 需要改进 如果存在这个文件的略缩图, 就不存进movieDict里
|
2023-07-09 00:25:39 +00:00
|
|
|
var movieDict map[string]*Movie = make(map[string]*Movie)
|
2023-07-08 19:00:29 +00:00
|
|
|
|
|
|
|
matches, err := filepath.Glob("movie/*")
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, filename := range matches {
|
|
|
|
base := filepath.Base(filename)
|
|
|
|
|
|
|
|
// ext := filepath.Ext(base)
|
|
|
|
base = base[:strings.IndexByte(base, '.')]
|
|
|
|
|
|
|
|
if _, ok := movieDict[base]; ok {
|
2023-07-09 00:25:39 +00:00
|
|
|
if !IsRemakePNG {
|
|
|
|
delete(movieDict, base)
|
|
|
|
}
|
2023-07-08 19:00:29 +00:00
|
|
|
} else {
|
2023-07-09 00:25:39 +00:00
|
|
|
movieDict[base] = &Movie{Name: filename}
|
2023-07-08 19:00:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// 初始化分类
|
|
|
|
categories = []Category{
|
|
|
|
{Name: "15min", Movies: []Movie{}},
|
|
|
|
{Name: "30min", Movies: []Movie{}},
|
|
|
|
{Name: "60min", Movies: []Movie{}},
|
|
|
|
{Name: "大于60min", Movies: []Movie{}},
|
|
|
|
}
|
|
|
|
|
|
|
|
filepath.Walk("./movie", func(path string, info fs.FileInfo, err error) error {
|
|
|
|
if !info.IsDir() && filepath.Ext(info.Name()) != ".png" {
|
|
|
|
base := info.Name()
|
|
|
|
cmd := exec.Command("ffprobe", "-v", "error", "-select_streams", "v:0", "-show_entries", "stream=duration", "-of", "default=nw=1:nk=1", "./movie/"+info.Name())
|
|
|
|
durationOutput, err := cmd.Output()
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("Error getting duration for %s: %v", info.Name(), err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
duration, err := strconv.ParseFloat(strings.Trim(string(durationOutput), "\n "), 64)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("Error parsing duration for %s: %v", info.Name(), err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
// log.Println(path, info.Name())
|
|
|
|
|
|
|
|
movie := Movie{
|
|
|
|
Name: info.Name(),
|
|
|
|
Image: base[:strings.IndexByte(base, '.')] + ".png",
|
|
|
|
Duration: int(duration / 60.0),
|
|
|
|
}
|
2023-07-09 00:25:39 +00:00
|
|
|
|
|
|
|
if m, ok := movieDict[base[:strings.IndexByte(base, '.')]]; ok {
|
|
|
|
m.Duration = movie.Duration
|
|
|
|
}
|
|
|
|
|
2023-07-08 19:00:29 +00:00
|
|
|
if movie.Duration <= 15 {
|
|
|
|
categories[0].Movies = append(categories[0].Movies, movie)
|
|
|
|
} else if movie.Duration <= 30 {
|
|
|
|
categories[1].Movies = append(categories[1].Movies, movie)
|
|
|
|
} else if movie.Duration <= 60 {
|
|
|
|
categories[2].Movies = append(categories[2].Movies, movie)
|
|
|
|
} else {
|
|
|
|
categories[3].Movies = append(categories[3].Movies, movie)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
for _, category := range categories {
|
|
|
|
var movies = category.Movies
|
|
|
|
sort.Slice(movies, func(i, j int) bool {
|
|
|
|
return movies[i].Duration < movies[j].Duration
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-07-09 00:25:39 +00:00
|
|
|
for key, movie := range movieDict {
|
|
|
|
// width := 160
|
|
|
|
// height := 120
|
|
|
|
// if movie.Duration <= 40 {
|
|
|
|
// continue
|
|
|
|
// }
|
|
|
|
|
|
|
|
log.Println(movie.Name, "时长:", movie.Duration)
|
|
|
|
var filter string
|
|
|
|
|
|
|
|
if movie.Duration <= 2 {
|
|
|
|
filter = "select='isnan(prev_selected_t)+gte(t-prev_selected_t\\,5)',scale=320:180,tile=3x3"
|
|
|
|
} else if movie.Duration <= 5 {
|
|
|
|
filter = "select='isnan(prev_selected_t)+gte(t-prev_selected_t\\,10)',scale=320:180,tile=3x3"
|
|
|
|
} else if movie.Duration <= 30 {
|
|
|
|
filter = "select='isnan(prev_selected_t)+gte(t-prev_selected_t\\,20)',scale=320:180,tile=3x3"
|
|
|
|
} else if movie.Duration <= 60 {
|
|
|
|
filter = "select='isnan(prev_selected_t)+gte(t-prev_selected_t\\,35)',scale=320:180,tile=3x3"
|
|
|
|
} else {
|
|
|
|
filter = "select='isnan(prev_selected_t)+gte(t-prev_selected_t\\,60)',scale=320:180,tile=3x3"
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd := exec.Command("ffmpeg",
|
|
|
|
"-i", movie.Name,
|
|
|
|
"-vf", filter,
|
|
|
|
"-frames:v", "1",
|
|
|
|
"-y",
|
|
|
|
"movie/"+key+".png",
|
|
|
|
)
|
|
|
|
|
|
|
|
var buffer bytes.Buffer
|
|
|
|
cmd.Stdout = &buffer
|
|
|
|
if cmd.Run() != nil {
|
|
|
|
log.Println(buffer.String())
|
|
|
|
panic(fmt.Errorf("could not generate frame %s %d", movie.Name, movie.Duration))
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-07-08 19:00:29 +00:00
|
|
|
// log.Printf("%##v", categories)
|
|
|
|
}
|