2018-10-14 14:16:14 +02:00
package nl.voidcorp.dbot.music
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer
import com.sedmelluq.discord.lavaplayer.player.event.AudioEventAdapter
2018-10-15 22:25:51 +02:00
import com.sedmelluq.discord.lavaplayer.source.http.HttpAudioTrack
2018-10-14 22:20:47 +02:00
import com.sedmelluq.discord.lavaplayer.source.soundcloud.SoundCloudAudioSourceManager
import com.sedmelluq.discord.lavaplayer.source.soundcloud.SoundCloudAudioTrack
import com.sedmelluq.discord.lavaplayer.source.youtube.YoutubeAudioTrack
2018-10-14 14:16:14 +02:00
import com.sedmelluq.discord.lavaplayer.track.AudioTrack
import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason
import net.dv8tion.jda.core.EmbedBuilder
2018-10-15 22:25:51 +02:00
import net.dv8tion.jda.core.entities.*
2018-10-14 14:16:14 +02:00
import nl.voidcorp.dbot.log
2018-10-14 22:20:47 +02:00
import java.awt.Color
2018-10-14 14:16:14 +02:00
import java.time.LocalDateTime
import java.util.*
2018-11-06 22:46:53 +01:00
import java.util.concurrent.TimeUnit
2018-10-15 22:25:51 +02:00
import kotlin.concurrent.timerTask
2018-11-05 17:41:18 +01:00
import kotlin.math.roundToInt
2018-10-14 14:16:14 +02:00
2018-11-05 17:41:18 +01:00
class TrackScheduler ( val player : AudioPlayer , val guild : Guild , val voiceChannel : VoiceChannel ) : AudioEventAdapter ( ) {
2018-10-14 14:16:14 +02:00
val musicChannel : TextChannel
2018-10-14 22:20:47 +02:00
2018-11-06 22:46:53 +01:00
var loop = false
2018-10-14 14:16:14 +02:00
init {
player . addListener ( this )
val audio = guild . audioManager
audio . sendingHandler = AudioPlayerSendHandler ( player )
2018-11-05 17:41:18 +01:00
audio . openAudioConnection ( voiceChannel )
2018-10-14 14:16:14 +02:00
2018-10-20 22:10:44 +02:00
musicChannel = guild . getTextChannelsByName ( " music-bot " , true ) . firstOrNull ( )
?: ( guild . getTextChannelsByName ( " music " , true ) . firstOrNull ( )
2018-11-05 17:41:18 +01:00
?: ( guild . getTextChannelsByName ( " bot " , true ) . firstOrNull ( )
?: ( guild . getTextChannelsByName ( " general " , true ) . firstOrNull ( )
?: guild . defaultChannel !! ) ) )
2018-10-14 14:16:14 +02:00
}
private val q = ArrayDeque < AudioTrack > ( )
/ * override fun onEvent ( event : AudioEvent ) {
if ( event is TrackEndEvent ) {
}
} * /
override fun onTrackEnd ( player : AudioPlayer , track : AudioTrack , endReason : AudioTrackEndReason ) {
2018-11-06 22:46:53 +01:00
pressedSkip = 0
2018-10-14 14:16:14 +02:00
if ( q . isNotEmpty ( ) ) {
2018-11-06 22:46:53 +01:00
val t = q . poll ( ) !!
if ( loop ) q . addLast ( t . makeClone ( ) . apply { userData = t . userData } )
player . playTrack ( t )
2018-10-14 14:16:14 +02:00
} else {
2018-11-06 22:46:53 +01:00
if ( loop ) {
player . playTrack ( track . makeClone ( ) . apply { userData = track . userData } )
return
}
2018-10-14 14:16:14 +02:00
stopPlay ( endReason )
player . destroy ( )
}
}
override fun onTrackStart ( player : AudioPlayer , track : AudioTrack ) {
2018-10-15 22:25:51 +02:00
musicChannel . sendMessage ( getCurrentTrackInfo ( ) ) . append ( " Now playing " ) . queue ( )
/ * if ( track is YoutubeAudioTrack ) {
2018-10-14 22:20:47 +02:00
if ( track . userData is Member )
} else if ( track is SoundCloudAudioTrack ) {
val scsm = track . sourceManager as SoundCloudAudioSourceManager
scsm . updateClientId ( )
val art = khttp . get ( " http://api.soundcloud.com/tracks/ ${track.info.identifier} ?client_id= ${scsm.clientId} " , headers = mapOf ( " Content-Type " to " application/json " ) ) . jsonObject [ " artwork_url " ] . toString ( ) . replace ( " large " , " t300x300 " )
if ( track . userData is Member )
musicChannel . sendMessage ( EmbedBuilder ( )
. setFooter ( " Requested by ${(track.userData as Member).effectiveName} " , ( track . userData as Member )
. user . effectiveAvatarUrl ) . setAuthor ( track . info . author ) . setTitle ( track . info . title , track . info . uri )
. setThumbnail ( art )
. setTimestamp ( LocalDateTime . now ( ) ) . setColor ( Color . decode ( " #ff8800 " ) ) . build ( ) ) . append ( " Now playing " ) . queue ( )
}
2018-10-15 22:25:51 +02:00
* /
2018-10-14 14:16:14 +02:00
}
fun queue ( track : AudioTrack , member : Member ) {
track . userData = member
if ( q . isEmpty ( ) && player . playingTrack == null ) {
log . info ( " Queue is empty, playing a track " )
player . playTrack ( track )
} else {
log . info ( " Track Queue'd " )
2018-10-14 22:20:47 +02:00
q . offer ( track )
2018-10-14 14:16:14 +02:00
}
}
fun insertFront ( track : AudioTrack , member : Member ) {
track . userData = member
if ( q . isEmpty ( ) && player . playingTrack == null ) {
log . info ( " Queue is empty, playing a track " )
player . playTrack ( track )
} else {
log . info ( " Track inserted " )
2018-10-14 22:20:47 +02:00
q . push ( track )
2018-10-14 14:16:14 +02:00
}
}
fun skip ( ) {
2018-10-14 22:20:47 +02:00
/ * if ( q . isNotEmpty ( ) ) {
2018-10-14 14:16:14 +02:00
log . info ( " skipped Track! " )
player . playTrack ( q . remove ( ) )
} else {
stopPlay ( AudioTrackEndReason . REPLACED )
player . destroy ( )
2018-10-14 22:20:47 +02:00
} * /
player . stopTrack ( )
2018-10-14 14:16:14 +02:00
}
fun isQueueEmpty ( ) = q . isEmpty ( )
2018-10-14 22:20:47 +02:00
fun isSongPlaying ( ) = player . playingTrack != null
2018-10-14 14:16:14 +02:00
fun stopPlay ( endReason : AudioTrackEndReason ) {
if ( endReason != AudioTrackEndReason . REPLACED ) {
guildMusicMap . remove ( guild . idLong )
2018-11-05 17:41:18 +01:00
musicChannel . sendMessage (
EmbedBuilder ( ) . setColor ( musicChannel . guild . selfMember . color ) . setTitle ( " I'm done here " ) . setDescription (
" There are no more songs left in the queue. "
) . setTimestamp ( LocalDateTime . now ( ) ) . build ( )
) . queue ( )
2018-10-15 22:25:51 +02:00
Timer ( ) . schedule ( timerTask {
guild . audioManager . closeAudioConnection ( )
} , 2000 )
}
}
fun getCurrentTrackInfo ( ) : MessageEmbed = getTrackInfo ( player . playingTrack )
fun getTrackInfo ( track : AudioTrack ) : MessageEmbed {
2018-11-06 22:46:53 +01:00
val eb = EmbedBuilder ( ) . setTimestamp ( LocalDateTime . now ( ) )
if ( track . userData is Member ) {
eb . setFooter (
" Requested by ${(track.userData as Member).effectiveName} " , ( track . userData as Member )
. user . effectiveAvatarUrl
)
}
when ( track ) {
is YoutubeAudioTrack -> eb . setAuthor ( track . info . author ) . setTitle ( track . info . title , track . info . uri )
. setThumbnail ( " https://img.youtube.com/vi/ ${track.info.identifier} /hqdefault.jpg " )
. setColor ( Color . decode ( " #ff0000 " ) )
is SoundCloudAudioTrack -> {
val scsm = track . sourceManager as SoundCloudAudioSourceManager
scsm . updateClientId ( )
val art = khttp . get (
" http://api.soundcloud.com/tracks/ ${track.info.identifier} ?client_id= ${scsm.clientId} " ,
headers = mapOf ( " Content-Type " to " application/json " )
) . jsonObject [ " artwork_url " ] . toString ( ) . replace ( " large " , " t300x300 " )
eb
. setAuthor ( track . info . author ) . setTitle ( track . info . title , track . info . uri )
2018-11-05 17:41:18 +01:00
. setThumbnail ( if ( art == " null " ) null else art )
2018-11-06 22:46:53 +01:00
. setColor ( Color . decode ( " #ff5500 " ) )
2018-10-15 22:25:51 +02:00
2018-11-06 22:46:53 +01:00
}
is HttpAudioTrack -> eb . setAuthor ( track . info . author ) . setTitle ( track . info . title , track . info . uri )
. setColor ( Color . decode ( " #005A9C " ) )
else ->
eb . setAuthor ( track . info . author ) . setTitle ( track . info . title , track . info . uri )
. setColor ( musicChannel . guild . selfMember . color )
2018-10-14 14:16:14 +02:00
}
2018-10-15 22:25:51 +02:00
2018-11-06 22:46:53 +01:00
eb . setDescription ( " ${millisToTime(track.position)} / ${millisToTime(track.duration)} " )
return eb . build ( )
}
fun millisToTime ( millis : Long ) : String {
var ms = millis
val days = TimeUnit . MILLISECONDS . toDays ( ms )
ms -= TimeUnit . DAYS . toMillis ( days )
val hours = TimeUnit . MILLISECONDS . toHours ( ms )
ms -= TimeUnit . HOURS . toMillis ( hours )
val minutes = TimeUnit . MILLISECONDS . toMinutes ( ms )
ms -= TimeUnit . MINUTES . toMillis ( minutes )
val seconds = TimeUnit . MILLISECONDS . toSeconds ( ms )
val current = String . format (
" %02d:%02d:%02d:%02d " ,
days , hours , minutes , seconds
) . removePrefix ( " 00: " ) . removePrefix ( " 00: " )
return current
2018-10-15 22:25:51 +02:00
}
fun getTrackList ( member : Member ) : MessageEmbed {
2018-11-06 22:46:53 +01:00
return EmbedBuilder ( ) . setTitle ( " Hey ${member.effectiveName} , here is the playlist ${if (loop) ", it loops!" else ""} " )
2018-11-05 17:41:18 +01:00
. setTimestamp ( LocalDateTime . now ( ) ) . setColor ( musicChannel . guild . selfMember . color )
. setFooter ( " Requested by ${member.effectiveName} " , member . user . effectiveAvatarUrl ) . setDescription (
" ** ${player.playingTrack.info.title} **, requested by ${if (player.playingTrack.userData is Member) (player.playingTrack.userData as Member).effectiveName else "someone unknown..."} (*now playing*) \n " +
q . joinToString ( separator = " \n " ) { " ** ${it.info.title} **, requested by ${if (it.userData is Member) (it.userData as Member).effectiveName else "someone unknown..."} " }
) . build ( )
}
var pressedSkip = 0
fun shouldSkip ( ) : Boolean {
val half = ( voiceChannel . members . size . run { this - 1 } . toDouble ( ) / 2 ) . roundToInt ( )
val press = ++ pressedSkip
return press >= half
2018-10-14 14:16:14 +02:00
}
2018-11-06 22:46:53 +01:00
fun clearQueue ( ) {
q . clear ( )
loop = false
player . stopTrack ( )
}
2018-10-14 14:16:14 +02:00
}