Fix ambiance download

pull/11/head
Stein Ivar Berghei 2023-09-06 22:46:05 +02:00
parent 1888592d07
commit b26b43f163
4 changed files with 170 additions and 21 deletions

View File

@ -5,7 +5,6 @@ import (
"fmt" "fmt"
"io" "io"
"log" "log"
"net/http"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
@ -15,7 +14,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
) )
var httpClient = new(http.Client) //var httpClient = new(http.Client)
type Ambiance struct { type Ambiance struct {
Id string Id string
@ -67,6 +66,22 @@ func GetAmbiances() (amb []Ambiance, err error) {
func AddAmbiance(uri, title string) (Ambiance, error) { func AddAmbiance(uri, title string) (Ambiance, error) {
var amb Ambiance var amb Ambiance
msg := make(map[string]interface{})
msg["event"] = "ambiance_add_start"
data := make(map[string]string)
data["name"] = title
msg["payload"] = data
ws_msg <- msg
defer func() {
msg = make(map[string]interface{})
msg["event"] = "ambiance_add_finish"
data = make(map[string]string)
data["name"] = title
msg["payload"] = data
ws_msg <- msg
}()
tmpfile, err := exec.Command("mktemp", "/tmp/dnd_XXXXXXXXXXXX.opus").Output() tmpfile, err := exec.Command("mktemp", "/tmp/dnd_XXXXXXXXXXXX.opus").Output()
if err != nil { if err != nil {
return amb, err return amb, err
@ -74,28 +89,23 @@ func AddAmbiance(uri, title string) (Ambiance, error) {
tmpfile = tmpfile[:len(tmpfile)-1] tmpfile = tmpfile[:len(tmpfile)-1]
log.Printf("Parsing vid from %s", uri)
vid, err := YTUrl(uri) vid, err := YTUrl(uri)
if err != nil { if err != nil {
return amb, err return amb, err
} }
log.Printf("Start YTdl for %s", uri) log.Printf("Start download with YTdl for %s", uri)
dluri, err := NewYTdl(vid) ytfile, err := NewYTdl(vid)
if err != nil { if err != nil {
return amb, err return amb, err
} }
log.Printf("Start download.. %s", uri) log.Printf("Start ffmpeg for %s", string(ytfile))
resp, err := httpClient.Get(string(dluri))
if err != nil {
return amb, err
}
defer resp.Body.Close()
ff := exec.Command( ff := exec.Command(
"ffmpeg", "ffmpeg",
"-y", "-y",
"-i", "-", "-i", string(ytfile),
"-vn", "-vn",
"-acodec", "copy", "-acodec", "copy",
"-movflags", "+faststart", "-movflags", "+faststart",
@ -113,7 +123,6 @@ func AddAmbiance(uri, title string) (Ambiance, error) {
} }
ff.Stderr = os.Stderr ff.Stderr = os.Stderr
ff.Stdin = resp.Body
err = ff.Start() err = ff.Start()
if err != nil { if err != nil {
@ -121,9 +130,10 @@ func AddAmbiance(uri, title string) (Ambiance, error) {
} }
log.Printf("Start ffmpeg to extract audio to %s", string(tmpfile)) log.Printf("Start ffmpeg to extract audio to %s", string(tmpfile))
msg := make(map[string]interface{})
msg = make(map[string]interface{})
msg["event"] = "ambiance_encode_start" msg["event"] = "ambiance_encode_start"
data := make(map[string]string) data = make(map[string]string)
data["name"] = title data["name"] = title
msg["payload"] = data msg["payload"] = data
ws_msg <- msg ws_msg <- msg
@ -146,6 +156,7 @@ func AddAmbiance(uri, title string) (Ambiance, error) {
ws_msg <- msg ws_msg <- msg
}) })
} }
if err := scanner.Err(); err != nil { if err := scanner.Err(); err != nil {
return amb, err return amb, err
} }
@ -197,6 +208,11 @@ func AddAmbiance(uri, title string) (Ambiance, error) {
return amb, err return amb, err
} }
err = os.Remove(string(ytfile))
if err != nil {
return amb, err
}
err = os.Remove(string(tmpfile)) err = os.Remove(string(tmpfile))
if err != nil { if err != nil {
return amb, err return amb, err

View File

@ -147,6 +147,39 @@ window.onload = function () {
avol.value = data.payload.ambiance avol.value = data.payload.ambiance
avol.nextElementSibling.value = data.payload.ambiance avol.nextElementSibling.value = data.payload.ambiance
break break
case "ambiance_download_start":
var progress = document.querySelector("#progressambiance progress")
progress.style.display = "initial"
progress.style.width = "100%"
progress.value = 0
break
case "ambiance_download_progress":
var progress = document.querySelector("#progressambiance progress")
progress.style.display = "initial"
progress.value = data.payload.percent
console.log(data)
break
case "ambiance_download_complete":
var progress = document.querySelector("#progressambiance progress")
progress.style.display = "initial"
progress.value = 100
break
case "ambiance_add_finish":
var title = document.querySelector("#inputambiance > input[name='title']")
var url = document.querySelector("#inputambiance > input[name='url']")
var submit = document.querySelector("#inputambiance > input[name='submit']")
var progress = document.querySelector("#progressambiance progress")
title.value = ""
url.value = ""
title.disabled = false
url.disabled = false
submit.disabled = false
progress.value = 0
progress.style.display = "none"
break
case "ambiance_add": case "ambiance_add":
const container = document.querySelector("#ambiance") const container = document.querySelector("#ambiance")
var newdiv = document.createElement('div'); var newdiv = document.createElement('div');
@ -164,6 +197,21 @@ window.onload = function () {
}) })
container.insertBefore(newdiv, document.querySelector("#ambiance div:last-child")) container.insertBefore(newdiv, document.querySelector("#ambiance div:last-child"))
var title = document.querySelector("#inputambiance > input[name='title']")
var url = document.querySelector("#inputambiance > input[name='url']")
var submit = document.querySelector("#inputambiance > input[name='submit']")
var progress = document.querySelector("#progressambiance progress")
title.value = ""
url.value = ""
title.disabled = false
url.disabled = false
submit.disabled = false
progress.value = 0
progress.style.display = "none"
break break
case "ambiance_play": case "ambiance_play":
document.querySelectorAll("#ambiance > div").forEach((e) => {e.style.removeProperty("background-color")}) document.querySelectorAll("#ambiance > div").forEach((e) => {e.style.removeProperty("background-color")})
@ -218,6 +266,7 @@ window.onload = function () {
//output.innerText = "" //output.innerText = ""
var title = document.querySelector("#inputambiance > input[name='title']") var title = document.querySelector("#inputambiance > input[name='title']")
var url = document.querySelector("#inputambiance > input[name='url']") var url = document.querySelector("#inputambiance > input[name='url']")
var submit = document.querySelector("#inputambiance > input[name='submit']")
if (title.value == "" || url.value == "") { if (title.value == "" || url.value == "") {
console.log("Title or Url is empty!") console.log("Title or Url is empty!")
return return
@ -231,8 +280,9 @@ window.onload = function () {
} }
})) }))
title.value = "" title.disabled = true
url.value = "" url.disabled = true
submit.disabled = true
}) })
addInteractHandler(submit, (e, isTouch) => { addInteractHandler(submit, (e, isTouch) => {

View File

@ -59,6 +59,12 @@
</div> </div>
</section> </section>
<section>
<div id="progressambiance" class="input-container">
<progress max="100" value="0" style="display:none">0%</progress>
</div>
</section>
<section> <section>
<div id="inputambiance" class="input-container"> <div id="inputambiance" class="input-container">
<input class="u-full-width" name="title" type="text" placeholder="Enter name.."> <input class="u-full-width" name="title" type="text" placeholder="Enter name..">

85
ytdl.go
View File

@ -1,10 +1,15 @@
package main package main
import ( import (
"bufio"
"encoding/json"
"fmt" "fmt"
"log"
"math"
"net/url" "net/url"
"os" "os"
"os/exec" "os/exec"
"strconv"
"time" "time"
"golang.org/x/time/rate" "golang.org/x/time/rate"
@ -14,28 +19,92 @@ var prate = rate.Sometimes{Interval: 1 * time.Second}
var yturl = "https://youtu.be/%s" var yturl = "https://youtu.be/%s"
func NewYTdl(vid string) ([]byte, error) { 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") ytdl := config.GetString("youtube.ytdl")
yt := exec.Command( yt := exec.Command(
ytdl, ytdl,
fmt.Sprintf(yturl, vid), fmt.Sprintf(yturl, vid),
"-q",
"--cookies", "./cookies.txt", "--cookies", "./cookies.txt",
"--no-call-home", "--no-call-home",
"--no-cache-dir", "--no-cache-dir",
"--ignore-errors", "--ignore-errors",
"--newline", "--newline",
"--restrict-filenames", "--restrict-filenames",
"--force-overwrites",
"--progress",
"--progress-template", "download:{ \"dl_bytes\": \"%(progress.downloaded_bytes)s\", \"total_bytes\": \"%(progress.total_bytes)s\" }",
"-f", "251", "-f", "251",
"--get-url", "-o", string(tmpfile),
) )
yt.Stderr = os.Stderr yt.Stderr = os.Stderr
ytprogress, err := yt.StdoutPipe()
uri, err := yt.Output()
if err != nil { if err != nil {
return nil, err 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) { func YTUrl(uri string) (vid string, err error) {
@ -47,10 +116,18 @@ func YTUrl(uri string) (vid string, err error) {
switch u.Host { switch u.Host {
case "youtu.be": case "youtu.be":
vid = u.Path[1:] vid = u.Path[1:]
case "m.youtube.com":
fallthrough
case "youtube.com": case "youtube.com":
fallthrough
case "www.youtube.com":
vid = u.Query().Get("v") vid = u.Query().Get("v")
} }
if vid == "" {
return vid, fmt.Errorf("unable to parse vid")
}
return return
} }