[maimai2] Support user portrait

This commit is contained in:
Mikira Sora
2022-12-11 04:47:44 +00:00
committed by Dom Eori
parent 75932c4b75
commit 709b977e73
8 changed files with 253 additions and 7 deletions

View File

@@ -0,0 +1,103 @@
package icu.samnyan.aqua.sega.maimai2.handler.impl;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonProcessingException;
import icu.samnyan.aqua.sega.maimai2.handler.BaseHandler;
import icu.samnyan.aqua.sega.maimai2.model.request.UploadUserPortrait;
import icu.samnyan.aqua.sega.maimai2.model.request.data.UserPortrait;
import icu.samnyan.aqua.sega.util.jackson.BasicMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.codec.Utf8;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.*;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component("Maimai2GetUserPortraitHandler")
public class GetUserPortraitHandler implements BaseHandler {
private static final Logger logger = LoggerFactory.getLogger(GetUserPortraitHandler.class);
private final BasicMapper mapper;
private final String picSavePath;
private final boolean enable;
public GetUserPortraitHandler(BasicMapper mapper, @Value("${game.maimai2.userPhoto.enable:}") boolean enable, @Value("${game.maimai2.userPhoto.picSavePath:}") String picSavePath) {
this.mapper = mapper;
this.picSavePath = picSavePath;
this.enable = enable;
if (enable) {
try {
Files.createDirectories(Paths.get(picSavePath));
} catch (Exception ignored) {
}
}
}
@Override
public String handle(Map<String, Object> request) throws JsonProcessingException {
if (enable) {
var userId = ((Number) request.get("userId")).longValue();
var list = new ArrayList<UserPortrait>();
try {
var filePath = Paths.get(picSavePath, userId + "-up.jpg");
var templateJsonStr = Files.readString(Paths.get(picSavePath, userId + "-up.json"));
var templateUserPortrait = mapper.read(templateJsonStr, UserPortrait.class);
var buffer = new byte[10240];
if (Files.exists(filePath)) {
var stream = new FileInputStream(filePath.toFile());
while (stream.available() > 0) {
var read = stream.read(buffer, 0, 10240);
var encodeBuffer = read == 10240 ? buffer : Arrays.copyOfRange(buffer, 0, read);
var userPortrait = new UserPortrait();
userPortrait.setFileName(templateUserPortrait.getFileName());
userPortrait.setPlaceId(templateUserPortrait.getPlaceId());
userPortrait.setUserId(templateUserPortrait.getUserId());
userPortrait.setClientId(templateUserPortrait.getClientId());
userPortrait.setUploadDate(templateUserPortrait.getUploadDate());
userPortrait.setDivData(Utf8.decode(Base64.getEncoder().encode(encodeBuffer)));
userPortrait.setDivNumber(list.size());
list.add(userPortrait);
}
stream.close();
for (var i = 0; i < list.size(); i++) {
var userPortrait = list.get(i);
userPortrait.setDivLength(list.size());
}
var map = new HashMap<String, Object>();
map.put("length", list.size());
map.put("userPortraitList", list);
var respJson = mapper.write(map);
return respJson;
}
} catch (Exception e) {
logger.error("Result: User photo save failed", e);
}
}
return "{\"length\":0,\"userPortraitList\":[]}";
}
}

View File

@@ -0,0 +1,88 @@
package icu.samnyan.aqua.sega.maimai2.handler.impl;
import com.fasterxml.jackson.core.JsonProcessingException;
import icu.samnyan.aqua.sega.maimai2.handler.BaseHandler;
import icu.samnyan.aqua.sega.maimai2.model.request.UploadUserPortrait;
import icu.samnyan.aqua.sega.util.jackson.BasicMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.Base64;
import java.util.Map;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component("Maimai2UploadUserPortraitHandler")
public class UploadUserPortraitHandler implements BaseHandler {
private static final Logger logger = LoggerFactory.getLogger(UploadUserPortraitHandler.class);
private final BasicMapper mapper;
private final String picSavePath;
private final boolean enable;
public UploadUserPortraitHandler(BasicMapper mapper, @Value("${game.maimai2.userPhoto.enable:}") boolean enable, @Value("${game.maimai2.userPhoto.picSavePath:}") String picSavePath) {
this.mapper = mapper;
this.picSavePath = picSavePath;
this.enable = enable;
if (enable) {
try {
Files.createDirectories(Paths.get(picSavePath));
} catch (Exception ignored) {
}
}
}
@Override
public String handle(Map<String, Object> request) throws JsonProcessingException {
/*
Maimai DX sends splited base64 data for one jpeg image.
So, make a temp file and keep append bytes until last part received.
If finished, rename it to other name so user can keep save multiple score cards in a single day.
*/
if (enable) {
var uploadUserPhoto = mapper.convert(request, UploadUserPortrait.class);
var userPhoto = uploadUserPhoto.getUserPortrait();
long userId = userPhoto.getUserId();
int divNumber = userPhoto.getDivNumber();
int divLength = userPhoto.getDivLength();
String divData = userPhoto.getDivData();
try {
var tmp_filename = Paths.get(picSavePath, userId + "-up.tmp");
if (divNumber == 0)
Files.deleteIfExists(tmp_filename);
byte[] imageData = Base64.getDecoder().decode(divData);
Files.write(tmp_filename, imageData, StandardOpenOption.CREATE, StandardOpenOption.APPEND);
logger.info(String.format("received user %d photo data %d/%d", userId, divNumber + 1, divLength));
if (divNumber == (divLength - 1)) {
var filename = Paths.get(picSavePath, userId + "-up.jpg");
Files.move(tmp_filename, filename, StandardCopyOption.REPLACE_EXISTING);
userPhoto.setDivData("");
var userPortaitMetaJson = mapper.write(userPhoto);
var json_filename = Paths.get(picSavePath, userId + "-up.json");
Files.write(json_filename, userPortaitMetaJson.getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING);
logger.info(String.format("saved user %d photo data", userId));
}
} catch (IOException e) {
logger.error("Result: User photo save failed", e);
}
}
return "{\"returnCode\":1,\"apiName\":\"com.sega.maimai2servlet.api.UploadUserPortraitApi\"}";
}
}