Compare commits
1 Commits
Author | SHA1 | Date |
---|---|---|
Stein Ivar Berghei | 8aa79a1e13 |
47
bot.go
47
bot.go
|
@ -9,17 +9,9 @@ import (
|
|||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/diamondburned/arikawa/v3/state"
|
||||
"github.com/diamondburned/arikawa/v3/voice"
|
||||
"github.com/faiface/beep"
|
||||
"github.com/fhs/gompd/v2/mpd"
|
||||
"github.com/gohugoio/hugo/cache/filecache"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/julienschmidt/httprouter"
|
||||
"github.com/kataras/go-events"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/spf13/viper"
|
||||
"google.golang.org/api/youtube/v3"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -30,8 +22,9 @@ const (
|
|||
)
|
||||
|
||||
var (
|
||||
app = new(App)
|
||||
config = viper.GetViper()
|
||||
bfs = afero.NewBasePathFs(afero.NewOsFs(), "cache")
|
||||
cache = filecache.NewCache(bfs, 1*time.Hour, "")
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -46,34 +39,12 @@ func init() {
|
|||
log.Fatal(err)
|
||||
}
|
||||
|
||||
app.plmutex = &sync.Mutex{}
|
||||
mpd_mutex = &sync.Mutex{}
|
||||
|
||||
log.Println("bot.go done.")
|
||||
}
|
||||
|
||||
type App struct {
|
||||
discord *state.State
|
||||
voice *voice.Session
|
||||
youtube *youtube.Service
|
||||
ambiance beep.Mixer
|
||||
curamb Ambiance
|
||||
events events.EventEmmiter
|
||||
db *pgx.Conn
|
||||
router *httprouter.Router
|
||||
active []string
|
||||
plidx int
|
||||
cache *filecache.Cache
|
||||
mpdc context.CancelFunc
|
||||
mpdw *mpd.Watcher
|
||||
mpd *mpd.Client
|
||||
plmutex *sync.Mutex
|
||||
plcancel context.CancelFunc
|
||||
}
|
||||
|
||||
func main() {
|
||||
bfs := afero.NewBasePathFs(afero.NewOsFs(), "cache")
|
||||
app.cache = filecache.NewCache(bfs, 1*time.Hour, "")
|
||||
|
||||
ticker := time.NewTicker(300 * time.Millisecond)
|
||||
|
||||
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
|
||||
|
@ -82,15 +53,15 @@ func main() {
|
|||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
app.db.Close(ctx)
|
||||
app.mpdw.Close()
|
||||
app.mpdc()
|
||||
app.voice.Leave(ctx)
|
||||
db.Close(ctx)
|
||||
mpdw.Close()
|
||||
mpdcf()
|
||||
dvoice.Leave(ctx)
|
||||
dgvc()
|
||||
app.discord.Close()
|
||||
dstate.Close()
|
||||
return
|
||||
case <-ticker.C:
|
||||
app.events.Emit("tick")
|
||||
ev.Emit("tick")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
16
db.go
16
db.go
|
@ -8,11 +8,13 @@ import (
|
|||
"github.com/jackc/pgx/v5"
|
||||
)
|
||||
|
||||
var db *pgx.Conn
|
||||
|
||||
func init() {
|
||||
log.Println("db.go loading..")
|
||||
var err error
|
||||
|
||||
app.db, err = pgx.Connect(context.Background(), config.GetString("db.connstring"))
|
||||
db, err = pgx.Connect(context.Background(), config.GetString("db.connstring"))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -25,8 +27,8 @@ type Playlist struct {
|
|||
Title string
|
||||
}
|
||||
|
||||
func (app App) GetPlaylists() (playlists []Playlist, err error) {
|
||||
rows, err := app.db.Query(context.Background(), "SELECT id, url, title FROM playlists")
|
||||
func GetPlaylists() (playlists []Playlist, err error) {
|
||||
rows, err := db.Query(context.Background(), "SELECT id, url, title FROM playlists")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -35,8 +37,8 @@ func (app App) GetPlaylists() (playlists []Playlist, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func (app App) GetPlaylist(id uuid.UUID) (*Playlist, error) {
|
||||
rows, err := app.db.Query(context.Background(), "SELECT id, url, title FROM playlists where id=$1 limit 1", id)
|
||||
func GetPlaylist(id uuid.UUID) (*Playlist, error) {
|
||||
rows, err := db.Query(context.Background(), "SELECT id, url, title FROM playlists where id=$1 limit 1", id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -50,9 +52,9 @@ func (app App) GetPlaylist(id uuid.UUID) (*Playlist, error) {
|
|||
return out, nil
|
||||
}
|
||||
|
||||
func (app App) AddPlaylist(title string, uri string) (uuid.UUID, error) {
|
||||
func AddPlaylist(title string, uri string) (uuid.UUID, error) {
|
||||
id := uuid.New()
|
||||
_, err := app.db.Exec(context.Background(), "INSERT INTO playlists VALUES ($1, $2, $3)", id, title, uri)
|
||||
_, err := db.Exec(context.Background(), "INSERT INTO playlists VALUES ($1, $2, $3)", id, title, uri)
|
||||
if err != nil {
|
||||
return *new(uuid.UUID), err
|
||||
}
|
||||
|
|
10
discord.go
10
discord.go
|
@ -11,7 +11,11 @@ import (
|
|||
"github.com/diamondburned/arikawa/v3/voice/voicegateway"
|
||||
)
|
||||
|
||||
var dgvc context.CancelFunc
|
||||
var (
|
||||
dstate *state.State
|
||||
dvoice *voice.Session
|
||||
dgvc context.CancelFunc
|
||||
)
|
||||
|
||||
func init() {
|
||||
log.Println("discord.go loading..")
|
||||
|
@ -47,8 +51,8 @@ func init() {
|
|||
|
||||
v.Speaking(ctx, voicegateway.NotSpeaking)
|
||||
|
||||
app.discord = s
|
||||
app.voice = v
|
||||
dstate = s
|
||||
dvoice = v
|
||||
|
||||
discordspeaker.Init(v)
|
||||
|
||||
|
|
162
events.go
162
events.go
|
@ -30,40 +30,46 @@ type SongInfo struct {
|
|||
Song string `json:"song,omitempty"`
|
||||
}
|
||||
|
||||
var l = rate.Sometimes{Interval: 800 * time.Millisecond}
|
||||
var (
|
||||
l = rate.Sometimes{Interval: 800 * time.Millisecond}
|
||||
)
|
||||
|
||||
var (
|
||||
ev events.EventEmmiter
|
||||
)
|
||||
|
||||
func init() {
|
||||
log.Println("events.go loading...")
|
||||
|
||||
app.events = events.New()
|
||||
ev = events.New()
|
||||
|
||||
app.events.On("load_playlist", app.loadPlaylist)
|
||||
app.events.On("add_playlist", app.addPlaylist)
|
||||
ev.On("load_playlist", loadPlaylist)
|
||||
ev.On("add_playlist", addPlaylist)
|
||||
|
||||
//app.events.On("preload_song", app.preloadSong)
|
||||
//app.events.On("song_over", app.songInfo)
|
||||
//app.events.On("song_start", app.songInfo)
|
||||
app.events.On("player", app.songInfo)
|
||||
//app.events.On("song_position", app.songPosition)
|
||||
//ev.On("preload_song", app.preloadSong)
|
||||
//ev.On("song_over", app.songInfo)
|
||||
//ev.On("song_start", app.songInfo)
|
||||
ev.On("player", songInfo)
|
||||
//ev.On("song_position", app.songPosition)
|
||||
|
||||
app.events.On("ambiance_play", app.ambiancePlay)
|
||||
app.events.On("ambiance_stop", app.ambianceStop)
|
||||
app.events.On("ambiance_add", app.ambianceAdd)
|
||||
ev.On("ambiance_play", ambiancePlay)
|
||||
ev.On("ambiance_stop", ambianceStop)
|
||||
ev.On("ambiance_add", ambianceAdd)
|
||||
|
||||
app.events.On("stop", app.stop)
|
||||
app.events.On("next", app.nextSong)
|
||||
app.events.On("prev", app.prevSong)
|
||||
ev.On("stop", stop)
|
||||
ev.On("next", nextSong)
|
||||
ev.On("prev", prevSong)
|
||||
|
||||
app.events.On("vol_up", app.volup)
|
||||
app.events.On("vol_down", app.voldown)
|
||||
app.events.On("vol_set", app.volset)
|
||||
ev.On("vol_up", volup)
|
||||
ev.On("vol_down", voldown)
|
||||
ev.On("vol_set", volset)
|
||||
|
||||
//app.events.On("tick", app.checkQueue)
|
||||
app.events.On("tick", app.songPosition)
|
||||
//app.events.On("tick", app.checkTimeleft)
|
||||
//ev.On("tick", app.checkQueue)
|
||||
ev.On("tick", songPosition)
|
||||
//ev.On("tick", app.checkTimeleft)
|
||||
}
|
||||
|
||||
func (app *App) volup(payload ...interface{}) {
|
||||
func volup(payload ...interface{}) {
|
||||
if !(len(payload) > 0) {
|
||||
log.Println("volup called without a payload.")
|
||||
return
|
||||
|
@ -91,7 +97,7 @@ func (app *App) volup(payload ...interface{}) {
|
|||
}
|
||||
}
|
||||
|
||||
func (app *App) voldown(payload ...interface{}) {
|
||||
func voldown(payload ...interface{}) {
|
||||
if !(len(payload) > 0) {
|
||||
log.Println("voldown called without a payload.")
|
||||
return
|
||||
|
@ -119,7 +125,7 @@ func (app *App) voldown(payload ...interface{}) {
|
|||
}
|
||||
}
|
||||
|
||||
func (app *App) volset(payload ...interface{}) {
|
||||
func volset(payload ...interface{}) {
|
||||
if !(len(payload) > 0) {
|
||||
log.Println("volset called without a payload.")
|
||||
return
|
||||
|
@ -147,10 +153,10 @@ func (app *App) volset(payload ...interface{}) {
|
|||
amb_volume.Volume = vol
|
||||
}
|
||||
|
||||
app.sendVolume()
|
||||
sendVolume()
|
||||
}
|
||||
|
||||
func (app *App) sendVolume() {
|
||||
func sendVolume() {
|
||||
msg := make(map[string]interface{})
|
||||
out := make(map[string]float64)
|
||||
msg["event"] = "volume"
|
||||
|
@ -160,16 +166,16 @@ func (app *App) sendVolume() {
|
|||
ws_msg <- msg
|
||||
}
|
||||
|
||||
func (app *App) songInfoEvent(event string) map[string]interface{} {
|
||||
func songInfoEvent(event string) map[string]interface{} {
|
||||
msg := make(map[string]interface{})
|
||||
msg["event"] = event
|
||||
status, err := app.mpd.Status()
|
||||
status, err := mpdc.Status()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
cur, err := app.mpd.CurrentSong()
|
||||
cur, err := mpdc.CurrentSong()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return nil
|
||||
|
@ -211,7 +217,7 @@ func (app *App) songInfoEvent(event string) map[string]interface{} {
|
|||
return nil
|
||||
}
|
||||
|
||||
pl, err := app.GetPlaylist(plid)
|
||||
pl, err := GetPlaylist(plid)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return nil
|
||||
|
@ -241,7 +247,7 @@ func (app *App) songInfoEvent(event string) map[string]interface{} {
|
|||
return msg
|
||||
}
|
||||
|
||||
func (app *App) ambiancePlay(payload ...interface{}) {
|
||||
func ambiancePlay(payload ...interface{}) {
|
||||
if !(len(payload) > 0) {
|
||||
log.Println("ambiance_play called without a payload.")
|
||||
return
|
||||
|
@ -289,14 +295,14 @@ func (app *App) ambiancePlay(payload ...interface{}) {
|
|||
}
|
||||
|
||||
discordspeaker.Lock()
|
||||
app.ambiance.Clear()
|
||||
app.ambiance.Add(volume)
|
||||
amb_mixer.Clear()
|
||||
amb_mixer.Add(volume)
|
||||
discordspeaker.Unlock()
|
||||
|
||||
msg := make(map[string]interface{})
|
||||
out := make(map[string]interface{})
|
||||
|
||||
app.curamb = amb
|
||||
amb_curr = amb
|
||||
|
||||
msg["event"] = "ambiance_play"
|
||||
out["id"] = id
|
||||
|
@ -304,10 +310,10 @@ func (app *App) ambiancePlay(payload ...interface{}) {
|
|||
ws_msg <- msg
|
||||
}
|
||||
|
||||
func (app *App) ambianceStop(payload ...interface{}) {
|
||||
func ambianceStop(payload ...interface{}) {
|
||||
log.Println("Stopping ambiance")
|
||||
discordspeaker.Lock()
|
||||
app.ambiance.Clear()
|
||||
amb_mixer.Clear()
|
||||
discordspeaker.Unlock()
|
||||
|
||||
msg := make(map[string]interface{})
|
||||
|
@ -316,7 +322,7 @@ func (app *App) ambianceStop(payload ...interface{}) {
|
|||
|
||||
}
|
||||
|
||||
func (app *App) ambianceAdd(payload ...interface{}) {
|
||||
func ambianceAdd(payload ...interface{}) {
|
||||
if !(len(payload) > 0) {
|
||||
log.Println("addPlaylist called without a payload.")
|
||||
return
|
||||
|
@ -359,8 +365,8 @@ func (app *App) ambianceAdd(payload ...interface{}) {
|
|||
ws_msg <- msg
|
||||
}
|
||||
|
||||
func (app *App) songPosition(payload ...interface{}) {
|
||||
status, err := app.mpd.Status()
|
||||
func songPosition(payload ...interface{}) {
|
||||
status, err := mpdc.Status()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
|
@ -395,24 +401,24 @@ func (app *App) songPosition(payload ...interface{}) {
|
|||
|
||||
}
|
||||
|
||||
func (app *App) songInfo(payload ...interface{}) {
|
||||
func songInfo(payload ...interface{}) {
|
||||
log.Println("song_info event received")
|
||||
|
||||
msg := app.songInfoEvent("song_info")
|
||||
msg := songInfoEvent("song_info")
|
||||
if msg != nil {
|
||||
ws_msg <- msg
|
||||
}
|
||||
}
|
||||
|
||||
func (app *App) stop(payload ...interface{}) {
|
||||
func stop(payload ...interface{}) {
|
||||
log.Println("stop event received")
|
||||
|
||||
app.plmutex.Lock()
|
||||
if app.plcancel != nil {
|
||||
app.plcancel()
|
||||
mpd_mutex.Lock()
|
||||
if mpd_plcf != nil {
|
||||
mpd_plcf()
|
||||
}
|
||||
app.mpd.Stop()
|
||||
app.plmutex.Unlock()
|
||||
mpdc.Stop()
|
||||
mpd_mutex.Unlock()
|
||||
|
||||
msg := make(map[string]interface{})
|
||||
msg["event"] = "stop"
|
||||
|
@ -420,28 +426,28 @@ func (app *App) stop(payload ...interface{}) {
|
|||
ws_msg <- msg
|
||||
}
|
||||
|
||||
func (app *App) prevSong(payload ...interface{}) {
|
||||
func prevSong(payload ...interface{}) {
|
||||
log.Println("prev_song event received")
|
||||
app.plmutex.Lock()
|
||||
err := app.mpd.Previous()
|
||||
app.plmutex.Unlock()
|
||||
mpd_mutex.Lock()
|
||||
err := mpdc.Previous()
|
||||
mpd_mutex.Unlock()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (app *App) nextSong(payload ...interface{}) {
|
||||
func nextSong(payload ...interface{}) {
|
||||
log.Println("next_song event received")
|
||||
|
||||
app.plmutex.Lock()
|
||||
err := app.mpd.Next()
|
||||
app.plmutex.Unlock()
|
||||
mpd_mutex.Lock()
|
||||
err := mpdc.Next()
|
||||
mpd_mutex.Unlock()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (app *App) addPlaylist(payload ...interface{}) {
|
||||
func addPlaylist(payload ...interface{}) {
|
||||
if !(len(payload) > 0) {
|
||||
log.Println("addPlaylist called without a payload.")
|
||||
return
|
||||
|
@ -481,12 +487,12 @@ func (app *App) addPlaylist(payload ...interface{}) {
|
|||
return
|
||||
}
|
||||
|
||||
_, err = app.Playlist(plid)
|
||||
_, err = YTPlaylist(plid)
|
||||
if err != nil {
|
||||
log.Println("Error getting youtube playlist info,", plid)
|
||||
}
|
||||
|
||||
id, err := app.AddPlaylist(pltitle, plid)
|
||||
id, err := AddPlaylist(pltitle, plid)
|
||||
if err != nil {
|
||||
log.Println("Error getting youtube playlist info,", plid)
|
||||
}
|
||||
|
@ -499,7 +505,7 @@ func (app *App) addPlaylist(payload ...interface{}) {
|
|||
ws_msg <- msg
|
||||
}
|
||||
|
||||
func (app *App) loadPlaylist(payload ...interface{}) {
|
||||
func loadPlaylist(payload ...interface{}) {
|
||||
log.Println("load_playlist event received")
|
||||
|
||||
if !(len(payload) > 0) {
|
||||
|
@ -526,13 +532,13 @@ func (app *App) loadPlaylist(payload ...interface{}) {
|
|||
}
|
||||
|
||||
log.Println("Loading new playlist: ", id)
|
||||
pl, err := app.GetPlaylist(id)
|
||||
pl, err := GetPlaylist(id)
|
||||
if err != nil {
|
||||
log.Println("Unable to find playlist with id,", id)
|
||||
return
|
||||
}
|
||||
|
||||
list, err := app.Playlist(pl.Url)
|
||||
list, err := YTPlaylist(pl.Url)
|
||||
if err != nil {
|
||||
log.Println("Error getting playlist info,", id)
|
||||
return
|
||||
|
@ -543,16 +549,16 @@ func (app *App) loadPlaylist(payload ...interface{}) {
|
|||
log.Println("Unable to shuffle playlist")
|
||||
return
|
||||
}
|
||||
app.plmutex.Lock()
|
||||
if app.plcancel != nil {
|
||||
app.plcancel()
|
||||
mpd_mutex.Lock()
|
||||
if mpd_plcf != nil {
|
||||
mpd_plcf()
|
||||
}
|
||||
app.mpd.Stop()
|
||||
app.mpd.Clear()
|
||||
app.plmutex.Unlock()
|
||||
mpdc.Stop()
|
||||
mpdc.Clear()
|
||||
mpd_mutex.Unlock()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
app.plcancel = cancel
|
||||
mpd_plcf = cancel
|
||||
|
||||
go func() {
|
||||
defer cancel()
|
||||
|
@ -560,13 +566,13 @@ func (app *App) loadPlaylist(payload ...interface{}) {
|
|||
for _, vid := range list {
|
||||
log.Printf("Adding %s", vid)
|
||||
|
||||
ytinfo, err := app.Video(vid)
|
||||
ytinfo, err := YTVideo(vid)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
|
||||
_, yt, err := app.cache.GetOrCreateBytes(vid+".txt", func() ([]byte, error) {
|
||||
_, yt, err := cache.GetOrCreateBytes(vid+".txt", func() ([]byte, error) {
|
||||
uri, err := NewYTdl(vid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -580,8 +586,8 @@ func (app *App) loadPlaylist(payload ...interface{}) {
|
|||
|
||||
// Run as a local function so we can defer the mutex unlock incase one of these errors.
|
||||
ok := func() (ok bool) {
|
||||
app.plmutex.Lock()
|
||||
defer app.plmutex.Unlock()
|
||||
mpd_mutex.Lock()
|
||||
defer mpd_mutex.Unlock()
|
||||
|
||||
if ctx.Err() != nil {
|
||||
return false
|
||||
|
@ -590,41 +596,41 @@ func (app *App) loadPlaylist(payload ...interface{}) {
|
|||
ok = true
|
||||
|
||||
// state:stop
|
||||
songid, err := app.mpd.AddID(string(yt), 0)
|
||||
songid, err := mpdc.AddID(string(yt), 0)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
mpdcmd := app.mpd.Command("%s %d %s %s", mpd.Quoted("addtagid"), songid, mpd.Quoted("artist"), ytinfo.Channel)
|
||||
mpdcmd := mpdc.Command("%s %d %s %s", mpd.Quoted("addtagid"), songid, mpd.Quoted("artist"), ytinfo.Channel)
|
||||
err = mpdcmd.OK()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
mpdcmd = app.mpd.Command("%s %d %s %s", mpd.Quoted("addtagid"), songid, mpd.Quoted("title"), ytinfo.Title)
|
||||
mpdcmd = mpdc.Command("%s %d %s %s", mpd.Quoted("addtagid"), songid, mpd.Quoted("title"), ytinfo.Title)
|
||||
err = mpdcmd.OK()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
mpdcmd = app.mpd.Command("%s %d %s %s", mpd.Quoted("addtagid"), songid, mpd.Quoted("location"), vid)
|
||||
mpdcmd = mpdc.Command("%s %d %s %s", mpd.Quoted("addtagid"), songid, mpd.Quoted("location"), vid)
|
||||
err = mpdcmd.OK()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
mpdcmd = app.mpd.Command("%s %d %s %s", mpd.Quoted("addtagid"), songid, mpd.Quoted("album"), pl.Id.String())
|
||||
mpdcmd = mpdc.Command("%s %d %s %s", mpd.Quoted("addtagid"), songid, mpd.Quoted("album"), pl.Id.String())
|
||||
err = mpdcmd.OK()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
app.mpd.Play(-1)
|
||||
mpdc.Play(-1)
|
||||
|
||||
return
|
||||
}()
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/faiface/beep"
|
||||
"github.com/faiface/beep/effects"
|
||||
|
||||
"dndmusicbot/ffmpeg"
|
||||
discordspeaker "dndmusicbot/speaker"
|
||||
)
|
||||
|
||||
var (
|
||||
pl_volume *effects.Volume
|
||||
amb_volume *effects.Volume
|
||||
amb_mixer beep.Mixer
|
||||
amb_curr Ambiance
|
||||
)
|
||||
|
||||
func init() {
|
||||
log.Println("queue.go loading..")
|
||||
|
||||
amb_mixer = beep.Mixer{}
|
||||
|
||||
amb_volume = &effects.Volume{
|
||||
Streamer: &amb_mixer,
|
||||
Base: 2,
|
||||
Volume: 2,
|
||||
Silent: false,
|
||||
}
|
||||
discordspeaker.Play(amb_volume)
|
||||
|
||||
mpdstream, err := NewMPD()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
pl_volume = &effects.Volume{
|
||||
Streamer: mpdstream,
|
||||
Base: 2,
|
||||
Volume: -2,
|
||||
Silent: false,
|
||||
}
|
||||
|
||||
discordspeaker.Play(pl_volume)
|
||||
|
||||
/*
|
||||
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
|
||||
}
|
27
mpd.go
27
mpd.go
|
@ -7,6 +7,7 @@ import (
|
|||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"sync"
|
||||
"syscall"
|
||||
"text/template"
|
||||
"time"
|
||||
|
@ -21,6 +22,14 @@ type MPD struct {
|
|||
f beep.Format
|
||||
}
|
||||
|
||||
var (
|
||||
mpdcf context.CancelFunc
|
||||
mpdw *mpd.Watcher
|
||||
mpdc *mpd.Client
|
||||
mpd_mutex *sync.Mutex
|
||||
mpd_plcf context.CancelFunc
|
||||
)
|
||||
|
||||
func init() {
|
||||
log.Println("mpd.go loading..")
|
||||
|
||||
|
@ -62,7 +71,7 @@ func init() {
|
|||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
app.mpdc = cancel
|
||||
mpdcf = cancel
|
||||
|
||||
cmd := exec.CommandContext(
|
||||
ctx,
|
||||
|
@ -86,20 +95,20 @@ func init() {
|
|||
// wait for mpd to start.
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
app.mpd, err = mpd.Dial("unix", config.GetString("mpd.sock"))
|
||||
mpdc, err = mpd.Dial("unix", config.GetString("mpd.sock"))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
app.mpd.Repeat(true)
|
||||
app.mpd.Random(true)
|
||||
mpdc.Repeat(true)
|
||||
mpdc.Random(true)
|
||||
|
||||
err = app.mpd.EnableOutput(0)
|
||||
err = mpdc.EnableOutput(0)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
app.mpdw, err = mpd.NewWatcher("unix", config.GetString("mpd.sock"), "")
|
||||
mpdw, err = mpd.NewWatcher("unix", config.GetString("mpd.sock"), "")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -107,9 +116,9 @@ func init() {
|
|||
go func() {
|
||||
for {
|
||||
select {
|
||||
case ev := <-app.mpdw.Event:
|
||||
app.events.Emit(events.EventName(ev))
|
||||
case err := <-app.mpdw.Error:
|
||||
case e := <-mpdw.Event:
|
||||
ev.Emit(events.EventName(e))
|
||||
case err := <-mpdw.Error:
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
|
203
queue.go
203
queue.go
|
@ -1,203 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/faiface/beep"
|
||||
"github.com/faiface/beep/effects"
|
||||
"github.com/kataras/go-events"
|
||||
|
||||
"dndmusicbot/ffmpeg"
|
||||
discordspeaker "dndmusicbot/speaker"
|
||||
)
|
||||
|
||||
var pl_volume *effects.Volume
|
||||
var amb_volume *effects.Volume
|
||||
|
||||
func init() {
|
||||
log.Println("queue.go loading..")
|
||||
|
||||
app.ambiance = beep.Mixer{}
|
||||
|
||||
amb_volume = &effects.Volume{
|
||||
Streamer: &app.ambiance,
|
||||
Base: 2,
|
||||
Volume: 2,
|
||||
Silent: false,
|
||||
}
|
||||
discordspeaker.Play(amb_volume)
|
||||
|
||||
mpdstream, err := NewMPD()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
pl_volume = &effects.Volume{
|
||||
Streamer: mpdstream,
|
||||
Base: 2,
|
||||
Volume: -2,
|
||||
Silent: false,
|
||||
}
|
||||
|
||||
discordspeaker.Play(pl_volume)
|
||||
|
||||
/*
|
||||
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())
|
||||
}
|
36
routes.go
36
routes.go
|
@ -18,16 +18,18 @@ var upgrader = websocket.Upgrader{
|
|||
WriteBufferSize: 1024,
|
||||
}
|
||||
|
||||
var router *httprouter.Router
|
||||
|
||||
func init() {
|
||||
app.router = httprouter.New()
|
||||
router = httprouter.New()
|
||||
|
||||
app.router.GET("/", app.Index)
|
||||
app.router.GET("/play/:playlist", app.Play)
|
||||
app.router.GET("/reset", app.Reset)
|
||||
app.router.GET("/public/*js", app.ServeFiles)
|
||||
app.router.GET("/css/*css", app.ServeFiles)
|
||||
router.GET("/", Index)
|
||||
router.GET("/play/:playlist", Play)
|
||||
router.GET("/reset", Reset)
|
||||
router.GET("/public/*js", ServeFiles)
|
||||
router.GET("/css/*css", ServeFiles)
|
||||
|
||||
app.router.HandlerFunc("GET", "/ws", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
router.HandlerFunc("GET", "/ws", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
log.Printf("WS connection from %v\n", r.RemoteAddr)
|
||||
conn, err := upgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
|
@ -42,7 +44,7 @@ func init() {
|
|||
}))
|
||||
|
||||
go func() {
|
||||
log.Fatal(http.ListenAndServe(":8824", app.router))
|
||||
log.Fatal(http.ListenAndServe(":8824", router))
|
||||
}()
|
||||
}
|
||||
|
||||
|
@ -51,7 +53,7 @@ type IndexData struct {
|
|||
Ambiance []Ambiance
|
||||
}
|
||||
|
||||
func (app App) ServeFiles(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
func ServeFiles(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
filePath := filepath.Join(".", r.URL.Path)
|
||||
|
||||
file, err := os.Open(filePath)
|
||||
|
@ -73,8 +75,8 @@ func (app App) ServeFiles(w http.ResponseWriter, r *http.Request, _ httprouter.P
|
|||
http.ServeContent(w, r, filename, t, file)
|
||||
}
|
||||
|
||||
func (app App) Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
playlists, err := app.GetPlaylists()
|
||||
func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
playlists, err := GetPlaylists()
|
||||
if err != nil {
|
||||
http.Error(w, "Unable to get playlists. "+err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
@ -94,11 +96,11 @@ func (app App) Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params
|
|||
}
|
||||
}
|
||||
|
||||
func (app *App) Play(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
||||
func Play(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
||||
plname := p.ByName("playlist")
|
||||
|
||||
if plname == "reset" {
|
||||
app.events.Emit("stop", nil)
|
||||
ev.Emit("stop", nil)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -107,14 +109,14 @@ func (app *App) Play(w http.ResponseWriter, r *http.Request, p httprouter.Params
|
|||
http.Error(w, "Unable to parse uuid. "+err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
app.events.Emit("new_playlist", plid)
|
||||
ev.Emit("new_playlist", plid)
|
||||
}
|
||||
|
||||
func (app *App) Add(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
func Add(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
r.ParseForm()
|
||||
|
||||
}
|
||||
|
||||
func (app *App) Reset(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
app.events.Emit("stop", nil)
|
||||
func Reset(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
ev.Emit("stop", nil)
|
||||
}
|
||||
|
|
8
ws.go
8
ws.go
|
@ -64,7 +64,7 @@ func handleWS(c *websocket.Conn) error {
|
|||
return nil
|
||||
})
|
||||
|
||||
msg := app.songInfoEvent("song_info")
|
||||
msg := songInfoEvent("song_info")
|
||||
|
||||
vol := make(map[string]interface{})
|
||||
volout := make(map[string]float64)
|
||||
|
@ -77,11 +77,11 @@ func handleWS(c *websocket.Conn) error {
|
|||
c.WriteJSON(msg)
|
||||
c.WriteJSON(vol)
|
||||
|
||||
if app.ambiance.Len() > 0 {
|
||||
if amb_mixer.Len() > 0 {
|
||||
msg := make(map[string]interface{})
|
||||
out := make(map[string]interface{})
|
||||
msg["event"] = "ambiance_play"
|
||||
out["id"] = app.curamb.Id
|
||||
out["id"] = amb_curr.Id
|
||||
msg["payload"] = out
|
||||
c.WriteJSON(msg)
|
||||
} else {
|
||||
|
@ -97,6 +97,6 @@ func handleWS(c *websocket.Conn) error {
|
|||
return err
|
||||
}
|
||||
|
||||
app.events.Emit(events.EventName(msg.Event), msg.Payload)
|
||||
ev.Emit(events.EventName(msg.Event), msg.Payload)
|
||||
}
|
||||
}
|
||||
|
|
48
youtube.go
48
youtube.go
|
@ -9,7 +9,6 @@ import (
|
|||
"errors"
|
||||
"io"
|
||||
"log"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
mrand "math/rand"
|
||||
|
@ -19,6 +18,8 @@ import (
|
|||
"google.golang.org/api/youtube/v3"
|
||||
)
|
||||
|
||||
var yt_svc *youtube.Service
|
||||
|
||||
func init() {
|
||||
log.Println("youtube.go loading..")
|
||||
|
||||
|
@ -26,7 +27,7 @@ func init() {
|
|||
|
||||
apikey := config.GetString("youtube.apikey")
|
||||
|
||||
app.youtube, err = youtube.NewService(context.Background(), option.WithAPIKey(apikey))
|
||||
yt_svc, err = youtube.NewService(context.Background(), option.WithAPIKey(apikey))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -46,39 +47,6 @@ func ShufflePlaylist(list []string) ([]string, error) {
|
|||
return list, nil
|
||||
}
|
||||
|
||||
func (app *App) GetSong(list []string) string {
|
||||
return list[app.plidx]
|
||||
}
|
||||
|
||||
func (app *App) GetNextSong(list []string) string {
|
||||
app.plidx++
|
||||
if app.plidx >= len(app.active) {
|
||||
app.plidx = 0
|
||||
}
|
||||
return list[app.plidx]
|
||||
}
|
||||
|
||||
func (app *App) GetPrevSong(list []string) string {
|
||||
app.plidx--
|
||||
if app.plidx < 0 {
|
||||
app.plidx = len(list)
|
||||
}
|
||||
return list[app.plidx]
|
||||
}
|
||||
|
||||
func GetRandomSong(list []string) string {
|
||||
if !(len(list) > 0) {
|
||||
return ""
|
||||
}
|
||||
|
||||
idx, err := rand.Int(rand.Reader, big.NewInt(int64(len(list)-1)))
|
||||
if err != nil {
|
||||
log.Println("Failed to get random int, ", err)
|
||||
return ""
|
||||
}
|
||||
return list[idx.Int64()]
|
||||
}
|
||||
|
||||
type VideoInfo struct {
|
||||
Title string
|
||||
Channel string
|
||||
|
@ -86,9 +54,9 @@ type VideoInfo struct {
|
|||
Uri string
|
||||
}
|
||||
|
||||
func (app App) Video(vid string) (out VideoInfo, err error) {
|
||||
_, r, err := app.cache.GetOrCreate(vid+".videoinfo", func() (io.ReadCloser, error) {
|
||||
call := app.youtube.Videos.List([]string{"snippet", "contentDetails"})
|
||||
func YTVideo(vid string) (out VideoInfo, err error) {
|
||||
_, r, err := cache.GetOrCreate(vid+".videoinfo", func() (io.ReadCloser, error) {
|
||||
call := yt_svc.Videos.List([]string{"snippet", "contentDetails"})
|
||||
call.MaxResults(1)
|
||||
call.Id(vid)
|
||||
resp, err := call.Do()
|
||||
|
@ -128,8 +96,8 @@ func (app App) Video(vid string) (out VideoInfo, err error) {
|
|||
return out, nil
|
||||
}
|
||||
|
||||
func (app App) Playlist(playlist string) ([]string, error) {
|
||||
call := app.youtube.PlaylistItems.List([]string{"contentDetails"})
|
||||
func YTPlaylist(playlist string) ([]string, error) {
|
||||
call := yt_svc.PlaylistItems.List([]string{"contentDetails"})
|
||||
pageToken := ""
|
||||
call = call.MaxResults(50)
|
||||
call = call.PlaylistId(playlist)
|
||||
|
|
Loading…
Reference in New Issue