Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
1 change: 1 addition & 0 deletions config/cli/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"inactiveDays": 7,
"updateInactive": false,
"profileUpdateInterval": 3,
"profileAPI": "mojang",
"minPlaytime": 60,
"excludeBanned": true,
"excludeOps": false,
Expand Down
1 change: 1 addition & 0 deletions config/plugin/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ players:
inactiveDays: 90
updateInactive: true
profileUpdateInterval: 3
profileAPI: "mojang"
minPlaytime: 60
excludeBanned: true
excludeOps: false
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/de/pdinklag/mcstats/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ public class Config {
private int playerCacheUUIDPrefix = 2;
private String defaultLanguage = "en";

private String profileAPI = "mojang";

public Config() {
}

Expand Down Expand Up @@ -177,4 +179,12 @@ public Path getEventsPath() {
public void setEventsPath(Path eventsPath) {
this.eventsPath = eventsPath;
}

public String getProfileAPI() {
return profileAPI;
}

public void setProfileAPI(String profileAPI) {
this.profileAPI = profileAPI;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package de.pdinklag.mcstats;

import de.pdinklag.mcstats.playerdb.API;
import de.pdinklag.mcstats.playerdb.APIRequestException;
import de.pdinklag.mcstats.playerdb.EmptyResponseException;

/**
* Provides player profiles via the PlayerDB API.
*/
public class PlayerDBAPIPlayerProfileProvider implements PlayerProfileProvider {
private final LogWriter log;

/**
* Constructs a new provider.
*/
public PlayerDBAPIPlayerProfileProvider(LogWriter log) {
this.log = log;
}

@Override
public PlayerProfile getPlayerProfile(Player player) {
if (player.getAccountType().maybeMojangAccount()) {
try {
PlayerProfile profile = API.requestPlayerProfile(player.getUuid());
player.setAccountType(AccountType.MOJANG);
return profile;
} catch (EmptyResponseException e) {
player.setAccountType(AccountType.OFFLINE);
} catch (APIRequestException e) {
log.writeError("PlayerDB API profile request for player failed: " + player.getUuid(), e);
}
}
return player.getProfile();
}
}
7 changes: 6 additions & 1 deletion src/main/java/de/pdinklag/mcstats/Updater.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,12 @@ public abstract class Updater {
private final Path dbPlayerlistPath;

protected PlayerProfileProvider getAuthenticProfileProvider() {
return new MojangAPIPlayerProfileProvider(log);
final String api = config.getProfileAPI();
if ("playerdb".equalsIgnoreCase(api)) {
return new PlayerDBAPIPlayerProfileProvider(log);
} else {
return new MojangAPIPlayerProfileProvider(log);
}
}

protected void gatherLocalProfileProviders(PlayerProfileProviderList providers) {
Expand Down
1 change: 1 addition & 0 deletions src/main/java/de/pdinklag/mcstats/bukkit/BukkitConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public BukkitConfig(Plugin plugin) {
setMinPlaytime(bukkitConfig.getInt("players.minPlaytime", getMinPlaytime()));
setUpdateInactive(bukkitConfig.getBoolean("players.updateInactive", isUpdateInactive()));
setProfileUpdateInterval(bukkitConfig.getInt("players.profileUpdateInterval", getProfileUpdateInterval()));
setProfileAPI(bukkitConfig.getString("players.profileAPI", getProfileAPI()));

setExcludeBanned(bukkitConfig.getBoolean("players.excludeBanned", isExcludeBanned()));
setExcludeOps(bukkitConfig.getBoolean("players.excludeOps", isExcludeOps()));
Expand Down
1 change: 1 addition & 0 deletions src/main/java/de/pdinklag/mcstats/cli/JSONConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public JSONConfig(Path jsonPath) throws IOException, JSONException {
setMinPlaytime(players.optInt("minPlaytime", getMinPlaytime()));
setUpdateInactive(players.optBoolean("updateInactive", isUpdateInactive()));
setProfileUpdateInterval(players.optInt("profileUpdateInterval", getProfileUpdateInterval()));
setProfileAPI(players.optString("profileAPI", getProfileAPI()));

setExcludeBanned(players.optBoolean("excludeBanned", isExcludeBanned()));
setExcludeOps(players.optBoolean("excludeOps", isExcludeOps()));
Expand Down
70 changes: 70 additions & 0 deletions src/main/java/de/pdinklag/mcstats/playerdb/API.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package de.pdinklag.mcstats.playerdb;

import java.net.URI;

import javax.net.ssl.HttpsURLConnection;

import org.json.JSONObject;

import de.pdinklag.mcstats.PlayerProfile;
import de.pdinklag.mcstats.util.StreamUtils;

/**
* PlayerDB API.
*/
public class API {
private static final String API_URL = "https://playerdb.co/api/player/minecraft/";
private static final String TEXTURES_URL_PREFIX = "https://textures.minecraft.net/texture/";
private static final String USER_AGENT = "MinecraftStats";

/**
* Requests a player profile from the PlayerDB API.
*
* @param id the UUID or username of the player in question
* @return the player profile associated to the given id
* @throws EmptyResponseException in case the PlayerDB API gives an empty response
* @throws APIRequestException in case any error occurs trying to request the
* profile
*/
public static PlayerProfile requestPlayerProfile(String id) throws EmptyResponseException, APIRequestException {
try {
final String response;
{
URI uri = URI.create(API_URL + id);
java.net.URL url = uri.toURL();
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setRequestProperty("User-Agent", USER_AGENT);
response = StreamUtils.readStreamFully(conn.getInputStream());
conn.disconnect();
}

if (response.isEmpty()) {
throw new EmptyResponseException();
}

JSONObject root = new JSONObject(response);
JSONObject data = root.optJSONObject("data");
JSONObject player = (data == null) ? null : data.optJSONObject("player");
if (player == null) {
throw new EmptyResponseException();
}

String name = player.optString("username", "");
if (name.isEmpty()) {
throw new EmptyResponseException();
}

String skin = null;
String skinTexture = player.optString("skin_texture", "");
if (skinTexture.startsWith(TEXTURES_URL_PREFIX) && skinTexture.length() > TEXTURES_URL_PREFIX.length()) {
skin = skinTexture.substring(TEXTURES_URL_PREFIX.length());
}

return new PlayerProfile(name, skin, System.currentTimeMillis());
} catch (EmptyResponseException e) {
throw e; // nb: delegate
} catch (Exception e) {
throw new APIRequestException(e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package de.pdinklag.mcstats.playerdb;

/**
* An exception raised while processing a PlayerDB API request.
*/
public class APIRequestException extends RuntimeException {
APIRequestException() {
}

APIRequestException(String message) {
super(message);
}

APIRequestException(Throwable cause) {
super(cause);
}

APIRequestException(String message, Throwable cause) {
super(message, cause);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package de.pdinklag.mcstats.playerdb;

/**
* Indicates an empty response from the PlayerDB API.
*/
public class EmptyResponseException extends RuntimeException {
EmptyResponseException() {
}
}