package main import ( "bytes" "io/fs" "log" "net/http" "os/exec" "path/filepath" "sort" "strconv" "strings" "github.com/gin-gonic/gin" ) // 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 func initMovie() { // 需要改进 如果存在这个文件的略缩图, 就不存进movieDict里 var movieDict map[string]string = make(map[string]string) 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 { delete(movieDict, base) } else { movieDict[base] = filename } } for key, filename := range movieDict { // width := 160 // height := 120 log.Println(filename) cmd := exec.Command("ffmpeg", "-i", filename, "-vf", "select='isnan(prev_selected_t)+gte(t-prev_selected_t\\,35)',scale=320:180,tile=3x3", "-frames:v", "1", "movie/"+key+".png", ) var buffer bytes.Buffer cmd.Stdout = &buffer if cmd.Run() != nil { log.Println(buffer.String()) panic("could not generate frame") } } // 初始化分类 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), } 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 }) } // log.Printf("%##v", categories) } func main() { initMovie() eg := gin.Default() eg.Use(Cors()) eg.Static("/res", "movie/") // 添加以下代码以提供frontend静态文件 eg.Static("/static", "../build/static") eg.NoRoute(func(c *gin.Context) { path := c.Request.URL.Path if filepath.Ext(path) == "" { c.File("../build/index.html") } else { c.Status(http.StatusNotFound) } }) movie := eg.Group("movie") movie.GET("/", MovieList) eg.Run(":4444") }