diff --git a/ytdl.go b/ytdl.go
index ab4d18d..895fde4 100644
--- a/ytdl.go
+++ b/ytdl.go
@@ -1,10 +1,15 @@
package main
import (
+ "bufio"
+ "encoding/json"
"fmt"
+ "log"
+ "math"
"net/url"
"os"
"os/exec"
+ "strconv"
"time"
"golang.org/x/time/rate"
@@ -14,28 +19,92 @@ var prate = rate.Sometimes{Interval: 1 * time.Second}
var yturl = "https://youtu.be/%s"
func NewYTdl(vid string) ([]byte, error) {
+ tmpfile, err := exec.Command("mktemp", "/tmp/dnd_ytdlp_XXXXXXXXXXXX.m4a").Output()
+ if err != nil {
+ return nil, err
+ }
+
+ tmpfile = tmpfile[:len(tmpfile)-1]
+
ytdl := config.GetString("youtube.ytdl")
yt := exec.Command(
ytdl,
fmt.Sprintf(yturl, vid),
+ "-q",
"--cookies", "./cookies.txt",
"--no-call-home",
"--no-cache-dir",
"--ignore-errors",
"--newline",
"--restrict-filenames",
+ "--force-overwrites",
+ "--progress",
+ "--progress-template", "download:{ \"dl_bytes\": \"%(progress.downloaded_bytes)s\", \"total_bytes\": \"%(progress.total_bytes)s\" }",
"-f", "251",
- "--get-url",
+ "-o", string(tmpfile),
)
yt.Stderr = os.Stderr
-
- uri, err := yt.Output()
+ ytprogress, err := yt.StdoutPipe()
if err != nil {
return nil, err
}
- return uri[:len(uri)-1], nil
+ err = yt.Start()
+ if err != nil {
+ return nil, err
+ }
+
+ log.Printf("Start ffmpeg to extract audio to %s", string(tmpfile))
+ msg := make(map[string]interface{})
+ msg["event"] = "ambiance_download_start"
+ data := make(map[string]string)
+ data["name"] = fmt.Sprintf(yturl, vid)
+ msg["payload"] = data
+ ws_msg <- msg
+
+ msg = make(map[string]interface{})
+ msg["event"] = "ambiance_download_progress"
+ data = make(map[string]string)
+ data["name"] = fmt.Sprintf(yturl, vid)
+
+ scanner := bufio.NewScanner(ytprogress)
+
+ for scanner.Scan() {
+ err := json.Unmarshal(scanner.Bytes(), &data)
+ if err != nil {
+ log.Println(err)
+ continue
+ }
+
+ dl, _ := strconv.ParseFloat(data["dl_bytes"], 64)
+ total, _ := strconv.ParseFloat(data["total_bytes"], 64)
+ percent := math.Floor((dl / total) * 100)
+ data["percent"] = strconv.FormatInt(int64(percent), 10)
+
+ prate.Do(func() {
+ msg["payload"] = data
+ ws_msg <- msg
+ })
+ }
+
+ if err := scanner.Err(); err != nil {
+ return nil, err
+ }
+
+ err = yt.Wait()
+ if err != nil {
+ return nil, err
+ }
+
+ msg = make(map[string]interface{})
+ msg["event"] = "ambiance_download_complete"
+ data = make(map[string]string)
+ data["name"] = fmt.Sprintf(yturl, vid)
+ msg["payload"] = data
+ ws_msg <- msg
+
+ return tmpfile, nil
}
func YTUrl(uri string) (vid string, err error) {
@@ -47,10 +116,18 @@ func YTUrl(uri string) (vid string, err error) {
switch u.Host {
case "youtu.be":
vid = u.Path[1:]
+ case "m.youtube.com":
+ fallthrough
case "youtube.com":
+ fallthrough
+ case "www.youtube.com":
vid = u.Query().Get("v")
}
+ if vid == "" {
+ return vid, fmt.Errorf("unable to parse vid")
+ }
+
return
}