Add auto publish feature

This commit is contained in:
Wieland Schöbl
2020-08-14 22:43:53 +02:00
parent d15fb92acf
commit 7bf483ab32
15 changed files with 274 additions and 130 deletions

View File

@@ -0,0 +1,27 @@
import net.dv8tion.jda.internal.requests.Method;
import net.dv8tion.jda.internal.requests.Route;
import java.lang.reflect.Constructor;
public class Inaccessibles {
/**
* This is private by default
*
* @param method look
* @param route somewhere
* @return else
*/
public static Route getRoute(Method method, String route) {
try {
Constructor<?> constructor = Route.class.getDeclaredConstructor(Method.class, String.class);
constructor.setAccessible(true);
return (Route) constructor.newInstance(method, route);
} catch (Exception e) {
return null;
}
}
public static String toUnsignedString(long num) {
return Long.toUnsignedString(num);
}
}

View File

@@ -4,17 +4,33 @@ import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration
import net.dv8tion.jda.api.EmbedBuilder
import net.dv8tion.jda.api.JDA
import net.dv8tion.jda.api.entities.Activity
import net.dv8tion.jda.api.entities.MessageEmbed
import net.dv8tion.jda.api.entities.User
import java.awt.Color
import java.sql.Time
import java.util.concurrent.TimeUnit
object Admin {
val userId: Long
val token: String
val updateMs: Long
var testModeEnabled: Boolean = false
set(value) {
if (field == value)
return
field = value
if (value) {
jda?.presence?.setPresence(Activity.of(Activity.ActivityType.DEFAULT, "Testing mode, hold on..."), true)
} else {
jda?.presence?.setPresence(Activity.watching("for new Blogposts"), false)
}
Channels.channels = Channels.refreshFromDisk()
Admin.info()
}
init {
val admin = Json(JsonConfiguration.Stable).parse(AdminFile.serializer(), ADMIN_FILE.readText())
userId = admin.adminId
@@ -55,14 +71,14 @@ object Admin {
)
}
fun error(msg: String, error: Exception) {
fun error(msg: String, error: String) {
sendDevMessage(
EmbedBuilder()
.setTitle(msg)
.setDescription(error.message)
.setDescription(error)
.setColor(Color.RED)
.build()
, "$msg\n\n${error.message}"
, "$msg\n\n${error}"
)
}

View File

@@ -1,21 +0,0 @@
package de.wulkanat
import net.dv8tion.jda.api.events.message.MessageReceivedEvent
import net.dv8tion.jda.api.hooks.ListenerAdapter
class Bot : ListenerAdapter() {
override fun onMessageReceived(event: MessageReceivedEvent) {
val message = event.message
if (message.contentRaw == "!ping") {
val channel = message.channel
val time = System.currentTimeMillis()
channel.sendMessage("Pong!")
.queue {
it.editMessageFormat("Pong: %d ms", System.currentTimeMillis() - time)
.queue()
}
}
}
}

View File

@@ -1,5 +1,6 @@
package de.wulkanat
import de.wulkanat.extensions.crosspost
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration
import kotlinx.serialization.list
@@ -15,8 +16,7 @@ object Channels {
/**
* List of (ServerID, ChannelID)
*/
val channels: MutableList<DiscordChannel> =
json.parse(DiscordChannel.serializer().list, SERVERS_FILE.readText()).toMutableList()
var channels: MutableList<DiscordChannel> = refreshFromDisk()
fun sentToAll(messageEmbed: MessageEmbed) {
if (jda == null)
@@ -33,7 +33,11 @@ object Channels {
}
channel.sendMessage(message).queue()
}
channel.sendMessage(messageEmbed).queue()
channel.sendMessage(messageEmbed).queue {
if (channel_pair.autoPublish) {
it.crosspost().queue()
}
}
}
}
@@ -52,6 +56,16 @@ object Channels {
}
}
fun refreshFromDisk(): MutableList<DiscordChannel> {
return json.parse(
DiscordChannel.serializer().list, (if (Admin.testModeEnabled) {
TEST_FILE
} else {
SERVERS_FILE
}).readText()
).toMutableList()
}
fun getServerNames(): List<String> {
if (jda == null)
return listOf()
@@ -63,12 +77,10 @@ object Channels {
return@map "**${it.id}** *(inactive)*"
}
val role = if (it.mentionedRole == null) {
""
} else if (it.mentionedRole == "everyone") {
" @everyone"
} else {
" @${channel.guild.getRoleById(it.mentionedRole)?.name}"
val role = when (it.mentionedRole) {
null -> ""
"everyone" -> " @everyone"
else -> " @${channel.guild.getRoleById(it.mentionedRole)?.name}"
}
"**${channel.guild.name}**\n#${channel.name}${role}"
}
@@ -88,6 +100,7 @@ object Channels {
json.stringify(
DiscordChannel.serializer().list,
channels
))
)
)
}
}

View File

