Compare commits
4 Commits
cd264e0fc9
...
8a019c0817
Author | SHA1 | Date |
---|---|---|
Stein Ivar Berghei | 8a019c0817 | |
Stein Ivar Berghei | 605bd7f29e | |
Stein Ivar Berghei | 891fa050e1 | |
Stein Ivar Berghei | 6124ed3dbf |
37
ambiance.go
37
ambiance.go
|
@ -5,10 +5,13 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/davecheney/xattr"
|
"github.com/davecheney/xattr"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
@ -23,7 +26,7 @@ type Ambiance struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAmbiance(id string) (amb Ambiance, err error) {
|
func GetAmbiance(id string) (amb Ambiance, err error) {
|
||||||
fp := filepath.Join("./ambiance", id+".opus")
|
fp := filepath.Join(config.GetString("ambiance.path"), id+".opus")
|
||||||
_, err = os.Stat(fp)
|
_, err = os.Stat(fp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -42,13 +45,13 @@ func GetAmbiance(id string) (amb Ambiance, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAmbiances() (amb []Ambiance, err error) {
|
func GetAmbiances() (amb []Ambiance, err error) {
|
||||||
files, err := os.ReadDir("./ambiance")
|
files, err := os.ReadDir(config.GetString("ambiance.path"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
title, err := xattr.Getxattr(filepath.Join("./ambiance", file.Name()), "title")
|
title, err := xattr.Getxattr(filepath.Join(config.GetString("ambiance.path"), file.Name()), "title")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
||||||
|
@ -56,7 +59,7 @@ func GetAmbiances() (amb []Ambiance, err error) {
|
||||||
amb = append(amb, Ambiance{
|
amb = append(amb, Ambiance{
|
||||||
Id: file.Name()[:len(file.Name())-len(filepath.Ext(file.Name()))],
|
Id: file.Name()[:len(file.Name())-len(filepath.Ext(file.Name()))],
|
||||||
Title: string(title),
|
Title: string(title),
|
||||||
Path: filepath.Join("./ambiance", file.Name()),
|
Path: filepath.Join(config.GetString("ambiance.path"), file.Name()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,22 +98,22 @@ func AddAmbiance(uri, title string) (Ambiance, error) {
|
||||||
return amb, err
|
return amb, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Start download with YTdl for %s", uri)
|
vinfo, err := app.youtube.GetVideoFromID(vid)
|
||||||
ytfile, err := NewYTdl(vid)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return amb, err
|
return amb, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Start ffmpeg for %s", string(ytfile))
|
log.Printf("Start ffmpeg for %s (%s)", vid, vinfo.VideoDetails.Title)
|
||||||
ff := exec.Command(
|
ff := exec.Command(
|
||||||
"ffmpeg",
|
"ffmpeg",
|
||||||
"-y",
|
"-y",
|
||||||
"-i", string(ytfile),
|
"-i", vinfo.GetHLSPlaylist("234"),
|
||||||
"-vn",
|
"-vn",
|
||||||
"-acodec", "copy",
|
//"-acodec", "copy",
|
||||||
"-movflags", "+faststart",
|
"-movflags", "+faststart",
|
||||||
"-t", "01:00:00",
|
"-t", "01:00:00",
|
||||||
"-v", "error",
|
"-ar", "48000",
|
||||||
|
"-v", "quiet",
|
||||||
// "-stats",
|
// "-stats",
|
||||||
"-progress", "pipe:1",
|
"-progress", "pipe:1",
|
||||||
// "-af", "loudnorm=I=-16:LRA=11:TP=-1.5",
|
// "-af", "loudnorm=I=-16:LRA=11:TP=-1.5",
|
||||||
|
@ -152,6 +155,13 @@ func AddAmbiance(uri, title string) (Ambiance, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
prate.Do(func() {
|
prate.Do(func() {
|
||||||
|
out_time, ok := data["out_time_ms"]
|
||||||
|
if ok {
|
||||||
|
out_time_ms, _ := strconv.Atoi(out_time)
|
||||||
|
percent := fmt.Sprintf("%.0f", math.Floor((float64(out_time_ms)/float64(time.Hour.Microseconds()))*100))
|
||||||
|
data["percent"] = percent
|
||||||
|
}
|
||||||
|
|
||||||
msg["payload"] = data
|
msg["payload"] = data
|
||||||
ws_msg <- msg
|
ws_msg <- msg
|
||||||
})
|
})
|
||||||
|
@ -174,7 +184,7 @@ func AddAmbiance(uri, title string) (Ambiance, error) {
|
||||||
ws_msg <- msg
|
ws_msg <- msg
|
||||||
|
|
||||||
id := uuid.New()
|
id := uuid.New()
|
||||||
fn := filepath.Join("./ambiance", fmt.Sprintf("%s.opus", id.String()))
|
fn := filepath.Join(config.GetString("ambiance.path"), fmt.Sprintf("%s.opus", id.String()))
|
||||||
|
|
||||||
log.Printf("Moving to %s", fn)
|
log.Printf("Moving to %s", fn)
|
||||||
|
|
||||||
|
@ -208,11 +218,6 @@ 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
|
||||||
|
|
2
bot.go
2
bot.go
|
@ -13,8 +13,8 @@ import (
|
||||||
|
|
||||||
"github.com/diamondburned/arikawa/v3/state"
|
"github.com/diamondburned/arikawa/v3/state"
|
||||||
"github.com/diamondburned/arikawa/v3/voice"
|
"github.com/diamondburned/arikawa/v3/voice"
|
||||||
"github.com/faiface/beep"
|
|
||||||
"github.com/gohugoio/hugo/cache/filecache"
|
"github.com/gohugoio/hugo/cache/filecache"
|
||||||
|
"github.com/gopxl/beep"
|
||||||
"github.com/jackc/pgx/v5"
|
"github.com/jackc/pgx/v5"
|
||||||
"github.com/julienschmidt/httprouter"
|
"github.com/julienschmidt/httprouter"
|
||||||
"github.com/kataras/go-events"
|
"github.com/kataras/go-events"
|
||||||
|
|
|
@ -6,14 +6,15 @@ import (
|
||||||
discordspeaker "dndmusicbot/speaker"
|
discordspeaker "dndmusicbot/speaker"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"log"
|
"log"
|
||||||
|
"math/rand"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/faiface/beep"
|
|
||||||
"github.com/faiface/beep/effects"
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"github.com/gopxl/beep"
|
||||||
|
"github.com/gopxl/beep/effects"
|
||||||
"github.com/kataras/go-events"
|
"github.com/kataras/go-events"
|
||||||
"github.com/steino/gompd/v2/mpd"
|
"github.com/steino/gompd/v2/mpd"
|
||||||
"golang.org/x/time/rate"
|
"golang.org/x/time/rate"
|
||||||
|
@ -528,16 +529,18 @@ func (app *App) loadPlaylist(payload ...interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
list, err := ytdl_client.GetPlaylist(pl.Url)
|
list, err := ytdl_client.GetPlaylist(pl.Url)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error getting playlist info,", id)
|
log.Println("Error getting playlist info,", id)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rand.Shuffle(len(list.Videos), func(i, j int) { list.Videos[i], list.Videos[j] = list.Videos[j], list.Videos[i] })
|
||||||
|
|
||||||
app.plmutex.Lock()
|
app.plmutex.Lock()
|
||||||
if app.plcancel != nil {
|
if app.plcancel != nil {
|
||||||
app.plcancel()
|
app.plcancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
app.mpd.Stop()
|
app.mpd.Stop()
|
||||||
app.mpd.Clear()
|
app.mpd.Clear()
|
||||||
app.plmutex.Unlock()
|
app.plmutex.Unlock()
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"math"
|
"math"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/faiface/beep"
|
"github.com/gopxl/beep"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PCM struct {
|
type PCM struct {
|
||||||
|
|
7
go.mod
7
go.mod
|
@ -5,13 +5,14 @@ go 1.21
|
||||||
toolchain go1.21.3
|
toolchain go1.21.3
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/IzumiSy/go-fdkaac v0.0.0-20220502080852-c56d1bb3e32d
|
||||||
github.com/bitly/go-simplejson v0.5.1
|
github.com/bitly/go-simplejson v0.5.1
|
||||||
github.com/davecheney/xattr v0.0.0-20151008032638-dc6dbbe49f0b
|
github.com/davecheney/xattr v0.0.0-20151008032638-dc6dbbe49f0b
|
||||||
github.com/diamondburned/arikawa/v3 v3.2.1-0.20230320210521-82c55dffac71
|
github.com/diamondburned/arikawa/v3 v3.2.1-0.20230320210521-82c55dffac71
|
||||||
github.com/faiface/beep v1.1.0
|
|
||||||
github.com/gohugoio/hugo v0.106.0
|
github.com/gohugoio/hugo v0.106.0
|
||||||
github.com/golang-jwt/jwt/v5 v5.0.0-rc.2
|
github.com/golang-jwt/jwt/v5 v5.0.0-rc.2
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
|
github.com/gopxl/beep v1.1.0
|
||||||
github.com/gorilla/sessions v1.1.1
|
github.com/gorilla/sessions v1.1.1
|
||||||
github.com/gorilla/websocket v1.5.0
|
github.com/gorilla/websocket v1.5.0
|
||||||
github.com/grafov/bcast v0.0.0-20190217190352-1447f067e08d
|
github.com/grafov/bcast v0.0.0-20190217190352-1447f067e08d
|
||||||
|
@ -26,10 +27,11 @@ require (
|
||||||
github.com/spf13/afero v1.9.5
|
github.com/spf13/afero v1.9.5
|
||||||
github.com/spf13/viper v1.16.0
|
github.com/spf13/viper v1.16.0
|
||||||
github.com/steino/gompd/v2 v2.3.1
|
github.com/steino/gompd/v2 v2.3.1
|
||||||
|
github.com/tejzpr/ordered-concurrently/v3 v3.0.1
|
||||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29
|
golang.org/x/exp v0.0.0-20230321023759-10a507213a29
|
||||||
golang.org/x/net v0.15.0
|
golang.org/x/net v0.15.0
|
||||||
golang.org/x/time v0.3.0
|
golang.org/x/time v0.3.0
|
||||||
gopkg.in/hraban/opus.v2 v2.0.0-20220302220929-eeacdbcb92d0
|
gopkg.in/hraban/opus.v2 v2.0.0-20230925203106-0188a62cb302
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
@ -71,6 +73,7 @@ require (
|
||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
github.com/niklasfasching/go-org v1.6.5 // indirect
|
github.com/niklasfasching/go-org v1.6.5 // indirect
|
||||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||||
|
github.com/oov/audio v0.0.0-20171004131523-88a2be6dbe38 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
||||||
github.com/rivo/uniseg v0.4.4 // indirect
|
github.com/rivo/uniseg v0.4.4 // indirect
|
||||||
github.com/rogpeppe/go-internal v1.11.0 // indirect
|
github.com/rogpeppe/go-internal v1.11.0 // indirect
|
||||||
|
|
14
go.sum
14
go.sum
|
@ -42,6 +42,8 @@ github.com/BurntSushi/locker v0.0.0-20171006230638-a6e239ea1c69/go.mod h1:L1AbZd
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||||
|
github.com/IzumiSy/go-fdkaac v0.0.0-20220502080852-c56d1bb3e32d h1:2Fn0vK/lH/pI2/TtUTFgb3iKkbw7TDlxBLglELToDRo=
|
||||||
|
github.com/IzumiSy/go-fdkaac v0.0.0-20220502080852-c56d1bb3e32d/go.mod h1:jmxJwIPbDUrofy2H3d28lYzz+RL9qt8GltDAAJ/mlb0=
|
||||||
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||||
|
@ -119,8 +121,6 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/evanw/esbuild v0.15.14 h1:J/cqgL3yfj/HDHDo9txKAqyzTBYfAMuqCknkS2jhX24=
|
github.com/evanw/esbuild v0.15.14 h1:J/cqgL3yfj/HDHDo9txKAqyzTBYfAMuqCknkS2jhX24=
|
||||||
github.com/evanw/esbuild v0.15.14/go.mod h1:iINY06rn799hi48UqEnaQvVfZWe6W9bET78LbvN8VWk=
|
github.com/evanw/esbuild v0.15.14/go.mod h1:iINY06rn799hi48UqEnaQvVfZWe6W9bET78LbvN8VWk=
|
||||||
github.com/faiface/beep v1.1.0 h1:A2gWP6xf5Rh7RG/p9/VAW2jRSDEGQm5sbOb38sf5d4c=
|
|
||||||
github.com/faiface/beep v1.1.0/go.mod h1:6I8p6kK2q4opL/eWb+kAkk38ehnTunWeToJB+s51sT4=
|
|
||||||
github.com/fhs/gompd/v2 v2.3.0 h1:wuruUjmOODRlJhrYx73rJnzS7vTSXSU7pWmZtM3VPE0=
|
github.com/fhs/gompd/v2 v2.3.0 h1:wuruUjmOODRlJhrYx73rJnzS7vTSXSU7pWmZtM3VPE0=
|
||||||
github.com/fhs/gompd/v2 v2.3.0/go.mod h1:nNdZtcpD5VpmzZbRl5rV6RhxeMmAWTxEsSIMBkmMIy4=
|
github.com/fhs/gompd/v2 v2.3.0/go.mod h1:nNdZtcpD5VpmzZbRl5rV6RhxeMmAWTxEsSIMBkmMIy4=
|
||||||
github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o=
|
github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o=
|
||||||
|
@ -231,6 +231,8 @@ github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
||||||
|
github.com/gopxl/beep v1.1.0 h1:YBfaDhZh4bC6IJfDsEi/8wmtUanir0dMIxpRu3F6Yeo=
|
||||||
|
github.com/gopxl/beep v1.1.0/go.mod h1:N5ClU2N8ESeO6ibbz5UThPRFpdEgbU9G60CLZ6u3v9s=
|
||||||
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
|
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
|
||||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||||
github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk=
|
github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk=
|
||||||
|
@ -338,6 +340,8 @@ github.com/niklasfasching/go-org v1.6.5 h1:5YAIqNTdl6lAOb7lD2AyQ1RuFGPVrAKvUexph
|
||||||
github.com/niklasfasching/go-org v1.6.5/go.mod h1:ybv0eGDnxylFUfFE+ySaQc734j/L3+/ChKZ/h63a2wM=
|
github.com/niklasfasching/go-org v1.6.5/go.mod h1:ybv0eGDnxylFUfFE+ySaQc734j/L3+/ChKZ/h63a2wM=
|
||||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||||
|
github.com/oov/audio v0.0.0-20171004131523-88a2be6dbe38 h1:4Upfs5rLQdx7KwBct3bmPYAhWsDDJdx660gYb7Lv9TQ=
|
||||||
|
github.com/oov/audio v0.0.0-20171004131523-88a2be6dbe38/go.mod h1:Xj06yMta9R1RSKiHmxL0Bo2TB8wiKVnMgA0KVopHHkk=
|
||||||
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
|
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
|
||||||
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||||
github.com/peterhellberg/link v1.2.0 h1:UA5pg3Gp/E0F2WdX7GERiNrPQrM1K6CVJUUWfHa4t6c=
|
github.com/peterhellberg/link v1.2.0 h1:UA5pg3Gp/E0F2WdX7GERiNrPQrM1K6CVJUUWfHa4t6c=
|
||||||
|
@ -394,6 +398,8 @@ github.com/tdewolff/parse/v2 v2.6.4 h1:KCkDvNUMof10e3QExio9OPZJT8SbdKojLBumw8YZy
|
||||||
github.com/tdewolff/parse/v2 v2.6.4/go.mod h1:woz0cgbLwFdtbjJu8PIKxhW05KplTFQkOdX78o+Jgrs=
|
github.com/tdewolff/parse/v2 v2.6.4/go.mod h1:woz0cgbLwFdtbjJu8PIKxhW05KplTFQkOdX78o+Jgrs=
|
||||||
github.com/tdewolff/test v1.0.7 h1:8Vs0142DmPFW/bQeHRP3MV19m1gvndjUb1sn8yy74LM=
|
github.com/tdewolff/test v1.0.7 h1:8Vs0142DmPFW/bQeHRP3MV19m1gvndjUb1sn8yy74LM=
|
||||||
github.com/tdewolff/test v1.0.7/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
|
github.com/tdewolff/test v1.0.7/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
|
||||||
|
github.com/tejzpr/ordered-concurrently/v3 v3.0.1 h1:TLHtzlQEDshbmGveS8S+hxLw4s5u67aoJw5LLf+X2xY=
|
||||||
|
github.com/tejzpr/ordered-concurrently/v3 v3.0.1/go.mod h1:mu/neZ6AGXm5jdPc7PEgViYK3rkYNPvVCEm15Cx/iRI=
|
||||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
@ -755,8 +761,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/fatih/set.v0 v0.2.1 h1:Xvyyp7LXu34P0ROhCyfXkmQCAoOUKb1E2JS9I7SE5CY=
|
gopkg.in/fatih/set.v0 v0.2.1 h1:Xvyyp7LXu34P0ROhCyfXkmQCAoOUKb1E2JS9I7SE5CY=
|
||||||
gopkg.in/fatih/set.v0 v0.2.1/go.mod h1:5eLWEndGL4zGGemXWrKuts+wTJR0y+w+auqUJZbmyBg=
|
gopkg.in/fatih/set.v0 v0.2.1/go.mod h1:5eLWEndGL4zGGemXWrKuts+wTJR0y+w+auqUJZbmyBg=
|
||||||
gopkg.in/hraban/opus.v2 v2.0.0-20220302220929-eeacdbcb92d0 h1:B8lK1KhYrE4H3urNYBAL/UquYftW65IHPY8JP3gpZ4M=
|
gopkg.in/hraban/opus.v2 v2.0.0-20230925203106-0188a62cb302 h1:xeVptzkP8BuJhoIjNizd2bRHfq9KB9HfOLZu90T04XM=
|
||||||
gopkg.in/hraban/opus.v2 v2.0.0-20220302220929-eeacdbcb92d0/go.mod h1:/L5E7a21VWl8DeuCPKxQBdVG5cy+L0MRZ08B1wnqt7g=
|
gopkg.in/hraban/opus.v2 v2.0.0-20230925203106-0188a62cb302/go.mod h1:/L5E7a21VWl8DeuCPKxQBdVG5cy+L0MRZ08B1wnqt7g=
|
||||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/neurosnap/sentences.v1 v1.0.6/go.mod h1:YlK+SN+fLQZj+kY3r8DkGDhDr91+S3JmTb5LSxFRQo0=
|
gopkg.in/neurosnap/sentences.v1 v1.0.6/go.mod h1:YlK+SN+fLQZj+kY3r8DkGDhDr91+S3JmTb5LSxFRQo0=
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package loop
|
package loop
|
||||||
|
|
||||||
import "github.com/faiface/beep"
|
import "github.com/gopxl/beep"
|
||||||
|
|
||||||
type loop struct {
|
type loop struct {
|
||||||
s beep.StreamSeekCloser
|
s beep.StreamSeekCloser
|
||||||
|
|
26
mpd.go
26
mpd.go
|
@ -3,6 +3,8 @@ package main
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
discordspeaker "dndmusicbot/speaker"
|
||||||
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
@ -11,7 +13,7 @@ import (
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/faiface/beep"
|
"github.com/gopxl/beep"
|
||||||
"github.com/kataras/go-events"
|
"github.com/kataras/go-events"
|
||||||
"github.com/steino/gompd/v2/mpd"
|
"github.com/steino/gompd/v2/mpd"
|
||||||
)
|
)
|
||||||
|
@ -116,14 +118,31 @@ func init() {
|
||||||
log.Println("mpd.go done.")
|
log.Println("mpd.go done.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var MPD_PCM *io.PipeReader
|
||||||
|
|
||||||
func NewMPD() (*MPD, error) {
|
func NewMPD() (*MPD, error) {
|
||||||
out := new(MPD)
|
out := new(MPD)
|
||||||
|
|
||||||
|
var pcm *io.PipeWriter
|
||||||
|
MPD_PCM, pcm = io.Pipe()
|
||||||
|
|
||||||
f, err := syscall.Open(config.GetString("mpd.fifo"), syscall.O_CREAT|syscall.O_RDONLY|syscall.O_CLOEXEC|syscall.O_NONBLOCK, 0644)
|
f, err := syscall.Open(config.GetString("mpd.fifo"), syscall.O_CREAT|syscall.O_RDONLY|syscall.O_CLOEXEC|syscall.O_NONBLOCK, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
buf := make([]byte, 2048)
|
||||||
|
for {
|
||||||
|
_, err := syscall.Read(f, buf)
|
||||||
|
if err != nil {
|
||||||
|
pcm.Write(make([]byte, 2048))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pcm.Write(buf)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
out.f = beep.Format{
|
out.f = beep.Format{
|
||||||
SampleRate: beep.SampleRate(sampleRate),
|
SampleRate: beep.SampleRate(sampleRate),
|
||||||
NumChannels: channels,
|
NumChannels: channels,
|
||||||
|
@ -143,13 +162,14 @@ func (m *MPD) Stream(samples [][2]float64) (n int, ok bool) {
|
||||||
tmp := make([]byte, m.f.NumChannels+2)
|
tmp := make([]byte, m.f.NumChannels+2)
|
||||||
|
|
||||||
for i := range samples {
|
for i := range samples {
|
||||||
dn, err := syscall.Read(m.file, tmp)
|
//dn, err := syscall.Read(m.file, tmp)
|
||||||
|
dn, err := MPD_PCM.Read(tmp)
|
||||||
if dn == len(tmp) {
|
if dn == len(tmp) {
|
||||||
samples[i], _ = m.f.DecodeSigned(tmp)
|
samples[i], _ = m.f.DecodeSigned(tmp)
|
||||||
ok = true
|
ok = true
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
samples[i] = [2]float64{}
|
samples[i] = discordspeaker.Silence
|
||||||
ok = true
|
ok = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/faiface/beep"
|
"github.com/gopxl/beep"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
opusd "gopkg.in/hraban/opus.v2"
|
opusd "gopkg.in/hraban/opus.v2"
|
||||||
)
|
)
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/faiface/beep"
|
"github.com/gopxl/beep"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -19,6 +19,7 @@ var (
|
||||||
buf []byte
|
buf []byte
|
||||||
maxBytes int = (frameSize * 2) * 2
|
maxBytes int = (frameSize * 2) * 2
|
||||||
done chan struct{}
|
done chan struct{}
|
||||||
|
f beep.Format
|
||||||
)
|
)
|
||||||
|
|
||||||
func update() {
|
func update() {
|
||||||
|
@ -62,6 +63,12 @@ func TestMain(t *testing.T) {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f = beep.Format{
|
||||||
|
SampleRate: beep.SampleRate(48000),
|
||||||
|
NumChannels: 2,
|
||||||
|
Precision: 2,
|
||||||
|
}
|
||||||
|
|
||||||
loop := beep.Loop(-1, d)
|
loop := beep.Loop(-1, d)
|
||||||
|
|
||||||
mu.Lock()
|
mu.Lock()
|
||||||
|
|
Binary file not shown.
168
queue.go
168
queue.go
|
@ -1,15 +1,11 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"container/list"
|
|
||||||
"log"
|
"log"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/faiface/beep"
|
"github.com/gopxl/beep"
|
||||||
"github.com/faiface/beep/effects"
|
"github.com/gopxl/beep/effects"
|
||||||
"github.com/kataras/go-events"
|
|
||||||
|
|
||||||
"dndmusicbot/ffmpeg"
|
|
||||||
discordspeaker "dndmusicbot/speaker"
|
discordspeaker "dndmusicbot/speaker"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -17,7 +13,7 @@ var pl_volume *effects.Volume
|
||||||
var amb_volume *effects.Volume
|
var amb_volume *effects.Volume
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
log.Println("queue.go loading..")
|
log.Println("beep.go loading..")
|
||||||
|
|
||||||
app.ambiance = beep.Mixer{}
|
app.ambiance = beep.Mixer{}
|
||||||
|
|
||||||
|
@ -43,161 +39,5 @@ func init() {
|
||||||
|
|
||||||
discordspeaker.Play(pl_volume)
|
discordspeaker.Play(pl_volume)
|
||||||
|
|
||||||
/*
|
log.Println("beep.go done.")
|
||||||
app.queue = new(Queue)
|
|
||||||
app.queue.list = list.New()
|
|
||||||
app.queue.Events = app.events
|
|
||||||
discordspeaker.Play(app.queue)
|
|
||||||
*/
|
|
||||||
|
|
||||||
log.Println("queue.go done.")
|
|
||||||
}
|
|
||||||
|
|
||||||
type Song struct {
|
|
||||||
Title string
|
|
||||||
Channel string
|
|
||||||
VideoID string
|
|
||||||
Length time.Duration
|
|
||||||
PCM *ffmpeg.PCM
|
|
||||||
Playlist Playlist
|
|
||||||
DLuri string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Song) NewStream() (err error) {
|
|
||||||
s.PCM, err = ffmpeg.NewPCM(s.DLuri, sampleRate, channels)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type Queue struct {
|
|
||||||
Events events.EventEmmiter
|
|
||||||
playing bool
|
|
||||||
list *list.List
|
|
||||||
current *list.Element
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q Queue) IsPlaying() bool {
|
|
||||||
return q.playing
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q *Queue) Play() {
|
|
||||||
q.playing = true
|
|
||||||
if q.list.Len() > 0 {
|
|
||||||
play := q.list.Front()
|
|
||||||
q.current = play
|
|
||||||
app.events.Emit("song_start")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q *Queue) Add(s *Song) {
|
|
||||||
el := q.list.PushBack(s)
|
|
||||||
if el == q.list.Front() {
|
|
||||||
q.Play()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q Queue) QLen() int {
|
|
||||||
return q.list.Len()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q Queue) Current() *Song {
|
|
||||||
if q.current == nil {
|
|
||||||
return new(Song)
|
|
||||||
}
|
|
||||||
return q.current.Value.(*Song)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q *Queue) Reset() {
|
|
||||||
err := app.mpd.Clear()
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q *Queue) Next() {
|
|
||||||
if q.current == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
next := q.current.Next()
|
|
||||||
if next == nil {
|
|
||||||
next = q.list.Front()
|
|
||||||
}
|
|
||||||
|
|
||||||
pcm := next.Value.(*Song).PCM
|
|
||||||
if pcm != nil && pcm.Position() != 0 {
|
|
||||||
err := next.Value.(*Song).NewStream()
|
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
q.current = next
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q *Queue) Prev() {
|
|
||||||
if q.current == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
prev := q.current.Prev()
|
|
||||||
if prev == nil {
|
|
||||||
prev = q.list.Back()
|
|
||||||
}
|
|
||||||
|
|
||||||
err := prev.Value.(*Song).NewStream()
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
q.current = prev
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q *Queue) Preload() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q *Queue) Stream(samples [][2]float64) (n int, ok bool) {
|
|
||||||
// We use the filled variable to track how many samples we've
|
|
||||||
// successfully filled already. We loop until all samples are filled.
|
|
||||||
filled := 0
|
|
||||||
|
|
||||||
for filled < len(samples) {
|
|
||||||
// There are no streamers in the queue, so we stream silence.
|
|
||||||
if q.current == nil || q.list.Len() == 0 {
|
|
||||||
for i := range samples[filled:] {
|
|
||||||
samples[i][0] = 0
|
|
||||||
samples[i][1] = 0
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// We stream from the first streamer in the queue.
|
|
||||||
n, ok := q.current.Value.(*Song).PCM.Stream(samples[filled:])
|
|
||||||
// If it's drained, we pop it from the queue, thus continuing with
|
|
||||||
// the next streamer.
|
|
||||||
if !ok {
|
|
||||||
q.Next()
|
|
||||||
q.Events.Emit("song_over", nil)
|
|
||||||
}
|
|
||||||
// We update the number of filled samples.
|
|
||||||
filled += n
|
|
||||||
}
|
|
||||||
|
|
||||||
return len(samples), true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q *Queue) Err() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q *Queue) Position() int {
|
|
||||||
if q.current == nil || q.current.Value.(*Song).PCM == nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
return q.current.Value.(*Song).PCM.Position()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q Queue) Len() int {
|
|
||||||
if q.current == nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
return int(q.current.Value.(*Song).Length.Milliseconds())
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,15 +2,20 @@ package discordspeaker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/diamondburned/arikawa/v3/voice"
|
"github.com/diamondburned/arikawa/v3/voice"
|
||||||
"github.com/diamondburned/arikawa/v3/voice/voicegateway"
|
"github.com/diamondburned/arikawa/v3/voice/voicegateway"
|
||||||
"github.com/faiface/beep"
|
"github.com/gopxl/beep"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"golang.org/x/time/rate"
|
||||||
"gopkg.in/hraban/opus.v2"
|
"gopkg.in/hraban/opus.v2"
|
||||||
|
|
||||||
|
cc "github.com/tejzpr/ordered-concurrently/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -19,7 +24,6 @@ var (
|
||||||
samples [][2]float64
|
samples [][2]float64
|
||||||
done chan struct{}
|
done chan struct{}
|
||||||
encoder *opus.Encoder
|
encoder *opus.Encoder
|
||||||
//voice *discordgo.VoiceConnection
|
|
||||||
frameSize int = 960
|
frameSize int = 960
|
||||||
channels int = 2
|
channels int = 2
|
||||||
sampleRate int = 48000
|
sampleRate int = 48000
|
||||||
|
@ -27,8 +31,14 @@ var (
|
||||||
buf []byte
|
buf []byte
|
||||||
session *voice.Session
|
session *voice.Session
|
||||||
spk bool
|
spk bool
|
||||||
|
input chan cc.WorkFunction
|
||||||
|
pw *io.PipeWriter
|
||||||
|
pr *io.PipeReader
|
||||||
|
spklimit = rate.NewLimiter(rate.Every(2*time.Second), 1)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var Silence = [2]float64{}
|
||||||
|
|
||||||
func Init(dgv *voice.Session) error {
|
func Init(dgv *voice.Session) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
@ -36,8 +46,9 @@ func Init(dgv *voice.Session) error {
|
||||||
defer mu.Unlock()
|
defer mu.Unlock()
|
||||||
Close()
|
Close()
|
||||||
|
|
||||||
mixer = beep.Mixer{}
|
pr, pw = io.Pipe()
|
||||||
buf = make([]byte, maxBytes)
|
buf = make([]byte, maxBytes)
|
||||||
|
mixer = beep.Mixer{}
|
||||||
samples = make([][2]float64, frameSize)
|
samples = make([][2]float64, frameSize)
|
||||||
|
|
||||||
session = dgv
|
session = dgv
|
||||||
|
@ -49,20 +60,44 @@ func Init(dgv *voice.Session) error {
|
||||||
return errors.Wrap(err, "failed to initialize speaker")
|
return errors.Wrap(err, "failed to initialize speaker")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input = make(chan cc.WorkFunction)
|
||||||
|
ctx := context.Background()
|
||||||
|
output := cc.Process(ctx, input, &cc.Options{PoolSize: 4, OutChannelBuffer: 4})
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
default:
|
default:
|
||||||
update()
|
update()
|
||||||
|
case out := <-output:
|
||||||
|
fmt.Println(pw.Write(out.Value.([]byte)))
|
||||||
case <-done:
|
case <-done:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
go ReadSend()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ReadSend() {
|
||||||
|
for {
|
||||||
|
buf := make([]byte, maxBytes)
|
||||||
|
n, err := pr.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = session.Write(buf[:n])
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func Close() {
|
func Close() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,56 +122,58 @@ func Clear() {
|
||||||
mu.Unlock()
|
mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Speak(s bool) {
|
||||||
|
switch s {
|
||||||
|
case true:
|
||||||
|
|
||||||
|
case false:
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func update() {
|
func update() {
|
||||||
mu.Lock()
|
mu.Lock()
|
||||||
mixer.Stream(samples)
|
mixer.Stream(samples)
|
||||||
mu.Unlock()
|
mu.Unlock()
|
||||||
var f32 []float32
|
|
||||||
|
|
||||||
for _, sample := range samples {
|
if IsSilent(samples) {
|
||||||
for _, val := range sample {
|
if spk && spklimit.Allow() {
|
||||||
f32 = append(f32, float32(val))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if Silence(f32) {
|
|
||||||
if spk {
|
|
||||||
log.Println("Notspeaking")
|
log.Println("Notspeaking")
|
||||||
session.Speaking(context.Background(), voicegateway.NotSpeaking)
|
session.Speaking(context.Background(), voicegateway.NotSpeaking)
|
||||||
spk = false
|
spk = false
|
||||||
}
|
}
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !spk {
|
if !spk && spklimit.Allow() {
|
||||||
log.Println("Speaking")
|
log.Println("Speaking")
|
||||||
session.Speaking(context.Background(), voicegateway.Microphone)
|
session.Speaking(context.Background(), voicegateway.Microphone)
|
||||||
spk = true
|
spk = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var f32 []float32
|
||||||
|
|
||||||
|
for _, sample := range samples {
|
||||||
|
f32 = append(f32, float32(sample[0]))
|
||||||
|
f32 = append(f32, float32(sample[1]))
|
||||||
|
}
|
||||||
|
|
||||||
n, err := encoder.EncodeFloat32(f32, buf)
|
n, err := encoder.EncodeFloat32(f32, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = session.Write(buf[:n])
|
pw.Write(buf[:n])
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Silence(in []float32) bool {
|
func IsSilent(in [][2]float64) bool {
|
||||||
for _, v := range in {
|
for _, v := range in {
|
||||||
if v != 0 {
|
if v != Silence {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
function on(eventType: any, listener: { (event: any): void; (this: Document, ev: any): any; }) {
|
||||||
|
document.addEventListener(eventType, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
function off(eventType: any, listener: { (event: any): void; (this: Document, ev: any): any; }) {
|
||||||
|
document.removeEventListener(eventType, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
function once(eventType: any, listener: (arg0: any) => void) {
|
||||||
|
on(eventType, handleEventOnce);
|
||||||
|
|
||||||
|
function handleEventOnce(event) {
|
||||||
|
listener(event);
|
||||||
|
off(eventType, handleEventOnce);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function trigger(eventType: string, data: any) {
|
||||||
|
const event = new CustomEvent(eventType, { detail: data });
|
||||||
|
document.dispatchEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { on, once, off, trigger };
|
|
@ -0,0 +1,77 @@
|
||||||
|
import React, { useEffect, useState, useCallback } from "react";
|
||||||
|
import CSS from "csstype";
|
||||||
|
import { on } from "./events";
|
||||||
|
import ws from "./ws";
|
||||||
|
|
||||||
|
export default function Playlists() {
|
||||||
|
interface Playlist {
|
||||||
|
Id: string;
|
||||||
|
Title: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [playlists, setPlaylists] = useState<Playlist[]>([]);
|
||||||
|
const [active, setActive] = useState("");
|
||||||
|
|
||||||
|
const activeStyle: CSS.Properties = {
|
||||||
|
backgroundColor: "burlywood",
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchPlaylists = () => {
|
||||||
|
fetch("/playlists")
|
||||||
|
.then((response) => {
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
setPlaylists(data);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchPlaylists();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const Play = (e: any) => {
|
||||||
|
console.log(e.target.dataset);
|
||||||
|
ws.send(
|
||||||
|
JSON.stringify({
|
||||||
|
event: "load_playlist",
|
||||||
|
payload: e.target.dataset.id,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Stop = () => {
|
||||||
|
ws.send(
|
||||||
|
JSON.stringify({
|
||||||
|
event: "stop",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
on("dnd:song_info", (e: any) => {
|
||||||
|
setActive(e.detail.playlist);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section>
|
||||||
|
<div id="items" className="item-container">
|
||||||
|
{playlists.map((playlist) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={playlist.Id}
|
||||||
|
onClick={Play}
|
||||||
|
className="item"
|
||||||
|
data-id={playlist.Id}
|
||||||
|
style={playlist.Id == active ? activeStyle : {}}
|
||||||
|
>
|
||||||
|
{playlist.Title}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
<div className="item locked stop" onClick={Stop} data-id="reset">
|
||||||
|
Stop
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
import React, { createContext } from "react";
|
||||||
|
import { createRoot } from "react-dom/client";
|
||||||
|
import { trigger, on } from "./events";
|
||||||
|
import Playlists from "./playlist";
|
||||||
|
import ws from "./ws";
|
||||||
|
|
||||||
|
function Content() {
|
||||||
|
ws.onmessage = (e) => {
|
||||||
|
const data = JSON.parse(e.data);
|
||||||
|
trigger("dnd:" + data.event, data.payload);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h2 className="bot">Playlists</h2>
|
||||||
|
<Playlists />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const domNode = document.getElementById("content");
|
||||||
|
const root = createRoot(domNode!);
|
||||||
|
root.render(<Content />);
|
|
@ -0,0 +1,9 @@
|
||||||
|
import ReconnectingWebSocket from "reconnecting-websocket";
|
||||||
|
|
||||||
|
const ws = new ReconnectingWebSocket(
|
||||||
|
(window.location.protocol === "https:" ? "wss://" : "ws://") +
|
||||||
|
window.location.host +
|
||||||
|
"/ws"
|
||||||
|
);
|
||||||
|
|
||||||
|
export default ws;
|
|
@ -1,9 +1,14 @@
|
||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "esbuild script.js --bundle --outdir=/public/"
|
"build": "esbuild script.js --bundle --outdir=/public/",
|
||||||
|
"build_test": "esbuild app/*.tsx --bundle --outfile=../public_test/script.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@types/react": "^18.2.33",
|
||||||
|
"@types/react-dom": "^18.2.14",
|
||||||
"esbuild": "^0.15.14",
|
"esbuild": "^0.15.14",
|
||||||
|
"react": "^18.2.0",
|
||||||
|
"react-dom": "^18.2.0",
|
||||||
"reconnecting-websocket": "^4.4.0",
|
"reconnecting-websocket": "^4.4.0",
|
||||||
"sortablejs": "^1.15.0"
|
"sortablejs": "^1.15.0"
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,19 +147,19 @@ 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":
|
case "ambiance_encode_start":
|
||||||
var progress = document.querySelector("#progressambiance progress")
|
var progress = document.querySelector("#progressambiance progress")
|
||||||
progress.style.display = "initial"
|
progress.style.display = "initial"
|
||||||
progress.style.width = "100%"
|
progress.style.width = "100%"
|
||||||
progress.value = 0
|
progress.value = 0
|
||||||
break
|
break
|
||||||
case "ambiance_download_progress":
|
case "ambiance_encode_progress":
|
||||||
var progress = document.querySelector("#progressambiance progress")
|
var progress = document.querySelector("#progressambiance progress")
|
||||||
progress.style.display = "initial"
|
progress.style.display = "initial"
|
||||||
progress.value = data.payload.percent
|
progress.value = data.payload.percent
|
||||||
console.log(data)
|
console.log(data)
|
||||||
break
|
break
|
||||||
case "ambiance_download_complete":
|
case "ambiance_encode_complete":
|
||||||
var progress = document.querySelector("#progressambiance progress")
|
var progress = document.querySelector("#progressambiance progress")
|
||||||
progress.style.display = "initial"
|
progress.style.display = "initial"
|
||||||
progress.value = 100
|
progress.value = 100
|
||||||
|
|
|
@ -12,6 +12,37 @@
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.15.14.tgz#1221684955c44385f8af34f7240088b7dc08d19d"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.15.14.tgz#1221684955c44385f8af34f7240088b7dc08d19d"
|
||||||
integrity sha512-eQi9rosGNVQFJyJWV0HCA5WZae/qWIQME7s8/j8DMvnylfBv62Pbu+zJ2eUDqNf2O4u3WB+OEXyfkpBoe194sg==
|
integrity sha512-eQi9rosGNVQFJyJWV0HCA5WZae/qWIQME7s8/j8DMvnylfBv62Pbu+zJ2eUDqNf2O4u3WB+OEXyfkpBoe194sg==
|
||||||
|
|
||||||
|
"@types/prop-types@*":
|
||||||
|
version "15.7.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.9.tgz#b6f785caa7ea1fe4414d9df42ee0ab67f23d8a6d"
|
||||||
|
integrity sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g==
|
||||||
|
|
||||||
|
"@types/react-dom@^18.2.14":
|
||||||
|
version "18.2.14"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.14.tgz#c01ba40e5bb57fc1dc41569bb3ccdb19eab1c539"
|
||||||
|
integrity sha512-V835xgdSVmyQmI1KLV2BEIUgqEuinxp9O4G6g3FqO/SqLac049E53aysv0oEFD2kHfejeKU+ZqL2bcFWj9gLAQ==
|
||||||
|
dependencies:
|
||||||
|
"@types/react" "*"
|
||||||
|
|
||||||
|
"@types/react@*", "@types/react@^18.2.33":
|
||||||
|
version "18.2.33"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.33.tgz#055356243dc4350a9ee6c6a2c07c5cae12e38877"
|
||||||
|
integrity sha512-v+I7S+hu3PIBoVkKGpSYYpiBT1ijqEzWpzQD62/jm4K74hPpSP7FF9BnKG6+fg2+62weJYkkBWDJlZt5JO/9hg==
|
||||||
|
dependencies:
|
||||||
|
"@types/prop-types" "*"
|
||||||
|
"@types/scheduler" "*"
|
||||||
|
csstype "^3.0.2"
|
||||||
|
|
||||||
|
"@types/scheduler@*":
|
||||||
|
version "0.16.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.5.tgz#4751153abbf8d6199babb345a52e1eb4167d64af"
|
||||||
|
integrity sha512-s/FPdYRmZR8SjLWGMCuax7r3qCWQw9QKHzXVukAuuIJkXkDRwp+Pu5LMIVFi0Fxbav35WURicYr8u1QsoybnQw==
|
||||||
|
|
||||||
|
csstype@^3.0.2:
|
||||||
|
version "3.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b"
|
||||||
|
integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==
|
||||||
|
|
||||||
esbuild-android-64@0.15.14:
|
esbuild-android-64@0.15.14:
|
||||||
version "0.15.14"
|
version "0.15.14"
|
||||||
resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.15.14.tgz#114e55b0d58fb7b45d7fa3d93516bd13fc8869cc"
|
resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.15.14.tgz#114e55b0d58fb7b45d7fa3d93516bd13fc8869cc"
|
||||||
|
@ -140,11 +171,45 @@ esbuild@^0.15.14:
|
||||||
esbuild-windows-64 "0.15.14"
|
esbuild-windows-64 "0.15.14"
|
||||||
esbuild-windows-arm64 "0.15.14"
|
esbuild-windows-arm64 "0.15.14"
|
||||||
|
|
||||||
|
"js-tokens@^3.0.0 || ^4.0.0":
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
||||||
|
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
|
||||||
|
|
||||||
|
loose-envify@^1.1.0:
|
||||||
|
version "1.4.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
||||||
|
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
||||||
|
dependencies:
|
||||||
|
js-tokens "^3.0.0 || ^4.0.0"
|
||||||
|
|
||||||
|
react-dom@^18.2.0:
|
||||||
|
version "18.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
|
||||||
|
integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
|
||||||
|
dependencies:
|
||||||
|
loose-envify "^1.1.0"
|
||||||
|
scheduler "^0.23.0"
|
||||||
|
|
||||||
|
react@^18.2.0:
|
||||||
|
version "18.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
|
||||||
|
integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
|
||||||
|
dependencies:
|
||||||
|
loose-envify "^1.1.0"
|
||||||
|
|
||||||
reconnecting-websocket@^4.4.0:
|
reconnecting-websocket@^4.4.0:
|
||||||
version "4.4.0"
|
version "4.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/reconnecting-websocket/-/reconnecting-websocket-4.4.0.tgz#3b0e5b96ef119e78a03135865b8bb0af1b948783"
|
resolved "https://registry.yarnpkg.com/reconnecting-websocket/-/reconnecting-websocket-4.4.0.tgz#3b0e5b96ef119e78a03135865b8bb0af1b948783"
|
||||||
integrity sha512-D2E33ceRPga0NvTDhJmphEgJ7FUYF0v4lr1ki0csq06OdlxKfugGzN0dSkxM/NfqCxYELK4KcaTOUOjTV6Dcng==
|
integrity sha512-D2E33ceRPga0NvTDhJmphEgJ7FUYF0v4lr1ki0csq06OdlxKfugGzN0dSkxM/NfqCxYELK4KcaTOUOjTV6Dcng==
|
||||||
|
|
||||||
|
scheduler@^0.23.0:
|
||||||
|
version "0.23.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe"
|
||||||
|
integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==
|
||||||
|
dependencies:
|
||||||
|
loose-envify "^1.1.0"
|
||||||
|
|
||||||
sortablejs@^1.15.0:
|
sortablejs@^1.15.0:
|
||||||
version "1.15.0"
|
version "1.15.0"
|
||||||
resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.15.0.tgz#53230b8aa3502bb77a29e2005808ffdb4a5f7e2a"
|
resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.15.0.tgz#53230b8aa3502bb77a29e2005808ffdb4a5f7e2a"
|
||||||
|
|
Loading…
Reference in New Issue