项目地址

https://github.com/Rain238/rain-robot/tree/master

支持功能

支持群内禁言
支持Lolicon
支持原神/米游社自动签到
支持原神福利签到
支持获取每日米游币
支持米游社社区签到
支持米游社频道签到:崩坏二/崩坏三/原神/未定/大墅野

实现原理

调用官方api实现

代码如下

所需Maven

     	<dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.15</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.13</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.8.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>love.forte.simple-robot</groupId>
            <artifactId>component-mirai-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.14.3</version>
        </dependency>
        <dependency>
            <groupId>net.sf.json-lib</groupId>
            <artifactId>json-lib</artifactId>
            <version>2.1</version>
            <classifier>jdk13</classifier>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.0</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

先创建以下所需的Bean对象

原神所需

Award

package qqrobot.module.mihoyo.genshin.bean;

public class Award {
    private String icon;
    private String name;
    private Integer cnt;

    //<editor-fold defaultstate="collapsed" desc="delombok">
    @SuppressWarnings("all")
    public String getIcon() {
        return this.icon;
    }

    @SuppressWarnings("all")
    public String getName() {
        return this.name;
    }

    @SuppressWarnings("all")
    public Integer getCnt() {
        return this.cnt;
    }

    @SuppressWarnings("all")
    public void setIcon(final String icon) {
        this.icon = icon;
    }

    @SuppressWarnings("all")
    public void setName(final String name) {
        this.name = name;
    }

    @SuppressWarnings("all")
    public void setCnt(final Integer cnt) {
        this.cnt = cnt;
    }

    @Override
    @SuppressWarnings("all")
    public String toString() {
        return "Award(icon=" + this.getIcon() + ", name=" + this.getName() + ", cnt=" + this.getCnt() + ")";
    }

    @SuppressWarnings("all")
    public Award() {
    }

    @SuppressWarnings("all")
    public Award(final String icon, final String name, final Integer cnt) {
        this.icon = icon;
        this.name = name;
        this.cnt = cnt;
    }
    //</editor-fold>
}

Http工具类

HttpUtils

package qqrobot.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Slf4j
public class HttpUtils {

//    private static Logger logger = LogManager.getLogger(HttpUtils.class.getName());

    private HttpUtils() {

    }

    private static final String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " +
            "(KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36 Edg/85.0.564.70";

    private static final RequestConfig REQUEST_CONFIG = RequestConfig.custom().setConnectTimeout(35000)
            .setConnectionRequestTimeout(35000)
            .setSocketTimeout(60000)
            .setRedirectsEnabled(true)
            .build();


    public static HttpEntity doPost(String url) {
        CloseableHttpResponse response = null;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        try {
            HttpPost httpPost = new HttpPost(url);
            httpPost.setHeader("Connection", "keep-alive");
            httpPost.setHeader("User-Agent", USER_AGENT);
            httpPost.setConfig(REQUEST_CONFIG);
            response = httpClient.execute(httpPost);
            return response.getEntity();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            closeResource(httpClient, response);
        }
        return null;
    }

    public static HttpEntity doPost(URI uri, StringEntity entity) {
        CloseableHttpResponse response = null;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        try {
            HttpPost httpPost = new HttpPost(uri);
            httpPost.setEntity(entity);
            httpPost.setHeader("Connection", "keep-alive");
            httpPost.setHeader("User-Agent", USER_AGENT);
            httpPost.setConfig(REQUEST_CONFIG);
            response = httpClient.execute(httpPost);
            return response.getEntity();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            closeResource(httpClient, response);
        }
        return null;
    }

    public static JSONObject doPost(String url, Header[] headers, Map<String, Object> data) {
        CloseableHttpResponse response = null;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        JSONObject resultJson = null;
        try {
            StringEntity entity = new StringEntity(JSON.toJSONString(data), StandardCharsets.UTF_8);
            HttpPost httpPost = new HttpPost(url);
            httpPost.setEntity(entity);
            if (headers != null && headers.length != 0) {
                for (Header header : headers) {
                    httpPost.addHeader(header);
                }
            }
            httpPost.setConfig(REQUEST_CONFIG);
            response = httpClient.execute(httpPost);
            if (response.getStatusLine().getStatusCode() == 200) {
                String result = EntityUtils.toString(response.getEntity());
                resultJson = JSON.parseObject(result);
            } else {
                log.warn(response.getStatusLine().getStatusCode() + "配置已失效,请更新配置信息");
            }
            return resultJson;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            closeResource(httpClient, response);
        }
        return resultJson;
    }

    public static HttpEntity doGetDefault(URI uri) {
        CloseableHttpResponse response = null;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        try {
            HttpGet httpGet = new HttpGet(uri);
            httpGet.setHeader("Connection", "keep-alive");
            httpGet.setHeader("User-Agent", USER_AGENT);
            httpGet.setConfig(REQUEST_CONFIG);
            response = httpClient.execute(httpGet);
            return response.getEntity();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            closeResource(httpClient, response);
        }
        return null;
    }

    public static HttpEntity doGetDefault(String url) {
        CloseableHttpResponse response = null;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        try {
            HttpGet httpGet = new HttpGet(url);
            httpGet.setHeader("Connection", "keep-alive");
            httpGet.setHeader("User-Agent", USER_AGENT);
            httpGet.setConfig(REQUEST_CONFIG);
            response = httpClient.execute(httpGet);
            return response.getEntity();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            closeResource(httpClient, response);
        }
        return null;
    }


    public static JSONObject doGet(String url, Header[] headers) {
        return doGet(url, headers, null);
    }


    public static JSONObject doGet(String url, Header[] headers, Map<String, Object> data) {
        CloseableHttpResponse response = null;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        JSONObject resultJson = null;
        try {
            URIBuilder uriBuilder = new URIBuilder(url);
            List<NameValuePair> params = null;
            if (data != null && !data.isEmpty()) {
                params = new ArrayList<>();
                for (String key : data.keySet()) {
                    params.add(new BasicNameValuePair(key, data.get(key) + ""));
                }
                uriBuilder.setParameters(params);
            }
            URI uri = uriBuilder.build();
            HttpGet httpGet = new HttpGet(uri);
            if (headers != null && headers.length != 0) {
                for (Header header : headers) {
                    httpGet.addHeader(header);
                }
            }
            httpGet.setConfig(REQUEST_CONFIG);
            response = httpClient.execute(httpGet);
            if (response.getStatusLine().getStatusCode() == 200) {
                String result = EntityUtils.toString(response.getEntity());
                resultJson = JSON.parseObject(result);
            } else {
                log.warn(response.getStatusLine().getStatusCode() + "配置已失效,请更新配置信息");
            }
            return resultJson;
        } catch (IOException | URISyntaxException e) {
            e.printStackTrace();
        } finally {
            closeResource(httpClient, response);
        }
        return resultJson;
    }


