Add online (aka ReplayCenter) module

Add localization extra (formally known as LocalizedResourcePack)
Add version checker extra
This commit is contained in:
johni0702
2015-11-14 15:36:49 +01:00
parent 5e5172fd3f
commit 7c8dde3322
54 changed files with 1186 additions and 1189 deletions

View 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;
}
}

View 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";
}

View 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();
}
}

View 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;
}
}
}

View File

@@ -0,0 +1,9 @@
package com.replaymod.online.api.replay.holders;
import lombok.Data;
@Data
public class AuthConfirmation {
private String username;
private int id;
}

View 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;
}

View 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;
}
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,8 @@
package com.replaymod.online.api.replay.holders;
import lombok.Data;
@Data
public class Favorites {
private int[] favorited;
}

View 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;
}
}

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,8 @@
package com.replaymod.online.api.replay.holders;
import lombok.Data;
@Data
public class RatedFiles {
private FileRating[] rated;
}

View 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);
}
}
}

View File

@@ -0,0 +1,8 @@
package com.replaymod.online.api.replay.holders;
import lombok.Data;
@Data
public class SearchResult {
private FileInfo[] results;
}

View File

@@ -0,0 +1,8 @@
package com.replaymod.online.api.replay.holders;
import lombok.Data;
@Data
public class Success {
private boolean success = false;
}

View 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;
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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
}

View File

@@ -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;
}
}