Add online (aka ReplayCenter) module
Add localization extra (formally known as LocalizedResourcePack) Add version checker extra
This commit is contained in:
268
src/main/java/com/replaymod/online/api/ApiClient.java
Executable file
268
src/main/java/com/replaymod/online/api/ApiClient.java
Executable file
@@ -0,0 +1,268 @@
|
||||
package com.replaymod.online.api;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.mojang.authlib.exceptions.AuthenticationException;
|
||||
import com.replaymod.core.ReplayMod;
|
||||
import com.replaymod.online.api.replay.ReplayModApiMethods;
|
||||
import com.replaymod.online.api.replay.SearchQuery;
|
||||
import com.replaymod.online.api.replay.holders.*;
|
||||
import eu.crushedpixel.replaymod.gui.elements.listeners.ProgressUpdateListener;
|
||||
import com.replaymod.online.AuthenticationHash;
|
||||
import eu.crushedpixel.replaymod.utils.Api;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
|
||||
public class ApiClient {
|
||||
|
||||
private static final Minecraft mc = Minecraft.getMinecraft();
|
||||
private static final Gson gson = new Gson();
|
||||
private static final JsonParser jsonParser = new JsonParser();
|
||||
|
||||
private final AuthData authData;
|
||||
|
||||
public ApiClient(AuthData authData) {
|
||||
this.authData = authData;
|
||||
}
|
||||
|
||||
public boolean isLoggedIn() {
|
||||
return authData.getUserName() != null && authData.getAuthKey() != null;
|
||||
}
|
||||
|
||||
public String getAuthKey() {
|
||||
return authData.getAuthKey();
|
||||
}
|
||||
|
||||
public void register(String userName, String eMail, String password) throws AuthenticationException, IOException, ApiException {
|
||||
AuthenticationHash authenticationHash = sessionserverJoin();
|
||||
|
||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.register);
|
||||
builder.put("username", userName);
|
||||
builder.put("email", eMail);
|
||||
builder.put("password", password);
|
||||
builder.put("uuid", mc.getSession().getProfile().getId().toString());
|
||||
builder.put("mcusername", authenticationHash.username);
|
||||
builder.put("timelong", authenticationHash.currentTime);
|
||||
builder.put("randomlong", authenticationHash.randomLong);
|
||||
AuthKey auth = invokeAndReturn(builder, AuthKey.class);
|
||||
|
||||
authData.setData(userName, auth.getAuth());
|
||||
}
|
||||
|
||||
public AuthData.AuthResult login(String userName, String password) {
|
||||
try {
|
||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.login);
|
||||
builder.put("user", userName);
|
||||
builder.put("pw", password);
|
||||
builder.put("mod", true);
|
||||
AuthKey result = invokeAndReturn(builder, AuthKey.class);
|
||||
authData.setData(userName, result.getAuth());
|
||||
return AuthData.AuthResult.SUCCESS;
|
||||
} catch(ApiException e) {
|
||||
return AuthData.AuthResult.INVALID_DATA;
|
||||
} catch(Exception e) {
|
||||
return AuthData.AuthResult.IO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
public AuthData.AuthResult logout() {
|
||||
try {
|
||||
authData.setData(null, null);
|
||||
|
||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.logout);
|
||||
builder.put("auth", authData.getAuthKey());
|
||||
builder.put("mod", true);
|
||||
invokeAndReturn(builder, Success.class);
|
||||
return AuthData.AuthResult.SUCCESS;
|
||||
} catch(ApiException e) {
|
||||
return AuthData.AuthResult.INVALID_DATA;
|
||||
} catch(Exception e) {
|
||||
return AuthData.AuthResult.IO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
private AuthenticationHash sessionserverJoin() throws AuthenticationException {
|
||||
AuthenticationHash hash = new AuthenticationHash();
|
||||
|
||||
mc.getSessionService().joinServer(
|
||||
mc.getSession().getProfile(), mc.getSession().getToken(), hash.hash);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
public AuthConfirmation checkAuthkey(String auth) {
|
||||
try {
|
||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.check_authkey);
|
||||
builder.put("auth", auth);
|
||||
return invokeAndReturn(builder, AuthConfirmation.class);
|
||||
} catch(Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public FileInfo[] getFileInfo(List<Integer> ids) throws IOException, ApiException {
|
||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.file_details);
|
||||
builder.put("id", buildListString(ids));
|
||||
return invokeAndReturn(builder, FileInfo[].class);
|
||||
}
|
||||
|
||||
public FileInfo[] searchFiles(SearchQuery query) throws IOException, ApiException {
|
||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.search);
|
||||
return invokeAndReturn(builder.toString() + query.buildQuery(), SearchResult.class).getResults();
|
||||
}
|
||||
|
||||
public String getTranslation(String languageCode) throws IOException, ApiException {
|
||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.get_language);
|
||||
builder.put("language", languageCode);
|
||||
return SimpleApiClient.invokeUrl(builder.toString());
|
||||
}
|
||||
|
||||
public BufferedImage downloadThumbnail(int file) throws IOException {
|
||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.get_thumbnail);
|
||||
builder.put("id", file);
|
||||
URL url = new URL(builder.toString());
|
||||
return ImageIO.read(url);
|
||||
}
|
||||
|
||||
private boolean cancelDownload = false;
|
||||
|
||||
public void downloadFile(int file, File target, ProgressUpdateListener listener) throws IOException, ApiException {
|
||||
cancelDownload = false;
|
||||
|
||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.download_file);
|
||||
builder.put("auth", authData.getAuthKey());
|
||||
builder.put("id", file);
|
||||
String url = builder.toString();
|
||||
URL website = new URL(url);
|
||||
HttpURLConnection con = (HttpURLConnection) website.openConnection();
|
||||
|
||||
int fileSize = con.getContentLength();
|
||||
|
||||
InputStream is = con.getInputStream();
|
||||
|
||||
if(con.getResponseCode() == 200) {
|
||||
BufferedInputStream bin = new BufferedInputStream(is);
|
||||
FileOutputStream fout = new FileOutputStream(target);
|
||||
try {
|
||||
final byte data[] = new byte[1024];
|
||||
int count;
|
||||
int read = 0;
|
||||
while ((count = bin.read(data, 0, 1024)) != -1) {
|
||||
if(cancelDownload) {
|
||||
bin.close();
|
||||
fout.close();
|
||||
|
||||
FileUtils.deleteQuietly(target);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
fout.write(data, 0, count);
|
||||
read += count;
|
||||
listener.onProgressChanged((float)(read)/fileSize);
|
||||
}
|
||||
} finally {
|
||||
bin.close();
|
||||
fout.close();
|
||||
}
|
||||
} else {
|
||||
JsonElement element = jsonParser.parse(IOUtils.toString(is));
|
||||
try {
|
||||
ApiError err = gson.fromJson(element, ApiError.class);
|
||||
if(err.getDesc() != null) {
|
||||
throw new ApiException(err);
|
||||
}
|
||||
} catch(JsonParseException e) {
|
||||
throw new ApiException(IOUtils.toString(is));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void cancelDownload() {
|
||||
this.cancelDownload = true;
|
||||
}
|
||||
|
||||
public void rateFile(int file, Rating.RatingType rating) throws IOException, ApiException {
|
||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.rate_file);
|
||||
builder.put("auth", authData.getAuthKey());
|
||||
builder.put("id", file);
|
||||
builder.put("rating", rating.getKey());
|
||||
invokeAndReturn(builder, Success.class);
|
||||
}
|
||||
|
||||
public FileRating[] getRatedFiles() throws IOException, ApiException {
|
||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.get_ratings);
|
||||
builder.put("auth", authData.getAuthKey());
|
||||
|
||||
return invokeAndReturn(builder, RatedFiles.class).getRated();
|
||||
}
|
||||
|
||||
public void favFile(int file, boolean fav) throws IOException, ApiException {
|
||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.fav_file);
|
||||
builder.put("auth", authData.getAuthKey());
|
||||
builder.put("id", file);
|
||||
builder.put("fav", fav);
|
||||
invokeAndReturn(builder, Success.class);
|
||||
}
|
||||
|
||||
public int[] getFavorites() throws IOException, ApiException {
|
||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.get_favorites);
|
||||
builder.put("auth", authData.getAuthKey());
|
||||
|
||||
return invokeAndReturn(builder, Favorites.class).getFavorited();
|
||||
}
|
||||
|
||||
@Api
|
||||
public void removeFile(int file) throws IOException, ApiException {
|
||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.remove_file);
|
||||
builder.put("auth", authData.getAuthKey());
|
||||
builder.put("id", file);
|
||||
invokeAndReturn(builder, Success.class);
|
||||
}
|
||||
|
||||
public boolean isVersionUpToDate(String versionIdentifier) throws IOException, ApiException {
|
||||
//in a development environment, getContainer().getVersion() will return ${version}
|
||||
if(versionIdentifier.equals("${version}")) return true;
|
||||
|
||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.up_to_date);
|
||||
builder.put("version", versionIdentifier);
|
||||
builder.put("minecraft", ReplayMod.getMinecraftVersion());
|
||||
return invokeAndReturn(builder, Success.class).isSuccess();
|
||||
}
|
||||
|
||||
private <T> T invokeAndReturn(QueryBuilder builder, Class<T> classOfT) throws IOException, ApiException {
|
||||
return invokeAndReturn(builder.toString(), classOfT);
|
||||
}
|
||||
|
||||
private <T> T invokeAndReturn(String url, Class<T> classOfT) throws IOException, ApiException {
|
||||
JsonElement ele = GsonApiClient.invokeJson(url);
|
||||
return gson.fromJson(ele, classOfT);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private String buildListString(List idList) {
|
||||
if(idList == null) return null;
|
||||
|
||||
String ids = "";
|
||||
Integer x = 0;
|
||||
for(Object id : idList) {
|
||||
x++;
|
||||
ids += id.toString();
|
||||
if(x != idList.size()) {
|
||||
ids += ",";
|
||||
}
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
}
|
||||
28
src/main/java/com/replaymod/online/api/ApiException.java
Executable file
28
src/main/java/com/replaymod/online/api/ApiException.java
Executable file
@@ -0,0 +1,28 @@
|
||||
package com.replaymod.online.api;
|
||||
|
||||
import com.replaymod.online.api.replay.holders.ApiError;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ApiException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 349073390504232810L;
|
||||
|
||||
private ApiError error;
|
||||
|
||||
public ApiException(ApiError error) {
|
||||
super(error.getTranslatedDesc());
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public ApiException(String error) {
|
||||
super(error);
|
||||
}
|
||||
|
||||
public ApiError getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
}
|
||||
45
src/main/java/com/replaymod/online/api/AuthData.java
Normal file
45
src/main/java/com/replaymod/online/api/AuthData.java
Normal file
@@ -0,0 +1,45 @@
|
||||
package com.replaymod.online.api;
|
||||
|
||||
/**
|
||||
* Represents a set of persistent authentication data.
|
||||
*/
|
||||
public interface AuthData {
|
||||
/**
|
||||
* Returns the user name of the authenticated user.
|
||||
* @return user name or {@code null} if not logged in
|
||||
*/
|
||||
String getUserName();
|
||||
|
||||
/**
|
||||
* Returns the authentication key of the authenticated user.
|
||||
* @return auth key or {@code null} if not logged in
|
||||
*/
|
||||
String getAuthKey();
|
||||
|
||||
/**
|
||||
* Store the authentication data after login.
|
||||
* @param userName The user name
|
||||
* @param authKey The authentication key
|
||||
*/
|
||||
void setData(String userName, String authKey);
|
||||
|
||||
/**
|
||||
* Result of authentication operations.
|
||||
*/
|
||||
enum AuthResult {
|
||||
/**
|
||||
* The operation succeeded without errors.
|
||||
*/
|
||||
SUCCESS,
|
||||
|
||||
/**
|
||||
* The data provided got rejected due to it being invalid.
|
||||
*/
|
||||
INVALID_DATA,
|
||||
|
||||
/**
|
||||
* Operation could not be performed due to connectivity problems.
|
||||
*/
|
||||
IO_ERROR,
|
||||
}
|
||||
}
|
||||
26
src/main/java/com/replaymod/online/api/GsonApiClient.java
Executable file
26
src/main/java/com/replaymod/online/api/GsonApiClient.java
Executable file
@@ -0,0 +1,26 @@
|
||||
package com.replaymod.online.api;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParser;
|
||||
import org.apache.commons.lang3.StringEscapeUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class GsonApiClient {
|
||||
|
||||
private static final JsonParser parser = new JsonParser();
|
||||
|
||||
public static JsonElement invoke(QueryBuilder query) throws IOException, ApiException {
|
||||
String apiResult = SimpleApiClient.invoke(query);
|
||||
return wrapWithJson(apiResult);
|
||||
}
|
||||
|
||||
public static JsonElement invokeJson(String url) throws IOException, ApiException {
|
||||
String apiResult = StringEscapeUtils.unescapeHtml4(SimpleApiClient.invokeUrl(url).replace(""", "\\\""));
|
||||
return wrapWithJson(apiResult);
|
||||
}
|
||||
|
||||
private static JsonElement wrapWithJson(String apiResult) {
|
||||
return parser.parse(apiResult);
|
||||
}
|
||||
}
|
||||
60
src/main/java/com/replaymod/online/api/QueryBuilder.java
Executable file
60
src/main/java/com/replaymod/online/api/QueryBuilder.java
Executable file
@@ -0,0 +1,60 @@
|
||||
package com.replaymod.online.api;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class QueryBuilder {
|
||||
|
||||
public String apiMethod;
|
||||
public Map<String, String> paramMap;
|
||||
|
||||
public QueryBuilder(String apiMethod) {
|
||||
this.apiMethod = apiMethod;
|
||||
}
|
||||
|
||||
public void put(String key, Object value) {
|
||||
if(key != null && value != null) {
|
||||
if(paramMap == null) {
|
||||
paramMap = new HashMap<String, String>();
|
||||
}
|
||||
paramMap.put(key, value.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public void put(Map<String, Object> paraMap) {
|
||||
if(paraMap == null) return;
|
||||
for(String key : paraMap.keySet()) {
|
||||
put(key, paraMap.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if(apiMethod == null) throw new IllegalArgumentException("apiMethod may not be null");
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
// build base url
|
||||
sb.append(apiMethod);
|
||||
|
||||
// process parameters
|
||||
try {
|
||||
if(paramMap != null) {
|
||||
boolean first = true;
|
||||
for(String paramName : paramMap.keySet()) {
|
||||
if(first) sb.append("?");
|
||||
if(!first) sb.append("&");
|
||||
first = false;
|
||||
sb.append(paramName);
|
||||
sb.append("=");
|
||||
String value = paramMap.get(paramName);
|
||||
sb.append(URLEncoder.encode(value, "UTF-8"));
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
} catch(UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
123
src/main/java/com/replaymod/online/api/SimpleApiClient.java
Executable file
123
src/main/java/com/replaymod/online/api/SimpleApiClient.java
Executable file
@@ -0,0 +1,123 @@
|
||||
package com.replaymod.online.api;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.replaymod.online.api.replay.holders.ApiError;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
|
||||
public class SimpleApiClient {
|
||||
|
||||
private static final JsonParser jsonParser = new JsonParser();
|
||||
private static final Gson gson = new Gson();
|
||||
|
||||
/**
|
||||
* Returns a Json String from the given QueryBuilder
|
||||
*
|
||||
* @param query The QueryBuilder to use
|
||||
* @return A Json String from the API
|
||||
* @throws IOException
|
||||
* @throws ApiException
|
||||
*/
|
||||
public static String invoke(QueryBuilder query) throws IOException, ApiException {
|
||||
return invokeImpl(query.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Json String from the given URL
|
||||
*
|
||||
* @param url The URL to parse the Json from
|
||||
* @return A Json String from the API
|
||||
* @throws IOException
|
||||
* @throws ApiException
|
||||
*/
|
||||
public static String invokeUrl(String url) throws IOException, ApiException {
|
||||
return invokeImpl(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Json String from the API
|
||||
*
|
||||
* @param method The apiMethod to be called
|
||||
* @param paramMap The parameters to apply
|
||||
* @return A Json String from the API
|
||||
* @throws IOException
|
||||
* @throws ApiException
|
||||
*/
|
||||
public static String invoke(String method, Map<String, Object> paramMap) throws IOException, ApiException {
|
||||
return invokeImpl(method, paramMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Json String from the API
|
||||
*
|
||||
* @param method The apiMethod to be called
|
||||
* @return A Json String from the API
|
||||
* @throws IOException
|
||||
* @throws ApiException
|
||||
*/
|
||||
public static String invoke(String method) throws IOException, ApiException {
|
||||
return invokeImpl(method, null);
|
||||
}
|
||||
|
||||
private static String invokeImpl(String urlString) throws IOException, ApiException {
|
||||
|
||||
// read response
|
||||
String responseContent = null;
|
||||
InputStream is = null;
|
||||
HttpURLConnection httpUrlConnection = null;
|
||||
try {
|
||||
URL url = new URL(urlString);
|
||||
httpUrlConnection = (HttpURLConnection) url.openConnection();
|
||||
|
||||
httpUrlConnection.setRequestMethod("GET");
|
||||
|
||||
// give it 15 seconds to respond
|
||||
httpUrlConnection.setReadTimeout(15 * 1000);
|
||||
httpUrlConnection.connect();
|
||||
|
||||
int responseCode = httpUrlConnection.getResponseCode();
|
||||
|
||||
if(responseCode != 200) {
|
||||
is = httpUrlConnection.getErrorStream();
|
||||
if(is != null) {
|
||||
responseContent = IOUtils.toString(is, "UTF-8");
|
||||
} else {
|
||||
responseContent = "";
|
||||
}
|
||||
try {
|
||||
JsonObject response = jsonParser.parse(responseContent).getAsJsonObject();
|
||||
throw new ApiException(gson.fromJson(response, ApiError.class));
|
||||
} catch(JsonParseException e) {
|
||||
throw new ApiException(responseContent);
|
||||
}
|
||||
}
|
||||
|
||||
is = httpUrlConnection.getInputStream();
|
||||
|
||||
responseContent = IOUtils.toString(is, "UTF-8");
|
||||
|
||||
} finally {
|
||||
if(is != null) {
|
||||
is.close();
|
||||
}
|
||||
if(httpUrlConnection != null) {
|
||||
httpUrlConnection.disconnect();
|
||||
}
|
||||
}
|
||||
return responseContent;
|
||||
}
|
||||
|
||||
private static String invokeImpl(String method, Map<String, Object> paramMap) throws IOException, ApiException {
|
||||
QueryBuilder queryBuilder = new QueryBuilder(method);
|
||||
queryBuilder.put(paramMap);
|
||||
return invokeImpl(queryBuilder.toString());
|
||||
}
|
||||
}
|
||||
159
src/main/java/com/replaymod/online/api/replay/FileUploader.java
Executable file
159
src/main/java/com/replaymod/online/api/replay/FileUploader.java
Executable file
@@ -0,0 +1,159 @@
|
||||
package com.replaymod.online.api.replay;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.replaymod.online.api.ApiClient;
|
||||
import com.replaymod.online.api.replay.holders.ApiError;
|
||||
import com.replaymod.online.api.replay.holders.Category;
|
||||
import com.replaymod.online.gui.GuiUploadFile;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.List;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class FileUploader {
|
||||
private static final Gson gson = new Gson();
|
||||
|
||||
private final ApiClient apiClient;
|
||||
|
||||
private boolean uploading = false;
|
||||
private long filesize;
|
||||
private long current;
|
||||
|
||||
private boolean cancel = false;
|
||||
|
||||
private GuiUploadFile parent;
|
||||
|
||||
public void uploadFile(GuiUploadFile gui, String filename, List<String> tags, File file, Category category, String description) {
|
||||
boolean success = false;
|
||||
String info = null;
|
||||
|
||||
try {
|
||||
parent = gui;
|
||||
gui.onStartUploading();
|
||||
filesize = 0;
|
||||
|
||||
if(uploading) throw new RuntimeException("FileUploader is already uploading");
|
||||
uploading = true;
|
||||
|
||||
String postData = "?auth=" + apiClient.getAuthKey() + "&category=" + category.getId();
|
||||
|
||||
if(tags.size() > 0) {
|
||||
postData += "&tags=";
|
||||
for(String tag : tags) {
|
||||
postData += tag;
|
||||
if(!tag.equals(tags.get(tags.size() - 1))) {
|
||||
postData += ",";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(description != null && description.length() > 0) {
|
||||
postData += "&description=" + URLEncoder.encode(description, "UTF-8");
|
||||
}
|
||||
|
||||
postData += "&name=" + URLEncoder.encode(filename, "UTF-8");
|
||||
|
||||
String url = ReplayModApiMethods.upload_file + postData;
|
||||
HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
|
||||
con.setUseCaches(false);
|
||||
con.setDoOutput(true);
|
||||
con.setRequestMethod("POST");
|
||||
con.setChunkedStreamingMode(1024);
|
||||
con.setRequestProperty("Connection", "Keep-Alive");
|
||||
con.setRequestProperty("Cache-Control", "no-cache");
|
||||
String boundary = "*****";
|
||||
con.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
|
||||
|
||||
DataOutputStream request = new DataOutputStream(con.getOutputStream());
|
||||
|
||||
String crlf = "\r\n";
|
||||
String twoHyphens = "--";
|
||||
request.writeBytes(twoHyphens + boundary + crlf);
|
||||
String attachmentName = "file";
|
||||
String attachmentFileName = "file.mcpr";
|
||||
request.writeBytes("Content-Disposition: form-data; name=\"" + attachmentName + "\";filename=\"" + attachmentFileName + "\"" + crlf);
|
||||
request.writeBytes(crlf);
|
||||
|
||||
byte[] buf = new byte[1024];
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
filesize = fis.getChannel().size();
|
||||
current = 0;
|
||||
int len;
|
||||
while((len = fis.read(buf)) != -1) {
|
||||
request.write(buf);
|
||||
current += len;
|
||||
|
||||
parent.onProgressChanged(getUploadProgress());
|
||||
|
||||
if(cancel) {
|
||||
parent.onProgressChanged(0f);
|
||||
|
||||
uploading = false;
|
||||
current = 0;
|
||||
cancel = false;
|
||||
parent.onFinishUploading(false, I18n.format("replaymod.gui.upload.canceled"));
|
||||
fis.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
fis.close();
|
||||
|
||||
request.writeBytes(crlf);
|
||||
request.writeBytes(twoHyphens + boundary + twoHyphens + crlf);
|
||||
|
||||
request.flush();
|
||||
request.close();
|
||||
|
||||
success = false;
|
||||
int responseCode = con.getResponseCode();
|
||||
InputStream is;
|
||||
if(responseCode == 200) {
|
||||
success = true;
|
||||
is = con.getInputStream();
|
||||
} else {
|
||||
success = false;
|
||||
is = con.getErrorStream();
|
||||
}
|
||||
|
||||
if(is != null) {
|
||||
BufferedReader r = new BufferedReader(new InputStreamReader(is));
|
||||
info = null;
|
||||
String result = "";
|
||||
while(r.ready()) {
|
||||
result += r.readLine();
|
||||
}
|
||||
if(responseCode != 200) {
|
||||
ApiError error = gson.fromJson(result, ApiError.class);
|
||||
info = error.getTranslatedDesc();
|
||||
}
|
||||
}
|
||||
con.disconnect();
|
||||
|
||||
if(info == null) info = I18n.format("replaymod.gui.unknownerror");
|
||||
} catch(Exception e) {
|
||||
success = false;
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
parent.onFinishUploading(success, info);
|
||||
uploading = false;
|
||||
}
|
||||
}
|
||||
|
||||
public float getUploadProgress() {
|
||||
if(!uploading || filesize == 0) return 0;
|
||||
return (float) ((double) current / (double) filesize);
|
||||
}
|
||||
|
||||
public boolean isUploading() {
|
||||
return uploading;
|
||||
}
|
||||
|
||||
public void cancelUploading() {
|
||||
cancel = true;
|
||||
}
|
||||
}
|
||||
24
src/main/java/com/replaymod/online/api/replay/ReplayModApiMethods.java
Executable file
24
src/main/java/com/replaymod/online/api/replay/ReplayModApiMethods.java
Executable file
@@ -0,0 +1,24 @@
|
||||
package com.replaymod.online.api.replay;
|
||||
|
||||
public class ReplayModApiMethods {
|
||||
|
||||
public static final String REPLAYMOD_BASE_URL = "http://ReplayMod.com/api/";
|
||||
|
||||
public static final String register = REPLAYMOD_BASE_URL+"register";
|
||||
public static final String check_authkey = REPLAYMOD_BASE_URL+"check_authkey";
|
||||
public static final String login = REPLAYMOD_BASE_URL+"login";
|
||||
public static final String logout = REPLAYMOD_BASE_URL+"logout";
|
||||
public static final String file_details = REPLAYMOD_BASE_URL+"file_details";
|
||||
public static final String upload_file = REPLAYMOD_BASE_URL+"upload_file";
|
||||
public static final String download_file = REPLAYMOD_BASE_URL+"download_file";
|
||||
public static final String get_thumbnail = REPLAYMOD_BASE_URL+"get_thumbnail";
|
||||
public static final String remove_file = REPLAYMOD_BASE_URL+"remove_file";
|
||||
public static final String rate_file = REPLAYMOD_BASE_URL+"rate_file";
|
||||
public static final String get_ratings = REPLAYMOD_BASE_URL+"get_ratings";
|
||||
public static final String fav_file = REPLAYMOD_BASE_URL+"fav_file";
|
||||
public static final String get_favorites = REPLAYMOD_BASE_URL+"get_favorites";
|
||||
public static final String check_auth = REPLAYMOD_BASE_URL+"check_auth";
|
||||
public static final String get_language = REPLAYMOD_BASE_URL+"get_language";
|
||||
public static final String search = REPLAYMOD_BASE_URL+"search";
|
||||
public static final String up_to_date = REPLAYMOD_BASE_URL+"up_to_date";
|
||||
}
|
||||
43
src/main/java/com/replaymod/online/api/replay/SearchQuery.java
Executable file
43
src/main/java/com/replaymod/online/api/replay/SearchQuery.java
Executable file
@@ -0,0 +1,43 @@
|
||||
package com.replaymod.online.api.replay;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class SearchQuery {
|
||||
|
||||
public Boolean order, singleplayer;
|
||||
public String player, tag, version, server, name, auth;
|
||||
public Integer category, offset;
|
||||
|
||||
public String buildQuery() {
|
||||
String query = "";
|
||||
boolean first = true;
|
||||
|
||||
//Please don't slaughter me for this code,
|
||||
//even if I deserve it, which I certainly do.
|
||||
for(Field f : this.getClass().getDeclaredFields()) {
|
||||
try {
|
||||
Object value = f.get(this);
|
||||
if(value == null) continue;
|
||||
query += first ? "?" : "&";
|
||||
first = false;
|
||||
query += f.getName() + "=";
|
||||
query += URLEncoder.encode(String.valueOf(value), "UTF-8");
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return buildQuery();
|
||||
}
|
||||
}
|
||||
22
src/main/java/com/replaymod/online/api/replay/holders/ApiError.java
Executable file
22
src/main/java/com/replaymod/online/api/replay/holders/ApiError.java
Executable file
@@ -0,0 +1,22 @@
|
||||
package com.replaymod.online.api.replay.holders;
|
||||
|
||||
import lombok.Data;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
|
||||
@Data
|
||||
public class ApiError {
|
||||
|
||||
private int id;
|
||||
private String desc;
|
||||
private String key;
|
||||
private String[] objects;
|
||||
|
||||
public String getTranslatedDesc() {
|
||||
try {
|
||||
return I18n.format(key, (Object[]) objects);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
return desc;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.replaymod.online.api.replay.holders;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class AuthConfirmation {
|
||||
private String username;
|
||||
private int id;
|
||||
}
|
||||
12
src/main/java/com/replaymod/online/api/replay/holders/AuthKey.java
Executable file
12
src/main/java/com/replaymod/online/api/replay/holders/AuthKey.java
Executable file
@@ -0,0 +1,12 @@
|
||||
package com.replaymod.online.api.replay.holders;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class AuthKey {
|
||||
private String auth;
|
||||
}
|
||||
53
src/main/java/com/replaymod/online/api/replay/holders/Category.java
Executable file
53
src/main/java/com/replaymod/online/api/replay/holders/Category.java
Executable file
@@ -0,0 +1,53 @@
|
||||
package com.replaymod.online.api.replay.holders;
|
||||
|
||||
import net.minecraft.client.resources.I18n;
|
||||
|
||||
public enum Category {
|
||||
|
||||
SURVIVAL(0, "replaymod.category.survival"), MINIGAME(1, "replaymod.category.minigame"),
|
||||
BUILD(2, "replaymod.category.build"), MISCELLANEOUS(3, "replaymod.category.misc");
|
||||
|
||||
private int id;
|
||||
private String name;
|
||||
|
||||
Category(int id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public static Category fromId(int id) {
|
||||
for(Category c : values()) {
|
||||
if(c.id == id) return c;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String toNiceString() {
|
||||
return I18n.format(this.name);
|
||||
}
|
||||
|
||||
public Category next() {
|
||||
for(int i = 0; i < values().length; i++) {
|
||||
if(values()[i] == this) {
|
||||
if(i == values().length - 1) {
|
||||
i = -1;
|
||||
}
|
||||
return values()[i + 1];
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public static String[] stringValues() {
|
||||
String[] values = new String[Category.values().length];
|
||||
int i = 0;
|
||||
for (Category c : Category.values()) {
|
||||
values[i++] = c.toNiceString();
|
||||
}
|
||||
return values;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.replaymod.online.api.replay.holders;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
|
||||
@Data
|
||||
public class Donated {
|
||||
|
||||
@Getter(AccessLevel.NONE)
|
||||
private boolean donated = false;
|
||||
|
||||
public boolean hasDonated() {
|
||||
return donated;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.replaymod.online.api.replay.holders;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class Favorites {
|
||||
private int[] favorited;
|
||||
}
|
||||
27
src/main/java/com/replaymod/online/api/replay/holders/FileInfo.java
Executable file
27
src/main/java/com/replaymod/online/api/replay/holders/FileInfo.java
Executable file
@@ -0,0 +1,27 @@
|
||||
package com.replaymod.online.api.replay.holders;
|
||||
|
||||
import de.johni0702.replaystudio.replay.ReplayMetaData;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class FileInfo {
|
||||
private int id;
|
||||
private ReplayMetaData metadata;
|
||||
private String owner;
|
||||
private Rating ratings;
|
||||
private int size;
|
||||
private int category;
|
||||
private int downloads;
|
||||
private String name;
|
||||
@Getter(AccessLevel.NONE)
|
||||
private boolean thumbnail;
|
||||
private int favorites;
|
||||
|
||||
public boolean hasThumbnail() {
|
||||
return thumbnail;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.replaymod.online.api.replay.holders;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class FileRating {
|
||||
private int file;
|
||||
@SerializedName("rating") private boolean ratingPositive;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.replaymod.online.api.replay.holders;
|
||||
|
||||
public enum MinecraftVersion {
|
||||
|
||||
MC_1_8("Minecraft 1.8", "1.8");
|
||||
|
||||
private String niceName, apiName;
|
||||
|
||||
MinecraftVersion(String niceName, String apiName) {
|
||||
this.niceName = niceName;
|
||||
this.apiName = apiName;
|
||||
}
|
||||
|
||||
public String toNiceName() {
|
||||
return niceName;
|
||||
}
|
||||
|
||||
public String getApiName() {
|
||||
return apiName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.replaymod.online.api.replay.holders;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class RatedFiles {
|
||||
private FileRating[] rated;
|
||||
}
|
||||
26
src/main/java/com/replaymod/online/api/replay/holders/Rating.java
Executable file
26
src/main/java/com/replaymod/online/api/replay/holders/Rating.java
Executable file
@@ -0,0 +1,26 @@
|
||||
package com.replaymod.online.api.replay.holders;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class Rating {
|
||||
private int negative, positive;
|
||||
|
||||
public enum RatingType {
|
||||
|
||||
LIKE("like"), DISLIKE("dislike"), NEUTRAL("neutral");
|
||||
|
||||
private String key;
|
||||
|
||||
public String getKey() { return key; }
|
||||
|
||||
RatingType(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public static RatingType fromBoolean(Boolean rating) {
|
||||
return rating == null ? RatingType.NEUTRAL :
|
||||
(rating ? RatingType.LIKE : RatingType.DISLIKE);
|
||||
}
|
||||
}
|
||||
}
|
||||
8
src/main/java/com/replaymod/online/api/replay/holders/SearchResult.java
Executable file
8
src/main/java/com/replaymod/online/api/replay/holders/SearchResult.java
Executable file
@@ -0,0 +1,8 @@
|
||||
package com.replaymod.online.api.replay.holders;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class SearchResult {
|
||||
private FileInfo[] results;
|
||||
}
|
||||
8
src/main/java/com/replaymod/online/api/replay/holders/Success.java
Executable file
8
src/main/java/com/replaymod/online/api/replay/holders/Success.java
Executable file
@@ -0,0 +1,8 @@
|
||||
package com.replaymod.online.api.replay.holders;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class Success {
|
||||
private boolean success = false;
|
||||
}
|
||||
10
src/main/java/com/replaymod/online/api/replay/holders/UserFiles.java
Executable file
10
src/main/java/com/replaymod/online/api/replay/holders/UserFiles.java
Executable file
@@ -0,0 +1,10 @@
|
||||
package com.replaymod.online.api.replay.holders;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class UserFiles {
|
||||
private String user;
|
||||
private FileInfo[] files;
|
||||
private int total_size;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.replaymod.online.api.replay.pagination;
|
||||
|
||||
import com.replaymod.online.ReplayModOnline;
|
||||
import com.replaymod.online.api.replay.holders.FileInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class DownloadedFilePagination implements Pagination {
|
||||
|
||||
private final ReplayModOnline mod;
|
||||
private int page;
|
||||
private HashMap<Integer, FileInfo> files = new HashMap<>();
|
||||
|
||||
public DownloadedFilePagination(ReplayModOnline mod) {
|
||||
this.mod = mod;
|
||||
this.page = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FileInfo> getFiles() {
|
||||
return new ArrayList<>(files.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLoadedPages() {
|
||||
return page;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean fetchPage() {
|
||||
page++;
|
||||
|
||||
List<Integer> toAdd = new ArrayList<>();
|
||||
for(String fileName : mod.getDownloadsFolder().list()) {
|
||||
int i;
|
||||
try {
|
||||
i = Integer.parseInt(fileName.substring(0, fileName.indexOf('.')));
|
||||
} catch (NumberFormatException e) {
|
||||
e.printStackTrace();
|
||||
continue;
|
||||
}
|
||||
if(!files.containsKey(i)) {
|
||||
toAdd.add(i);
|
||||
if(toAdd.size() >= Pagination.PAGE_SIZE) break;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
FileInfo[] fis = mod.getApiClient().getFileInfo(toAdd);
|
||||
if(fis.length < 1) {
|
||||
page--;
|
||||
return false;
|
||||
}
|
||||
|
||||
for(FileInfo info : fis) {
|
||||
files.put(info.getId(), info);
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
page--;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.replaymod.online.api.replay.pagination;
|
||||
|
||||
import com.replaymod.online.api.ApiClient;
|
||||
import com.replaymod.online.api.replay.holders.FileInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class FavoritedFilePagination implements Pagination {
|
||||
|
||||
private final ApiClient apiClient;
|
||||
private int page;
|
||||
private HashMap<Integer, FileInfo> files = new HashMap<>();
|
||||
|
||||
public FavoritedFilePagination(ApiClient apiClient) {
|
||||
this.apiClient = apiClient;
|
||||
this.page = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FileInfo> getFiles() {
|
||||
return new ArrayList<>(files.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLoadedPages() {
|
||||
return page;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean fetchPage() {
|
||||
page++;
|
||||
|
||||
try {
|
||||
int[] f = apiClient.getFavorites();
|
||||
List<Integer> toAdd = new ArrayList<>();
|
||||
for(int i : f) {
|
||||
if(!files.containsKey(i)) {
|
||||
toAdd.add(i);
|
||||
if(toAdd.size() >= Pagination.PAGE_SIZE) break;
|
||||
}
|
||||
}
|
||||
|
||||
FileInfo[] fis = apiClient.getFileInfo(toAdd);
|
||||
if(fis.length < 1) {
|
||||
page--;
|
||||
return false;
|
||||
}
|
||||
|
||||
for(FileInfo info : fis) {
|
||||
files.put(info.getId(), info);
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
page--;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.replaymod.online.api.replay.pagination;
|
||||
|
||||
import com.replaymod.online.api.replay.holders.FileInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface Pagination {
|
||||
List<FileInfo> getFiles();
|
||||
|
||||
int getLoadedPages();
|
||||
|
||||
boolean fetchPage();
|
||||
|
||||
int PAGE_SIZE = 30; //defined by the Website API
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.replaymod.online.api.replay.pagination;
|
||||
|
||||
import com.replaymod.online.api.ApiClient;
|
||||
import com.replaymod.online.api.replay.SearchQuery;
|
||||
import com.replaymod.online.api.replay.holders.FileInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class SearchPagination implements Pagination {
|
||||
|
||||
private final ApiClient apiClient;
|
||||
private final SearchQuery searchQuery;
|
||||
private int page;
|
||||
private List<FileInfo> files = new ArrayList<FileInfo>();
|
||||
|
||||
public SearchPagination(ApiClient apiClient, SearchQuery searchQuery) {
|
||||
this.apiClient = apiClient;
|
||||
this.page = -1;
|
||||
this.searchQuery = searchQuery;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FileInfo> getFiles() {
|
||||
return Collections.unmodifiableList(files);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLoadedPages() {
|
||||
return page;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean fetchPage() {
|
||||
page++;
|
||||
searchQuery.offset = page;
|
||||
|
||||
try {
|
||||
FileInfo[] fis = apiClient.searchFiles(searchQuery);
|
||||
if(fis.length < 1) {
|
||||
page--;
|
||||
return false;
|
||||
}
|
||||
|
||||
files.addAll(Arrays.asList(fis));
|
||||
|
||||
return true;
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
page--;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user