Add more music commands and clean them up a bit. Add version string to discord presence.
This commit is contained in:
parent
faab0c818c
commit
1a0b3a1cd0
|
@ -1,3 +1,5 @@
|
||||||
|
import org.apache.tools.ant.filters.ReplaceTokens
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id 'java'
|
id 'java'
|
||||||
id 'org.jetbrains.kotlin.jvm' version '1.3.31'
|
id 'org.jetbrains.kotlin.jvm' version '1.3.31'
|
||||||
|
@ -5,6 +7,8 @@ plugins {
|
||||||
id "io.spring.dependency-management" version "1.0.7.RELEASE"
|
id "io.spring.dependency-management" version "1.0.7.RELEASE"
|
||||||
id 'org.jetbrains.kotlin.plugin.spring' version '1.3.31'
|
id 'org.jetbrains.kotlin.plugin.spring' version '1.3.31'
|
||||||
id 'org.jetbrains.kotlin.plugin.jpa' version '1.3.31'
|
id 'org.jetbrains.kotlin.plugin.jpa' version '1.3.31'
|
||||||
|
id "org.jetbrains.kotlin.kapt" version "1.3.31"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply plugin: 'kotlin-jpa'
|
apply plugin: 'kotlin-jpa'
|
||||||
|
@ -40,6 +44,7 @@ dependencies {
|
||||||
implementation "com.h2database:h2"
|
implementation "com.h2database:h2"
|
||||||
|
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||||
|
kapt 'org.springframework.boot:spring-boot-configuration-processor'
|
||||||
implementation "org.springframework:spring-web"
|
implementation "org.springframework:spring-web"
|
||||||
implementation "com.fasterxml.jackson.core:jackson-databind"
|
implementation "com.fasterxml.jackson.core:jackson-databind"
|
||||||
implementation "com.fasterxml.jackson.module:jackson-module-kotlin"
|
implementation "com.fasterxml.jackson.module:jackson-module-kotlin"
|
||||||
|
|
|
@ -1,24 +1,28 @@
|
||||||
package nl.voidcorp.discord
|
package nl.voidcorp.discord
|
||||||
|
|
||||||
import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager
|
|
||||||
import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers
|
import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers
|
||||||
|
import net.dv8tion.jda.api.entities.Activity
|
||||||
import net.dv8tion.jda.api.sharding.DefaultShardManagerBuilder
|
import net.dv8tion.jda.api.sharding.DefaultShardManagerBuilder
|
||||||
import nl.voidcorp.discord.events.CommandListener
|
import nl.voidcorp.discord.events.CommandListener
|
||||||
import nl.voidcorp.discord.events.OttoListener
|
import nl.voidcorp.discord.events.OttoListener
|
||||||
|
import nl.voidcorp.discord.music.PlayerManager
|
||||||
|
import nl.voidcorp.discord.storage.ConfigStore
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class Loader(listener: CommandListener, playerManager: DefaultAudioPlayerManager) {
|
class Loader(listener: CommandListener, playerManager: PlayerManager, store: ConfigStore, otto: OttoListener) {
|
||||||
init {
|
init {
|
||||||
val token = System.getenv("DISCORD_TOKEN") ?: throw RuntimeException("'DISCORD_TOKEN' not set!")
|
val token = System.getenv("DISCORD_TOKEN") ?: throw RuntimeException("'DISCORD_TOKEN' not set!")
|
||||||
val builder = DefaultShardManagerBuilder(token)
|
val builder = DefaultShardManagerBuilder(token)
|
||||||
|
|
||||||
|
|
||||||
|
builder.addEventListeners(otto, listener)
|
||||||
builder.addEventListeners(OttoListener, listener)
|
|
||||||
|
|
||||||
jda = builder.build()
|
jda = builder.build()
|
||||||
|
jda.setActivityProvider {
|
||||||
|
Activity.playing("v${store.version} ($it)")
|
||||||
|
}
|
||||||
AudioSourceManagers.registerRemoteSources(playerManager)
|
AudioSourceManagers.registerRemoteSources(playerManager)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,17 +1,21 @@
|
||||||
package nl.voidcorp.discord
|
package nl.voidcorp.discord
|
||||||
|
|
||||||
import net.dv8tion.jda.api.sharding.ShardManager
|
import net.dv8tion.jda.api.sharding.ShardManager
|
||||||
|
import nl.voidcorp.discord.storage.ConfigStore
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties
|
||||||
import org.springframework.boot.runApplication
|
import org.springframework.boot.runApplication
|
||||||
|
import java.util.jar.Manifest
|
||||||
|
|
||||||
val logger: Logger = LoggerFactory.getLogger("OttoBot")
|
val logger: Logger = LoggerFactory.getLogger("OttoBot")
|
||||||
lateinit var jda: ShardManager
|
lateinit var jda: ShardManager
|
||||||
|
|
||||||
val creator = 168743656738521088
|
const val creator = 168743656738521088
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
|
@EnableConfigurationProperties(ConfigStore::class)
|
||||||
class SpringApp
|
class SpringApp
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
package nl.voidcorp.discord.commands.music
|
package nl.voidcorp.discord.commands.music
|
||||||
|
|
||||||
import nl.voidcorp.discord.command.*
|
import nl.voidcorp.discord.command.*
|
||||||
|
import nl.voidcorp.discord.music.PlayerManager
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class ForceLeave : Command(
|
class ForceLeave(val playerManager: PlayerManager) : Command(
|
||||||
"forceleave",
|
"forceleave",
|
||||||
group = CommandGroup.MUSIC,
|
group = CommandGroup.MUSIC,
|
||||||
location = CommandSource.GUILD,
|
location = CommandSource.GUILD,
|
||||||
|
@ -12,6 +13,7 @@ class ForceLeave : Command(
|
||||||
) {
|
) {
|
||||||
override fun handle(event: CommandMessage): CommandResult {
|
override fun handle(event: CommandMessage): CommandResult {
|
||||||
event.guild!!.audioManager.closeAudioConnection()
|
event.guild!!.audioManager.closeAudioConnection()
|
||||||
|
playerManager.delGuildPlayer(event.guild)
|
||||||
return CommandResult.SUCCESS
|
return CommandResult.SUCCESS
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,20 +7,27 @@ import org.springframework.stereotype.Service
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class Play(val playerManager: PlayerManager) :
|
class Play(val playerManager: PlayerManager) :
|
||||||
Command("play", location = CommandSource.GUILD, group = CommandGroup.MUSIC) {
|
Command("play", location = CommandSource.GUILD, group = CommandGroup.MUSIC, usage = "play song url (or song name prepended with ytsearch:)") {
|
||||||
override fun handle(event: CommandMessage): CommandResult {
|
override fun handle(event: CommandMessage): CommandResult {
|
||||||
val chan = event.member!!.voiceState!!.channel
|
val chan = event.member!!.voiceState!!.channel
|
||||||
if (chan == null) {
|
if (chan == null) {
|
||||||
event.reply("Please join a voice channel to play music!")
|
event.reply("Please join a voice channel to play music!")
|
||||||
return CommandResult.SUCCESS
|
return CommandResult.SUCCESS
|
||||||
|
} else if (event.params.drop(1).isEmpty()) {
|
||||||
|
event.reply("I'm going to need a url or a search term to actually find a song...")
|
||||||
|
return CommandResult.PARAMETERS
|
||||||
}
|
}
|
||||||
|
|
||||||
val am = event.guild!!.audioManager
|
val am = event.guild!!.audioManager
|
||||||
|
|
||||||
am.openAudioConnection(chan)
|
|
||||||
|
|
||||||
val ts = playerManager.getGuildPlayer(event.guild)
|
val ts = playerManager.getGuildPlayer(event.guild)
|
||||||
|
|
||||||
playerManager.loadItem("https://www.youtube.com/watch?v=kPgiJUeSP6Q", AudioLoadHandler(ts))
|
if (!ts.playing) {
|
||||||
|
am.openAudioConnection(chan)
|
||||||
|
}
|
||||||
|
|
||||||
|
playerManager.loadItem(event.params.drop(1).joinToString(" "), AudioLoadHandler(ts))
|
||||||
|
|
||||||
|
|
||||||
return CommandResult.SUCCESS
|
return CommandResult.SUCCESS
|
||||||
|
|
14
src/main/kotlin/nl/voidcorp/discord/commands/music/Skip.kt
Normal file
14
src/main/kotlin/nl/voidcorp/discord/commands/music/Skip.kt
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
package nl.voidcorp.discord.commands.music
|
||||||
|
|
||||||
|
import nl.voidcorp.discord.command.*
|
||||||
|
import nl.voidcorp.discord.music.PlayerManager
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
|
@Service
|
||||||
|
class Skip(val playerManager: PlayerManager) :
|
||||||
|
Command("skip", location = CommandSource.GUILD, group = CommandGroup.MUSIC) {
|
||||||
|
override fun handle(event: CommandMessage): CommandResult {
|
||||||
|
playerManager.getGuildPlayer(event.guild!!).skip()
|
||||||
|
return CommandResult.SUCCESS
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,24 @@
|
||||||
package nl.voidcorp.discord.events
|
package nl.voidcorp.discord.events
|
||||||
|
|
||||||
|
import net.dv8tion.jda.api.entities.Activity
|
||||||
import net.dv8tion.jda.api.events.ReadyEvent
|
import net.dv8tion.jda.api.events.ReadyEvent
|
||||||
|
import net.dv8tion.jda.api.events.ReconnectedEvent
|
||||||
import net.dv8tion.jda.api.hooks.ListenerAdapter
|
import net.dv8tion.jda.api.hooks.ListenerAdapter
|
||||||
import nl.voidcorp.discord.logger
|
import nl.voidcorp.discord.logger
|
||||||
|
import nl.voidcorp.discord.storage.ConfigStore
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
object OttoListener : ListenerAdapter() {
|
@Service
|
||||||
|
class OttoListener(val configStore: ConfigStore) : ListenerAdapter() {
|
||||||
override fun onReady(event: ReadyEvent) {
|
override fun onReady(event: ReadyEvent) {
|
||||||
logger.info("Found ${event.guildTotalCount} different guilds!")
|
logger.info("Found ${event.guildTotalCount} different guilds!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onReconnect(event: ReconnectedEvent) {
|
||||||
|
val id = event.jda.shardInfo!!.shardId
|
||||||
|
val reconn = event.responseNumber
|
||||||
|
val version = configStore.version
|
||||||
|
event.jda.presence.activity = Activity.playing("v$version ($id~$reconn)")
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -4,7 +4,6 @@ import com.sedmelluq.discord.lavaplayer.player.AudioLoadResultHandler
|
||||||
import com.sedmelluq.discord.lavaplayer.tools.FriendlyException
|
import com.sedmelluq.discord.lavaplayer.tools.FriendlyException
|
||||||
import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist
|
import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist
|
||||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrack
|
import com.sedmelluq.discord.lavaplayer.track.AudioTrack
|
||||||
import nl.voidcorp.discord.logger
|
|
||||||
|
|
||||||
|
|
||||||
class AudioLoadHandler(private val trackScheduler: TrackScheduler) : AudioLoadResultHandler {
|
class AudioLoadHandler(private val trackScheduler: TrackScheduler) : AudioLoadResultHandler {
|
||||||
|
@ -14,7 +13,6 @@ class AudioLoadHandler(private val trackScheduler: TrackScheduler) : AudioLoadRe
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun trackLoaded(track: AudioTrack) {
|
override fun trackLoaded(track: AudioTrack) {
|
||||||
logger.info("loaded track ${track.identifier}")
|
|
||||||
trackScheduler.queue(track)
|
trackScheduler.queue(track)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,8 +21,11 @@ class AudioLoadHandler(private val trackScheduler: TrackScheduler) : AudioLoadRe
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun playlistLoaded(playlist: AudioPlaylist) {
|
override fun playlistLoaded(playlist: AudioPlaylist) {
|
||||||
for (t in playlist.tracks) {
|
if (playlist.isSearchResult) {
|
||||||
trackScheduler.queue(t)
|
trackScheduler.queue(playlist.selectedTrack ?: playlist.tracks.first())
|
||||||
}
|
} else
|
||||||
|
for (t in playlist.tracks) {
|
||||||
|
trackScheduler.queue(t)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
12
src/main/kotlin/nl/voidcorp/discord/music/MusicAnnouncer.kt
Normal file
12
src/main/kotlin/nl/voidcorp/discord/music/MusicAnnouncer.kt
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
package nl.voidcorp.discord.music
|
||||||
|
|
||||||
|
import com.sedmelluq.discord.lavaplayer.track.AudioTrack
|
||||||
|
import net.dv8tion.jda.api.entities.TextChannel
|
||||||
|
import nl.voidcorp.discord.logger
|
||||||
|
|
||||||
|
class MusicAnnouncer(val channel: TextChannel) {
|
||||||
|
|
||||||
|
fun sendPlayTrack(track: AudioTrack) {
|
||||||
|
logger.info(track.info.uri)
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,21 +2,42 @@ package nl.voidcorp.discord.music
|
||||||
|
|
||||||
import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager
|
import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager
|
||||||
import net.dv8tion.jda.api.entities.Guild
|
import net.dv8tion.jda.api.entities.Guild
|
||||||
|
import nl.voidcorp.discord.storage.GuildRepo
|
||||||
|
import nl.voidcorp.discord.storage.GuildStore
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class PlayerManager : DefaultAudioPlayerManager() {
|
class PlayerManager(val repo: GuildRepo) : DefaultAudioPlayerManager() {
|
||||||
val guildPlayMap = mutableMapOf<Long, TrackScheduler>()
|
val guildPlayMap = mutableMapOf<Long, TrackScheduler>()
|
||||||
fun getGuildPlayer(guild: Guild): TrackScheduler {
|
fun getGuildPlayer(guild: Guild): TrackScheduler {
|
||||||
return if (guildPlayMap.containsKey(guild.idLong)) {
|
return if (guildPlayMap.containsKey(guild.idLong)) {
|
||||||
guildPlayMap[guild.idLong] ?: error("oof?")
|
guildPlayMap[guild.idLong] ?: error("oof?")
|
||||||
} else {
|
} else {
|
||||||
val player = createPlayer()
|
val player = createPlayer()
|
||||||
val ts = TrackScheduler(player)
|
val store = repo.findByGuildId(guild.idLong) ?: GuildStore(guild.idLong)
|
||||||
|
val channel = store.musicChannels.firstOrNull()
|
||||||
|
?: store.botChannels.firstOrNull()
|
||||||
|
?: guild.textChannels.firstOrNull {
|
||||||
|
it.name.contains("music", true) && it.name.contains(
|
||||||
|
"bot",
|
||||||
|
true
|
||||||
|
)
|
||||||
|
}?.idLong
|
||||||
|
?: guild.textChannels.firstOrNull { it.name.contains("music", true) }?.idLong
|
||||||
|
?: guild.textChannels.firstOrNull { it.name.contains("bot", true) }?.idLong
|
||||||
|
?: guild.defaultChannel!!.idLong
|
||||||
|
player.volume = 50
|
||||||
|
|
||||||
|
val ts = TrackScheduler(player, MusicAnnouncer(guild.getTextChannelById(channel)!!)) {
|
||||||
|
delGuildPlayer(guild)
|
||||||
|
}
|
||||||
|
|
||||||
player.addListener(ts)
|
player.addListener(ts)
|
||||||
guild.audioManager.sendingHandler = AudioPlayerSendHandler(player)
|
guild.audioManager.sendingHandler = AudioPlayerSendHandler(player)
|
||||||
guildPlayMap[guild.idLong] = ts
|
guildPlayMap[guild.idLong] = ts
|
||||||
ts
|
ts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun delGuildPlayer(guild: Guild) = guildPlayMap.remove(guild.idLong)
|
||||||
}
|
}
|
|
@ -4,22 +4,40 @@ import com.sedmelluq.discord.lavaplayer.player.AudioPlayer
|
||||||
import com.sedmelluq.discord.lavaplayer.player.event.AudioEventAdapter
|
import com.sedmelluq.discord.lavaplayer.player.event.AudioEventAdapter
|
||||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrack
|
import com.sedmelluq.discord.lavaplayer.track.AudioTrack
|
||||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason
|
import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason
|
||||||
|
import nl.voidcorp.discord.logger
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class TrackScheduler(private val player: AudioPlayer) : AudioEventAdapter() {
|
class TrackScheduler(private val player: AudioPlayer, private val announcer: MusicAnnouncer, val delet: () -> Unit) :
|
||||||
|
AudioEventAdapter() {
|
||||||
private val queue = ArrayDeque<AudioTrack>()
|
private val queue = ArrayDeque<AudioTrack>()
|
||||||
|
|
||||||
fun queue(track: AudioTrack) {
|
fun queue(track: AudioTrack) {
|
||||||
if (!player.startTrack(track, true)) {
|
if (!player.startTrack(track, true)) {
|
||||||
queue.addLast(track)
|
queue.addLast(track)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun pop() = queue.pop()
|
override fun onTrackStart(player: AudioPlayer, track: AudioTrack) {
|
||||||
|
announcer.sendPlayTrack(track)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onTrackEnd(player: AudioPlayer, track: AudioTrack, endReason: AudioTrackEndReason) {
|
override fun onTrackEnd(player: AudioPlayer, track: AudioTrack, endReason: AudioTrackEndReason) {
|
||||||
if (endReason.mayStartNext && queue.isNotEmpty()) {
|
if (endReason.mayStartNext && queue.isNotEmpty()) {
|
||||||
player.startTrack(pop(), true)
|
player.startTrack(queue.pop(), true)
|
||||||
|
} else if (queue.isEmpty()) {
|
||||||
|
announcer.channel.guild.audioManager.closeAudioConnection()
|
||||||
|
delet()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val playing
|
||||||
|
get() = player.playingTrack != null
|
||||||
|
|
||||||
|
fun skip() {
|
||||||
|
if (queue.isEmpty()) {
|
||||||
|
player.stopTrack()
|
||||||
|
} else {
|
||||||
|
player.startTrack(queue.pop(), false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package nl.voidcorp.discord.storage
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties
|
||||||
|
|
||||||
|
@ConfigurationProperties("ottobot")
|
||||||
|
class ConfigStore {
|
||||||
|
lateinit var version: String
|
||||||
|
}
|
|
@ -5,5 +5,4 @@ import org.springframework.data.jpa.repository.JpaRepository
|
||||||
|
|
||||||
interface GuildRepo : JpaRepository<GuildStore, Long> {
|
interface GuildRepo : JpaRepository<GuildStore, Long> {
|
||||||
fun findByGuildId(id: Long): GuildStore?
|
fun findByGuildId(id: Long): GuildStore?
|
||||||
fun existsByGuildId(id: Long): Boolean
|
|
||||||
}
|
}
|
|
@ -7,3 +7,5 @@ spring.datasource.url=jdbc:h2:mem:
|
||||||
spring.jpa.generate-ddl=true
|
spring.jpa.generate-ddl=true
|
||||||
spring.jpa.hibernate.ddl-auto=create-drop
|
spring.jpa.hibernate.ddl-auto=create-drop
|
||||||
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
|
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
|
||||||
|
|
||||||
|
ottobot.version=1.0
|
Loading…
Reference in a new issue