Add server icon route
All checks were successful
Deploy App / docker (ubuntu-latest, 2.44.0) (push) Successful in 1m11s

This commit is contained in:
Braydon 2024-04-07 23:17:46 -04:00
parent a5725849f3
commit 9315182e3c
8 changed files with 70 additions and 20 deletions

@ -10,7 +10,7 @@ A simple, yet useful RESTful API for Minecraft utilizing Springboot.
Hi there! Looking for usage? View the [Wiki](https://git.rainnny.club/Rainnny/RESTfulMC/wiki) for more information!
## TODO
- [ ] Server Icon Route
- [x] Server Icon Route
- [ ] Unit Tests
- [ ] Blacklist Checking
- [ ] HTTP Codes in wiki

@ -692,7 +692,7 @@ import java.net.URL;
* @author Braydon
*/
@UtilityClass
public final class PlayerUtils {
public final class ImageUtils {
public static final int SKIN_TEXTURE_SIZE = 64; // The skin of a skin texture
/**

@ -686,6 +686,8 @@ import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.Base64;
/**
* The controller for handling
* {@link MinecraftServer} related requests.
@ -696,6 +698,8 @@ import org.springframework.web.bind.annotation.*;
@RequestMapping(value = "/server", produces = MediaType.APPLICATION_JSON_VALUE)
@Log4j2(topic = "Server Controller")
public final class ServerController {
private static final String DEFAULT_SERVER_ICON = "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";
/**
* The Mojang service to use for server information.
*/
@ -715,9 +719,28 @@ public final class ServerController {
*/
@GetMapping("/{platform}/{hostname}")
@ResponseBody
public ResponseEntity<CachedMinecraftServer> getServer(@PathVariable @NonNull String platform,
@PathVariable @NonNull String hostname
) {
public ResponseEntity<CachedMinecraftServer> getServer(@PathVariable @NonNull String platform, @PathVariable @NonNull String hostname) {
return ResponseEntity.ofNullable(mojangService.getMinecraftServer(platform, hostname));
}
/**
* Get the server icon of a Minecraft
* server by its platform and hostname.
*
* @param platform the platform of the server
* @param hostname the hostname of the server
* @return the server icon
*/
@GetMapping("/icon/{platform}/{hostname}")
@ResponseBody
public ResponseEntity<byte[]> getServerIcon(@PathVariable @NonNull String platform, @PathVariable @NonNull String hostname) {
MinecraftServer.Favicon favicon = mojangService.getMinecraftServer(platform, hostname).getValue().getFavicon();
String icon = favicon == null ? DEFAULT_SERVER_ICON : favicon.getBase64(); // Get the server icon
if (favicon != null) { // Remove the data type from the server icon
icon = icon.substring(icon.indexOf(",") + 1);
}
return ResponseEntity.ok()
.contentType(MediaType.IMAGE_PNG)
.body(Base64.getDecoder().decode(icon));
}
}

@ -678,6 +678,7 @@ package me.braydon.mc.model;
import lombok.*;
import me.braydon.mc.common.ColorUtils;
import me.braydon.mc.config.AppConfig;
import me.braydon.mc.service.pinger.MinecraftServerPinger;
import me.braydon.mc.service.pinger.impl.BedrockMinecraftServerPinger;
import me.braydon.mc.service.pinger.impl.JavaMinecraftServerPinger;
@ -712,16 +713,16 @@ public class MinecraftServer {
*/
@NonNull private final Players players;
/**
* The favicon of this server, null if none.
*/
private final Favicon favicon;
/**
* The MOTD of this server.
*/
@NonNull private final MOTD motd;
/**
* The Base64 encoded icon of this server, null if no icon.
*/
private final String icon;
/**
* Player count data for a server.
*/
@ -759,6 +760,32 @@ public class MinecraftServer {
}
}
/**
* The favicon for a server.
*/
@AllArgsConstructor @Getter @ToString
public static class Favicon {
/**
* The raw Base64 encoded favicon.
*/
@NonNull private final String base64;
/**
* The URL to the favicon.
*/
@NonNull private final String url;
public static Favicon create(String base64, @NonNull Platform platform, @NonNull String hostname) {
if (base64 == null) { // No favicon to create
return null;
}
return new Favicon(
base64,
AppConfig.INSTANCE.getServerPublicUrl() + "/server/icon/" + platform.name().toLowerCase() + "/" + hostname
);
}
}
/**
* The MOTD for a server.
*/

@ -679,7 +679,7 @@ package me.braydon.mc.model;
import com.google.gson.JsonObject;
import com.google.gson.annotations.SerializedName;
import lombok.*;
import me.braydon.mc.common.PlayerUtils;
import me.braydon.mc.common.ImageUtils;
import me.braydon.mc.config.AppConfig;
import java.util.HashMap;
@ -754,7 +754,7 @@ public final class Skin {
*/
@AllArgsConstructor @Getter @ToString
public enum Part {
HEAD(8, 8, PlayerUtils.SKIN_TEXTURE_SIZE / 8, PlayerUtils.SKIN_TEXTURE_SIZE / 8);
HEAD(8, 8, ImageUtils.SKIN_TEXTURE_SIZE / 8, ImageUtils.SKIN_TEXTURE_SIZE / 8);
/**
* The coordinates of this part.

@ -686,7 +686,7 @@ import me.braydon.mc.model.MinecraftServer;
*/
public final class BedrockMinecraftServer extends MinecraftServer {
private BedrockMinecraftServer(@NonNull String hostname, String ip, int port, @NonNull Players players,
@NonNull MOTD motd, String icon) {
super(hostname, ip, port, players, motd, icon);
Favicon favicon, @NonNull MOTD motd) {
super(hostname, ip, port, players, favicon, motd);
}
}

@ -724,9 +724,9 @@ public final class JavaMinecraftServer extends MinecraftServer {
private final boolean mojangBanned;
private JavaMinecraftServer(@NonNull String hostname, String ip, int port, @NonNull Players players,
@NonNull MOTD motd, String icon, @NonNull Version version, ModInfo modInfo,
Favicon favicon, @NonNull MOTD motd, @NonNull Version version, ModInfo modInfo,
boolean enforcesSecureChat, boolean preventsChatReports, boolean mojangBanned) {
super(hostname, ip, port, players, motd, icon);
super(hostname, ip, port, players, favicon, motd);
this.version = version;
this.modInfo = modInfo;
this.enforcesSecureChat = enforcesSecureChat;
@ -749,9 +749,9 @@ public final class JavaMinecraftServer extends MinecraftServer {
if (motdString == null) { // Not a string motd, convert from Json
motdString = new TextComponent(ComponentSerializer.parse(RESTfulMC.GSON.toJson(token.getDescription()))).toLegacyText();
}
return new JavaMinecraftServer(hostname, ip, port, token.getPlayers(), MOTD.create(motdString),
token.getFavicon(), token.getVersion().detailedCopy(), token.getModInfo(),
token.isEnforcesSecureChat(), token.isPreventsChatReports(), false
return new JavaMinecraftServer(hostname, ip, port, token.getPlayers(), Favicon.create(token.getFavicon(), Platform.JAVA, hostname),
MOTD.create(motdString), token.getVersion().detailedCopy(), token.getModInfo(), token.isEnforcesSecureChat(),
token.isPreventsChatReports(), false
);
}

@ -850,7 +850,7 @@ public final class MojangService {
if (target == null) { // Fallback to the default skin
target = Skin.DEFAULT_STEVE;
}
return PlayerUtils.getSkinPart(target, part, size);
return ImageUtils.getSkinPart(target, part, size);
}
/**