meta: add editorconfig
This commit is contained in:
parent
c472a61322
commit
d3b8f06f15
|
@ -0,0 +1,11 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
charset = utf-8
|
||||||
|
|
||||||
|
[*.go]
|
||||||
|
indent_style = tab
|
||||||
|
indent_size = 4
|
54
event.go
54
event.go
|
@ -1,27 +1,27 @@
|
||||||
package gavalink
|
package gavalink
|
||||||
|
|
||||||
// EventHandler defines events that Lavalink may send to a player
|
// EventHandler defines events that Lavalink may send to a player
|
||||||
type EventHandler interface {
|
type EventHandler interface {
|
||||||
OnTrackEnd(player *Player, track string, reason string) error
|
OnTrackEnd(player *Player, track string, reason string) error
|
||||||
OnTrackException(player *Player, track string, reason string) error
|
OnTrackException(player *Player, track string, reason string) error
|
||||||
OnTrackStuck(player *Player, track string, threshold int) error
|
OnTrackStuck(player *Player, track string, threshold int) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// DummyEventHandler provides an empty event handler for users who
|
// DummyEventHandler provides an empty event handler for users who
|
||||||
// wish to drop events outright. This is not recommended.
|
// wish to drop events outright. This is not recommended.
|
||||||
type DummyEventHandler struct{}
|
type DummyEventHandler struct{}
|
||||||
|
|
||||||
// OnTrackEnd is raised when a track ends
|
// OnTrackEnd is raised when a track ends
|
||||||
func (d DummyEventHandler) OnTrackEnd(player *Player, track string, reason string) error {
|
func (d DummyEventHandler) OnTrackEnd(player *Player, track string, reason string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnTrackException is raised when a track throws an exception
|
// OnTrackException is raised when a track throws an exception
|
||||||
func (d DummyEventHandler) OnTrackException(player *Player, track string, reason string) error {
|
func (d DummyEventHandler) OnTrackException(player *Player, track string, reason string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnTrackStuck is raised when a track gets stuck
|
// OnTrackStuck is raised when a track gets stuck
|
||||||
func (d DummyEventHandler) OnTrackStuck(player *Player, track string, threshold int) error {
|
func (d DummyEventHandler) OnTrackStuck(player *Player, track string, threshold int) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
220
lavalink.go
220
lavalink.go
|
@ -1,110 +1,110 @@
|
||||||
package gavalink
|
package gavalink
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Log sets the log.Logger gavalink will write to
|
// Log sets the log.Logger gavalink will write to
|
||||||
var Log *log.Logger
|
var Log *log.Logger
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Log = log.New(os.Stdout, "(gavalink) ", 0)
|
Log = log.New(os.Stdout, "(gavalink) ", 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lavalink manages a connection to Lavalink Nodes
|
// Lavalink manages a connection to Lavalink Nodes
|
||||||
type Lavalink struct {
|
type Lavalink struct {
|
||||||
shards string
|
shards string
|
||||||
userID string
|
userID string
|
||||||
|
|
||||||
nodes []Node
|
nodes []Node
|
||||||
players map[string]*Player
|
players map[string]*Player
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errNoNodes = errors.New("No nodes present")
|
errNoNodes = errors.New("No nodes present")
|
||||||
errNodeNotFound = errors.New("Couldn't find that node")
|
errNodeNotFound = errors.New("Couldn't find that node")
|
||||||
errPlayerNotFound = errors.New("Couldn't find a player for that guild")
|
errPlayerNotFound = errors.New("Couldn't find a player for that guild")
|
||||||
errVolumeOutOfRange = errors.New("Volume is out of range, must be within [0, 1000]")
|
errVolumeOutOfRange = errors.New("Volume is out of range, must be within [0, 1000]")
|
||||||
errInvalidVersion = errors.New("This library requires Lavalink >= 3")
|
errInvalidVersion = errors.New("This library requires Lavalink >= 3")
|
||||||
errUnknownPayload = errors.New("Lavalink sent an unknown payload")
|
errUnknownPayload = errors.New("Lavalink sent an unknown payload")
|
||||||
errNilHandler = errors.New("You must provide an event handler. Use gavalink.DummyEventHandler if you wish to ignore events")
|
errNilHandler = errors.New("You must provide an event handler. Use gavalink.DummyEventHandler if you wish to ignore events")
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewLavalink creates a new Lavalink manager
|
// NewLavalink creates a new Lavalink manager
|
||||||
func NewLavalink(shards string, userID string) *Lavalink {
|
func NewLavalink(shards string, userID string) *Lavalink {
|
||||||
return &Lavalink{
|
return &Lavalink{
|
||||||
shards: shards,
|
shards: shards,
|
||||||
userID: userID,
|
userID: userID,
|
||||||
/* nodes: make([]Node, 1),*/
|
/* nodes: make([]Node, 1),*/
|
||||||
players: make(map[string]*Player),
|
players: make(map[string]*Player),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddNodes adds a node to the Lavalink manager
|
// AddNodes adds a node to the Lavalink manager
|
||||||
func (lavalink *Lavalink) AddNodes(nodeConfigs ...NodeConfig) error {
|
func (lavalink *Lavalink) AddNodes(nodeConfigs ...NodeConfig) error {
|
||||||
nodes := make([]Node, len(nodeConfigs))
|
nodes := make([]Node, len(nodeConfigs))
|
||||||
for i, c := range nodeConfigs {
|
for i, c := range nodeConfigs {
|
||||||
n := Node{
|
n := Node{
|
||||||
config: c,
|
config: c,
|
||||||
manager: lavalink,
|
manager: lavalink,
|
||||||
}
|
}
|
||||||
err := n.open()
|
err := n.open()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
nodes[i] = n
|
nodes[i] = n
|
||||||
}
|
}
|
||||||
lavalink.nodes = append(lavalink.nodes, nodes...)
|
lavalink.nodes = append(lavalink.nodes, nodes...)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveNode removes a node from the manager
|
// RemoveNode removes a node from the manager
|
||||||
func (lavalink *Lavalink) removeNode(node *Node) error {
|
func (lavalink *Lavalink) removeNode(node *Node) error {
|
||||||
idx := -1
|
idx := -1
|
||||||
for i, n := range lavalink.nodes {
|
for i, n := range lavalink.nodes {
|
||||||
if n == *node {
|
if n == *node {
|
||||||
idx = i
|
idx = i
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if idx == -1 {
|
if idx == -1 {
|
||||||
return errNodeNotFound
|
return errNodeNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
node.stop()
|
node.stop()
|
||||||
|
|
||||||
// temp var for easier reading
|
// temp var for easier reading
|
||||||
n := lavalink.nodes
|
n := lavalink.nodes
|
||||||
z := len(n) - 1
|
z := len(n) - 1
|
||||||
|
|
||||||
n[idx] = n[z] // swap idx with last
|
n[idx] = n[z] // swap idx with last
|
||||||
n = n[:z]
|
n = n[:z]
|
||||||
|
|
||||||
lavalink.nodes = n
|
lavalink.nodes = n
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// BestNode returns the Node with the lowest latency
|
// BestNode returns the Node with the lowest latency
|
||||||
func (lavalink *Lavalink) BestNode() (*Node, error) {
|
func (lavalink *Lavalink) BestNode() (*Node, error) {
|
||||||
if len(lavalink.nodes) < 1 {
|
if len(lavalink.nodes) < 1 {
|
||||||
return nil, errNoNodes
|
return nil, errNoNodes
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.SliceStable(lavalink.nodes, func(i, j int) bool {
|
sort.SliceStable(lavalink.nodes, func(i, j int) bool {
|
||||||
return lavalink.nodes[i].load < lavalink.nodes[j].load
|
return lavalink.nodes[i].load < lavalink.nodes[j].load
|
||||||
})
|
})
|
||||||
|
|
||||||
return &lavalink.nodes[0], nil
|
return &lavalink.nodes[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPlayer gets a player for a guild
|
// GetPlayer gets a player for a guild
|
||||||
func (lavalink *Lavalink) GetPlayer(guild string) (*Player, error) {
|
func (lavalink *Lavalink) GetPlayer(guild string) (*Player, error) {
|
||||||
p, ok := lavalink.players[guild]
|
p, ok := lavalink.players[guild]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errPlayerNotFound
|
return nil, errPlayerNotFound
|
||||||
}
|
}
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
394
node.go
394
node.go
|
@ -1,197 +1,197 @@
|
||||||
package gavalink
|
package gavalink
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NodeConfig configures a Lavalink Node
|
// NodeConfig configures a Lavalink Node
|
||||||
type NodeConfig struct {
|
type NodeConfig struct {
|
||||||
// REST is the host where Lavalink's REST server runs
|
// REST is the host where Lavalink's REST server runs
|
||||||
//
|
//
|
||||||
// This value is expected without a trailing slash, e.g. like
|
// This value is expected without a trailing slash, e.g. like
|
||||||
// `http://localhost:2333`
|
// `http://localhost:2333`
|
||||||
REST string
|
REST string
|
||||||
// WebSocket is the host where Lavalink's WebSocket server runs
|
// WebSocket is the host where Lavalink's WebSocket server runs
|
||||||
//
|
//
|
||||||
// This value is expected without a trailing slash, e.g. like
|
// This value is expected without a trailing slash, e.g. like
|
||||||
// `http://localhost:8012`
|
// `http://localhost:8012`
|
||||||
WebSocket string
|
WebSocket string
|
||||||
// Password is the expected Authorization header for the Node
|
// Password is the expected Authorization header for the Node
|
||||||
Password string
|
Password string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Node wraps a Lavalink Node
|
// Node wraps a Lavalink Node
|
||||||
type Node struct {
|
type Node struct {
|
||||||
config NodeConfig
|
config NodeConfig
|
||||||
load float32
|
load float32
|
||||||
manager *Lavalink
|
manager *Lavalink
|
||||||
wsConn *websocket.Conn
|
wsConn *websocket.Conn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *Node) open() error {
|
func (node *Node) open() error {
|
||||||
header := http.Header{}
|
header := http.Header{}
|
||||||
header.Set("Authorization", node.config.Password)
|
header.Set("Authorization", node.config.Password)
|
||||||
header.Set("Num-Shards", node.manager.shards)
|
header.Set("Num-Shards", node.manager.shards)
|
||||||
header.Set("User-Id", node.manager.userID)
|
header.Set("User-Id", node.manager.userID)
|
||||||
|
|
||||||
ws, resp, err := websocket.DefaultDialer.Dial(node.config.WebSocket, header)
|
ws, resp, err := websocket.DefaultDialer.Dial(node.config.WebSocket, header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
vstr := resp.Header.Get("Lavalink-Major-Version")
|
vstr := resp.Header.Get("Lavalink-Major-Version")
|
||||||
v, err := strconv.Atoi(vstr)
|
v, err := strconv.Atoi(vstr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if v < 3 {
|
if v < 3 {
|
||||||
return errInvalidVersion
|
return errInvalidVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
node.wsConn = ws
|
node.wsConn = ws
|
||||||
go node.listen()
|
go node.listen()
|
||||||
|
|
||||||
Log.Println("node", node.config.WebSocket, "opened")
|
Log.Println("node", node.config.WebSocket, "opened")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *Node) stop() {
|
func (node *Node) stop() {
|
||||||
// someone already stopped this
|
// someone already stopped this
|
||||||
if node.wsConn == nil {
|
if node.wsConn == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_ = node.wsConn.Close()
|
_ = node.wsConn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *Node) listen() {
|
func (node *Node) listen() {
|
||||||
for {
|
for {
|
||||||
msgType, msg, err := node.wsConn.ReadMessage()
|
msgType, msg, err := node.wsConn.ReadMessage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Log.Println(err)
|
Log.Println(err)
|
||||||
// try to reconnect
|
// try to reconnect
|
||||||
oerr := node.open()
|
oerr := node.open()
|
||||||
if oerr != nil {
|
if oerr != nil {
|
||||||
Log.Println("node", node.config.WebSocket, "failed and could not reconnect, destroying.", err, oerr)
|
Log.Println("node", node.config.WebSocket, "failed and could not reconnect, destroying.", err, oerr)
|
||||||
node.manager.removeNode(node)
|
node.manager.removeNode(node)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
Log.Println("node", node.config.WebSocket, "reconnected")
|
Log.Println("node", node.config.WebSocket, "reconnected")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = node.onEvent(msgType, msg)
|
err = node.onEvent(msgType, msg)
|
||||||
// TODO: better error handling?
|
// TODO: better error handling?
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Log.Println(err)
|
Log.Println(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *Node) onEvent(msgType int, msg []byte) error {
|
func (node *Node) onEvent(msgType int, msg []byte) error {
|
||||||
if msgType != websocket.TextMessage {
|
if msgType != websocket.TextMessage {
|
||||||
return errUnknownPayload
|
return errUnknownPayload
|
||||||
}
|
}
|
||||||
|
|
||||||
m := message{}
|
m := message{}
|
||||||
err := json.Unmarshal(msg, &m)
|
err := json.Unmarshal(msg, &m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch m.Op {
|
switch m.Op {
|
||||||
case opPlayerUpdate:
|
case opPlayerUpdate:
|
||||||
player, err := node.manager.GetPlayer(m.GuildID)
|
player, err := node.manager.GetPlayer(m.GuildID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
player.time = m.State.Time
|
player.time = m.State.Time
|
||||||
player.position = m.State.Position
|
player.position = m.State.Position
|
||||||
case opEvent:
|
case opEvent:
|
||||||
player, err := node.manager.GetPlayer(m.GuildID)
|
player, err := node.manager.GetPlayer(m.GuildID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch m.Type {
|
switch m.Type {
|
||||||
case eventTrackEnd:
|
case eventTrackEnd:
|
||||||
err = player.handler.OnTrackEnd(player, m.Track, m.Reason)
|
err = player.handler.OnTrackEnd(player, m.Track, m.Reason)
|
||||||
case eventTrackException:
|
case eventTrackException:
|
||||||
err = player.handler.OnTrackException(player, m.Track, m.Reason)
|
err = player.handler.OnTrackException(player, m.Track, m.Reason)
|
||||||
case eventTrackStuck:
|
case eventTrackStuck:
|
||||||
err = player.handler.OnTrackStuck(player, m.Track, m.ThresholdMs)
|
err = player.handler.OnTrackStuck(player, m.Track, m.ThresholdMs)
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
case opStats:
|
case opStats:
|
||||||
node.load = m.StatCPU.Load
|
node.load = m.StatCPU.Load
|
||||||
Log.Println("dbg-node", node.config.WebSocket, "load", node.load)
|
Log.Println("dbg-node", node.config.WebSocket, "load", node.load)
|
||||||
default:
|
default:
|
||||||
return errUnknownPayload
|
return errUnknownPayload
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatePlayer creates an audio player on this node
|
// CreatePlayer creates an audio player on this node
|
||||||
func (node *Node) CreatePlayer(guildID string, sessionID string, event VoiceServerUpdate, handler EventHandler) (*Player, error) {
|
func (node *Node) CreatePlayer(guildID string, sessionID string, event VoiceServerUpdate, handler EventHandler) (*Player, error) {
|
||||||
msg := message{
|
msg := message{
|
||||||
Op: opVoiceUpdate,
|
Op: opVoiceUpdate,
|
||||||
GuildID: guildID,
|
GuildID: guildID,
|
||||||
SessionID: sessionID,
|
SessionID: sessionID,
|
||||||
Event: &event,
|
Event: &event,
|
||||||
}
|
}
|
||||||
data, err := json.Marshal(msg)
|
data, err := json.Marshal(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = node.wsConn.WriteMessage(websocket.TextMessage, data)
|
err = node.wsConn.WriteMessage(websocket.TextMessage, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
player := &Player{
|
player := &Player{
|
||||||
guildID: guildID,
|
guildID: guildID,
|
||||||
manager: node.manager,
|
manager: node.manager,
|
||||||
node: node,
|
node: node,
|
||||||
handler: handler,
|
handler: handler,
|
||||||
}
|
}
|
||||||
node.manager.players[guildID] = player
|
node.manager.players[guildID] = player
|
||||||
return player, nil
|
return player, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadTracks queries lavalink to return a Tracks object
|
// LoadTracks queries lavalink to return a Tracks object
|
||||||
//
|
//
|
||||||
// query should be a valid Lavaplayer query, including but not limited to:
|
// query should be a valid Lavaplayer query, including but not limited to:
|
||||||
// - A direct media URI
|
// - A direct media URI
|
||||||
// - A direct Youtube /watch URI
|
// - A direct Youtube /watch URI
|
||||||
// - A search query, prefixed with ytsearch: or scsearch:
|
// - A search query, prefixed with ytsearch: or scsearch:
|
||||||
//
|
//
|
||||||
// See the Lavaplayer Source Code for all valid options.
|
// See the Lavaplayer Source Code for all valid options.
|
||||||
func (node *Node) LoadTracks(query string) (*Tracks, error) {
|
func (node *Node) LoadTracks(query string) (*Tracks, error) {
|
||||||
url := fmt.Sprintf("%s/loadtracks?identifier=%s", node.config.REST, query)
|
url := fmt.Sprintf("%s/loadtracks?identifier=%s", node.config.REST, query)
|
||||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
req.Header.Set("Authorization", node.config.Password)
|
req.Header.Set("Authorization", node.config.Password)
|
||||||
|
|
||||||
resp, err := http.DefaultClient.Do(req)
|
resp, err := http.DefaultClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
data, err := ioutil.ReadAll(resp.Body)
|
data, err := ioutil.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
tracks := new(Tracks)
|
tracks := new(Tracks)
|
||||||
err = json.Unmarshal(data, &tracks)
|
err = json.Unmarshal(data, &tracks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return tracks, nil
|
return tracks, nil
|
||||||
}
|
}
|
||||||
|
|
326
player.go
326
player.go
|
@ -1,163 +1,163 @@
|
||||||
package gavalink
|
package gavalink
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Player is a Lavalink player
|
// Player is a Lavalink player
|
||||||
type Player struct {
|
type Player struct {
|
||||||
guildID string
|
guildID string
|
||||||
time int
|
time int
|
||||||
position int
|
position int
|
||||||
paused bool
|
paused bool
|
||||||
manager *Lavalink
|
manager *Lavalink
|
||||||
node *Node
|
node *Node
|
||||||
handler EventHandler
|
handler EventHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
// Play will play the given track completely
|
// Play will play the given track completely
|
||||||
func (player *Player) Play(track string) error {
|
func (player *Player) Play(track string) error {
|
||||||
return player.PlayAt(track, 0, 0)
|
return player.PlayAt(track, 0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PlayAt will play the given track at the specified start and end times
|
// PlayAt will play the given track at the specified start and end times
|
||||||
//
|
//
|
||||||
// Setting a time to 0 will omit it.
|
// Setting a time to 0 will omit it.
|
||||||
func (player *Player) PlayAt(track string, startTime int, endTime int) error {
|
func (player *Player) PlayAt(track string, startTime int, endTime int) error {
|
||||||
start := strconv.Itoa(startTime)
|
start := strconv.Itoa(startTime)
|
||||||
end := strconv.Itoa(endTime)
|
end := strconv.Itoa(endTime)
|
||||||
|
|
||||||
msg := message{
|
msg := message{
|
||||||
Op: opPlay,
|
Op: opPlay,
|
||||||
GuildID: player.guildID,
|
GuildID: player.guildID,
|
||||||
Track: track,
|
Track: track,
|
||||||
StartTime: start,
|
StartTime: start,
|
||||||
EndTime: end,
|
EndTime: end,
|
||||||
}
|
}
|
||||||
data, err := json.Marshal(msg)
|
data, err := json.Marshal(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = player.node.wsConn.WriteMessage(websocket.TextMessage, data)
|
err = player.node.wsConn.WriteMessage(websocket.TextMessage, data)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop will stop the currently playing track
|
// Stop will stop the currently playing track
|
||||||
func (player *Player) Stop() error {
|
func (player *Player) Stop() error {
|
||||||
msg := message{
|
msg := message{
|
||||||
Op: opStop,
|
Op: opStop,
|
||||||
GuildID: player.guildID,
|
GuildID: player.guildID,
|
||||||
}
|
}
|
||||||
data, err := json.Marshal(msg)
|
data, err := json.Marshal(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = player.node.wsConn.WriteMessage(websocket.TextMessage, data)
|
err = player.node.wsConn.WriteMessage(websocket.TextMessage, data)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pause will pause or resume the player, depending on the pause parameter
|
// Pause will pause or resume the player, depending on the pause parameter
|
||||||
func (player *Player) Pause(pause bool) error {
|
func (player *Player) Pause(pause bool) error {
|
||||||
player.paused = pause
|
player.paused = pause
|
||||||
msg := message{
|
msg := message{
|
||||||
Op: opPause,
|
Op: opPause,
|
||||||
GuildID: player.guildID,
|
GuildID: player.guildID,
|
||||||
Pause: &pause,
|
Pause: &pause,
|
||||||
}
|
}
|
||||||
data, err := json.Marshal(msg)
|
data, err := json.Marshal(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = player.node.wsConn.WriteMessage(websocket.TextMessage, data)
|
err = player.node.wsConn.WriteMessage(websocket.TextMessage, data)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Paused returns whether or not the player is currently paused
|
// Paused returns whether or not the player is currently paused
|
||||||
func (player *Player) Paused() bool {
|
func (player *Player) Paused() bool {
|
||||||
return player.paused
|
return player.paused
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seek will seek the player to the speicifed position, in millis
|
// Seek will seek the player to the speicifed position, in millis
|
||||||
func (player *Player) Seek(position int) error {
|
func (player *Player) Seek(position int) error {
|
||||||
msg := message{
|
msg := message{
|
||||||
Op: opSeek,
|
Op: opSeek,
|
||||||
GuildID: player.guildID,
|
GuildID: player.guildID,
|
||||||
Position: &position,
|
Position: &position,
|
||||||
}
|
}
|
||||||
data, err := json.Marshal(msg)
|
data, err := json.Marshal(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = player.node.wsConn.WriteMessage(websocket.TextMessage, data)
|
err = player.node.wsConn.WriteMessage(websocket.TextMessage, data)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Position returns the player's position, as reported by Lavalink
|
// Position returns the player's position, as reported by Lavalink
|
||||||
func (player *Player) Position() int {
|
func (player *Player) Position() int {
|
||||||
return player.position
|
return player.position
|
||||||
}
|
}
|
||||||
|
|
||||||
// Volume will set the player's volume to the specified value
|
// Volume will set the player's volume to the specified value
|
||||||
//
|
//
|
||||||
// volume must be within [0, 1000]
|
// volume must be within [0, 1000]
|
||||||
func (player *Player) Volume(volume int) error {
|
func (player *Player) Volume(volume int) error {
|
||||||
if volume < 0 || volume > 1000 {
|
if volume < 0 || volume > 1000 {
|
||||||
return errVolumeOutOfRange
|
return errVolumeOutOfRange
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := message{
|
msg := message{
|
||||||
Op: opVolume,
|
Op: opVolume,
|
||||||
GuildID: player.guildID,
|
GuildID: player.guildID,
|
||||||
Volume: &volume,
|
Volume: &volume,
|
||||||
}
|
}
|
||||||
data, err := json.Marshal(msg)
|
data, err := json.Marshal(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = player.node.wsConn.WriteMessage(websocket.TextMessage, data)
|
err = player.node.wsConn.WriteMessage(websocket.TextMessage, data)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Forward will forward a new VOICE_SERVER_UPDATE to a Lavalink node for
|
// Forward will forward a new VOICE_SERVER_UPDATE to a Lavalink node for
|
||||||
// this player.
|
// this player.
|
||||||
//
|
//
|
||||||
// This should always be used if a VOICE_SERVER_UPDATE is received for
|
// This should always be used if a VOICE_SERVER_UPDATE is received for
|
||||||
// a guild which already has a player.
|
// a guild which already has a player.
|
||||||
//
|
//
|
||||||
// To move a player to a new Node, first player.Destroy() it, and then
|
// To move a player to a new Node, first player.Destroy() it, and then
|
||||||
// create a new player on the new node.
|
// create a new player on the new node.
|
||||||
func (player *Player) Forward(sessionID string, event VoiceServerUpdate) error {
|
func (player *Player) Forward(sessionID string, event VoiceServerUpdate) error {
|
||||||
msg := message{
|
msg := message{
|
||||||
Op: opVoiceUpdate,
|
Op: opVoiceUpdate,
|
||||||
GuildID: player.guildID,
|
GuildID: player.guildID,
|
||||||
SessionID: sessionID,
|
SessionID: sessionID,
|
||||||
Event: &event,
|
Event: &event,
|
||||||
}
|
}
|
||||||
data, err := json.Marshal(msg)
|
data, err := json.Marshal(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = player.node.wsConn.WriteMessage(websocket.TextMessage, data)
|
err = player.node.wsConn.WriteMessage(websocket.TextMessage, data)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroy will destroy this player
|
// Destroy will destroy this player
|
||||||
func (player *Player) Destroy() error {
|
func (player *Player) Destroy() error {
|
||||||
msg := message{
|
msg := message{
|
||||||
Op: opDestroy,
|
Op: opDestroy,
|
||||||
GuildID: player.guildID,
|
GuildID: player.guildID,
|
||||||
}
|
}
|
||||||
data, err := json.Marshal(msg)
|
data, err := json.Marshal(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = player.node.wsConn.WriteMessage(websocket.TextMessage, data)
|
err = player.node.wsConn.WriteMessage(websocket.TextMessage, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
player.manager.players[player.guildID] = nil
|
player.manager.players[player.guildID] = nil
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue