package main import ( "bufio" "fmt" "os" "os/exec" "path/filepath" "strconv" "strings" "time" "github.com/tidwall/gjson" "golang.org/x/time/rate" ) var prate = rate.Sometimes{Interval: 1 * time.Second} var yturl = "https://youtu.be/%s" func NewYTdl(vid string) ([]byte, error) { ytdl := config.GetString("youtube.ytdl") uri, err := exec.Command( ytdl, fmt.Sprintf(yturl, vid), "--cookies", "./cookies.txt", "--no-call-home", "--no-cache-dir", "--ignore-errors", "--newline", "--restrict-filenames", "-f", "140", "--get-url", ).Output() if err != nil { return nil, err } return uri[:len(uri)-1], nil } func DownloadAmbiance(uri string, name string) error { ytdl := config.GetString("youtube.ytdl") tmpfile, err := exec.Command("mktemp", "/tmp/dnd_XXXXXXXXXXXX.aac").Output() if err != nil { return err } tmpfile = tmpfile[:len(tmpfile)-1] cmd := exec.Command( ytdl, uri, "--no-call-home", "--no-cache-dir", "-f", "140", "--cookies", "../cookies.txt", "-o", string(tmpfile), "--force-overwrites", "-q", "--progress", "--progress-template", "%(progress)j", "--no-colors", "--newline", "--fixup", "never", ) cmdout, err := cmd.StdoutPipe() if err != nil { return err } err = cmd.Start() if err != nil { return err } msg := make(map[string]interface{}) msg["event"] = "ambiance_download_start" data := make(map[string]string) data["name"] = name msg["payload"] = data ws_msg <- msg msg = make(map[string]interface{}) msg["event"] = "ambiance_download_progress" data = make(map[string]string) scanner := bufio.NewScanner(cmdout) for scanner.Scan() { prate.Do(func() { js := gjson.GetManyBytes(scanner.Bytes(), "status", "downloaded_bytes", "total_bytes", "eta", "speed") data["name"] = name data["status"] = js[0].String() data["downloaded_bytes"] = js[1].String() data["total_bytes"] = js[2].String() data["eta"] = js[3].String() data["speed"] = js[4].String() msg["payload"] = data ws_msg <- msg }) } if err := scanner.Err(); err != nil { fmt.Fprintln(os.Stderr, "reading output:", err) } err = cmd.Wait() if err != nil { return err } msg = make(map[string]interface{}) msg["event"] = "ambiance_download_complete" data = make(map[string]string) data["name"] = name msg["payload"] = data ws_msg <- msg ff := exec.Command( "ffmpeg", "-i", string(tmpfile), "-v", "error", // "-stats", "-progress", "pipe:1", "-ar", strconv.Itoa(sampleRate), "-ac", strconv.Itoa(channels), "-af", "loudnorm=I=-16:LRA=11:TP=-1.5", "-threads", "4", filepath.Join("./ambiance/", name+".mp3"), ) ffprogress, err := ff.StdoutPipe() if err != nil { return err } err = ff.Start() if err != nil { return err } msg = make(map[string]interface{}) msg["event"] = "ambiance_encode_start" data = make(map[string]string) data["name"] = name msg["payload"] = data ws_msg <- msg msg = make(map[string]interface{}) msg["event"] = "ambiance_encode_progress" data = make(map[string]string) data["name"] = name scanner = bufio.NewScanner(ffprogress) for scanner.Scan() { p := strings.Split(scanner.Text(), "=") if len(p) == 2 { data[p[0]] = p[1] } prate.Do(func() { msg["payload"] = data ws_msg <- msg }) } if err := scanner.Err(); err != nil { return err } err = ff.Wait() if err != nil { return err } msg = make(map[string]interface{}) msg["event"] = "ambiance_encode_complete" data = make(map[string]string) data["name"] = name msg["payload"] = data ws_msg <- msg return nil }