Add logger for the server, it can be used to log edits, deletions and nickname alters
Add admin role thing, this can be used to set admin roles Add @random to @ a random user
This commit is contained in:
parent
6b93a5dcc1
commit
948b32f387
|
@ -1,10 +1,13 @@
|
|||
package nl.voidcorp.dbot
|
||||
|
||||
import net.dv8tion.jda.core.OnlineStatus
|
||||
import net.dv8tion.jda.core.Permission
|
||||
import net.dv8tion.jda.core.events.guild.voice.GuildVoiceLeaveEvent
|
||||
import net.dv8tion.jda.core.events.message.MessageReceivedEvent
|
||||
import net.dv8tion.jda.core.events.message.react.MessageReactionAddEvent
|
||||
import net.dv8tion.jda.core.events.message.react.MessageReactionRemoveEvent
|
||||
import net.dv8tion.jda.core.hooks.ListenerAdapter
|
||||
import nl.voidcorp.dbot.commands.GSM
|
||||
import nl.voidcorp.dbot.music.guildMusicMap
|
||||
|
||||
object Events : ListenerAdapter() {
|
||||
|
@ -32,6 +35,16 @@ object Events : ListenerAdapter() {
|
|||
}
|
||||
}
|
||||
}*/
|
||||
if (event.message.contentRaw.contains("@random") and
|
||||
(event.author != event.jda.selfUser) and
|
||||
(GSM.getSettings(event.guild).adminRoles.any { it in event.member.roles.map { role -> role.idLong } }
|
||||
or event.member.hasPermission(Permission.ADMINISTRATOR))
|
||||
) {
|
||||
val mem = event.textChannel.members.filter { !it.user.isBot }
|
||||
.filter { it.onlineStatus in mutableListOf(OnlineStatus.ONLINE, OnlineStatus.IDLE) }
|
||||
.filter { it.user.idLong != event.author.idLong }.random()
|
||||
event.channel.sendMessage("Hey, ${mem.asMention} look here ^").queue()
|
||||
}
|
||||
if (event.author.idLong == 168743656738521088 && event.message.mentionedMembers.contains(
|
||||
event.guild.getMember(
|
||||
event.jda.selfUser
|
||||
|
|
120
src/main/kotlin/nl/voidcorp/dbot/Logging.kt
Normal file
120
src/main/kotlin/nl/voidcorp/dbot/Logging.kt
Normal file
|
@ -0,0 +1,120 @@
|
|||
package nl.voidcorp.dbot
|
||||
|
||||
import net.dv8tion.jda.core.EmbedBuilder
|
||||
import net.dv8tion.jda.core.entities.*
|
||||
import net.dv8tion.jda.core.events.guild.member.GuildMemberNickChangeEvent
|
||||
import net.dv8tion.jda.core.events.message.guild.GuildMessageDeleteEvent
|
||||
import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent
|
||||
import net.dv8tion.jda.core.events.message.guild.GuildMessageUpdateEvent
|
||||
import net.dv8tion.jda.core.hooks.ListenerAdapter
|
||||
import nl.voidcorp.dbot.commands.GSM
|
||||
import java.awt.Color
|
||||
import java.time.LocalDateTime
|
||||
import java.time.temporal.TemporalAccessor
|
||||
import java.util.*
|
||||
|
||||
object Logging : ListenerAdapter() {
|
||||
val map = mutableMapOf<Long, Queue<Message>>()
|
||||
|
||||
enum class Colors(val colorString: String) {
|
||||
NAMECHANGE("#00cc66"),
|
||||
MESSAGEDELETE("#ff3300"),
|
||||
MESSAGEEDIT("#ffcc66"),
|
||||
UNKNOWN("#000000")
|
||||
}
|
||||
|
||||
override fun onGuildMessageReceived(event: GuildMessageReceivedEvent) {
|
||||
if (map[event.guild.idLong] == null) map[event.guild.idLong] = ArrayDeque()
|
||||
map[event.guild.idLong]?.apply {
|
||||
while (size > 100) {
|
||||
poll()
|
||||
}
|
||||
offer(event.message)
|
||||
}
|
||||
}
|
||||
|
||||
fun logChannel(guild: Guild): TextChannel? {
|
||||
val log = GSM.getSettings(guild).logChannel
|
||||
return if (log != null) {
|
||||
guild.getTextChannelById(log)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun buildEmbed(
|
||||
affectedMember: Member?,
|
||||
message: String = "",
|
||||
color: Colors = Colors.UNKNOWN,
|
||||
title: String = color.name.toLowerCase().capitalize(),
|
||||
fields: Map<String, String> = mutableMapOf(),
|
||||
timestamp: TemporalAccessor = LocalDateTime.now()
|
||||
): MessageEmbed {
|
||||
val em = EmbedBuilder()
|
||||
.setTimestamp(timestamp)
|
||||
.setColor(Color.decode(color.colorString))
|
||||
if (title.isNotBlank()) em.setTitle(title)
|
||||
if (message.isNotBlank()) em.setDescription(message)
|
||||
fields.forEach { name, content -> em.addField(name, content, true) }
|
||||
if (affectedMember != null) em.setFooter(affectedMember.user.name, affectedMember.user.effectiveAvatarUrl)
|
||||
return em.build()
|
||||
}
|
||||
|
||||
override fun onGuildMemberNickChange(event: GuildMemberNickChangeEvent) {
|
||||
val lc = logChannel(event.guild)
|
||||
if ((event.user.idLong == 144116077129891840) or (event.user.idLong == 131399667442384896)) return
|
||||
if (lc != null) {
|
||||
val em = buildEmbed(
|
||||
event.member,
|
||||
fields = mutableMapOf(
|
||||
"Old name" to (event.prevNick ?: event.user.name),
|
||||
"New Name" to (event.newNick ?: event.user.name)
|
||||
),
|
||||
color = Colors.NAMECHANGE
|
||||
)
|
||||
lc.sendMessage(em).queue()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onGuildMessageDelete(event: GuildMessageDeleteEvent) {
|
||||
val lc = logChannel(event.guild)
|
||||
if (lc != null) {
|
||||
map[event.guild.idLong]?.firstOrNull { it.idLong == event.messageIdLong }.let {
|
||||
|
||||
val em = buildEmbed(
|
||||
it?.member,
|
||||
color = Colors.MESSAGEDELETE,
|
||||
fields = mutableMapOf(
|
||||
"Message" to (it?.contentDisplay ?: "Something else (message too old...)"),
|
||||
"Channel" to event.channel.asMention
|
||||
),
|
||||
timestamp = (it?.editedTime ?: it?.creationTime) ?: LocalDateTime.now()
|
||||
)
|
||||
lc.sendMessage(em).queue()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onGuildMessageUpdate(event: GuildMessageUpdateEvent) {
|
||||
val lc = logChannel(event.guild)
|
||||
if (lc != null) {
|
||||
(map[event.guild.idLong]?.firstOrNull { it.idLong == event.messageIdLong }).let {
|
||||
|
||||
val em = buildEmbed(
|
||||
event.member, color = Colors.MESSAGEEDIT,
|
||||
fields = mutableMapOf(
|
||||
"Old message" to (it?.contentStripped ?: "Something else (message too old...)"),
|
||||
"New message" to event.message.contentStripped,
|
||||
"Channel" to event.channel.asMention
|
||||
)
|
||||
)
|
||||
|
||||
map[event.guild.idLong]?.removeAll { old -> old.idLong == event.messageIdLong }
|
||||
map[event.guild.idLong]?.offer(event.message)
|
||||
lc.sendMessage(em).queue()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -39,7 +39,7 @@ fun main(args: Array<String>) {
|
|||
custom.version = "1.5"
|
||||
|
||||
|
||||
bot = JDABuilder(args[0]).addEventListener(custom).addEventListener(nl.voidcorp.dbot.Events)
|
||||
bot = JDABuilder(args[0]).addEventListener(custom).addEventListener(Events).addEventListener(Logging)
|
||||
.setAudioSendFactory(NativeAudioSendFactory()).build()
|
||||
|
||||
/*Runtime.getRuntime().addShutdownHook(thread(start = false) {
|
||||
|
|
|
@ -12,6 +12,8 @@ fun initAdmin() {
|
|||
commands += ListPrefixes
|
||||
commands += RemovePrefix
|
||||
commands += AddRoleCommand
|
||||
commands += addAdminRole
|
||||
commands += logSetCommand
|
||||
/*commands += MuteCommand
|
||||
commands += LuaExec*/
|
||||
}
|
||||
|
@ -100,6 +102,24 @@ object AddRoleCommand : UnityCommand(
|
|||
}
|
||||
})
|
||||
|
||||
val addAdminRole = UnityCommand("addadminrole", "Add a role that is considered and admin role", AdminCategory) { ce ->
|
||||
val g = GSM.getSettings(ce.guild)
|
||||
|
||||
g.adminRoles.addAll(ce.message.mentionedRoles.map { it.idLong })
|
||||
ce.guild.getRolesByName("admin", true).firstOrNull()?.idLong?.let { g.adminRoles.add(it) }
|
||||
ce.reply("The admin roles are ${g.adminRoles.joinToString { "`${ce.guild.getRoleById(it).name}`" }}")
|
||||
}
|
||||
|
||||
val logSetCommand = UnityCommand("loghere", "Set the logging channel", AdminCategory) { ce ->
|
||||
val g = GSM.getSettings(ce.guild)
|
||||
if (ce.textChannel != null) {
|
||||
ce.reply("Set logging channel to ${ce.textChannel!!.asMention}!")
|
||||
g.logChannel = ce.textChannel!!.idLong
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
object LuaExec : UnityCommand("luaexec", "Executes a bit of lua code", AdminCategory, exec = { ce ->
|
||||
ce.message.delete().queue()
|
||||
|
||||
|
|
|
@ -79,20 +79,32 @@ object GeneralCategory : UnityCategory("general")
|
|||
|
||||
}*/
|
||||
|
||||
object MusicCategory : UnityCategory("Music Commands", listOf("bot", "music", "music-bot"), errorMessage = { "Music commands can only be used in ${it.asMention}!" })
|
||||
object MusicCategoryPrivate : UnityCategory("Music Commands", listOf("bot", "music", "music-bot"), listOf("admin"), { "Music commands can only be used in ${it.asMention}!" })
|
||||
object MusicCategory : UnityCategory(
|
||||
"Music Commands",
|
||||
listOf("bot", "music", "music-bot"),
|
||||
errorMessage = { "Music commands can only be used in ${it.asMention}!" })
|
||||
|
||||
object AdminCategory : UnityCategory("Admin Stuff") {
|
||||
object MusicCategoryPrivate : UnityCategory(
|
||||
"Music Commands",
|
||||
listOf("bot", "music", "music-bot"), errorMessage =
|
||||
{ "Music commands can only be used in ${it.asMention}!" }) {
|
||||
override fun test(ce: UnityCommandEvent): Boolean {
|
||||
val res = when {
|
||||
|
||||
return super.test(ce) and AdminCategory.test(ce)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
object AdminCategory : UnityCategory("Admin Stuff", errorMessage = { "You need to be and admin to use this!" }) {
|
||||
override fun test(ce: UnityCommandEvent): Boolean {
|
||||
return when {
|
||||
ce.member.hasPermission(Permission.ADMINISTRATOR) -> true
|
||||
ce.member.roles.firstOrNull { it.name.equals("admin", true) } != null -> true
|
||||
ce.member.roles.map { it.idLong }.any {
|
||||
GSM.getSettings(ce.guild).adminRoles.contains(it)
|
||||
} -> true
|
||||
else -> false
|
||||
}
|
||||
if (!res) {
|
||||
ce.reply("You are not an admin!")
|
||||
}
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,13 +14,19 @@ import java.time.temporal.ChronoUnit
|
|||
import kotlin.random.Random
|
||||
|
||||
|
||||
val helloCommand = UnityCommand("hello", "Say hello to Andy!") {
|
||||
val helloCommand = UnityCommand("hello", "Say hello to Andy!") { uce ->
|
||||
val nick: String? = uce.selfMember.nickname
|
||||
uce.guild.controller.setNickname(uce.selfMember, "Andy Zaidman").queue {
|
||||
val i = Random.nextInt(10)
|
||||
if (i > 8) {
|
||||
it.reply("Can you speak up or I'll throw you a microphone")
|
||||
uce.reply("Can you speak up or I'll throw you a microphone")
|
||||
} else {
|
||||
it.reply(MessageBuilder("Hello, ").append(it.author).append("!").build())
|
||||
uce.reply(MessageBuilder("Hello, ").append(uce.author).append("!").build())
|
||||
}
|
||||
uce.guild.controller.setNickname(uce.selfMember, nick).queue()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -269,6 +269,47 @@ fun initMusic() {
|
|||
event.reply("Stopped all playback!")
|
||||
}
|
||||
|
||||
val pauseCommand = UnityMusicCommand(
|
||||
"pause",
|
||||
"Pauses the song, or resumes it!",
|
||||
MusicCategory,
|
||||
aliases = mutableListOf("resume")
|
||||
) { event, scheduler ->
|
||||
if (scheduler.isPaused()) {
|
||||
scheduler.resume()
|
||||
event.reply("Resuming playback!")
|
||||
} else {
|
||||
scheduler.pause()
|
||||
event.reply("Paused playback!")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
val seekCommand = UnityMusicCommand(
|
||||
"seek",
|
||||
"Seeks to a specified point in the song!",
|
||||
aliases = mutableListOf(),
|
||||
arguments = "dd:hh:mm:ss"
|
||||
) { event, scheduler ->
|
||||
var a = event.args
|
||||
|
||||
if ((a.toLongOrNull() == null) and (a.indexOf(":") == -1) and !a.split(':').map { it.toLongOrNull() }.any { it == null }) {
|
||||
event.reply("Please supply your time in the format `dd:hh:mm:ss` (values that are `00:` can be omitted)")
|
||||
return@UnityMusicCommand
|
||||
} else {
|
||||
while (a.count { it == ':' } < 3) {
|
||||
a = "00:$a"
|
||||
}
|
||||
|
||||
val millis = scheduler.timeToMillis(a)
|
||||
scheduler.seek(millis)
|
||||
event.reply(scheduler.getCurrentTrackInfo())
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
commands.addAll(
|
||||
playCommand,
|
||||
skipCommand,
|
||||
|
@ -279,7 +320,9 @@ fun initMusic() {
|
|||
attachmentPlay,
|
||||
voteSkipCommand,
|
||||
loopCommand,
|
||||
stopCommand
|
||||
stopCommand,
|
||||
pauseCommand,
|
||||
seekCommand
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -312,7 +355,7 @@ fun getLinkFromSearch(
|
|||
}
|
||||
|
||||
override fun noMatches() {
|
||||
|
||||
event.reply("Sorry, I ")
|
||||
}
|
||||
|
||||
override fun playlistLoaded(playlist: AudioPlaylist) {
|
||||
|
|
|
@ -5,6 +5,7 @@ import net.dv8tion.jda.core.EmbedBuilder
|
|||
import nl.voidcorp.dbot.commands
|
||||
import nl.voidcorp.dbot.commands.MusicCategory
|
||||
import nl.voidcorp.dbot.commands.UnityCommand
|
||||
import java.net.URLEncoder
|
||||
import java.time.LocalDateTime
|
||||
|
||||
val lyricsCommand = UnityCommand("lyrics", "Search for lyrics!", MusicCategory) { ce ->
|
||||
|
@ -53,7 +54,7 @@ data class Song(val artist: String, val title: String)
|
|||
|
||||
fun findInfo(search: String): Song? {
|
||||
val res = khttp.get(
|
||||
"https://api.genius.com/search?q=${search.replace(" ", "%20")}",
|
||||
"https://api.genius.com/search?q=${URLEncoder.encode(search, "UTF8")}",
|
||||
headers = mapOf("Authorization" to "Bearer eqn-1xrvrAKtoIFC-pIgNiW7cRzSvaF49wjFzasEu7coSLpufVVnv_IGVnxUIT43")
|
||||
)
|
||||
val hits = res.jsonObject.getJSONObject("response").getJSONArray("hits")!!
|
||||
|
@ -69,9 +70,9 @@ fun findInfo(search: String): Song? {
|
|||
fun findText(song: Song): String {
|
||||
val res =
|
||||
get(
|
||||
"https://orion.apiseeds.com/api/music/lyric/${song.artist}/${song.title.replace(
|
||||
" ",
|
||||
"%20"
|
||||
"https://orion.apiseeds.com/api/music/lyric/${URLEncoder.encode(song.artist, "UTF8")}/${URLEncoder.encode(
|
||||
song.title,
|
||||
"UTF8"
|
||||
)}?apikey=8pLAxkCnWJNGWRaoPcbCFpUAKdKD77zmlcjs2FKYjdH00MDyNr6lXLHb3PQZsKJI"
|
||||
)
|
||||
return if (res.jsonObject.isNull("error")) {
|
||||
|
|
|
@ -51,7 +51,7 @@ class TrackScheduler(val player: AudioPlayer, val guild: Guild, val voiceChannel
|
|||
pressedSkip = 0
|
||||
if (q.isNotEmpty()) {
|
||||
val t = q.poll()!!
|
||||
if (loop) q.addLast(t.makeClone().apply { userData = t.userData })
|
||||
if (loop) q.addLast(track.makeClone().apply { userData = t.userData })
|
||||
player.playTrack(t)
|
||||
} else {
|
||||
if (loop) {
|
||||
|
@ -180,7 +180,7 @@ class TrackScheduler(val player: AudioPlayer, val guild: Guild, val voiceChannel
|
|||
}
|
||||
|
||||
|
||||
eb.setDescription("${millisToTime(track.position)}/${millisToTime(track.duration)}")
|
||||
eb.setDescription(genTrackTime(track))
|
||||
|
||||
return eb.build()
|
||||
}
|
||||
|
@ -195,20 +195,43 @@ class TrackScheduler(val player: AudioPlayer, val guild: Guild, val voiceChannel
|
|||
val minutes = TimeUnit.MILLISECONDS.toMinutes(ms)
|
||||
ms -= TimeUnit.MINUTES.toMillis(minutes)
|
||||
val seconds = TimeUnit.MILLISECONDS.toSeconds(ms)
|
||||
val current = String.format(
|
||||
return String.format(
|
||||
"%02d:%02d:%02d:%02d",
|
||||
days, hours, minutes, seconds
|
||||
).removePrefix("00:").removePrefix("00:")
|
||||
return current
|
||||
)
|
||||
}
|
||||
|
||||
fun timeToMillis(time: String): Long {
|
||||
val times = time.split(':').map { it.toLong() }
|
||||
return TimeUnit.DAYS.toMillis(times[0]) + TimeUnit.HOURS.toMillis(times[1]) +
|
||||
TimeUnit.MINUTES.toMillis(times[2]) + TimeUnit.SECONDS.toMillis(times[3])
|
||||
|
||||
}
|
||||
|
||||
fun genTrackTime(audioTrack: AudioTrack): String {
|
||||
val total = millisToTime(audioTrack.duration)
|
||||
val current = millisToTime(audioTrack.position)
|
||||
return if (current == "00:00:00:00") {
|
||||
""
|
||||
} else {
|
||||
val t = total.substring(total.lastIndexOf("00:") + 3)
|
||||
val c = current.substring(current.length - t.length)
|
||||
"$c/$t"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun getTrackList(member: Member): MessageEmbed {
|
||||
return EmbedBuilder().setTitle("Hey ${member.effectiveName}, here is the playlist${if (loop) ", it loops!" else ""}")
|
||||
val eb =
|
||||
EmbedBuilder().setTitle("Hey ${member.effectiveName}, here is the playlist${if (loop) ", it loops!" else ""}")
|
||||
.setTimestamp(LocalDateTime.now()).setColor(musicChannel.guild.selfMember.color)
|
||||
.setFooter("Requested by ${member.effectiveName}", member.user.effectiveAvatarUrl).setDescription(
|
||||
.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()
|
||||
)
|
||||
|
||||
return eb.build()
|
||||
}
|
||||
|
||||
var pressedSkip = 0
|
||||
|
@ -225,5 +248,24 @@ class TrackScheduler(val player: AudioPlayer, val guild: Guild, val voiceChannel
|
|||
player.stopTrack()
|
||||
}
|
||||
|
||||
fun pause() {
|
||||
player.isPaused = true
|
||||
}
|
||||
|
||||
fun resume() {
|
||||
player.isPaused = false
|
||||
}
|
||||
|
||||
fun isPaused() = player.isPaused
|
||||
|
||||
fun seek(ms: Long): Boolean {
|
||||
return if (!player.playingTrack.isSeekable) false
|
||||
else {
|
||||
player.playingTrack.position = ms
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,9 @@ import java.time.LocalDateTime
|
|||
data class GuildSettings(
|
||||
val prefixes: MutableList<String> = mutableListOf(),
|
||||
val muted: MutableMap<LocalDateTime, MutableList<MuteInfo>> = mutableMapOf(),
|
||||
val roleMap: MutableMap<String, Long> = mutableMapOf()
|
||||
val roleMap: MutableMap<String, Long> = mutableMapOf(),
|
||||
val adminRoles: MutableSet<Long> = mutableSetOf(),
|
||||
var logChannel: Long? = null
|
||||
) {
|
||||
fun getPrefixes(): MutableCollection<String> {
|
||||
return prefixes
|
||||
|
|
Loading…
Reference in a new issue