This repository has been archived on 2019-06-23. You can view files and clone it, but cannot push or open issues/pull-requests.
mumbledj/bot/skiptracker.go

145 lines
3.9 KiB
Go

/*
* MumbleDJ
* By Matthieu Grieger
* bot/skiptracker.go
* Copyright (c) 2016 Matthieu Grieger (MIT License)
*/
package bot
import (
"fmt"
"sync"
"github.com/layeh/gumble/gumble"
"github.com/spf13/viper"
)
// SkipTracker keeps track of the list of users who have skipped the current
// track or playlist.
type SkipTracker struct {
TrackSkips []*gumble.User
PlaylistSkips []*gumble.User
trackMutex sync.RWMutex
playlistMutex sync.RWMutex
}
// NewSkipTracker returns an empty SkipTracker.
func NewSkipTracker() *SkipTracker {
return &SkipTracker{
TrackSkips: make([]*gumble.User, 0),
PlaylistSkips: make([]*gumble.User, 0),
}
}
// AddTrackSkip adds a skip to the SkipTracker for the current track.
func (s *SkipTracker) AddTrackSkip(skipper *gumble.User) error {
s.trackMutex.Lock()
for _, user := range s.TrackSkips {
if user.Name == skipper.Name {
s.trackMutex.Unlock()
return fmt.Errorf("%s has already voted to skip the track", skipper.Name)
}
}
s.TrackSkips = append(s.TrackSkips, skipper)
s.trackMutex.Unlock()
s.evaluateTrackSkips()
return nil
}
// AddPlaylistSkip adds a skip to the SkipTracker for the current playlist.
func (s *SkipTracker) AddPlaylistSkip(skipper *gumble.User) error {
s.playlistMutex.Lock()
for _, user := range s.PlaylistSkips {
if user.Name == skipper.Name {
s.playlistMutex.Unlock()
return fmt.Errorf("%s has already voted to skip the playlist", skipper.Name)
}
}
s.PlaylistSkips = append(s.PlaylistSkips, skipper)
s.playlistMutex.Unlock()
s.evaluatePlaylistSkips()
return nil
}
// RemoveTrackSkip removes a skip from the SkipTracker for the current track.
func (s *SkipTracker) RemoveTrackSkip(skipper *gumble.User) error {
s.trackMutex.Lock()
for i, user := range s.TrackSkips {
if user.Name == skipper.Name {
s.TrackSkips = append(s.TrackSkips[:i], s.TrackSkips[i+1:]...)
s.trackMutex.Unlock()
return nil
}
}
s.trackMutex.Unlock()
return fmt.Errorf("%s did not previously vote to skip the track", skipper.Name)
}
// RemovePlaylistSkip removes a skip from the SkipTracker for the current playlist.
func (s *SkipTracker) RemovePlaylistSkip(skipper *gumble.User) error {
s.playlistMutex.Lock()
for i, user := range s.PlaylistSkips {
if user.Name == skipper.Name {
s.PlaylistSkips = append(s.PlaylistSkips[:i], s.PlaylistSkips[i+1:]...)
s.playlistMutex.Unlock()
return nil
}
}
s.playlistMutex.Unlock()
return fmt.Errorf("%s did not previously vote to skip the playlist", skipper.Name)
}
// NumTrackSkips returns the number of users who have skipped the current track.
func (s *SkipTracker) NumTrackSkips() int {
s.trackMutex.RLock()
length := len(s.TrackSkips)
s.trackMutex.RUnlock()
return length
}
// NumPlaylistSkips returns the number of users who have skipped the current playlist.
func (s *SkipTracker) NumPlaylistSkips() int {
s.playlistMutex.RLock()
length := len(s.PlaylistSkips)
s.playlistMutex.RUnlock()
return length
}
// ResetTrackSkips resets the skip slice for the current track.
func (s *SkipTracker) ResetTrackSkips() {
s.trackMutex.Lock()
s.TrackSkips = s.TrackSkips[:0]
s.trackMutex.Unlock()
}
// ResetPlaylistSkips resets the skip slice for the current playlist.
func (s *SkipTracker) ResetPlaylistSkips() {
s.playlistMutex.Lock()
s.PlaylistSkips = s.PlaylistSkips[:0]
s.playlistMutex.Unlock()
}
func (s *SkipTracker) evaluateTrackSkips() {
s.trackMutex.RLock()
skipRatio := viper.GetFloat64("queue.track_skip_ratio")
DJ.Client.Do(func() {
if float64(len(s.TrackSkips))/float64(len(DJ.Client.Self.Channel.Users)) >= skipRatio {
// Stopping an audio stream triggers a skip.
DJ.Queue.StopCurrent()
}
})
s.trackMutex.RUnlock()
}
func (s *SkipTracker) evaluatePlaylistSkips() {
s.playlistMutex.RLock()
skipRatio := viper.GetFloat64("queue.playlist_skip_ratio")
DJ.Client.Do(func() {
if float64(len(s.PlaylistSkips))/float64(len(DJ.Client.Self.Channel.Users)) >= skipRatio {
DJ.Queue.SkipPlaylist()
}
})
s.playlistMutex.RUnlock()
}