-
-
Save natemort/26d70114b834f71fb3b4 to your computer and use it in GitHub Desktop.
| /* | |
| * Copyright (c) 2015 Nate Mortensen | |
| * | |
| * 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 com.evilmidget38; | |
| import com.google.common.collect.ImmutableList; | |
| import org.json.simple.JSONArray; | |
| import org.json.simple.JSONObject; | |
| import org.json.simple.parser.JSONParser; | |
| import java.io.InputStreamReader; | |
| import java.io.OutputStream; | |
| import java.net.HttpURLConnection; | |
| import java.net.URL; | |
| import java.nio.ByteBuffer; | |
| import java.util.*; | |
| import java.util.concurrent.Callable; | |
| public class UUIDFetcher implements Callable<Map<String, UUID>> { | |
| private static final double PROFILES_PER_REQUEST = 100; | |
| private static final String PROFILE_URL = "https://api.mojang.com/profiles/minecraft"; | |
| private final JSONParser jsonParser = new JSONParser(); | |
| private final List<String> names; | |
| private final boolean rateLimiting; | |
| public UUIDFetcher(List<String> names, boolean rateLimiting) { | |
| this.names = ImmutableList.copyOf(names); | |
| this.rateLimiting = rateLimiting; | |
| } | |
| public UUIDFetcher(List<String> names) { | |
| this(names, true); | |
| } | |
| public Map<String, UUID> call() throws Exception { | |
| Map<String, UUID> uuidMap = new HashMap<String, UUID>(); | |
| int requests = (int) Math.ceil(names.size() / PROFILES_PER_REQUEST); | |
| for (int i = 0; i < requests; i++) { | |
| HttpURLConnection connection = createConnection(); | |
| String body = JSONArray.toJSONString(names.subList(i * 100, Math.min((i + 1) * 100, names.size()))); | |
| writeBody(connection, body); | |
| JSONArray array = (JSONArray) jsonParser.parse(new InputStreamReader(connection.getInputStream())); | |
| for (Object profile : array) { | |
| JSONObject jsonProfile = (JSONObject) profile; | |
| String id = (String) jsonProfile.get("id"); | |
| String name = (String) jsonProfile.get("name"); | |
| UUID uuid = UUIDFetcher.getUUID(id); | |
| uuidMap.put(name, uuid); | |
| } | |
| if (rateLimiting && i != requests - 1) { | |
| Thread.sleep(100L); | |
| } | |
| } | |
| return uuidMap; | |
| } | |
| private static void writeBody(HttpURLConnection connection, String body) throws Exception { | |
| OutputStream stream = connection.getOutputStream(); | |
| stream.write(body.getBytes()); | |
| stream.flush(); | |
| stream.close(); | |
| } | |
| private static HttpURLConnection createConnection() throws Exception { | |
| URL url = new URL(PROFILE_URL); | |
| HttpURLConnection connection = (HttpURLConnection) url.openConnection(); | |
| connection.setRequestMethod("POST"); | |
| connection.setRequestProperty("Content-Type", "application/json"); | |
| connection.setUseCaches(false); | |
| connection.setDoInput(true); | |
| connection.setDoOutput(true); | |
| return connection; | |
| } | |
| private static UUID getUUID(String id) { | |
| return UUID.fromString(id.substring(0, 8) + "-" + id.substring(8, 12) + "-" + id.substring(12, 16) + "-" + id.substring(16, 20) + "-" +id.substring(20, 32)); | |
| } | |
| public static byte[] toBytes(UUID uuid) { | |
| ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[16]); | |
| byteBuffer.putLong(uuid.getMostSignificantBits()); | |
| byteBuffer.putLong(uuid.getLeastSignificantBits()); | |
| return byteBuffer.array(); | |
| } | |
| public static UUID fromBytes(byte[] array) { | |
| if (array.length != 16) { | |
| throw new IllegalArgumentException("Illegal byte array length: " + array.length); | |
| } | |
| ByteBuffer byteBuffer = ByteBuffer.wrap(array); | |
| long mostSignificant = byteBuffer.getLong(); | |
| long leastSignificant = byteBuffer.getLong(); | |
| return new UUID(mostSignificant, leastSignificant); | |
| } | |
| public static UUID getUUIDOf(String name) throws Exception { | |
| return new UUIDFetcher(Arrays.asList(name)).call().get(name); | |
| } | |
| } |
Thank you so much for providing this. It works great for 85% of the users in our db. I checked a handful of the users it failed on and they all seem to have 1 thing in common. They're all usernames that have been renamed.
EDIT: After checking over the mojang web api for acquiring UUIDs i see that the bulk retrieve method isn't intended to lookup former names. If a username fails in the bulk retrive then i just request it individually with the &at=0 query string:
https://api.mojang.com/users/profiles/minecraft/player&at=0
This works great for me as it only retruns the original uuid of that account. If you have usernames that have possibly been renamed and then acquired by a different uuid then you'll need to make use of the name history method in conjunction with the &at= method. Be aware of the request limit of 600 per 10 minutes (1 per second).
This doesn't appear to work anymore :/, returning html error 400, with the exact code copy, pasted and checked.