Skip to content
This repository has been archived by the owner on Jan 20, 2024. It is now read-only.

Commit

Permalink
Plugin: add chat visualization of url images
Browse files Browse the repository at this point in the history
  • Loading branch information
TheFaser committed Dec 21, 2023
1 parent deccc0c commit 3e8d613
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 3 deletions.
12 changes: 10 additions & 2 deletions src/main/java/net/flectone/chat/component/FComponent.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package net.flectone.chat.component;

import lombok.Getter;
import net.flectone.chat.FlectoneChat;
import net.flectone.chat.model.file.FConfiguration;
import net.md_5.bungee.api.chat.BaseComponent;
Expand All @@ -16,6 +17,8 @@ public class FComponent {
private final BaseComponent component;
protected final FConfiguration locale;
protected final FConfiguration config;
@Getter
private HoverEvent hoverEvent;

public FComponent(@Nullable BaseComponent baseComponent) {
this.component = baseComponent;
Expand Down Expand Up @@ -54,7 +57,7 @@ public FComponent addHoverText(@NotNull String showText) {

@NotNull
public FComponent addHoverText(@NotNull BaseComponent[] baseComponents) {
component.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, baseComponents));
setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, baseComponents));
return this;
}

Expand All @@ -66,7 +69,7 @@ public FComponent addOpenURL(@NotNull String url) {

@NotNull
public FComponent addHoverItem(@NotNull String itemJson) {
component.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_ITEM, new BaseComponent[]{new TextComponent(itemJson)}));
setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_ITEM, new BaseComponent[]{new TextComponent(itemJson)}));
return this;
}

Expand All @@ -81,4 +84,9 @@ public FComponent addSuggestCommand(@NotNull String command) {
component.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command));
return this;
}

public void setHoverEvent(@NotNull HoverEvent hoverEvent) {
component.setHoverEvent(hoverEvent);
this.hoverEvent = hoverEvent;
}
}
100 changes: 100 additions & 0 deletions src/main/java/net/flectone/chat/component/FImageComponent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package net.flectone.chat.component;

import lombok.Getter;
import net.flectone.chat.util.ColorUtil;
import org.apache.commons.io.FilenameUtils;
import org.jetbrains.annotations.NotNull;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

