/
queue.go
196 lines (164 loc) · 4.16 KB
/
queue.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
package player
import (
"fmt"
"math/rand"
"strconv"
"sync"
"time"
"github.com/bwmarrin/discordgo"
"github.com/hako/durafmt"
"github.com/Depado/fox/tracks"
)
type Queue struct {
sync.RWMutex
tracks tracks.Tracks
state *State
}
func NewQueue(s *State) *Queue {
return &Queue{state: s}
}
// Duration will return the total duration of the active queue.
func (q *Queue) Duration() int {
q.Lock()
defer q.Unlock()
var tot int
for _, t := range q.tracks {
tot += t.Duration()
}
return tot
}
// DurationString will return the total duration of the active queue in human
// readable format.
func (q *Queue) DurationString() string {
return durafmt.Parse(time.Duration(q.Duration()) * time.Millisecond).LimitFirstN(2).String()
}
// Len will return the current number of tracks in queue.
func (q *Queue) Len() int {
q.Lock()
defer q.Unlock()
return len(q.tracks)
}
// Prepend will add tracks to the start of the queue, either right after the
// currently playing track, or right at the start if the player is stopped.
func (q *Queue) Prepend(t ...tracks.Track) {
q.Lock()
defer q.Unlock()
if q.state.Playing && len(q.tracks) != 0 {
tr := append(tracks.Tracks{q.tracks[0]}, t...)
q.tracks = append(tr, q.tracks[1:]...)
} else {
q.tracks = append(t, q.tracks...)
}
}
// Append will append tracks at the end of queue.
func (q *Queue) Append(t ...tracks.Track) {
q.Lock()
defer q.Unlock()
q.tracks = append(q.tracks, t...)
}
// Pop will remove the first track in queue.
func (q *Queue) Pop() {
q.Lock()
defer q.Unlock()
if len(q.tracks) != 0 {
q.tracks = q.tracks[1:]
}
}
// Loop will move the first track at the end of the queue if there is more than
// one track in queue. Otherwise it does nothing, leaving the first track in its
// position to be played once more.
func (q *Queue) Loop() {
q.Lock()
defer q.Unlock()
if len(q.tracks) > 1 {
t := q.tracks[0]
q.tracks = q.tracks[1:]
q.tracks = append(q.tracks, t)
}
}
// Get will return the first track in queue if any. If there is no track in
// queue, nil will be returned.
func (q *Queue) Get() tracks.Track {
q.Lock()
defer q.Unlock()
if len(q.tracks) != 0 {
return q.tracks[0]
}
return nil
}
// Shuffle will shuffle all the tracks in queue, except the first one if it's
// currently being played.
func (q *Queue) Shuffle() {
q.Lock()
defer q.Unlock()
// Either there is one track or none, do nothing
if len(q.tracks) < 2 {
return
}
// If the first track is currently being played, do not shuffle it
if q.state.Playing {
t := q.tracks[0]
ts := q.tracks[1:]
rand.Shuffle(len(ts), func(i, j int) { ts[i], ts[j] = ts[j], ts[i] })
q.tracks = append(tracks.Tracks{t}, ts...)
} else {
rand.Shuffle(len(q.tracks), func(i, j int) { q.tracks[i], q.tracks[j] = q.tracks[j], q.tracks[i] })
}
}
// Clear will reset the queue, removing all tracks from it except the first one
// if it is currently played.
func (q *Queue) Clear() {
q.Lock()
defer q.Unlock()
if len(q.tracks) == 0 {
return
}
if q.state.Playing {
q.tracks = tracks.Tracks{q.tracks[0]}
} else {
q.tracks = tracks.Tracks{}
}
}
// RemoveN will remove the next n tracks in queue
func (q *Queue) RemoveN(n int) {
q.Lock()
defer q.Unlock()
if n >= len(q.tracks) || (q.state.Playing && n+1 >= len(q.tracks)) {
q.Clear()
return
}
if q.state.Playing {
q.tracks = append(tracks.Tracks{q.tracks[0]}, q.tracks[n+1:]...)
} else {
q.tracks = q.tracks[n:]
}
}
func (q *Queue) GenerateQueueEmbed() *discordgo.MessageEmbed {
q.Lock()
defer q.Unlock()
var body string
var tot int
if len(q.tracks) > 0 {
for i, t := range q.tracks {
if i <= 10 {
body += t.MarkdownLink()
}
tot += t.Duration()
}
if len(q.tracks) > 10 {
body += fmt.Sprintf("\nAnd **%d** other tracks", len(q.tracks)-10)
}
} else {
body = "There is currently no track in queue"
}
e := &discordgo.MessageEmbed{
Title: "Current Queue",
Description: body,
Color: 0xff5500,
Fields: []*discordgo.MessageEmbedField{
{Name: "Tracks", Value: strconv.Itoa(len(q.tracks)), Inline: true},
{Name: "Duration", Value: durafmt.Parse(time.Duration(tot) * time.Millisecond).LimitFirstN(2).String(), Inline: true},
},
}
return e
}