package main import ( "bufio" "fmt" "io" "log" "math" "os" "os/exec" "path/filepath" "strconv" "strings" "time" "github.com/davecheney/xattr" "github.com/google/uuid" ) //var httpClient = new(http.Client) type Ambiance struct { Id string Title string Path string } func GetAmbiance(id string) (amb Ambiance, err error) { fp := filepath.Join(config.GetString("ambiance.path"), id+".opus") _, err = os.Stat(fp) if err != nil { fp = filepath.Join(config.GetString("ambiance.path"), id+".aac") _, err = os.Stat(fp) if err != nil { return } } title, err := xattr.Getxattr(fp, "title") if err != nil { return } return Ambiance{ Id: id, Title: string(title), Path: fp, }, nil } func GetAmbiances() (amb []Ambiance, err error) { files, err := os.ReadDir(config.GetString("ambiance.path")) if err != nil { return nil, err } for _, file := range files { title, err := xattr.Getxattr(filepath.Join(config.GetString("ambiance.path"), file.Name()), "title") if err != nil { return nil, err } amb = append(amb, Ambiance{ Id: file.Name()[:len(file.Name())-len(filepath.Ext(file.Name()))], Title: string(title), Path: filepath.Join(config.GetString("ambiance.path"), file.Name()), }) } return } func AddAmbiance(uri, title string) (Ambiance, error) { var amb Ambiance ev := Event{"ambiance_add_start", map[string]string{ "name": title, }} go ws.SendEvent(ev) defer func() { ev = Event{"ambiance_add_finish", map[string]string{ "name": title, }} go ws.SendEvent(ev) }() tmpfile, err := exec.Command("mktemp", "/tmp/dnd_XXXXXXXXXXXX.aac").Output() if err != nil { return amb, err } tmpfile = tmpfile[:len(tmpfile)-1] log.Printf("Parsing vid from %s", uri) vid, err := YTUrl(uri) if err != nil { return amb, err } vinfo, err := app.youtube.GetVideoFromID(vid) if err != nil { return amb, err } log.Printf("Start ffmpeg for %s (%s)", vid, vinfo.VideoDetails.Title) ff := exec.Command( "ffmpeg", "-y", "-i", vinfo.GetHLSPlaylist("234"), "-vn", "-acodec", "copy", "-movflags", "+faststart", "-t", "01:00:00", "-ar", "48000", "-v", "quiet", // "-stats", "-progress", "pipe:1", // "-af", "loudnorm=I=-16:LRA=11:TP=-1.5", string(tmpfile), ) ffprogress, err := ff.StdoutPipe() if err != nil { return amb, err } ff.Stderr = os.Stderr err = ff.Start() if err != nil { return amb, err } log.Printf("Start ffmpeg to extract audio to %s", string(tmpfile)) ev = Event{"ambiance_encode_start", map[string]string{ "name": title, }} go ws.SendEvent(ev) data := make(map[string]string) data["name"] = title scanner := bufio.NewScanner(ffprogress) for scanner.Scan() { p := strings.Split(scanner.Text(), "=") if len(p) == 2 { data[p[0]] = strings.TrimSpace(p[1]) } prate.Do(func() { out_time, ok := data["out_time_ms"] if ok { out_time_ms, _ := strconv.Atoi(out_time) percent := fmt.Sprintf("%.0f", math.Floor((float64(out_time_ms)/float64(time.Hour.Microseconds()))*100)) data["percent"] = percent } go ws.SendEvent(Event{"ambiance_encode_progress", data}) }) } if err := scanner.Err(); err != nil { return amb, err } err = ff.Wait() if err != nil { return amb, err } ev = Event{"ambiance_encode_complete", map[string]string{ "name": title, }} go ws.SendEvent(ev) id := uuid.New() fn := filepath.Join(config.GetString("ambiance.path"), fmt.Sprintf("%s.aac", id.String())) log.Printf("Moving to %s", fn) in, err := os.Open(string(tmpfile)) if err != nil { return amb, err } of, err := os.Create(fn) if err != nil { return amb, err } _, err = io.Copy(of, in) if err != nil { return amb, err } err = of.Sync() if err != nil { return amb, err } err = of.Close() if err != nil { return amb, err } err = in.Close() if err != nil { return amb, err } err = os.Remove(string(tmpfile)) if err != nil { return amb, err } log.Println("Setting xattr") err = xattr.Setxattr(fn, "title", []byte(title)) if err != nil { return amb, err } amb.Id = id.String() amb.Title = title log.Println("Return info.") return amb, nil }