    private static void closeResource(CloseableHttpClient httpClient, CloseableHttpResponse response) {
        if (null != httpClient) {
            try {
                httpClient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

获取token工具类

GetstokenUtils

package qqrobot.util;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.yaml.snakeyaml.Yaml;
import qqrobot.module.mihoyo.MiHoYoAbstractSign;
import qqrobot.module.mihoyo.MiHoYoConfig;

import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

@Slf4j
public class GetstokenUtils {

    static String cookie = "";

    private GetstokenUtils() {
    }


    public static void main(String[] args) {
        log.info(String.valueOf(doGen(cookie)));
    }

    public static String doGen(String cookie) {
        String stoken;
        Map<String, String> headers = getCookieHeader(cookie);
        String url = String.format(MiHoYoConfig.HUB_COOKIE2_URL, headers.get("login_ticket"), headers.get("login_uid"));
        MiHoYoAbstractSign helperHeader = new MiHoYoAbstractSign() {
            @Override
            public Object sign() {
                return null;
            }
        };
        JSONObject result = HttpUtils.doGet(url, helperHeader.getHeaders());
        log.info(String.valueOf(result));
        if (!"OK".equals(result.get("message"))) {
            stoken = "login_ticket已失效,请重新登录获取";
        } else {
            stoken = (String) result.getJSONObject("data").getJSONArray("list").getJSONObject(0).get("token");
        }
        return stoken;
    }

    public static Map<String, String> getCookieHeader(String cookie) {
        String[] split = cookie.split(";");
        Map<String, String> map = new HashMap<>();
        for (String s : split) {
            String h = s.trim();
            String[] item = h.split("=");
            map.put(item[0], item[1]);
        }
        return map;
    }

}

米游社所需Bean对象

Certification

package qqrobot.module.mihoyo.bean;

public class Certification {
    private String label;
    private int type;

    //<editor-fold defaultstate="collapsed" desc="delombok">
    @SuppressWarnings("all")
    public String getLabel() {
        return this.label;
    }

    @SuppressWarnings("all")
    public int getType() {
        return this.type;
    }

    @SuppressWarnings("all")
    public void setLabel(final String label) {
        this.label = label;
    }

    @SuppressWarnings("all")
    public void setType(final int type) {
        this.type = type;
    }
    //</editor-fold>
}

Forum

package qqrobot.module.mihoyo.bean;

public class Forum {
    private String name;
    private String icon;
    private int id;
    private int game_id;

    //<editor-fold defaultstate="collapsed" desc="delombok">
    @SuppressWarnings("all")
    public String getName() {
        return this.name;
    }

    @SuppressWarnings("all")
    public String getIcon() {
        return this.icon;
    }

    @SuppressWarnings("all")
    public int getId() {
        return this.id;
    }

    @SuppressWarnings("all")
    public int getGame_id() {
        return this.game_id;
    }

    @SuppressWarnings("all")
    public void setName(final String name) {
        this.name = name;
    }

    @SuppressWarnings("all")
    public void setIcon(final String icon) {
        this.icon = icon;
    }

    @SuppressWarnings("all")
    public void setId(final int id) {
        this.id = id;
    }

    @SuppressWarnings("all")
    public void setGame_id(final int game_id) {
        this.game_id = game_id;
    }
    //</editor-fold>
}

HelpSys

package qqrobot.module.mihoyo.bean;

import java.util.List;

public class HelpSys {
    private int answer_num;
    private List<String> top_n;

    //<editor-fold defaultstate="collapsed" desc="delombok">
    @SuppressWarnings("all")
    public int getAnswer_num() {
        return this.answer_num;
    }

    @SuppressWarnings("all")
    public List<String> getTop_n() {
        return this.top_n;
    }

    @SuppressWarnings("all")
    public void setAnswer_num(final int answer_num) {
        this.answer_num = answer_num;
    }

    @SuppressWarnings("all")
    public void setTop_n(final List<String> top_n) {
        this.top_n = top_n;
    }
    //</editor-fold>
}

LevelExp

package qqrobot.module.mihoyo.bean;

public class LevelExp {
    private int level;
    private int exp;

    //<editor-fold defaultstate="collapsed" desc="delombok">
    @SuppressWarnings("all")
    public int getLevel() {
        return this.level;
    }

    @SuppressWarnings("all")
    public int getExp() {
        return this.exp;
    }

    @SuppressWarnings("all")
    public void setLevel(final int level) {
        this.level = level;
    }

    @SuppressWarnings("all")
    public void setExp(final int exp) {
        this.exp = exp;
    }
    //</editor-fold>
}

Post

package qqrobot.module.mihoyo.bean;

import java.util.Date;
import java.util.List;

public class Post {
    private int review_id;
    private List<String> images;
    private List<String> topic_ids;
    private int is_original;
    private String subject;
    private Date reply_time;
    private boolean is_interactive;
    private int view_type;
    private long created_at;
    private String content;
    private String structured_content;
    private String cover;
    private String uid;
    private int f_forum_id;
    private int is_deleted;
    private String post_id;
    private boolean is_profit;
    private PostStatus post_status;
    private int republish_authorization;
    private int max_floor;
    private List<String> structured_content_rows;
    private int game_id;
    private int view_status;
    private boolean is_in_profit;

    //<editor-fold defaultstate="collapsed" desc="delombok">
    @SuppressWarnings("all")
    public int getReview_id() {
        return this.review_id;
    }

    @SuppressWarnings("all")
    public List<String> getImages() {
        return this.images;
    }

    @SuppressWarnings("all")
    public List<String> getTopic_ids() {
        return this.topic_ids;
    }

    @SuppressWarnings("all")
    public int getIs_original() {
        return this.is_original;
    }

    @SuppressWarnings("all")
    public String getSubject() {
        return this.subject;
    }

    @SuppressWarnings("all")
    public Date getReply_time() {
        return this.reply_time;
    }

    @SuppressWarnings("all")
    public boolean is_interactive() {
        return this.is_interactive;
    }

    @SuppressWarnings("all")
    public int getView_type() {
        return this.view_type;
    }

    @SuppressWarnings("all")
    public long getCreated_at() {
        return this.created_at;
    }

    @SuppressWarnings("all")
    public String getContent() {
        return this.content;
    }

    @SuppressWarnings("all")
    public String getStructured_content() {
        return this.structured_content;
    }

    @SuppressWarnings("all")
    public String getCover() {
        return this.cover;
    }

    @SuppressWarnings("all")
    public String getUid() {
        return this.uid;
    }

    @SuppressWarnings("all")
    public int getF_forum_id() {
        return this.f_forum_id;
    }

    @SuppressWarnings("all")
    public int getIs_deleted() {
        return this.is_deleted;
    }

    @SuppressWarnings("all")
    public String getPost_id() {
        return this.post_id;
    }

    @SuppressWarnings("all")
    public boolean is_profit() {
        return this.is_profit;
    }

    @SuppressWarnings("all")
    public PostStatus getPost_status() {
        return this.post_status;
    }

    @SuppressWarnings("all")
    public int getRepublish_authorization() {
        return this.republish_authorization;
    }

    @SuppressWarnings("all")
    public int getMax_floor() {
        return this.max_floor;
    }

    @SuppressWarnings("all")
    public List<String> getStructured_content_rows() {
        return this.structured_content_rows;
    }

    @SuppressWarnings("all")
    public int getGame_id() {
        return this.game_id;
    }

    @SuppressWarnings("all")
    public int getView_status() {
        return this.view_status;
    }

    @SuppressWarnings("all")
    public boolean is_in_profit() {
        return this.is_in_profit;
    }

    @SuppressWarnings("all")
    public void setReview_id(final int review_id) {
        this.review_id = review_id;
    }

    @SuppressWarnings("all")
    public void setImages(final List<String> images) {
        this.images = images;
    }

    @SuppressWarnings("all")
    public void setTopic_ids(final List<String> topic_ids) {
        this.topic_ids = topic_ids;
    }

    @SuppressWarnings("all")
    public void setIs_original(final int is_original) {
        this.is_original = is_original;
    }

    @SuppressWarnings("all")
    public void setSubject(final String subject) {
        this.subject = subject;
    }

    @SuppressWarnings("all")
    public void setReply_time(final Date reply_time) {
        this.reply_time = reply_time;
    }

    @SuppressWarnings("all")
    public void set_interactive(final boolean is_interactive) {
        this.is_interactive = is_interactive;
    }

    @SuppressWarnings("all")
    public void setView_type(final int view_type) {
        this.view_type = view_type;
    }

    @SuppressWarnings("all")
    public void setCreated_at(final long created_at) {
        this.created_at = created_at;
    }

    @SuppressWarnings("all")
    public void setContent(final String content) {
        this.content = content;
    }

    @SuppressWarnings("all")
    public void setStructured_content(final String structured_content) {
        this.structured_content = structured_content;
    }

    @SuppressWarnings("all")
    public void setCover(final String cover) {
        this.cover = cover;
    }

    @SuppressWarnings("all")
    public void setUid(final String uid) {
        this.uid = uid;
    }

    @SuppressWarnings("all")
    public void setF_forum_id(final int f_forum_id) {
        this.f_forum_id = f_forum_id;
    }

    @SuppressWarnings("all")
    public void setIs_deleted(final int is_deleted) {
        this.is_deleted = is_deleted;
    }

    @SuppressWarnings("all")
    public void setPost_id(final String post_id) {
        this.post_id = post_id;
    }

    @SuppressWarnings("all")
    public void set_profit(final boolean is_profit) {
        this.is_profit = is_profit;
    }

    @SuppressWarnings("all")
    public void setPost_status(final PostStatus post_status) {
        this.post_status = post_status;
    }

    @SuppressWarnings("all")
    public void setRepublish_authorization(final int republish_authorization) {
        this.republish_authorization = republish_authorization;
    }

    @SuppressWarnings("all")
    public void setMax_floor(final int max_floor) {
        this.max_floor = max_floor;
    }

    @SuppressWarnings("all")
    public void setStructured_content_rows(final List<String> structured_content_rows) {
        this.structured_content_rows = structured_content_rows;
    }

    @SuppressWarnings("all")
    public void setGame_id(final int game_id) {
        this.game_id = game_id;
    }

    @SuppressWarnings("all")
    public void setView_status(final int view_status) {
        this.view_status = view_status;
    }

    @SuppressWarnings("all")
    public void set_in_profit(final boolean is_in_profit) {
        this.is_in_profit = is_in_profit;
    }

    @Override
    @SuppressWarnings("all")
    public String toString() {
        return "Post(review_id=" + this.getReview_id() + ", images=" + this.getImages() + ", topic_ids=" + this.getTopic_ids() + ", is_original=" + this.getIs_original() + ", subject=" + this.getSubject() + ", reply_time=" + this.getReply_time() + ", is_interactive=" + this.is_interactive() + ", view_type=" + this.getView_type() + ", created_at=" + this.getCreated_at() + ", content=" + this.getContent() + ", structured_content=" + this.getStructured_content() + ", cover=" + this.getCover() + ", uid=" + this.getUid() + ", f_forum_id=" + this.getF_forum_id() + ", is_deleted=" + this.getIs_deleted() + ", post_id=" + this.getPost_id() + ", is_profit=" + this.is_profit() + ", post_status=" + this.getPost_status() + ", republish_authorization=" + this.getRepublish_authorization() + ", max_floor=" + this.getMax_floor() + ", structured_content_rows=" + this.getStructured_content_rows() + ", game_id=" + this.getGame_id() + ", view_status=" + this.getView_status() + ", is_in_profit=" + this.is_in_profit() + ")";
    }
    //</editor-fold>
}

创建签到接口

Sign

package qqrobot.module.mihoyo;

import org.apache.http.Header;

/**
 * &#064;Author  Light rain
 * &#064;Date  2022/5/20 12:08
 */
public interface Sign {
    //签到
    Object sign();

    //请求头
    Header[] getHeaders();
}

PostResult

package qqrobot.module.mihoyo.bean;

import java.util.List;

public class PostResult {
    private Stat stat;
    private List<String> vod_list;
    private List<String> topics;
    private int last_modify_time;
    private boolean is_user_master;
    private String recommend_type;
    private SelfOperation self_operation;
    private Forum forum;
    private boolean is_official_master;
    private Post post;
    private boolean is_block_on;
    private User user;
    private HelpSys help_sys;
    private int vote_count;
    private List<String> image_list;
    private boolean hot_reply_exist;

    //<editor-fold defaultstate="collapsed" desc="delombok">
    @SuppressWarnings("all")
    public Stat getStat() {
        return this.stat;
    }

    @SuppressWarnings("all")
    public List<String> getVod_list() {
        return this.vod_list;
    }

    @SuppressWarnings("all")
    public List<String> getTopics() {
        return this.topics;
    }

    @SuppressWarnings("all")
    public int getLast_modify_time() {
        return this.last_modify_time;
    }

    @SuppressWarnings("all")
    public boolean is_user_master() {
        return this.is_user_master;
    }

    @SuppressWarnings("all")
    public String getRecommend_type() {
        return this.recommend_type;
    }

    @SuppressWarnings("all")
    public SelfOperation getSelf_operation() {
        return this.self_operation;
    }

    @SuppressWarnings("all")
    public Forum getForum() {
        return this.forum;
    }

    @SuppressWarnings("all")
    public boolean is_official_master() {
        return this.is_official_master;
    }

    @SuppressWarnings("all")
    public Post getPost() {
        return this.post;
    }

    @SuppressWarnings("all")
    public boolean is_block_on() {
        return this.is_block_on;
    }

    @SuppressWarnings("all")
    public User getUser() {
        return this.user;
    }

    @SuppressWarnings("all")
    public HelpSys getHelp_sys() {
        return this.help_sys;
    }

    @SuppressWarnings("all")
    public int getVote_count() {
        return this.vote_count;
    }

    @SuppressWarnings("all")
    public List<String> getImage_list() {
        return this.image_list;
    }

    @SuppressWarnings("all")
    public boolean isHot_reply_exist() {
        return this.hot_reply_exist;
    }

    @SuppressWarnings("all")
    public void setStat(final Stat stat) {
        this.stat = stat;
    }

    @SuppressWarnings("all")
    public void setVod_list(final List<String> vod_list) {
        this.vod_list = vod_list;
    }

    @SuppressWarnings("all")
    public void setTopics(final List<String> topics) {
        this.topics = topics;
    }

    @SuppressWarnings("all")
    public void setLast_modify_time(final int last_modify_time) {
        this.last_modify_time = last_modify_time;
    }

    @SuppressWarnings("all")
    public void set_user_master(final boolean is_user_master) {
        this.is_user_master = is_user_master;
    }

    @SuppressWarnings("all")
    public void setRecommend_type(final String recommend_type) {
        this.recommend_type = recommend_type;
    }

    @SuppressWarnings("all")
    public void setSelf_operation(final SelfOperation self_operation) {
        this.self_operation = self_operation;
    }

    @SuppressWarnings("all")
    public void setForum(final Forum forum) {
        this.forum = forum;
    }

    @SuppressWarnings("all")
    public void set_official_master(final boolean is_official_master) {
        this.is_official_master = is_official_master;
    }

    @SuppressWarnings("all")
    public void setPost(final Post post) {
        this.post = post;
    }

    @SuppressWarnings("all")
    public void set_block_on(final boolean is_block_on) {
        this.is_block_on = is_block_on;
    }

    @SuppressWarnings("all")
    public void setUser(final User user) {
        this.user = user;
    }

    @SuppressWarnings("all")
    public void setHelp_sys(final HelpSys help_sys) {
        this.help_sys = help_sys;
    }

    @SuppressWarnings("all")
    public void setVote_count(final int vote_count) {
        this.vote_count = vote_count;
    }

    @SuppressWarnings("all")
    public void setImage_list(final List<String> image_list) {
        this.image_list = image_list;
    }

    @SuppressWarnings("all")
    public void setHot_reply_exist(final boolean hot_reply_exist) {
        this.hot_reply_exist = hot_reply_exist;
    }
    //</editor-fold>
}

PostStatus

package qqrobot.module.mihoyo.bean;

public class PostStatus {
    private boolean is_official;
    private boolean is_good;
    private boolean is_top;

    //<editor-fold defaultstate="collapsed" desc="delombok">
    @SuppressWarnings("all")
    public boolean is_official() {
        return this.is_official;
    }

    @SuppressWarnings("all")
    public boolean is_good() {
        return this.is_good;
    }

    @SuppressWarnings("all")
    public boolean is_top() {
        return this.is_top;
    }

    @SuppressWarnings("all")
    public void set_official(final boolean is_official) {
        this.is_official = is_official;
    }

    @SuppressWarnings("all")
    public void set_good(final boolean is_good) {
        this.is_good = is_good;
    }

    @SuppressWarnings("all")
    public void set_top(final boolean is_top) {
        this.is_top = is_top;
    }
    //</editor-fold>
}

SelfOperation

package qqrobot.module.mihoyo.bean;

public class SelfOperation {
    private boolean is_collected;
    private int attitude;

    //<editor-fold defaultstate="collapsed" desc="delombok">
    @SuppressWarnings("all")
    public boolean is_collected() {
        return this.is_collected;
    }

    @SuppressWarnings("all")
    public int getAttitude() {
        return this.attitude;
    }

    @SuppressWarnings("all")
    public void set_collected(final boolean is_collected) {
        this.is_collected = is_collected;
    }

    @SuppressWarnings("all")
    public void setAttitude(final int attitude) {
        this.attitude = attitude;
    }
    //</editor-fold>
}

Stat

package qqrobot.module.mihoyo.bean;

public class Stat {
    private int view_num;
    private int like_num;
    private int reply_num;
    private int bookmark_num;

    //<editor-fold defaultstate="collapsed" desc="delombok">
    @SuppressWarnings("all")
    public int getView_num() {
        return this.view_num;
    }

    @SuppressWarnings("all")
    public int getLike_num() {
        return this.like_num;
    }

    @SuppressWarnings("all")
    public int getReply_num() {
        return this.reply_num;
    }

    @SuppressWarnings("all")
    public int getBookmark_num() {
        return this.bookmark_num;
    }

    @SuppressWarnings("all")
    public void setView_num(final int view_num) {
        this.view_num = view_num;
    }

    @SuppressWarnings("all")
    public void setLike_num(final int like_num) {
        this.like_num = like_num;
    }

    @SuppressWarnings("all")
    public void setReply_num(final int reply_num) {
        this.reply_num = reply_num;
    }

    @SuppressWarnings("all")
    public void setBookmark_num(final int bookmark_num) {
        this.bookmark_num = bookmark_num;
    }
    //</editor-fold>
}

User

package qqrobot.module.mihoyo.bean;

public class User {
    private String uid;
    private int gender;
    private String avatar_url;
    private String introduce;
    private String nickname;
    private boolean is_followed;
    private String avatar;
    private String pendant;
    private boolean is_following;
    private LevelExp level_exp;
    private Certification certification;

    //<editor-fold defaultstate="collapsed" desc="delombok">
    @SuppressWarnings("all")
    public String getUid() {
        return this.uid;
    }

    @SuppressWarnings("all")
    public int getGender() {
        return this.gender;
    }

    @SuppressWarnings("all")
    public String getAvatar_url() {
        return this.avatar_url;
    }

    @SuppressWarnings("all")
    public String getIntroduce() {
        return this.introduce;
    }

    @SuppressWarnings("all")
    public String getNickname() {
        return this.nickname;
    }

    @SuppressWarnings("all")
    public boolean is_followed() {
        return this.is_followed;
    }

    @SuppressWarnings("all")
    public String getAvatar() {
        return this.avatar;
    }

    @SuppressWarnings("all")
    public String getPendant() {
        return this.pendant;
    }

    @SuppressWarnings("all")
    public boolean is_following() {
        return this.is_following;
    }

    @SuppressWarnings("all")
    public LevelExp getLevel_exp() {
        return this.level_exp;
    }

    @SuppressWarnings("all")
    public Certification getCertification() {
        return this.certification;
    }

    @SuppressWarnings("all")
    public void setUid(final String uid) {
        this.uid = uid;
    }

    @SuppressWarnings("all")
    public void setGender(final int gender) {
        this.gender = gender;
    }

    @SuppressWarnings("all")
    public void setAvatar_url(final String avatar_url) {
        this.avatar_url = avatar_url;
    }

    @SuppressWarnings("all")
    public void setIntroduce(final String introduce) {
        this.introduce = introduce;
    }

    @SuppressWarnings("all")
    public void setNickname(final String nickname) {
        this.nickname = nickname;
    }

    @SuppressWarnings("all")
    public void set_followed(final boolean is_followed) {
        this.is_followed = is_followed;
    }

    @SuppressWarnings("all")
    public void setAvatar(final String avatar) {
        this.avatar = avatar;
    }

    @SuppressWarnings("all")
    public void setPendant(final String pendant) {
        this.pendant = pendant;
    }

    @SuppressWarnings("all")
    public void set_following(final boolean is_following) {
        this.is_following = is_following;
    }

    @SuppressWarnings("all")
    public void setLevel_exp(final LevelExp level_exp) {
        this.level_exp = level_exp;
    }

    @SuppressWarnings("all")
    public void setCertification(final Certification certification) {
        this.certification = certification;
    }
    //</editor-fold>
}

创建配置类

MiHoYoConfig

package qqrobot.module.mihoyo;

/**
 * &#064;Author  Light rain
 * &#064;Date  2022/5/20 12:08
 */
public class MiHoYoConfig {
    //版本号
    public static final String APP_VERSION = "2.3.0"; // 切勿乱修改

    /**
     * 原神API
     */
    //米游社原神签到官方ID
    public static final String ACT_ID = "e202009291139501"; // 切勿乱修改
    //Referer请求头来源地址
    public static final String REFERER_URL = String.format("https://webstatic.mihoyo.com/bbs/event/signin-ys/index.html?bbs_auth_required=%s&act_id=%s&utm_source=%s&utm_medium=%s&utm_campaign=%s", true, ACT_ID, "bbs", "mys", "icon");
    //原神奖励
    public static final String AWARD_URL = String.format("https://api-takumi.mihoyo.com/event/bbs_sign_reward/home?act_id=%s", ACT_ID);
    //角色信息
    public static final String ROLE_URL = String.format("https://api-takumi.mihoyo.com/binding/api/getUserGameRolesByCookie?game_biz=%s", "hk4e_cn");
    //原神签到效验地址
    public static final String INFO_URL = "https://api-takumi.mihoyo.com/event/bbs_sign_reward/info";
    //原神签到地址
    public static final String SIGN_URL = "https://api-takumi.mihoyo.com/event/bbs_sign_reward/sign";
    //代理设备
    public static final String USER_AGENT = String.format("Mozilla/5.0 (iPhone; CPU iPhone OS 14_0_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/%s", APP_VERSION);

    /**
     * hub
     */
    //效验Token
    public static final String HUB_COOKIE2_URL = "https://api-takumi.mihoyo.com/auth/api/getMultiTokenByLoginTicket?login_ticket=%s&token_types=3&uid=%s";
    //登陆接口
    public static final String HUB_SIGN_URL = "https://bbs-api.mihoyo.com/apihub/sapi/signIn?gids=%s";
    //获取论坛帖子列表
    public static final String HUB_LIST1_URL = "https://bbs-api.mihoyo.com/post/api/getForumPostList?forum_id=%s&is_good=false&is_hot=false&page_size=25&sort_type=1";
    //获取帖子
    public static final String HUB_LIST2_URL = "https://bbs-api.mihoyo.com/post/api/feeds/posts?fresh_action=1&gids=%s&last_id=";
    //获取完整帖子
    public static final String HUB_VIEW_URL = "https://bbs-api.mihoyo.com/post/api/getPostFull?post_id=%s";
    //米游社分享帖子
    public static final String HUB_SHARE_URL = "https://bbs-api.mihoyo.com/apihub/api/getShareConf?entity_id=%s&entity_type=1";
    //米游社帖子点赞
    public static final String HUB_VOTE_URL = "https://bbs-api.mihoyo.com/apihub/sapi/upvotePost";

    //枚举
    public enum HubsEnum {
        BH3(new Hub.Builder().setId("1").setForumId("1").setName("崩坏3").setUrl("https://bbs.mihoyo.com/bh3/").build()),
        YS(new Hub.Builder().setId("2").setForumId("26").setName("原神").setUrl("https://bbs.mihoyo.com/ys/").build()),
        BH2(new Hub.Builder().setId("3").setForumId("30").setName("崩坏2").setUrl("https://bbs.mihoyo.com/bh2/").build()),
        WD(new Hub.Builder().setId("4").setForumId("37").setName("未定事件簿").setUrl("https://bbs.mihoyo.com/wd/").build()),
        DBY(new Hub.Builder().setId("5").setForumId("34").setName("大别野").setUrl("https://bbs.mihoyo.com/dby/").build());

        private final Hub game;

        HubsEnum(Hub game) {
            this.game = game;
        }

        public Hub getGame() {
            return game;
        }
    }

    public static class Hub {
        private String id;
        private String forumId;
        private String name;
        private String url;

        public Hub() {
        }

        private Hub(Builder builder) {
            this.id = builder.id;
            this.forumId = builder.forumId;
            this.name = builder.name;
            this.url = builder.url;
        }

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getForumId() {
            return forumId;
        }

        public void setForumId(String forumId) {
            this.forumId = forumId;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getUrl() {
            return url;
        }

        public void setUrl(String url) {
            this.url = url;
        }

        public static class Builder {

            private String id;
            private String forumId;
            private String name;
            private String url;

            public Builder setId(String id) {
                this.id = id;
                return this;
            }

            public Builder setForumId(String forumId) {
                this.forumId = forumId;
                return this;
            }

            public Builder setName(String name) {
                this.name = name;
                return this;
            }

            public Builder setUrl(String url) {
                this.url = url;
                return this;
            }

            public Hub build() {
                return new Hub(this);
            }
        }
    }

}

创建米游社签到抽象类并继承Sign接口

实现签到必要的请求头/Cookie/DS算法

MiHoYoAbstractSign

package qqrobot.module.mihoyo;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.Header;
import org.apache.http.message.BasicHeader;
import java.security.SecureRandom;
import java.util.*;

/**
 * 网址必要的请求头/Cookie/DS算法
 *
 * &#064;Author  Light rain
 * &#064;Date  2022/5/20 12:08
 */
public abstract class MiHoYoAbstractSign implements Sign {
    //构造器注入
    public final String cookie;
    //构造器注入
    public final String uid;
    //服务器id
    public String region;
    //类型
    private String clientType;
    //版本号
    private String appVersion;
    //校验码
    private String salt;

    public MiHoYoAbstractSign(String cookie, String uid) {
        this.cookie = cookie;
        this.uid = uid;
    }

    public MiHoYoAbstractSign(String cookie) {
        this.cookie = cookie;
        this.uid = "";
    }

    //空参数构造器cookie/uid必须初始化
    public MiHoYoAbstractSign() {
        this.cookie = "";
        this.uid = "";
    }

    /**
     * 重写接口请求头getHeaders方法
     *
     * @return Header[]
     */
    @Override
    public Header[] getHeaders() {
        return new HeaderBuilder.Builder().add("x-rpc-device_id", UUID.randomUUID().toString().replace("-", "").toUpperCase()).add("Content-Type", "application/json;charset=UTF-8").add("x-rpc-client_type", getClientType()).add("x-rpc-app_version", getAppVersion()).add("DS", getDS()).addAll(getBasicHeaders()).build();
    }

    /**
     * 请求头基本参数
     *
     * @return Header[]
     */
    protected Header[] getBasicHeaders() {
        return new HeaderBuilder.Builder().add("Cookie", cookie).add("User-Agent", MiHoYoConfig.USER_AGENT).add("Referer", MiHoYoConfig.REFERER_URL).add("Accept-Encoding", "gzip, deflate, br").add("x-rpc-channel", "appstore").add("accept-language", "zh-CN,zh;q=0.9,ja-JP;q=0.8,ja;q=0.7,en-US;q=0.6,en;q=0.5").add("accept-encoding", "gzip, deflate").add("accept-encoding", "gzip, deflate").add("x-requested-with", "com.mihoyo.hyperion").add("Host", "api-takumi.mihoyo.com").build();
    }

    /**
     * 原神签到DS算法
     *
     * @return String
     */
    protected String getDS() {
        String i = (System.currentTimeMillis() / 1000) + "";
        String r = getRandomStr();
        return createDS(getSalt(), i, r);
    }

    /**
     * 获取随机字符串用于DS算法中
     *
     * @return String
     */
    protected String getRandomStr() {
        SecureRandom random = new SecureRandom();
        StringBuilder sb = new StringBuilder();
        for (int i = 1; i <= 6; i++) {
            String CONSTANTS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
            int number = random.nextInt(CONSTANTS.length());
            char charAt = CONSTANTS.charAt(number);
            sb.append(charAt);
        }
        return sb.toString();
    }

    /**
     * 创建DS算法
     *
     * @param n salt
     * @param i t
     * @param r r
     * @return String
     */
    private String createDS(String n, String i, String r) {
        String c = DigestUtils.md5Hex("salt=" + n + "&t=" + i + "&r=" + r);
        return String.format("%s,%s,%s", i, r, c);
    }


//<editor-fold defaultstate="collapsed" desc="delombok">
//</editor-fold>
    /**
     * 建造者模式,用于创建header
     */
    public static class HeaderBuilder {

        public static class Builder {
            private final Map<String, String> header = new HashMap<>();

            public Builder add(String name, String value) {
                this.header.put(name, value);
                return this;
            }

            public Builder addAll(Header[] headers) {
                for (Header h : headers) {
                    this.header.put(h.getName(), h.getValue());
                }
                return this;
            }

            public Header[] build() {
                List<Header> list = new ArrayList<>();
                for (String key : this.header.keySet()) {
                    list.add(new BasicHeader(key, this.header.get(key)));
                }
                return list.toArray(new Header[0]);
            }
        }
    }

    //<editor-fold defaultstate="collapsed" desc="delombok">
    @SuppressWarnings("all")
    public String getCookie() {
        return this.cookie;
    }

    @SuppressWarnings("all")
    public String getUid() {
        return this.uid;
    }

    @SuppressWarnings("all")
    public String getRegion() {
        return this.region;
    }

    @SuppressWarnings("all")
    public String getClientType() {
        return this.clientType;
    }

    @SuppressWarnings("all")
    public String getAppVersion() {
        return this.appVersion;
    }

    @SuppressWarnings("all")
    public String getSalt() {
        return this.salt;
    }

    @SuppressWarnings("all")
    public void setRegion(final String region) {
        this.region = region;
    }

    @SuppressWarnings("all")
    public void setClientType(final String clientType) {
        this.clientType = clientType;
    }

    @SuppressWarnings("all")
    public void setAppVersion(final String appVersion) {
        this.appVersion = appVersion;
    }

    @SuppressWarnings("all")
    public void setSalt(final String salt) {
        this.salt = salt;
    }
    //</editor-fold>
}

创建米游社签到实现类并继承MiHoYoAbstractSign

MiHoYoSignMiHoYo

package qqrobot.module.mihoyo;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.Header;
import qqrobot.module.mihoyo.bean.PostResult;
import qqrobot.util.DateTimeUtils;
import qqrobot.util.HttpUtils;
import com.alibaba.fastjson.TypeReference;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.security.SecureRandom;
import java.util.*;
import java.util.concurrent.*;

/**
 * &#064;Author  Light rain
 * &#064;Date  2022/5/20 12:08
 */
public class MiHoYoSignMiHoYo extends MiHoYoAbstractSign {
    @SuppressWarnings("all")
    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MiHoYoSignMiHoYo.class);
    private MiHoYoConfig.Hub hub;
    private final String stuid;
    private final String stoken;
    private final SecureRandom random = new SecureRandom();
    //浏览帖子数
    private static final int VIEW_NUM = 10;
    //点赞帖子数
    private static final int UP_VOTE_NUM = 10;
    //分享帖子数
    private static final int SHARE_NUM = 3;
    private final CountDownLatch countDownLatch = new CountDownLatch(3);
    //线程
    private final ExecutorService pool;

    /**
     * 构造器注入参数
     *
     * @param cookie   cookie
     * @param hub      签到类型
     * @param stuid    米游社通行证id
     * @param stoken   服务器令牌
     * @param executor 线程池
     */
    public MiHoYoSignMiHoYo(String cookie, MiHoYoConfig.Hub hub, String stuid, String stoken, ThreadPoolExecutor executor) {
        //将cookie赋值给父类
        super(cookie);
        //签到执行类型
        this.hub = hub;
        //社区通行证id
        this.stuid = stuid;
        //服务器令牌
        this.stoken = stoken;
        //设置类型 请勿修改
        setClientType("2");
        //设置版本号 请勿修改
        setAppVersion("2.8.0");
        //设置设置校验码 请勿修改
        setSalt("dmq2p7ka6nsu0d3ev6nex4k1ndzrnfiy");
        //设置线程池
        this.pool = executor;
    }
	//签到
    public Object doSign() throws Exception {
        log.info("{}社区签到任务开始", hub.getName());
        String sign = (String) sign();
        if (sign.contains("登录失效")) {
            return "米游社Cookie失效\n请重新绑定米游社";
        }
        List<PostResult> genShinHomePosts = getGenShinHomePosts();
        List<PostResult> homePosts = getPosts();
        genShinHomePosts.addAll(homePosts);
        log.info("{}获取社区帖子数: {}", hub.getName(), genShinHomePosts.size());
        //执行任务
        Future<Integer> vpf = pool.submit(createTask(this, "viewPost", VIEW_NUM, genShinHomePosts));
        Future<Integer> spf = pool.submit(createTask(this, "sharePost", SHARE_NUM, genShinHomePosts));
        Future<Integer> upf = pool.submit(createTask(this, "upVotePost", UP_VOTE_NUM, genShinHomePosts));
        //打印日志
        log.info("浏览帖子,成功: {},失败:{}", vpf.get(), VIEW_NUM - vpf.get());
        log.info("点赞帖子,成功: {},失败:{}", upf.get(), UP_VOTE_NUM - upf.get());
        log.info("分享帖子,成功: {},失败:{}", spf.get(), SHARE_NUM - spf.get());
        log.info("{}社区签到任务完成", hub.getName());
        String executionTime = DateTimeUtils.convertTimest(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss");
        String msg = "执行时间: %s\n社区签到: %s\n获取社区帖子数: %s\n浏览帖子: %s,点赞帖子: %s,分享帖子: %s\n已领取今日米游币";
        return String.format(msg, executionTime, sign, genShinHomePosts.size(), vpf.get(), upf.get(), spf.get());
    }
	//创建任务
    public Callable<Integer> createTask(Object obj, String methodName, int num, List<PostResult> posts) {
        return () -> {
            try {
                return doTask(obj, obj.getClass().getDeclaredMethod(methodName, PostResult.class), num, posts);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
            return 0;
        };
    }

    public int doTask(Object obj, Method method, int num, List<PostResult> posts) {
        countDownLatch.countDown();
        int sc = 0;
        // 保证每个浏览(点赞,分享)的帖子不重复
        HashSet<Object> set = new HashSet<>(num);
        for (int i = 0; i < num; i++) {
            int index = 0;
            while (set.contains(index)) {
                index = random.nextInt(posts.size());
            }
            set.add(index);
            try {
                method.invoke(obj, posts.get(index));
                sc++;
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                TimeUnit.SECONDS.sleep(random.nextInt(2));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return sc;
    }

    /**
     * 社区签到
     */
    public Object sign() {
        JSONObject signResult = HttpUtils.doPost(String.format(MiHoYoConfig.HUB_SIGN_URL, hub.getForumId()), getHeaders(), null);
        if ("OK".equals(signResult.get("message")) || "重复".equals(signResult.get("message"))) {
            log.info("社区签到: {}", signResult.get("message"));
        } else {
            log.info("社区签到失败: {}", signResult.get("message"));
        }
        return signResult.get("message");
    }

    /**
     * 游戏频道
     *
     * @throws Exception
     */
    public List<PostResult> getGenShinHomePosts() throws Exception {
        return getPosts(String.format(MiHoYoConfig.HUB_LIST1_URL, hub.getForumId()));
    }

    /**
     * 讨论区
     *
     * @throws Exception
     */
    public List<PostResult> getPosts() throws Exception {
        return getPosts(String.format(MiHoYoConfig.HUB_LIST2_URL, hub.getId()));
    }

    /**
     * 获取帖子
     *
     * @throws Exception
     */
    public List<PostResult> getPosts(String url) throws Exception {
        JSONObject result = HttpUtils.doGet(url, getHeaders());
        if ("OK".equals(result.get("message"))) {
            JSONArray jsonArray = result.getJSONObject("data").getJSONArray("list");
            return JSON.parseObject(JSON.toJSONString(jsonArray), new TypeReference<List<PostResult>>() {
            });
        } else {
            throw new Exception("帖子数为空,请查配置并更新!!!");
        }
    }

    /**
     * 看帖
     *
     * @param post
     */
    public boolean viewPost(PostResult post) {
        Map<String, Object> data = new HashMap<>();
        data.put("post_id", post.getPost().getPost_id());
        data.put("is_cancel", false);
        JSONObject result = HttpUtils.doGet(String.format(MiHoYoConfig.HUB_VIEW_URL, hub.getForumId()), getHeaders(), data);
        return "OK".equals(result.get("message"));
    }

    /**
     * 点赞
     *
     * @param post
     */
    public boolean upVotePost(PostResult post) {
        Map<String, Object> data = new HashMap<>();
        data.put("post_id", post.getPost().getPost_id());
        data.put("is_cancel", false);
        JSONObject result = HttpUtils.doPost(MiHoYoConfig.HUB_VOTE_URL, getHeaders(), data);
        return "OK".equals(result.get("message"));
    }

    /**
     * 分享
     *
     * @param post
     */
    public boolean sharePost(PostResult post) {
        JSONObject result = HttpUtils.doGet(String.format(MiHoYoConfig.HUB_SHARE_URL, hub.getForumId()), getHeaders());
        return "OK".equals(result.get("message"));
    }

    /**
     * 获取 stoken
     *
     * @throws URISyntaxException
     */
    public String getCookieToken() throws Exception {
        JSONObject result = HttpUtils.doGet(String.format(MiHoYoConfig.HUB_COOKIE2_URL, getCookieByName("login_ticket"), getCookieByName("account_id")), getHeaders());
        if (!"OK".equals(result.get("message"))) {
            log.info("login_ticket已失效,请重新登录获取");
            throw new Exception("login_ticket已失效,请重新登录获取");
        }
        return (String) result.getJSONObject("data").getJSONArray("list").getJSONObject(0).get("token");
    }

    public String getCookieByName(String name) {
        String[] split = cookie.split(";");
        for (String s : split) {
            String h = s.trim();
            if (h.startsWith(name)) {
                return h.substring(h.indexOf('=') + 1);
            }
        }
        return null;
    }

    @Override
    public Header[] getHeaders() {
        return new HeaderBuilder.Builder().add("x-rpc-client_type", getClientType()).add("x-rpc-app_version", getAppVersion()).add("x-rpc-sys_version", "10").add("x-rpc-channel", "miyousheluodi").add("x-rpc-device_id", UUID.randomUUID().toString().replace("-", "").toLowerCase()).add("x-rpc-device_name", "Xiaomi Redmi Note 4").add("Referer", "https://app.mihoyo.com").add("Content-Type", "application/json").add("Host", "bbs-api.mihoyo.com").add("Connection", "Keep-Alive").add("Accept-Encoding", "gzip").add("User-Agent", "okhttp/4.8.0").add("x-rpc-device_model", "Redmi Note 4").add("isLogin", "true").add("DS", getDS()).add("cookie", "stuid=" + stuid + ";stoken=" + stoken + ";").build();
    }

    public void reSetHub(MiHoYoConfig.Hub hub) {
        this.hub = hub;
    }
}

创建原神签到实现类并继承MiHoYoAbstractSign

GenShinSignMiHoYo

package qqrobot.module.mihoyo.genshin;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import qqrobot.module.mihoyo.MiHoYoAbstractSign;
import qqrobot.module.mihoyo.MiHoYoConfig;
import qqrobot.module.mihoyo.genshin.bean.Award;
import qqrobot.util.HttpUtils;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 原神签到实现类
 *
 * &#064;Author  Light rain
 * &#064;Date  2022/5/20 2:34
 */
public class GenShinSignMiHoYo extends MiHoYoAbstractSign {
    //<editor-fold defaultstate="collapsed" desc="delombok">
    @SuppressWarnings("all")
    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(GenShinSignMiHoYo.class);
    //</editor-fold>

    public GenShinSignMiHoYo(String cookie, String uid) {
        //将cookie/uid赋值给父类
        super(cookie, uid);
        //设置类型 请勿修改
        setClientType("5");
        //设置版本号 请勿修改
        setAppVersion("2.3.0");
        //设置校验码 请勿修改
        setSalt("h8w582wxwgqvahcdkpvdhbh2w9casgfl");
        //设置服务器id
        setRegion(getRegion());
    }

    /**
     * 米游社原神福利签到
     *
     * @return message
     */
    public Object sign() {
        Map<String, Object> data = new HashMap<>();
        data.put("act_id", MiHoYoConfig.ACT_ID);
        data.put("region", this.region);
        data.put("uid", this.uid);
        JSONObject signResult = HttpUtils.doPost(MiHoYoConfig.SIGN_URL, getHeaders(), data);
        if (signResult.getInteger("retcode") == 0) {
            log.info("原神签到福利成功:{}", signResult.get("message"));
        } else {
            log.info("原神签到福利签到失败:{}", signResult.get("message"));
        }
        return signResult.get("message");
    }

    /**
     * 获取uid和昵称
     *
     * @return nickname
     */
    public String getName() {
        try {
            JSONObject result = HttpUtils.doGet(MiHoYoConfig.ROLE_URL, getBasicHeaders());
            String uid = (String) result.getJSONObject("data").getJSONArray("list").getJSONObject(0).get("game_uid");
            String nickname = (String) result.getJSONObject("data").getJSONArray("list").getJSONObject(0).get("nickname");
            log.info("获取用户UID:{}", uid);
            log.info("当前用户名称:{}", nickname);
            return nickname;
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * 获取原神服务器id 官服:cn_gf01天空岛/B服:cn_qd01世界树
     * @return String
     */
    public String getRegion() {
        try {
            JSONObject result = HttpUtils.doGet(MiHoYoConfig.ROLE_URL, getBasicHeaders());
            return (String) result.getJSONObject("data").getJSONArray("list").getJSONObject(0).get("region");
        } catch (NullPointerException e) {
            return "";
        }
    }

    /**
     * 获取今天奖励详情
     *
     * @param day 天数
     * @return List<Award>
     */
    public Award getAwardInfo(int day) {
        JSONObject awardResult = HttpUtils.doGet(MiHoYoConfig.AWARD_URL, getHeaders());
        JSONArray jsonArray = awardResult.getJSONObject("data").getJSONArray("awards");
        List<Award> awards = JSON.parseObject(JSON.toJSONString(jsonArray), new TypeReference<>() {
        });
        return awards.get(day - 1);
    }

    /**
     * 社区签到并查询当天奖励
     *
     * @return %s月已签到%s天
     * 已获取%s%s
     */
    public String hubSign() {
        try {
            Map<String, Object> data = new HashMap<>();
            data.put("act_id", MiHoYoConfig.ACT_ID);
            data.put("region", this.region);
            data.put("uid", this.uid);
            JSONObject signInfoResult = HttpUtils.doGet(MiHoYoConfig.INFO_URL, getHeaders(), data);
            LocalDateTime time = LocalDateTime.now();
            Boolean isSign = signInfoResult.getJSONObject("data").getBoolean("is_sign");
            Integer totalSignDay = signInfoResult.getJSONObject("data").getInteger("total_sign_day");
            int day = isSign ? totalSignDay : totalSignDay + 1;
            Award award = getAwardInfo(day);
            log.info("{}月已签到{}天", time.getMonth().getValue(), totalSignDay);
            log.info("{}签到获取{}{}", signInfoResult.getJSONObject("data").get("today"), award.getCnt(), award.getName());
            return String.format("%s月已签到%s天\n已获取%s%s", time.getMonth().getValue(), totalSignDay, award.getCnt(), award.getName());
        } catch (Exception e) {
            return "";
        }
    }

}


不知道如何获取Cookie

原神cookie获取
米游社cookie获取

测试

package qqrobot;

import qqrobot.module.mihoyo.MiHoYoConfig;
import qqrobot.module.mihoyo.MiHoYoSignMiHoYo;
import qqrobot.module.mihoyo.genshin.GenShinSignMiHoYo;
import qqrobot.util.GetstokenUtils;

import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

public class Main {
    public static void main(String[] args) throws Exception {
        /********************米游社签到测试**********************/
        String 米游社Cookie = "请填写你自己的米游社Cookie";
        String 米游社通行证id = "请填写你自己的通行证id";
        //根据米游社Cookie获取token
        String token = GetstokenUtils.doGen(米游社Cookie);
//        String token = "RAhvsueASxnSFa8cK6bn0OXP319LL9lHWwJr5wzS";
        ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool();
        MiHoYoSignMiHoYo mihoyo = new MiHoYoSignMiHoYo(米游社Cookie, MiHoYoConfig.HubsEnum.DBY.getGame(), 米游社通行证id, token, executor);
        mihoyo.doSign();

        /********************原神签到测试**********************/
        String 原神Cookie = "请填写你自己的原神Cookie";
        String 原神uid = "请填写你自己的原神uid";
        GenShinSignMiHoYo gs = new GenShinSignMiHoYo(原神Cookie,原神uid);
        gs.sign();
    }
}

运行结果

在这里插入图片描述
在这里插入图片描述
本项目已开源
开源地址为https://github.com/Rain238/rain-robot/tree/master
如有其他问题加Q:3164395730
好友申请备注CSDN

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