Commit 9eb22c22 authored by Spotlight Deveaux's avatar Spotlight Deveaux 🦊

[bot] Implement rendering

This provides the necessary information to render color, and respond with the appropiate file.
parent 60a83c15
package space.joscomputing.discord.cssexpress;
import com.jagrosh.jdautilities.command.Command;
import com.jagrosh.jdautilities.command.CommandEvent;
import net.dv8tion.jda.api.MessageBuilder;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Message;
import java.nio.file.Files;
import java.nio.file.Path;
public class DrawCommand extends Command {
DrawCommand() { = "draw";
this.aliases = new String[]{"fly", "color", "render"}; = "draws the color you'd like to see rendered!";
this.ownerCommand = false;
this.botPermissions = new Permission[]{Permission.MESSAGE_ATTACH_FILES, Permission.MESSAGE_WRITE};
protected void execute(CommandEvent event) {
if (event.getArgs().isEmpty()) {
// We'll assume the raw message has nothing funny hidden.
event.replyError("Run me as `" + event.getMessage().getContentStripped() + " #fff`, or the many other syntaxes of CSS3 color formats!");
String progress = " Loading, please wait...";
if (event.getSelfMember().hasPermission(Permission.MESSAGE_EXT_EMOJI)) {
// We can use the animated loading message from Discord Bots.
progress = "<a:loading:393852367751086090>" + progress;
} else {
progress = "✅" + progress;
Message sent = event.getChannel().sendMessage(progress).complete();
// Visibly show progress in addition to the above
try {
// This is expected to be time consuming. Statements afterwards should be in a delayed manner.
byte[] result = Main.torso.getScreenshotByColor(event.getArgs());
// We don't really mind if this specific part fails - it's just tidying from earlier
// Write out a temporary file
String id = event.getAuthor().getId();
Path temp = Files.createTempFile(id, ".png");
Files.write(temp, result);
event.reply("Here's your color:", temp.toFile(), id + ".png");
} catch (InterruptedException e) {
event.replyError("Hm.. I failed to render this for some reason. Send a message to my owner :(");
} catch (IOException e) {
event.replyError("Hm.. I failed to send a file for some reason. Send a message to my owner :(");
\ No newline at end of file
......@@ -31,7 +31,7 @@ public class Main extends ListenerAdapter implements EventListener {
String chromeExecutable;
private static WebdriverTorso torso;
static WebdriverTorso torso;
public static void main(String[] args) throws IOException, LoginException {
// Check for config.json in the current directory.
......@@ -51,6 +51,7 @@ public class Main extends ListenerAdapter implements EventListener {
new DrawCommand(),
new ShutdownCommand()
......@@ -2,17 +2,57 @@ package space.joscomputing.discord.cssexpress;
import java.util.Base64;
import java.util.concurrent.Semaphore;
* WebdriverTorso manages the lifecycle of a Chrome devtools connection.
* It also provides queueing abilities for necessary "rendered document" actions.
class WebdriverTorso {
private Chrome chrome;
private final Chrome chrome;;
private static Semaphore mutex = new Semaphore(1);
WebdriverTorso(String hostLocation) {
chrome = Chrome.start(hostLocation, true);
byte[] getScreenshotByColor(String input) throws InterruptedException {
try {
// Go to page
// Take a screenshot of the body
return chrome.screenshot(".fox");
} finally {
* Takes a given color and uses JS to apply the CSS style to the body.
* Encodes the URL for easy browsing.
* @param input The CSS-typed color to apply to the body.
* @return data text/html (base64 encoded) URL
private String formulateURL(String input) {
// For all intents and purposes, we deem this escaped.
// It goes directly to the node's style via JS.
String sanitized = input.replaceAll("\'", "\\'");
String formulated = "<!DOCTYPE html>" +
"<html>" +
// We have to manually define the body style in order to prevent a
// 0x0 px view screenshot.
"<body>" +
"<div class='fox' style='height: 64px; width: 64px;'></div>" +
"<script>document.querySelector('.fox').style.backgroundColor = '" + sanitized + "';</script>" +
"</body>" +
return "data:text/html;base64," + Base64.getEncoder().encodeToString(formulated.getBytes());
void shutdown() {
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment