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.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class DrawCommand extends Command {
DrawCommand() {
this.name = "draw";
this.aliases = new String[]{"fly", "color", "render"};
this.help = "draws the color you'd like to see rendered!";
this.ownerCommand = false;
this.botPermissions = new Permission[]{Permission.MESSAGE_ATTACH_FILES, Permission.MESSAGE_WRITE};
}
@Override
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!");
return;
}
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
event.getChannel().sendTyping().complete();
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
sent.delete().complete();
// 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");
temp.toFile().delete();
} catch (InterruptedException e) {
event.replyError("Hm.. I failed to render this for some reason. Send a message to my owner :(");
e.printStackTrace();
} catch (IOException e) {
event.replyError("Hm.. I failed to send a file for some reason. Send a message to my owner :(");
e.printStackTrace();
}
}
}
\ 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 {
client.setOwnerId(config.botOwner);
client.setPrefix(config.prefix);
client.addCommands(
new DrawCommand(),
new ShutdownCommand()
);
......
......@@ -2,17 +2,57 @@ package space.joscomputing.discord.cssexpress;
import com.intuit.karate.driver.chrome.Chrome;
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 {
mutex.acquire();
// Go to page
chrome.setUrl(formulateURL(input));
// Take a screenshot of the body
return chrome.screenshot(".fox");
} finally {
mutex.release();
}
}
/**
* 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>" +
"</html>";
return "data:text/html;base64," + Base64.getEncoder().encodeToString(formulated.getBytes());
}
void shutdown() {
chrome.quit();
}
......
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