package main import ( "bufio" "fmt" "io" "log" "net/http" "os" "os/exec" "path/filepath" "strings" "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("./ambiance", id+".opus") _, 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("./ambiance") if err != nil { return nil, err } for _, file := range files { title, err := xattr.Getxattr(filepath.Join("./ambiance", 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("./ambiance", file.Name()), }) } return } func AddAmbiance(uri, title string) (Ambiance, error) { var amb Ambiance tmpfile, err := exec.Command("mktemp", "/tmp/dnd_XXXXXXXXXXXX.opus").Output() if err != nil { return amb, err } tmpfile = tmpfile[:len(tmpfile)-1] vid, err := YTUrl(uri) if err != nil { return amb, err } log.Printf("Start YTdl for %s", uri) dluri, err := NewYTdl(vid) if err != nil { return amb, err } log.Printf("Start download.. %s", uri) resp, err := httpClient.Get(string(dluri)) if err != nil { return amb, err } defer resp.Body.Close() ff := exec.Command( "ffmpeg", "-y", "-i", "-", "-vn", "-acodec", "copy", "-movflags", "+faststart", "-t", "01:00:00", "-v", "error", // "-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 ff.Stdin = resp.Body err = ff.Start() if err != nil { return amb, err } log.Printf("Start ffmpeg to extract audio to %s", string(tmpfile)) msg := make(map[string]interface{}) msg["event"] = "ambiance_encode_start" data := make(map[string]string) data["name"] = title msg["payload"] = data ws_msg <- msg msg = make(map[string]interface{}) msg["event"] = "ambiance_encode_progress" 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() { msg["payload"] = data ws_msg <- msg }) } if err := scanner.Err(); err != nil { return amb, err } err = ff.Wait() if err != nil { return amb, err } msg = make(map[string]interface{}) msg["event"] = "ambiance_encode_complete" data = make(map[string]string) data["name"] = title msg["payload"] = data ws_msg <- msg id := uuid.New() fn := filepath.Join("./ambiance", fmt.Sprintf("%s.opus", 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 }