package gavalink import ( "encoding/json" "io" "net/http" "os" "time" ) const ( // TrackLoaded is a Tracks Type for a succesful single track load TrackLoaded = "TRACK_LOADED" // PlaylistLoaded is a Tracks Type for a succseful playlist load PlaylistLoaded = "PLAYLIST_LOADED" // SearchResult is a Tracks Type for a search containing many tracks SearchResult = "SEARCH_RESULT" // NoMatches is a Tracks Type for a query yielding no matches NoMatches = "NO_MATCHES" // LoadFailed is a Tracks Type for an internal Lavalink error LoadFailed = "LOAD_FAILED" ) // Tracks contains data for a Lavalink Tracks response type Tracks struct { // Type contains the type of response // // This will be one of TrackLoaded, PlaylistLoaded, SearchResult, // NoMatches, or LoadFailed Type string `json:"loadType"` PlaylistInfo *PlaylistInfo `json:"playlistInfo"` Tracks []*Track `json:"tracks"` } // PlaylistInfo contains information about a loaded playlist type PlaylistInfo struct { // Name is the friendly of the playlist Name string `json:"name"` // SelectedTrack is the index of the track that loaded the playlist, // if one is present. SelectedTrack int `json:"selectedTrack"` } // Track contains information about a loaded track type Track struct { // Data contains the base64 encoded Lavaplayer track Data string `json:"track"` Info *TrackInfo `json:"info"` } // TrackInfo contains more data about a loaded track type TrackInfo struct { Identifier string `json:"identifier"` Title string `json:"title"` Author string `json:"author"` URI string `json:"uri"` Seekable bool `json:"isSeekable"` Stream bool `json:"isStream"` Length time.Duration `json:"length"` Position int `json:"position"` } func (t *TrackInfo) MarshalJSON() ([]byte, error) { type Alias TrackInfo return json.Marshal(&struct { Length int64 `json:"length"` *Alias }{ Length: int64(t.Length / time.Millisecond), Alias: (*Alias)(t), }) } func (t *TrackInfo) UnmarshalJSON(data []byte) error { type Alias TrackInfo aux := &struct { Length int64 `json:"length"` *Alias }{ Alias: (*Alias)(t), } if err := json.Unmarshal(data, &aux); err != nil { return err } t.Length = time.Duration(aux.Length) * time.Millisecond return nil } const ( opVoiceUpdate = "voiceUpdate" opUserJoin = "userJoin" opUserLeave = "userLeave" opUserListen = "userListen" opPlay = "play" opStop = "stop" opPause = "pause" opSeek = "seek" opVolume = "volume" opDestroy = "destroy" opPlayerUpdate = "playerUpdate" opEvent = "event" opStats = "stats" eventTrackStart = "TrackStartEvent" eventTrackEnd = "TrackEndEvent" eventTrackException = "TrackExceptionEvent" eventTrackStuck = "TrackStuckEvent" eventVoiceProcessed = "VoiceProcessedEvent" ) // Exception is a message from the Lavalink server type Exception struct { Message string Severity string Cause string } // VoiceServerUpdate is a raw Discord VOICE_SERVER_UPDATE event type VoiceServerUpdate struct { GuildID string `json:"guild_id"` Endpoint string `json:"endpoint"` Token string `json:"token"` } // VoiceProcessingData is an event containing methods to easily download captured voice data type VoiceProcessingData struct { io.ReadCloser node *Node UserID string URL string File string res *http.Response } func (v *VoiceProcessingData) open() error { req, err := http.NewRequest(http.MethodGet, v.URL, nil) req.Header.Set("Authorization", v.node.config.Password) res, err := v.node.client.Do(req) if err != nil { return err } v.res = res return nil } func (v *VoiceProcessingData) Close() error { if v.res != nil { return v.res.Body.Close() } return nil } func (v *VoiceProcessingData) Read(buf []byte) (n int, err error) { if v.res == nil { err = v.open() if err != nil { return } } n, err = v.res.Body.Read(buf) return } func (v *VoiceProcessingData) SaveTo(file string) error { f, err := os.Create(file) if err != nil { return err } defer f.Close() if v.res == nil { err = v.open() if err != nil { return err } } defer v.res.Body.Close() _, err = io.Copy(f, v.res.Body) return err }