src/music/queue.go (view raw)
1package music
2
3import (
4 "os"
5
6 "github.com/birabittoh/disgord/src/mylog"
7 "github.com/bwmarrin/discordgo"
8 "github.com/kkdai/youtube/v2"
9)
10
11var logger = mylog.NewLogger(os.Stdin, "music", mylog.DEBUG)
12
13type Queue struct {
14 nowPlaying *youtube.Video
15 items []*youtube.Video
16 audioStream *Audio
17 vc *discordgo.VoiceConnection
18}
19
20// queues stores all guild queues
21var queues = map[string]*Queue{}
22
23// GetOrCreateQueue fetches or creates a new queue for the guild
24func GetOrCreateQueue(vc *discordgo.VoiceConnection) (q *Queue) {
25 q, ok := queues[vc.GuildID]
26 if !ok {
27 q = &Queue{vc: vc}
28 queues[vc.GuildID] = q
29 return
30 }
31
32 if !q.vc.Ready {
33 q.vc = vc
34 }
35 return
36}
37
38// GetQueue returns either nil or the queue for the requested guild
39func GetQueue(guildID string) *Queue {
40 q, ok := queues[guildID]
41 if ok {
42 return q
43 }
44 return nil
45}
46
47// AddVideo adds a new video to the queue
48func (q *Queue) AddVideo(video *youtube.Video) {
49 q.items = append(q.items, video)
50 if q.nowPlaying == nil {
51 q.PlayNext()
52 }
53}
54
55// AddVideos adds a list of videos to the queue
56func (q *Queue) AddVideos(videos []*youtube.Video) {
57 q.items = append(q.items, videos...)
58 if q.nowPlaying == nil {
59 err := q.PlayNext()
60 if err != nil {
61 logger.Error(err)
62 }
63 }
64}
65
66// PlayNext starts playing the next video in the queue
67func (q *Queue) PlayNext() (err error) {
68 if q.audioStream != nil {
69 q.audioStream.Stop()
70 }
71
72 if len(q.items) == 0 {
73 q.nowPlaying = nil
74 return q.vc.Disconnect()
75 }
76
77 q.nowPlaying = q.items[0]
78 q.items = q.items[1:]
79
80 format := getFormat(*q.nowPlaying)
81 if format == nil {
82 logger.Debug("no formats with audio channels available for video " + q.nowPlaying.ID)
83 return q.PlayNext()
84 }
85
86 q.audioStream, err = NewAudio(format.URL, q.vc)
87 if err != nil {
88 return
89 }
90
91 q.audioStream.Monitor(func() { q.PlayNext() })
92 return
93}
94
95// Stop stops the player and clears the queue
96func (q *Queue) Stop() error {
97 q.Clear()
98 q.nowPlaying = nil
99
100 if q.audioStream != nil {
101 q.audioStream.Stop()
102 }
103
104 if q.vc != nil {
105 return q.vc.Disconnect()
106 }
107
108 return nil
109}
110
111// Pause pauses the player
112func (q *Queue) Pause() {
113 q.audioStream.Pause()
114}
115
116// Resume resumes the player
117func (q *Queue) Resume() {
118 q.audioStream.Resume()
119}
120
121// Clear clears the video queue
122func (q *Queue) Clear() {
123 q.items = []*youtube.Video{}
124}
125
126// Videos returns all videos in the queue including the now playing one
127func (q *Queue) Videos() []*youtube.Video {
128 if q.nowPlaying != nil {
129 return append([]*youtube.Video{q.nowPlaying}, q.items...)
130 }
131 return q.items
132}
133
134func (q *Queue) VoiceChannelID() string {
135 return q.vc.ChannelID
136}
137
138func (q *Queue) AudioStream() *Audio {
139 return q.audioStream
140}
141
142func (q *Queue) VoiceConnection() *discordgo.VoiceConnection {
143 return q.vc
144}
145
146func (q *Queue) NowPlaying() *youtube.Video {
147 return q.nowPlaying
148}