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 {
|
||||
id 'java'
|
||||
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 'org.jetbrains.kotlin.plugin.spring' 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'
|
||||
|
@ -40,6 +44,7 @@ dependencies {
|
|||
implementation "com.h2database:h2"
|
||||
|
||||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||
kapt 'org.springframework.boot:spring-boot-configuration-processor'
|
||||
implementation "org.springframework:spring-web"
|
||||
implementation "com.fasterxml.jackson.core:jackson-databind"
|
||||
implementation "com.fasterxml.jackson.module:jackson-module-kotlin"
|
||||
|
|
|
@ -1,24 +1,28 @@
|
|||
package nl.voidcorp.discord
|
||||
|
||||
import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager
|
||||
import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers
|
||||
import net.dv8tion.jda.api.entities.Activity
|
||||
import net.dv8tion.jda.api.sharding.DefaultShardManagerBuilder
|
||||
import nl.voidcorp.discord.events.CommandListener
|
||||
import nl.voidcorp.discord.events.OttoListener
|
||||
import nl.voidcorp.discord.music.PlayerManager
|
||||
import nl.voidcorp.discord.storage.ConfigStore
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
|
||||
@Service
|
||||
class Loader(listener: CommandListener, playerManager: DefaultAudioPlayerManager) {
|
||||
class Loader(listener: CommandListener, playerManager: PlayerManager, store: ConfigStore, otto: OttoListener) {
|
||||
init {
|
||||
val token = System.getenv("DISCORD_TOKEN") ?: throw RuntimeException("'DISCORD_TOKEN' not set!")
|
||||
val builder = DefaultShardManagerBuilder(token)
|
||||
|
||||
|
||||
|
||||
builder.addEventListeners(OttoListener, listener)
|
||||
builder.addEventListeners(otto, listener)
|
||||
|
||||
jda = builder.build()
|
||||
jda.setActivityProvider {
|
||||
Activity.playing("v${store.version} ($it)")
|
||||
}
|
||||
AudioSourceManagers.registerRemoteSources(playerManager)
|
||||
}
|
||||
}
|
|
@ -1,17 +1,21 @@
|
|||
package nl.voidcorp.discord
|
||||
|
||||
import net.dv8tion.jda.api.sharding.ShardManager
|
||||
import nl.voidcorp.discord.storage.ConfigStore
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties
|
||||
import org.springframework.boot.runApplication
|
||||
import java.util.jar.Manifest
|
||||
|
||||
val logger: Logger = LoggerFactory.getLogger("OttoBot")
|
||||
lateinit var jda: ShardManager
|
||||
|
||||
val creator = 168743656738521088
|
||||
const val creator = 168743656738521088
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableConfigurationProperties(ConfigStore::class)
|
||||
class SpringApp
|
||||
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
package nl.voidcorp.discord.commands.music
|
||||
|
||||
import nl.voidcorp.discord.command.*
|
||||
import nl.voidcorp.discord.music.PlayerManager
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
class ForceLeave : Command(
|
||||
class ForceLeave(val playerManager: PlayerManager) : Command(
|
||||
"forceleave",
|
||||
group = CommandGroup.MUSIC,
|
||||
location = CommandSource.GUILD,
|
||||
|
@ -12,6 +13,7 @@ class ForceLeave : Command(
|
|||
) {
|
||||
override fun handle(event: CommandMessage): CommandResult {
|
||||
event.guild!!.audioManager.closeAudioConnection()
|
||||
playerManager.delGuildPlayer(event.guild)
|
||||
return CommandResult.SUCCESS
|
||||
}
|
||||
}
|
|
@ -7,20 +7,27 @@ import org.springframework.stereotype.Service
|
|||
|
||||
@Service
|
||||
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 {
|
||||
val chan = event.member!!.voiceState!!.channel
|
||||
if (chan == null) {
|
||||
event.reply("Please join a voice channel to play music!")
|
||||
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
|
||||
|
||||
am.openAudioConnection(chan)
|
||||
|
||||
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
|
||||
|
|
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
|
||||
|
||||
import net.dv8tion.jda.api.entities.Activity
|
||||
import net.dv8tion.jda.api.events.ReadyEvent
|
||||
import net.dv8tion.jda.api.events.ReconnectedEvent
|
||||
import net.dv8tion.jda.api.hooks.ListenerAdapter
|
||||
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) {
|
||||
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.track.AudioPlaylist
|
||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrack
|
||||
import nl.voidcorp.discord.logger
|
||||
|
||||
|
||||
class AudioLoadHandler(private val trackScheduler: TrackScheduler) : AudioLoadResultHandler {
|
||||
|
@ -14,7 +13,6 @@ class AudioLoadHandler(private val trackScheduler: TrackScheduler) : AudioLoadRe
|
|||
}
|
||||
|
||||
override fun trackLoaded(track: AudioTrack) {
|
||||
logger.info("loaded track ${track.identifier}")
|
||||
trackScheduler.queue(track)
|
||||
}
|
||||
|
||||
|
@ -23,8 +21,11 @@ class AudioLoadHandler(private val trackScheduler: TrackScheduler) : AudioLoadRe
|
|||
}
|
||||
|
||||
override fun playlistLoaded(playlist: AudioPlaylist) {
|
||||
for (t in playlist.tracks) {
|
||||
trackScheduler.queue(t)
|
||||
}
|
||||
if (playlist.isSearchResult) {
|
||||
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 net.dv8tion.jda.api.entities.Guild
|
||||
import nl.voidcorp.discord.storage.GuildRepo
|
||||
import nl.voidcorp.discord.storage.GuildStore
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
class PlayerManager : DefaultAudioPlayerManager() {
|
||||
class PlayerManager(val repo: GuildRepo) : DefaultAudioPlayerManager() {
|
||||
val guildPlayMap = mutableMapOf<Long, TrackScheduler>()
|
||||
fun getGuildPlayer(guild: Guild): TrackScheduler {
|
||||
return if (guildPlayMap.containsKey(guild.idLong)) {
|
||||
guildPlayMap[guild.idLong] ?: error("oof?")
|
||||
} else {
|
||||
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)
|
||||
guild.audioManager.sendingHandler = AudioPlayerSendHandler(player)
|
||||
guildPlayMap[guild.idLong] = 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.track.AudioTrack
|
||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason
|
||||
import nl.voidcorp.discord.logger
|
||||
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>()
|
||||
|
||||
fun queue(track: AudioTrack) {
|
||||
if (!player.startTrack(track, true)) {
|
||||
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) {
|
||||
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> {
|
||||
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.hibernate.ddl-auto=create-drop
|
||||
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
|
||||
|
||||
ottobot.version=1.0
|
Loading…
Reference in a new issue