diff --git a/ytdl.go b/ytdl.go index c3de3c6..fb7bc6f 100644 --- a/ytdl.go +++ b/ytdl.go @@ -1,11 +1,20 @@ 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) { @@ -31,23 +40,144 @@ func NewYTdl(vid string) ([]byte, error) { func DownloadAmbiance(uri string, name string) error { ytdl := config.GetString("youtube.ytdl") - err := exec.Command( + + 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, - "-x", - "--audio-format", "mp3", - "--postprocessor-args", "-ar 48000 -ac 2", - "--cookies", "./cookies.txt", "--no-call-home", "--no-cache-dir", - "--restrict-filenames", "-f", "140", - "-o", filepath.Join("./ambiance/", name+".mp3"), - ).Run() + "--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 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 }