@Getter
public class FImageComponent extends FComponent {

private boolean isCorrect;

private String text;

public FImageComponent(@NotNull String imageUrl) {
try {
this.isCorrect = convertImageUrl(imageUrl);
} catch (Exception ignored) {}
}

// Idea taken from here
// https://github.com/QuiltServerTools/BlockBot/blob/5d5fa854002de2c12200edbe22f12382350ca7eb/src/main/kotlin/io/github/quiltservertools/blockbotdiscord/extensions/BlockBotApiExtension.kt#L136
public boolean convertImageUrl(@NotNull String imageUrl) throws Exception {
URL url = new URL(imageUrl);

BufferedImage bufferedImage = ImageIO.read(url);
if (bufferedImage == null) return false;

text = FilenameUtils.getName(url.getPath());

int width = bufferedImage.getWidth();
int height = bufferedImage.getHeight();

if (height * width >= 8 * 1024 * 1024) return false;

int stepSize = Math.max((int) Math.ceil(bufferedImage.getWidth() / 48.0), 1);
int stepSquared = stepSize * stepSize;

int x = 0;
int y = 0;

List<String> loreList = new ArrayList<>();
loreList.add("");

while (y < height) {
StringBuilder text = new StringBuilder();
while (x < width) {
int rgb;

if (stepSize != 1) {
int r = 0;
int g = 0;
int b = 0;

for (int x2 = 0; x2 < stepSize; x2++) {
for (int y2 = 0; y2 < stepSize; y2++) {
int color = bufferedImage.getRGB(clamp(x + x2, 0, width - 1), clamp(y + y2, 0, height - 1));
r += (color >> 16) & 0xFF;
g += (color >> 8) & 0xFF;
b += color & 0xFF;
}
}

rgb = ((r / stepSquared) << 16) | ((g / stepSquared) << 8) | (b / stepSquared);
} else {
rgb = bufferedImage.getRGB(x, y) & 0xFFFFFF;
}

String hexColor = String.format("#%06x", rgb);
String pixel = "█";
text.append(hexColor).append(pixel);
x += stepSize;
}

loreList.add(text.toString());
y += stepSize;
x = 0;
}

StringBuilder stringBuilder = new StringBuilder();
for (String loreText : loreList) {
String translatedColor = ColorUtil.translateHexToColor(loreText);
stringBuilder.append(translatedColor).append("\n");
}

addHoverText(stringBuilder.toString());

return true;
}

private static int clamp(int value, int min, int max) {
return Math.max(min, Math.min(value, max));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import lombok.Getter;
import lombok.Setter;
import net.flectone.chat.component.FImageComponent;
import org.bukkit.ChatColor;

import java.util.ArrayList;
Expand All @@ -15,6 +16,8 @@ public class WordParams {
private String playerPingName;
private String urlText;
private String hideMessage;
private FImageComponent imageComponent;
private boolean isImage;
private boolean clickable;
private boolean isHide;
private boolean isPlayerPing;
Expand Down Expand Up @@ -45,7 +48,7 @@ public String getChatColor(String param) {
}

public boolean isEdited() {
return isPlayerPing() || isHide() || isUrl() || isClickable() || isItem() || isCords() || isStats() || isPing();
return isPlayerPing() || isHide() || isUrl() || isClickable() || isItem() || isCords() || isStats() || isPing() || isImage();
}

public void addParameters(List<String> parameters) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,21 @@ private void splitStringToWordParams(@Nullable Player sender, @NotNull String co
}
}

if (isAsync
&& isUrlAllowed(sender, word)
&& config.getVaultBoolean(sender, this + ".list.url.image.enable")
&& !hasNoPermission(sender, "url.image")) {
FImageComponent fImageComponent = new FImageComponent(word);
if (fImageComponent.isCorrect()) {
word = config.getVaultString(sender, this + ".list.url.image.format")
.replace("<image>", fImageComponent.getText());
wordParams.setText(word);
wordParams.setImageComponent(fImageComponent);
wordParams.setImage(true);
return wordParams;
}
}

Matcher urlMatcher = Pattern.compile(formattingMap.get("url")).matcher(word);
if (urlMatcher.find()) {
wordParams.setUrlText(word.substring(urlMatcher.start(0), urlMatcher.end(0)));
Expand Down Expand Up @@ -328,4 +343,18 @@ private void splitStringToWordParams(@Nullable Player sender, @NotNull String co
}
}

public boolean isUrlAllowed(@Nullable CommandSender player, @NotNull String urlString) {
Pattern pattern = Pattern.compile("^(?:https?://)?([^/]+)");
Matcher matcher = pattern.matcher(urlString);

if (matcher.find()) {
String host = matcher.group(1).toLowerCase();
return FlectoneChat.getPlugin().getFileManager()
.getConfig()
.getVaultStringList(player, this + ".list.url.image.whitelist-site")
.contains(host);
}

return false;
}
}
9 changes: 9 additions & 0 deletions src/main/resources/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,15 @@ default:

markdown-support: true

image:
enable: true

format: "&&1🎨<image>"

whitelist-site:
- "cdn.discordapp.com"
- "i.imgur.com"

trigger: ((https?|ftp|gopher|telnet|file):((//)|(\\))+[\w:#@%/;$()~_?+-=\\.&]*)

format: "&&1<message>"
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ permissions:
default: true
flectonechat.player-message.formatting.markdown-url:
default: true
flectonechat.player-message.formatting.url.image:
default: true
flectonechat.player-message.formatting.item:
default: true
flectonechat.player-message.formatting.mention:
Expand Down

0 comments on commit 3e8d613

Please sign in to comment.