Compare commits

...
16 Commits
Author SHA1 Message Date
Andre601 f9574d2f83 Add DISCORD_WEBHOOK_URL env variable to workflow 2024-02-22 13:42:41 +01:00
Andre601 7e45439dfe Merge pull request 'Make better local favicon handling' (#230) from feature/better-local-favicon-handling into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/230
2024-02-22 12:41:03 +00:00
Andre601 2a8b4ed640 Optimize Imports 2024-02-22 13:32:29 +01:00
Andre601 86c053e445 Remove unused createFavicon method in GenericEventWrapper 2024-02-22 13:29:39 +01:00
Andre601 7eba04bb9a Make better local favicon handling 2024-02-22 13:27:27 +01:00
Andre601 b4ac677f67 Merge pull request 'Update dependency org.apache.maven.plugins:maven-shade-plugin to v3.5.2' (#228) from renovate/org.apache.maven.plugins-maven-shade-plugin-3.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/228
2024-02-21 12:15:13 +00:00
Andre601 989d44cc5e Merge pull request 'Update dependency net.kyori:adventure-text-serializer-legacy to v4.16.0' (#229) from renovate/net.kyori-adventure-text-serializer-legacy-4.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/229
2024-02-21 12:15:00 +00:00
Andre601's Renovate Bot 9821875e7a Update dependency net.kyori:adventure-text-serializer-legacy to v4.16.0 2024-02-21 12:01:15 +00:00
Andre601's Renovate Bot 07e3b6702b Update dependency org.apache.maven.plugins:maven-shade-plugin to v3.5.2 2024-02-21 12:01:09 +00:00
Andre601 31889fbd9c Merge pull request 'Update dependency net.kyori:adventure-text-minimessage to v4.16.0' (#227) from renovate/net.kyori-adventure-text-minimessage-4.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/227
2024-02-20 12:12:40 +00:00
Andre601 87a089a0fa Merge pull request 'Update dependency net.kyori:adventure-api to v4.16.0' (#226) from renovate/net.kyori-adventure-api-4.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/226
2024-02-20 12:12:14 +00:00
Andre601 88b91e8859 Add AdvancedBan to special registry lookup 2024-02-20 12:09:55 +00:00
Andre601's Renovate Bot f8097e3c72 Update dependency net.kyori:adventure-text-minimessage to v4.16.0 2024-02-20 12:01:39 +00:00
Andre601's Renovate Bot e237c990d8 Update dependency net.kyori:adventure-api to v4.16.0 2024-02-20 12:01:33 +00:00
Andre601 21c0ba975c Merge pull request 'Update dependency mkdocs-material to v9.5.10' (#225) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/225
2024-02-19 12:02:37 +00:00
Andre601's Renovate Bot 642ce922c3 Update dependency mkdocs-material to v9.5.10 2024-02-19 12:01:15 +00:00
36 changed files with 361 additions and 193 deletions

No files matched your search

+2
View File
@@ -12,6 +12,8 @@ steps:
target: modrinth_api_token
- source: hangar_api_token
target: hangar_api_token
- source: discord_webhook_url
target: discord_webhook_url
commands:
# Create the jar files.
- mvn clean install
@@ -25,8 +25,8 @@
package ch.andre601.advancedserverlist.banplugins.bungeecord;
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
import ch.andre601.advancedserverlist.api.AdvancedServerListAPI;
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
import net.md_5.bungee.api.plugin.Plugin;
import java.util.Map;
@@ -25,10 +25,10 @@
package ch.andre601.advancedserverlist.banplugins.placeholders;
import ch.andre601.advancedserverlist.banplugins.providers.AdvancedBanProvider;
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.banplugins.providers.AdvancedBanProvider;
import java.util.Arrays;
@@ -44,7 +44,7 @@ public class AdvancedBanPlaceholders extends PlaceholderProvider{
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
String[] args = placeholder.split("\\s");
return switch(placeholder) {
return switch(args[0]) {
// Mute-related placeholders
case "isMuted" -> String.valueOf(provider.muted(player));
case "muteReason" -> provider.muteReason(player);
@@ -27,8 +27,6 @@ package ch.andre601.advancedserverlist.banplugins.providers;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import java.time.format.DateTimeFormatter;
public interface PunishmentProvider{
boolean muted(GenericPlayer player);
+3 -3
View File
@@ -81,13 +81,13 @@
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-api</artifactId>
<version>4.15.0</version>
<version>4.16.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-text-minimessage</artifactId>
<version>4.15.0</version>
<version>4.16.0</version>
<scope>compile</scope>
</dependency>
<dependency>
@@ -127,7 +127,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.1</version>
<version>3.5.2</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
@@ -40,6 +40,7 @@ import net.md_5.bungee.api.plugin.Plugin;
import org.bstats.bungeecord.Metrics;
import org.bstats.charts.SimplePie;
import java.awt.image.BufferedImage;
import java.nio.file.Path;
public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
@@ -77,12 +78,17 @@ public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
}
@Override
public void loadFaviconHandler(AdvancedServerList<Favicon> core){
faviconHandler = new FaviconHandler<>(core);
}
@Override
public void clearFaviconCache(){
if(faviconHandler == null)
return;
faviconHandler.clearCache();
faviconHandler.cleanCache();
}
@Override
@@ -122,4 +128,9 @@ public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
public String getLoader(){
return "bungeecord";
}
@Override
public Favicon createFavicon(BufferedImage image) throws IllegalArgumentException{
return Favicon.create(image);
}
}
@@ -25,11 +25,11 @@
package ch.andre601.advancedserverlist.bungeecord.listeners;
import ch.andre601.advancedserverlist.api.events.GenericServerListEvent;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
import ch.andre601.advancedserverlist.bungeecord.objects.BungeePlayerImpl;
import ch.andre601.advancedserverlist.api.events.GenericServerListEvent;
import ch.andre601.advancedserverlist.bungeecord.objects.BungeeProxyImpl;
import ch.andre601.advancedserverlist.core.events.PingEventHandler;
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
@@ -46,7 +46,6 @@ import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.ProxyPingEvent;
import java.awt.image.BufferedImage;
import java.net.InetSocketAddress;
import java.util.List;
import java.util.Map;
@@ -205,9 +204,4 @@ public class BungeeEventWrapper implements GenericEventWrapper<Favicon, BungeePl
return new BungeeProxyImpl(servers, playersOnline, playersMax, host);
}
@Override
public Favicon createFavicon(BufferedImage image) throws IllegalArgumentException{
return Favicon.create(image);
}
}
+5 -5
View File
@@ -41,7 +41,7 @@
<properties>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
<plugin.config.version>3</plugin.config.version>
<plugin.config.version>4</plugin.config.version>
</properties>
<repositories>
@@ -77,19 +77,19 @@
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-api</artifactId>
<version>4.15.0</version>
<version>4.16.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-text-minimessage</artifactId>
<version>4.15.0</version>
<version>4.16.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-text-serializer-legacy</artifactId>
<version>4.15.0</version>
<version>4.16.0</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -151,7 +151,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.1</version>
<version>3.5.2</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<filters>
@@ -36,7 +36,6 @@ import ch.andre601.advancedserverlist.core.profiles.players.PlayerHandler;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
@@ -148,9 +147,7 @@ public class AdvancedServerList<F>{
return;
}
Path folder = getPlugin().getFolderPath().resolve("favicons");
if(!folder.toFile().exists() && folder.toFile().mkdirs())
getPlugin().getPluginLogger().info("Successfully created favicons folder.");
getPlugin().loadFaviconHandler(this);
getPlugin().getPluginLogger().info("Loading Commands...");
plugin.loadCommands();
@@ -27,7 +27,10 @@ package ch.andre601.advancedserverlist.core.compat.papi;
import net.william278.papiproxybridge.api.PlaceholderAPI;
import java.util.*;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
@@ -30,10 +30,10 @@ import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import ch.andre601.advancedserverlist.core.compat.maintenance.MaintenanceUtil;
import ch.andre601.advancedserverlist.core.compat.papi.PAPIUtil;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
import ch.andre601.advancedserverlist.core.interfaces.events.GenericEventWrapper;
import ch.andre601.advancedserverlist.core.compat.papi.PAPIUtil;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileManager;
@@ -148,26 +148,18 @@ public class PingEventHandler{
if(ProfileManager.checkOption(entry.favicon())){
logger.debug(PingEventHandler.class, "Favicon set. Resolving '%s'...", entry.favicon());
String favicon = StringReplacer.replace(entry.favicon(), player, server);
String faviconString = StringReplacer.replace(entry.favicon(), player, server);
F fav = plugin.getFaviconHandler().getFavicon(favicon, image -> {
try{
logger.debug(PingEventHandler.class, "Converting BufferedImage to Server or Proxy Favicon instance...");
return event.createFavicon(image);
}catch(Exception ex){
plugin.getPluginLogger().warn("Encountered an Exception while creating Favicon!", ex);
return null;
}
});
F favicon = plugin.getFaviconHandler().getFavicon(faviconString);
if(fav == null){
if(favicon == null){
logger.debugWarn(PingEventHandler.class, "Favicon was invalid or not yet resolved! Using default favicon of Server/Proxy...");
event.setDefaultFavicon();
}else{
logger.debug(PingEventHandler.class, "Applying favicon...");
event.setFavicon(fav);
event.setFavicon(favicon);
}
}
@@ -46,18 +46,29 @@ public class ConfigMigrator{
public static ConfigurationTransformation.Versioned create(){
return ConfigurationTransformation.versionedBuilder()
.versionKey("configVersion")
.addVersion(LATEST, twoToThree())
.addVersion(LATEST, threeToFour())
.addVersion(3, twoToThree())
.addVersion(2, oneToTwo())
.build();
}
public static ConfigurationTransformation threeToFour(){
return ConfigurationTransformation.builder()
.addAction(NodePath.path(), (path, value) -> {
value.node("faviconCacheTime").set(1);
return null;
})
.build();
}
public static ConfigurationTransformation twoToThree(){
return ConfigurationTransformation.builder()
.addAction(NodePath.path(), ((path, value) -> {
.addAction(NodePath.path(), (path, value) -> {
value.node("debug").set(false);
return null;
}))
})
.build();
}
@@ -25,10 +25,10 @@
package ch.andre601.advancedserverlist.core.file;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileSerializer;
import org.spongepowered.configurate.ConfigurateException;
import org.spongepowered.configurate.ConfigurationNode;
@@ -191,6 +191,11 @@ public class FileHandler{
return node.node(path).getBoolean();
}
public long getLong(long def, long limit, Object... path){
long value = node.node(path).getLong(def);
return Math.max(value, limit);
}
public boolean isOldConfig(){
return node.node("configVersion").virtual() || node.node("configVersion").getInt(0) < ConfigMigrator.LATEST;
}
@@ -29,6 +29,7 @@ import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.profiles.favicon.FaviconHandler;
import java.awt.image.BufferedImage;
import java.nio.file.Path;
public interface PluginCore<F>{
@@ -39,6 +40,8 @@ public interface PluginCore<F>{
void loadMetrics();
void loadFaviconHandler(AdvancedServerList<F> core);
void clearFaviconCache();
AdvancedServerList<F> getCore();
@@ -55,7 +58,12 @@ public interface PluginCore<F>{
String getLoader();
F createFavicon(BufferedImage image) throws Exception;
default boolean isDebugEnabled(){
if(getCore() == null)
return false;
return getCore().getFileHandler().getBoolean("debug");
}
}
@@ -25,15 +25,14 @@
package ch.andre601.advancedserverlist.core.interfaces.events;
import ch.andre601.advancedserverlist.api.events.GenericServerListEvent;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import ch.andre601.advancedserverlist.api.events.GenericServerListEvent;
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
import net.kyori.adventure.text.Component;
import java.awt.image.BufferedImage;
import java.net.InetSocketAddress;
import java.util.List;
@@ -79,8 +78,6 @@ public interface GenericEventWrapper<F, P extends GenericPlayer>{
GenericServer createGenericServer(int playersOnline, int playersMax, String host);
F createFavicon(BufferedImage image) throws Exception;
default String resolveHost(InetSocketAddress address){
return address == null ? null : address.getHostString();
}
@@ -27,7 +27,6 @@ package ch.andre601.advancedserverlist.core.profiles.conditions;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.profiles.conditions.expressions.ExpressionsWarnHelper;
import ch.andre601.advancedserverlist.core.profiles.conditions.tokens.Token;
import ch.andre601.advancedserverlist.core.profiles.conditions.tokens.readers.TokenReader;
@@ -70,7 +69,7 @@ public class ExpressionTokenizer{
}
}
warnHelper.appendWarning(position.getIndex(), "Illegal token '%c'.");
warnHelper.appendWarning(position.getIndex(), "Illegal token '%c'.", text.charAt(position.getIndex()));
break;
}
@@ -27,7 +27,6 @@ package ch.andre601.advancedserverlist.core.profiles.conditions.expressions;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.profiles.conditions.ExpressionTokenizer;
import ch.andre601.advancedserverlist.core.profiles.conditions.operators.ListOperator;
import ch.andre601.advancedserverlist.core.profiles.conditions.operators.Operator;
@@ -26,145 +26,167 @@
package ch.andre601.advancedserverlist.core.profiles.favicon;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.*;
import java.util.function.Function;
import java.util.stream.Stream;
public class FaviconHandler<F>{
private final Cache<String, CompletableFuture<F>> favicons = CacheBuilder.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES)
.build();
private final AdvancedServerList<F> core;
private final PluginLogger logger;
private final ThreadPoolExecutor faviconThreadPool;
private final Cache<String, CompletableFuture<F>> faviconCache;
private final Map<String, F> localFavicons = new HashMap<>();
private final HttpClient client = HttpClient.newHttpClient();
public FaviconHandler(AdvancedServerList<F> core){
this.core = core;
this.logger = core.getPlugin().getPluginLogger();
this.faviconThreadPool = createFaviconThreadPool();
this.faviconCache = CacheBuilder.newBuilder()
.expireAfterWrite(core.getFileHandler().getLong(1, 1, "faviconCacheTime"), TimeUnit.MINUTES)
.build();
loadLocalFavicons();
}
public F getFavicon(String input, Function<BufferedImage, F> function){
public F getFavicon(String input){
if(localFavicons.containsKey(input.toLowerCase(Locale.ROOT).split("\\.")[0])){
return localFavicons.get(input.toLowerCase(Locale.ROOT).split("\\.")[0]);
}
try{
return favicons.get(input, () -> convert(input, function)).getNow(null);
}catch(ExecutionException e){
return faviconCache.get(input, () -> getFuture(input)).getNow(null);
}catch(ExecutionException ex){
logger.warn("Received ExecutionException while retrieving Favicon for '%s'.", ex, input);
return null;
}
}
public void clearCache(){
favicons.invalidateAll();
public void cleanCache(){
faviconCache.invalidateAll();
loadLocalFavicons();
}
private CompletableFuture<F> convert(String input, Function<BufferedImage, F> function){
return CompletableFuture.supplyAsync(() -> {
core.getPlugin().getPluginLogger().debug(FaviconHandler.class, "Getting BufferedImage for input '%s'...", input);
BufferedImage img = resolveImage(core, input);
if(img == null){
core.getPlugin().getPluginLogger().debugWarn(FaviconHandler.class, "No BufferedImage could be created!");
return null;
}
core.getPlugin().getPluginLogger().debug(FaviconHandler.class, "Received BufferedImage! Applying it...");
return function.apply(img);
}, faviconThreadPool);
}
private BufferedImage resolveImage(AdvancedServerList<F> core, String input){
core.getPlugin().getPluginLogger().debug(FaviconHandler.class, "Resolving favicon for input '%s'...", input);
InputStream stream;
private CompletableFuture<F> getFuture(String input){
if(input.toLowerCase(Locale.ROOT).startsWith("https://")){
core.getPlugin().getPluginLogger().debug(FaviconHandler.class, "URL detected. Getting file from it...");
stream = getFromUrl(core, input);
logger.debug(FaviconHandler.class, "Resolving URL '%s'...", input);
return CompletableFuture.supplyAsync(() -> fromURL(core, input), this.faviconThreadPool);
}else
if(input.toLowerCase(Locale.ROOT).endsWith(".png")){
core.getPlugin().getPluginLogger().debug(FaviconHandler.class, "Image file detected. Trying to reolve it...");
File folder = core.getPlugin().getFolderPath().resolve("favicons").toFile();
if(!folder.exists()){
core.getPlugin().getPluginLogger().warn("Cannot get Favicon %s from favicons folder. Folder doesn't exist!", input);
return null;
}
File file = new File(folder, input);
try{
stream = new FileInputStream(file);
core.getPlugin().getPluginLogger().debug(FaviconHandler.class, "Resolved image file!");
}catch(IOException ex){
core.getPlugin().getPluginLogger().warn("Cannot create Favicon from File %s.", input);
core.getPlugin().getPluginLogger().warn("Cause: %s", ex.getMessage());
return null;
}
logger.debug(FaviconHandler.class, "Resolving image file '%s'...", input);
return CompletableFuture.completedFuture(localFavicons.get(input.toLowerCase(Locale.ROOT).split("\\.")[0]));
}else{
core.getPlugin().getPluginLogger().debug(FaviconHandler.class, "Possible player name/UUID detected. Using https://mc-heads.net/avatar/%s/64...", input);
stream = getFromUrl(core, "https://mc-heads.net/avatar/" + input + "/64");
logger.debug(FaviconHandler.class, "Resolving Name/UUID as https://mc-heads.net/avatar/%s/64...", input);
return CompletableFuture.supplyAsync(() -> fromURL(core, "https://mc-heads.net/avatar/" + input + "/64"), this.faviconThreadPool);
}
}
private void loadLocalFavicons(){
this.localFavicons.clear();
logger.info("Loading local image files as Favicons...");
Path folder = core.getPlugin().getFolderPath().resolve("favicons");
if(!Files.exists(folder)){
try{
Files.createDirectories(folder);
logger.info("Created favicons folder.");
}catch(IOException ex){
logger.warn("Cannot create favicons folder. Encountered an IOException.", ex);
return;
}
}
if(stream == null){
core.getPlugin().getPluginLogger().warn("Cannot create Favicon. InputStream was null.");
return null;
try(Stream<Path> pathStream = Files.list(folder)){
pathStream.filter(Files::isRegularFile)
.filter(file -> file.getFileName().toString().endsWith(".png"))
.forEach(this::loadFile);
}catch(IOException ex){
logger.warn("Cannot load files from Favicons folder.", ex);
}
try{
BufferedImage original = ImageIO.read(stream);
if(original == null){
core.getPlugin().getPluginLogger().warn("Cannot create Favicon. Unable to create BufferedImage.");
return null;
}
private void loadFile(Path path){
try(InputStream stream = Files.newInputStream(path)){
F favicon = createFavicon(stream);
if(favicon == null){
logger.warn("Cannot create Favicon from file '%s'. Received Favicon was null.", path.getFileName().toString());
return;
}
core.getPlugin().getPluginLogger().debug(FaviconHandler.class, "Resizing image to 64x64 pixels...");
BufferedImage favicon = new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB);
Graphics2D img = favicon.createGraphics();
// Resize original image to 64x64 and apply to favicon.
img.drawImage(original, 0, 0, 64, 64, null);
img.dispose();
core.getPlugin().getPluginLogger().debug(FaviconHandler.class, "Image resized!");
return favicon;
localFavicons.put(path.getFileName().toString().split("\\.")[0], favicon);
logger.info("Loaded file '%s' as Favicon.", path.getFileName().toString());
}catch(IOException ex){
core.getPlugin().getPluginLogger().warn("Unable to create Favicon. Encountered IOException during creation.");
core.getPlugin().getPluginLogger().warn("Cause: %s", ex.getMessage());
logger.warn("Cannot create Favicon from file '%s'. Encountered IOException.", ex);
}
}
private F fromURL(AdvancedServerList<F> core, String url){
try{
logger.debug(FaviconHandler.class, "Creating Request for URL '%s'...", url);
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI(url))
.header("User-Agent", "AdvancedServerList-" + core.getPlugin().getLoader() + "/" + core.getVersion())
.build();
try(InputStream stream = client.send(request, HttpResponse.BodyHandlers.ofInputStream()).body()){
return createFavicon(stream);
}catch(InterruptedException | IOException ex){
logger.warn("Cannot create Favicon from URL '%s'. Encountered an Exception.", ex, url);
return null;
}
}catch(URISyntaxException ex){
logger.warn("Cannot create Favicon from URL '%s'. Encountered an IOException.", ex, url);
return null;
}
}
private InputStream getFromUrl(AdvancedServerList<F> core, String url){
private F createFavicon(InputStream stream){
try{
core.getPlugin().getPluginLogger().debug(FaviconHandler.class, "Resolving URL '%s'...", url);
logger.debug(FaviconHandler.class, "Creating BufferedImage from InputStream...");
BufferedImage original = ImageIO.read(stream);
if(original == null){
logger.warn("Cannot create Favicon. Received null BufferedImage.");
return null;
}
URL faviconUrl = new URL(url);
URLConnection connection = faviconUrl.openConnection();
connection.setRequestProperty("User-Agent", "AdvancedServerList/" + core.getVersion());
connection.connect();
// Don't waste resources resizing images already having right size.
if(original.getWidth() == 64 && original.getHeight() == 64){
logger.debug(FaviconHandler.class, "BufferedImage is 64x64 pixels. No resizing needed.");
return core.getPlugin().createFavicon(original);
}
core.getPlugin().getPluginLogger().debug(FaviconHandler.class, "URL resolved!");
return connection.getInputStream();
}catch(IOException ex){
core.getPlugin().getPluginLogger().warn("Error while connecting to %s for Favicon creation.", url);
core.getPlugin().getPluginLogger().warn("Cause: %s", ex.getMessage());
logger.debug(FaviconHandler.class, "Resizing image to 64x64 pixels...");
BufferedImage image = new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics2D = image.createGraphics();
graphics2D.drawImage(original, 0, 0, 64, 64, null);
graphics2D.dispose();
logger.debug(FaviconHandler.class, "Image resized! Returning Favicon...");
return core.getPlugin().createFavicon(image);
}catch(Exception ex){
logger.warn("Unable to create Favicon. Received Exception.", ex);
return null;
}
}
@@ -38,7 +38,9 @@ import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class PlayerHandler{
@@ -28,9 +28,9 @@ package ch.andre601.advancedserverlist.core.profiles.profile;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.api.objects.NullBool;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.serialize.SerializationException;
@@ -25,11 +25,11 @@
package ch.andre601.advancedserverlist.core.profiles.profile;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.serialize.SerializationException;
import org.spongepowered.configurate.serialize.TypeSerializer;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import java.lang.reflect.Type;
+8
View File
@@ -42,6 +42,14 @@ checkUpdates: true
#
debug: false
#
# Sets the time in minutes for favicons to be cached.
# The number cannot be less than 1.
#
# Defaults to 1 if not set.
#
faviconCacheTime: 1
#
# DO NOT EDIT!
#
+1 -1
View File
@@ -117,7 +117,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.1</version>
<version>3.5.2</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
@@ -42,6 +42,7 @@ import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.util.CachedServerIcon;
import java.awt.image.BufferedImage;
import java.nio.file.Path;
public class PaperCore extends JavaPlugin implements PluginCore<CachedServerIcon>{
@@ -107,12 +108,17 @@ public class PaperCore extends JavaPlugin implements PluginCore<CachedServerIcon
));
}
@Override
public void loadFaviconHandler(AdvancedServerList<CachedServerIcon> core){
faviconHandler = new FaviconHandler<>(core);
}
@Override
public void clearFaviconCache(){
if(faviconHandler == null)
return;
faviconHandler.clearCache();
faviconHandler.cleanCache();
}
@Override
@@ -153,6 +159,11 @@ public class PaperCore extends JavaPlugin implements PluginCore<CachedServerIcon
return "paper";
}
@Override
public CachedServerIcon createFavicon(BufferedImage image) throws Exception{
return Bukkit.loadServerIcon(image);
}
public WorldCache getWorldCache(){
if(worldCache != null)
return worldCache;
@@ -45,8 +45,9 @@ import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.util.CachedServerIcon;
import java.awt.image.BufferedImage;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon, PaperPlayerImpl>{
@@ -186,9 +187,4 @@ public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon,
public GenericServer createGenericServer(int playersOnline, int playersMax, String host){
return new PaperServerImpl(plugin.getWorldCache().worlds(), playersOnline, playersMax, host);
}
@Override
public CachedServerIcon createFavicon(BufferedImage image) throws Exception{
return Bukkit.loadServerIcon(image);
}
}
+1 -1
View File
@@ -38,7 +38,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.build.commit/>
<plugin.version>4.0.0</plugin.version>
<plugin.version>4.1.0</plugin.version>
<plugin.description>Create multiple Server lists based on conditions.</plugin.description>
<api.version>v3.1.0</api.version>
+2 -1
View File
@@ -12,7 +12,8 @@
"ch.andre601.asl-api:platform-bukkit",
"ch.andre601.asl-api:platform-bungeecord",
"ch.andre601.asl-api:platform-velocity",
"ch.andre601.asl-api:api"
"ch.andre601.asl-api:api",
"com.github.DevLeoko:AdvancedBan"
],
"registryUrls": [
"https://jitpack.io"
+1 -1
View File
@@ -1,4 +1,4 @@
mkdocs-material==9.5.9
mkdocs-material==9.5.10
mkdocs-glightbox==0.3.7
mkdocs-awesome-pages-plugin==2.9.2
git+https://github.com/Andre601/mkdocs-pagenav-generator
+1 -1
View File
@@ -100,7 +100,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.1</version>
<version>3.5.2</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
@@ -47,6 +47,7 @@ import org.bstats.charts.SimplePie;
import org.bstats.velocity.Metrics;
import org.slf4j.LoggerFactory;
import java.awt.image.BufferedImage;
import java.nio.file.Path;
public class VelocityCore implements PluginCore<Favicon>{
@@ -101,12 +102,17 @@ public class VelocityCore implements PluginCore<Favicon>{
));
}
@Override
public void loadFaviconHandler(AdvancedServerList<Favicon> core){
faviconHandler = new FaviconHandler<>(core);
}
@Override
public void clearFaviconCache(){
if(faviconHandler == null)
return;
faviconHandler.clearCache();
faviconHandler.cleanCache();
}
@Override
@@ -147,6 +153,11 @@ public class VelocityCore implements PluginCore<Favicon>{
return "velocity";
}
@Override
public Favicon createFavicon(BufferedImage image) throws Exception{
return Favicon.create(image);
}
public ProxyServer getProxy(){
return proxy;
}
@@ -44,7 +44,6 @@ import com.velocitypowered.api.proxy.server.ServerPing;
import com.velocitypowered.api.util.Favicon;
import net.kyori.adventure.text.Component;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -205,9 +204,4 @@ public class VelocityEventWrapper implements GenericEventWrapper<Favicon, Veloci
return new VelocityProxyImpl(servers, playersOnline, playersMax, host);
}
@Override
public Favicon createFavicon(BufferedImage image){
return Favicon.create(image);
}
}
+7 -1
View File
@@ -73,6 +73,12 @@
<version>2.0.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>club.minnced</groupId>
<artifactId>discord-webhooks</artifactId>
<version>0.8.2</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
@@ -109,7 +115,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.1</version>
<version>3.5.2</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
@@ -0,0 +1,42 @@
/*
* MIT License
*
* Copyright (c) 2022-2024 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.versionuploader;
import java.util.HashMap;
import java.util.Map;
public class ModrinthRelease{
Map<String, String> releases = new HashMap<>();
public void addRelease(String platform, String id){
releases.put(platform, id);
}
public Map<String, String> getReleases(){
return releases;
}
}
@@ -29,12 +29,18 @@ import ch.andre601.advancedserverlist.versionuploader.data.CodebergRelease;
import ch.andre601.advancedserverlist.versionuploader.data.CodebergReleaseFetcher;
import ch.andre601.advancedserverlist.versionuploader.hangar.HangarVersionUploader;
import ch.andre601.advancedserverlist.versionuploader.modrinth.ModrinthVersionUploader;
import club.minnced.discord.webhook.WebhookClient;
import club.minnced.discord.webhook.WebhookClientBuilder;
import club.minnced.discord.webhook.receive.ReadonlyMessage;
import club.minnced.discord.webhook.send.WebhookEmbed;
import club.minnced.discord.webhook.send.WebhookEmbedBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.CompletableFuture;
@@ -47,7 +53,7 @@ public class VersionUploader{
if(args.length == 0){
LOGGER.warn("MISSING ARGUMENT!");
LOGGER.warn("COMMAND USAGE: java -jar VersionUploader.jar [--all|--modrinth|--hangar]");
LOGGER.warn("COMMAND USAGE: java -jar VersionUploader.jar <--all|--modrinth|--hangar> [--dryrun]");
System.exit(1);
return;
}
@@ -60,32 +66,28 @@ public class VersionUploader{
return;
}
boolean dryrun = false;
if(args.length >= 2){
dryrun = args[1].equalsIgnoreCase("--dryrun");
}
CompletableFuture<?> future;
ModrinthRelease modrinthRelease = null;
switch(args[0].toLowerCase(Locale.ROOT)){
case "--modrinth" -> future = new ModrinthVersionUploader().performUpload(release, false);
case "--hangar" -> future = new HangarVersionUploader().performUpload(release, false);
case "--all" -> future = CompletableFuture.allOf(
new ModrinthVersionUploader().performUpload(release, false),
new HangarVersionUploader().performUpload(release, false)
);
case "--dryrun" -> {
LOGGER.info("Performing Dry-run for Modrinth and Hangar...");
case "--modrinth" -> {
modrinthRelease = new ModrinthRelease();
future = new ModrinthVersionUploader().performUpload(release, modrinthRelease, dryrun);
}
case "--hangar" -> future = new HangarVersionUploader().performUpload(release, dryrun);
case "--all" -> {
modrinthRelease = new ModrinthRelease();
future = CompletableFuture.allOf(
new ModrinthVersionUploader().performUpload(release, true),
new HangarVersionUploader().performUpload(release, true)
new ModrinthVersionUploader().performUpload(release, modrinthRelease, dryrun),
new HangarVersionUploader().performUpload(release, dryrun)
);
try{
future.join();
}catch(Exception ex){
LOGGER.warn("Exception while waiting for CompletableFutures to end...", ex);
}
LOGGER.info("Dry-run completed!");
return;
}
default -> {
LOGGER.warn("Unknown argument '{}' provided. Supported are '--all', '--modrinth', '--hangar' and '--dryrun'", args[0]);
LOGGER.warn("Unknown argument '{}' provided. Supported are '--all', '--modrinth' or '--hangar'", args[0]);
System.exit(1);
return;
}
@@ -99,11 +101,62 @@ public class VersionUploader{
try{
future.join();
LOGGER.info("Upload completed!");
if(dryrun){
LOGGER.info("Dryrun complete!");
}else{
LOGGER.info("Upload completed!");
}
}catch(Exception ex){
LOGGER.warn("Upload was not successful! Encountered an Exception!", ex);
System.exit(1);
}
if(modrinthRelease == null || modrinthRelease.getReleases().isEmpty()){
LOGGER.warn("No Modrinth release info on Discord to share... Skipping.");
return;
}
String webhookUrl = System.getenv("DISCORD_WEBHOOK_URL");
if(webhookUrl == null || webhookUrl.isEmpty()){
LOGGER.warn("No valid DISCORD_WEBHOOK_URL Environment Variable found. Skipping Webhook sending.");
return;
}
WebhookEmbedBuilder builder = new WebhookEmbedBuilder()
.setTitle(new WebhookEmbed.EmbedTitle("New Release", null))
.setDescription("A new release of AdvancedServerList is available on Modrinth for you to download!")
.setColor(0x1BD96A);
for(Map.Entry<String, String> entry : modrinthRelease.getReleases().entrySet()){
builder.addField(new WebhookEmbed.EmbedField(
false,
entry.getKey(),
"https://modrinth.com/plugin/advancedserverlist/version/" + entry.getValue()
));
}
try(WebhookClient client = new WebhookClientBuilder(webhookUrl).build()){
CompletableFuture<ReadonlyMessage> webhookFuture = client.send(builder.build()).whenComplete((readonlyMessage, throwable) -> {
if(throwable != null){
LOGGER.warn("Error while sending webhook message!", throwable);
System.exit(1);
return;
}
LOGGER.info("Webhook message send!");
client.close();
});
try{
webhookFuture.join();
}catch(Exception ex){
LOGGER.warn("Unable to complete webhook message sending!", ex);
System.exit(1);
}
}catch(Exception ex){
LOGGER.warn("Encountered Exception while creating WebhookClient!", ex);
System.exit(1);
}
}
public static String retrieveVersion(){
@@ -28,8 +28,10 @@ package ch.andre601.advancedserverlist.versionuploader.hangar;
import ch.andre601.advancedserverlist.versionuploader.PlatformInfo;
import ch.andre601.advancedserverlist.versionuploader.VersionUploader;
import ch.andre601.advancedserverlist.versionuploader.data.CodebergRelease;
import ch.andre601.advancedserverlist.versionuploader.hangar.version.*;
import ch.andre601.advancedserverlist.versionuploader.hangar.version.Dependency;
import ch.andre601.advancedserverlist.versionuploader.hangar.version.MultipartObject;
import ch.andre601.advancedserverlist.versionuploader.hangar.version.Platform;
import ch.andre601.advancedserverlist.versionuploader.hangar.version.Version;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
@@ -25,6 +25,7 @@
package ch.andre601.advancedserverlist.versionuploader.modrinth;
import ch.andre601.advancedserverlist.versionuploader.ModrinthRelease;
import ch.andre601.advancedserverlist.versionuploader.PlatformInfo;
import ch.andre601.advancedserverlist.versionuploader.VersionUploader;
import ch.andre601.advancedserverlist.versionuploader.data.CodebergRelease;
@@ -61,7 +62,7 @@ public class ModrinthVersionUploader{
this.api = createClient();
}
public CompletableFuture<?> performUpload(CodebergRelease release, boolean dryrun){
public CompletableFuture<?> performUpload(CodebergRelease release, ModrinthRelease modrinthRelease, boolean dryrun){
LOGGER.info("Starting ModrinthVersionUploader...");
if(api == null){
@@ -130,6 +131,7 @@ public class ModrinthVersionUploader{
continue;
}
final int index = i;
futures[i] = api.versions().createProjectVersion(builder.build()).whenComplete(((projectVersion, throwable) -> {
if(throwable != null){
LOGGER.warn("Encountered an exception while uploading a new release to Modrinth!", throwable);
@@ -138,6 +140,8 @@ public class ModrinthVersionUploader{
LOGGER.info("Created new release!");
LOGGER.info("Link: https://modrinth.com/plugin/advancedserverlist/version/{}", projectVersion.getId());
modrinthRelease.addRelease(String.join(", ", platforms.get(index).getLoaders()), projectVersion.getId());
}));
}