@@ -4,59 +4,47 @@ import de.wulkanat.model.BlogPostPreview
import net.dv8tion.jda.api.events.message.MessageReceivedEvent
import net.dv8tion.jda.api.hooks.ListenerAdapter
import de.wulkanat.web.SiteWatcher
import net.dv8tion.jda.api.events.ExceptionEvent
import net.dv8tion.jda.api.events.message.priv.PrivateMessageReceivedEvent
import kotlin.system.exitProcess
class Cli : ListenerAdapter() {
override fun onMessageReceived(event: MessageReceivedEvent) {
override fun onPrivateMessageReceived(event: PrivateMessageReceivedEvent) {
val msg = event.message.contentRaw
if (event.author.idLong != Admin.userId ||
!msg.startsWith("%!")
!msg.startsWith("!")
) {
return
}
val command = msg.removePrefix("%!").split(" ")
val command = msg.removePrefix("!").split(Regex("\\s+"))
try {
when (command[0]) {
"stop" -> exitProcess(1)
"fakeUpdate" -> {
SiteWatcher.newestBlog = BlogPostPreview(
title = "FakePost",
imgUrl = "",
fullPostUrl = "",
author = "wulkanat",
date = "now",
description = "Lorem Ipsum"
)
when (command[0]) {
"stop" -> exitProcess(1)
"fakeUpdate" -> {
SiteWatcher.newestBlog = BlogPostPreview(
title = "FakePost",
imgUrl = "",
fullPostUrl = "",
author = "wulkanat",
date = "now",
description = "Lorem Ipsum"
)
Admin.println("Posting on next update cycle.")
}
"addChannel" -> {
val channel = command[1].toLong()
var role: String? = null
if (command.size == 3) {
role = command[2]
}
val serverChannel = Channels.testServerId(channel)
val roleName = serverChannel?.guild?.getRoleById(role ?: "")
if (serverChannel != null) {
if (roleName != null || role == null || role == "everyone") {
Channels.addChannel(channel, role)
Admin.println("Added server '${serverChannel.name}' for role '${roleName ?: role}'")
} else {
Admin.warning("Unknown Role ID")
}
} else {
Admin.warning("Unknown Channel ID")
}
}
"info" -> {
Admin.info()
}
Admin.println("Posting on next update cycle.")
}
"info" -> {
Admin.info()
}
"refreshList" -> {
Channels.channels = Channels.refreshFromDisk()
Admin.info()
}
"testMode" -> {
Admin.testModeEnabled = true
}
"productionMode" -> {
Admin.testModeEnabled = false
}
} catch (e: ArrayIndexOutOfBoundsException) {
// noop
}
}
}

View File

@@ -6,7 +6,8 @@ import java.io.File
@Serializable
data class DiscordChannel(
val id: Long,
val mentionedRole: String? = null
val mentionedRole: String? = null,
val autoPublish: Boolean = false
)
@Serializable
@@ -17,4 +18,5 @@ data class AdminFile(
)
val SERVERS_FILE = File("servers.json")
val TEST_FILE = File("test.json")
val ADMIN_FILE = File("admin.json")

View File

@@ -0,0 +1,10 @@
package de.wulkanat
import net.dv8tion.jda.api.events.ExceptionEvent
import net.dv8tion.jda.api.hooks.ListenerAdapter
class ErrorHandler : ListenerAdapter() {
override fun onException(event: ExceptionEvent) {
Admin.error(event.cause.message ?: event.cause.localizedMessage, event.cause.stackTrace.toString())
}
}

View File

@@ -7,15 +7,14 @@ import de.wulkanat.web.SiteWatcher
import kotlin.concurrent.timer
fun main() {
// TODO: move toke into file
val builder = JDABuilder.createLight(
Admin.token,
GatewayIntent.GUILD_MESSAGES, GatewayIntent.DIRECT_MESSAGES)
.addEventListeners(Bot())
.setActivity(Activity.watching("for new Blogposts"))
.build()
builder.addEventListener(Cli())
builder.addEventListener(ErrorHandler())
builder.awaitReady()
Channels.jda = builder

View File

@@ -0,0 +1,28 @@
package de.wulkanat.extensions
import Inaccessibles
import net.dv8tion.jda.api.entities.Message
import net.dv8tion.jda.api.entities.MessageChannel
import net.dv8tion.jda.api.requests.restaction.MessageAction
import net.dv8tion.jda.internal.requests.Method
import net.dv8tion.jda.internal.requests.Route
import net.dv8tion.jda.internal.requests.restaction.MessageActionImpl
import net.dv8tion.jda.internal.utils.Checks
fun MessageChannel.crosspostById(messageId: String): MessageAction {
Checks.isSnowflake(messageId, "Message ID")
val route = CROSSPOST_MESSAGE.compile(id, messageId)
return MessageActionImpl(jda, route, this).append("This is not of your interest.")
}
fun Message.crosspost(): MessageAction {
val messageId = Inaccessibles.toUnsignedString(idLong)
return channel.crosspostById(messageId)
}
val CROSSPOST_MESSAGE: Route = Inaccessibles.getRoute(
Method.POST,
"channels/{channel_id}/messages/{message_id}/crosspost"
)

View File

@@ -27,7 +27,7 @@ object SiteWatcher {
newestBlog = newBlog
}
} catch (e: IOException) {
Admin.error("Connection to Hytale Server failed", e)
Admin.error("Connection to Hytale Server failed", e.message ?: e.localizedMessage)
return false
}