Compare commits

..

No commits in common. "605bd7f29e8e1d02d4b52b44913e428642167316" and "cd264e0fc92d3599ef04d968d4c856bea906920b" have entirely different histories.

13 changed files with 227 additions and 148 deletions

View File

@ -5,13 +5,10 @@ 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"
@ -26,7 +23,7 @@ type Ambiance struct {
} }
func GetAmbiance(id string) (amb Ambiance, err error) { func GetAmbiance(id string) (amb Ambiance, err error) {
fp := filepath.Join(config.GetString("ambiance.path"), id+".opus") fp := filepath.Join("./ambiance", id+".opus")
_, err = os.Stat(fp) _, err = os.Stat(fp)
if err != nil { if err != nil {
return return
@ -45,13 +42,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(config.GetString("ambiance.path")) files, err := os.ReadDir("./ambiance")
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(config.GetString("ambiance.path"), file.Name()), "title") title, err := xattr.Getxattr(filepath.Join("./ambiance", file.Name()), "title")
if err != nil { if err != nil {
return nil, err return nil, err
@ -59,7 +56,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(config.GetString("ambiance.path"), file.Name()), Path: filepath.Join("./ambiance", file.Name()),
}) })
} }
@ -98,22 +95,22 @@ func AddAmbiance(uri, title string) (Ambiance, error) {
return amb, err return amb, err
} }
vinfo, err := app.youtube.GetVideoFromID(vid) log.Printf("Start download with YTdl for %s", uri)
ytfile, err := NewYTdl(vid)
if err != nil { if err != nil {
return amb, err return amb, err
} }
log.Printf("Start ffmpeg for %s (%s)", vid, vinfo.VideoDetails.Title) log.Printf("Start ffmpeg for %s", string(ytfile))
ff := exec.Command( ff := exec.Command(
"ffmpeg", "ffmpeg",
"-y", "-y",
"-i", vinfo.GetHLSPlaylist("234"), "-i", string(ytfile),
"-vn", "-vn",
//"-acodec", "copy", "-acodec", "copy",
"-movflags", "+faststart", "-movflags", "+faststart",
"-t", "01:00:00", "-t", "01:00:00",
"-ar", "48000", "-v", "error",
"-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",
@ -155,13 +152,6 @@ 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
}) })
@ -184,7 +174,7 @@ func AddAmbiance(uri, title string) (Ambiance, error) {
ws_msg <- msg ws_msg <- msg
id := uuid.New() id := uuid.New()
fn := filepath.Join(config.GetString("ambiance.path"), fmt.Sprintf("%s.opus", id.String())) fn := filepath.Join("./ambiance", fmt.Sprintf("%s.opus", id.String()))
log.Printf("Moving to %s", fn) log.Printf("Moving to %s", fn)
@ -218,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

2
bot.go
View File

@ -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"

View File

@ -6,15 +6,14 @@ 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"
@ -529,18 +528,16 @@ 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()

View File

@ -7,7 +7,7 @@ import (
"math" "math"
"time" "time"
"github.com/gopxl/beep" "github.com/faiface/beep"
) )
type PCM struct { type PCM struct {

7
go.mod
View File

@ -5,14 +5,13 @@ 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
@ -27,11 +26,10 @@ 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-20230925203106-0188a62cb302 gopkg.in/hraban/opus.v2 v2.0.0-20220302220929-eeacdbcb92d0
) )
require ( require (
@ -73,7 +71,6 @@ 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
View File

@ -42,8 +42,6 @@ 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=
@ -121,6 +119,8 @@ 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,8 +231,6 @@ 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=
@ -340,8 +338,6 @@ 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=
@ -398,8 +394,6 @@ 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=
@ -761,8 +755,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-20230925203106-0188a62cb302 h1:xeVptzkP8BuJhoIjNizd2bRHfq9KB9HfOLZu90T04XM= gopkg.in/hraban/opus.v2 v2.0.0-20220302220929-eeacdbcb92d0 h1:B8lK1KhYrE4H3urNYBAL/UquYftW65IHPY8JP3gpZ4M=
gopkg.in/hraban/opus.v2 v2.0.0-20230925203106-0188a62cb302/go.mod h1:/L5E7a21VWl8DeuCPKxQBdVG5cy+L0MRZ08B1wnqt7g= gopkg.in/hraban/opus.v2 v2.0.0-20220302220929-eeacdbcb92d0/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=

View File

@ -1,6 +1,6 @@
package loop package loop
import "github.com/gopxl/beep" import "github.com/faiface/beep"
type loop struct { type loop struct {
s beep.StreamSeekCloser s beep.StreamSeekCloser

26
mpd.go
View File

@ -3,8 +3,6 @@ package main
import ( import (
"bytes" "bytes"
"context" "context"
discordspeaker "dndmusicbot/speaker"
"io"
"log" "log"
"os" "os"
"os/exec" "os/exec"
@ -13,7 +11,7 @@ import (
"text/template" "text/template"
"time" "time"
"github.com/gopxl/beep" "github.com/faiface/beep"
"github.com/kataras/go-events" "github.com/kataras/go-events"
"github.com/steino/gompd/v2/mpd" "github.com/steino/gompd/v2/mpd"
) )
@ -118,31 +116,14 @@ 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,
@ -162,14 +143,13 @@ 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] = discordspeaker.Silence samples[i] = [2]float64{}
ok = true ok = true
break break
} }

View File

@ -5,7 +5,7 @@ import (
"log" "log"
"sync" "sync"
"github.com/gopxl/beep" "github.com/faiface/beep"
"github.com/pkg/errors" "github.com/pkg/errors"
opusd "gopkg.in/hraban/opus.v2" opusd "gopkg.in/hraban/opus.v2"
) )

View File

@ -8,7 +8,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/gopxl/beep" "github.com/faiface/beep"
) )
var ( var (
@ -19,7 +19,6 @@ 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() {
@ -63,12 +62,6 @@ 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
View File

@ -1,11 +1,15 @@
package main package main
import ( import (
"container/list"
"log" "log"
"time"
"github.com/gopxl/beep" "github.com/faiface/beep"
"github.com/gopxl/beep/effects" "github.com/faiface/beep/effects"
"github.com/kataras/go-events"
"dndmusicbot/ffmpeg"
discordspeaker "dndmusicbot/speaker" discordspeaker "dndmusicbot/speaker"
) )
@ -13,7 +17,7 @@ var pl_volume *effects.Volume
var amb_volume *effects.Volume var amb_volume *effects.Volume
func init() { func init() {
log.Println("beep.go loading..") log.Println("queue.go loading..")
app.ambiance = beep.Mixer{} app.ambiance = beep.Mixer{}
@ -39,5 +43,161 @@ 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())
} }

View File

@ -2,20 +2,15 @@ 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/gopxl/beep" "github.com/faiface/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 (
@ -24,6 +19,7 @@ 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
@ -31,14 +27,8 @@ 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
@ -46,9 +36,8 @@ func Init(dgv *voice.Session) error {
defer mu.Unlock() defer mu.Unlock()
Close() Close()
pr, pw = io.Pipe()
buf = make([]byte, maxBytes)
mixer = beep.Mixer{} mixer = beep.Mixer{}
buf = make([]byte, maxBytes)
samples = make([][2]float64, frameSize) samples = make([][2]float64, frameSize)
session = dgv session = dgv
@ -60,44 +49,20 @@ 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() {
} }
@ -122,58 +87,56 @@ 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
if IsSilent(samples) { for _, sample := range samples {
if spk && spklimit.Allow() { for _, val := range sample {
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 && spklimit.Allow() { if !spk {
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
} }
pw.Write(buf[:n]) _, err = session.Write(buf[:n])
if err != nil {
log.Println(err)
time.Sleep(100 * time.Millisecond)
return
}
} }
func IsSilent(in [][2]float64) bool { func Silence(in []float32) bool {
for _, v := range in { for _, v := range in {
if v != Silence { if v != 0 {
return false return false
} }
} }
return true return true
} }