All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.dennisit.vplus.data.utils.LeetUtils Maven / Gradle / Ivy

There is a newer version: 2.0.8
Show newest version
package com.github.dennisit.vplus.data.utils;

import cn.hutool.core.text.UnicodeUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.data.annotation.Id;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@Slf4j
public class LeetUtils {

    private static final String DEFAULT_PATH = "/var/hexo_leet/";

    private static final RestTemplate restTemplate = new RestTemplate();

    private static final String SOURCE =
            "---\n" +
                    "title: {title}\n" +
                    "date: 2014-01-01 20:40:53\n" +
                    "tags: [Leet, {difficulty}]\n" +
                    "categories: [算法实践]\n" +
                    "---\n" +
                    "\n" +
                    "> {title}\n" +
                    "\n" +
                    "### 题目描述\n" +
                    "\n" +
                    "{content}\n" +
                    "\n" +
                    "### 力扣地址\n" +
                    "\n" +
                    "- {enUrl}" +
                    "\n" +
                    "- {cnUrl}" +
                    "\n" +
                    "\n" +
                    "\n" +
                    "### 解题报告\n" +
                    "\n" +
                    "\n" +
                    "``` java\n" +
                    "\n" +
                    "```\n" +
                    "\n";

    private static final String QUERY = "query getQuestionDetail($titleSlug: String!) {\n" +
            "            question(titleSlug: $titleSlug) {\n" +
            "                questionId\n" +
            "                questionFrontendId\n" +
            "                questionTitle\n" +
            "                questionTitleSlug\n" +
            "                content\n" +
            "                translatedTitle\n" +
            "                translatedContent\n" +
            "                isPaidOnly\n" +
            "                difficulty\n" +
            "                stats\n" +
            "                solution {\n" +
            "                   id\n" +
            "                   canSeeDetail\n" +
            "                   __typename\n" +
            "                }\n" +
            "                similarQuestions\n" +
            "                metaData\n" +
            "                categoryTitle\n" +
            "                topicTags {\n" +
            "                        name\n" +
            "                        slug\n" +
            "                }\n" +
            "            }\n" +
            "        }";


    public static JSONObject getOneQuestion(String titleSlug) {
        HttpHeaders headers = defaultHeathers();
        headers.add("Content-Type", "application/json");
        headers.add("Referer", "https://leetcode-cn.com/problems/" + titleSlug);
        Map map = Maps.newHashMap();
        map.put("operationName", "getQuestionDetail");
        map.put("variables", JSON.toJSONString(Pair.of("titleSlug", titleSlug)));
        map.put("query", QUERY);
        HttpEntity httpEntity = new HttpEntity<>(UnicodeUtil.toUnicode(JSON.toJSONString(map)), headers);
        JSONObject json = restTemplate.postForObject("https://leetcode-cn.com/graphql", httpEntity, JSONObject.class);
        JSONObject question = Optional.ofNullable(json).map(x -> x.getJSONObject("data")).map(x -> x.getJSONObject("question")).orElse(null);
        return question;
    }


    public static List getAllQuestion() {
        HttpHeaders headers = defaultHeathers();
        HttpEntity httpEntity = new HttpEntity<>(headers);
        ResponseEntity responseEntity = restTemplate.exchange("https://leetcode.com/api/problems/all/", HttpMethod.GET, httpEntity, String.class);
        JSONObject json = JSON.parseObject(responseEntity.getBody(), JSONObject.class); //JSON.parseObject(source, JSONObject.class);
        JSONArray arr = Optional.ofNullable(json).map(x -> x.getJSONArray("stat_status_pairs")).orElse(null);
        List list = Lists.newArrayList();
        if (null != arr) {
            for (int i = 0; i < arr.size(); i++) {
                JSONObject statJSON = Optional.ofNullable(arr.getJSONObject(i)).map(x -> x.getJSONObject("stat")).orElse(null);
                JSONObject levelJSON = Optional.ofNullable(arr.getJSONObject(i)).map(x -> x.getJSONObject("difficulty")).orElse(null);
                if (null == statJSON || null == levelJSON) {
                    continue;
                }
                LView view = new LView(statJSON.getIntValue("question_id"), levelJSON.getIntValue("level"), statJSON.getString("question__title"),
                        statJSON.getString("question__title_slug"),
                        Optional.ofNullable(arr.getJSONObject(i)).map(x -> x.getBooleanValue("paid_only")).orElse(false)
                );
                list.add(view);
            }
        }
        return list;
    }

    public static List getFullQuestion() {
        List list = getAllQuestion();
        Optional.ofNullable(list).orElse(Lists.newArrayList()).stream()
                .forEach(x -> {
                    JSONObject json = getOneQuestion(x.getTitleSlug());
                    json.getString("");
                    x.setDifficulty(Optional.ofNullable(json).map(e -> e.getString("difficulty")).orElse(""));
                    x.setCategory(Optional.ofNullable(json).map(e -> e.getString("category")).orElse(""));
                    x.setContent(Optional.ofNullable(json).map(e -> e.getString("content")).orElse(""));
                    x.setCnContent(Optional.ofNullable(json).map(e -> e.getString("translatedContent")).orElse(""));
                    x.setCnTitle(Optional.ofNullable(json).map(e -> e.getString("translatedTitle")).orElse(""));
                    x.setFrontId(Optional.ofNullable(json).map(e -> e.getLongValue("questionFrontendId")).orElse(-1L));
                });
        return list;
    }

    private static HttpHeaders defaultHeathers() {
        HttpHeaders headers = new HttpHeaders();
        headers.add("Referer", "https://leetcode-cn.com/");
        headers.add("Origin", " https://leetcode-cn.com");
        headers.add("Connection", "keep-alive");
        headers.add("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36");
        return headers;
    }

    public static void createHexoFile() {
        createHexoFile(DEFAULT_PATH, false);
    }

    public static void createHexoFile(String path) {
        createHexoFile(path, false);
    }

    public static void createHexoFile(boolean isContent) {
        createHexoFile(LeetUtils.getFullQuestion(), isContent);
    }

    public static void createHexoFile(List list, boolean isContent) {
        createHexoFile(DEFAULT_PATH, list, isContent);
    }

    public static void createHexoFile(String path, boolean isContent) {
        createHexoFile(path, LeetUtils.getFullQuestion(), isContent);
    }

    public static void createHexoFile(String path, List list, boolean isContent) {
        Optional.ofNullable(list).orElse(Lists.newArrayList()).stream().filter(x -> !x.isPaid()).forEach(x -> createHexoFile(path, x, isContent));
    }

    public static void createHexoFile(LeetUtils.LView lView, boolean isContent) {
        createHexoFile(DEFAULT_PATH, lView, isContent);
    }

    public static void createHexoFile(String path, LeetUtils.LView lView, boolean isContent) {
        createHexoFile(path, lView, true, isContent);
    }

    public static void createHexoFile(String path, LeetUtils.LView lView, boolean zh, boolean isContent) {
        path = org.apache.commons.lang3.StringUtils.isBlank(path) ? DEFAULT_PATH : org.apache.commons.lang3.StringUtils.trim(path);
        String source = formatContent(lView, zh, isContent);
        Path file = Paths.get(path + formatTitle(lView, zh) + ".md");
        try {
            if (!Files.exists(file)) {
                Files.createFile(file);
            }
            Files.write(file, source.getBytes(StandardCharsets.UTF_8));
            log.info("[Leet] Leet To Hexo: {}", formatTitle(lView, zh));
        } catch (Exception e) {
            log.error(e.getLocalizedMessage(), e);
        }
    }

    private static String formatTitle(LeetUtils.LView lView, boolean zh) {
        return org.apache.commons.lang3.StringUtils.leftPad(String.valueOf(lView.getFrontId()), 5, '0') + " " + StringUtils.trim(zh ? lView.getCnTitle() : lView.getContent());
    }

    private static String formatContent(LeetUtils.LView lView, boolean zh, boolean isContent) {
        return SOURCE
                .replaceAll("\\{title\\}", formatTitle(lView, zh))
                .replaceAll("\\{difficulty\\}", lView.getDifficulty())
                .replaceAll("\\{content\\}", isContent ? (zh ? lView.getCnContent() : lView.getContent()) : "")
                .replaceAll("\\{enUrl\\}", lView.getEnUrl())
                .replaceAll("\\{cnUrl\\}", lView.getCnUrl());

    }


    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class LView implements Serializable {

        @Id
        private long id;

        private long frontId;

        private int level;

        private String title;

        private String titleSlug;

        private String content;

        private String cnTitle;

        private String cnContent;

        private String enUrl;

        private String cnUrl;

        private String difficulty;

        private String category;

        private boolean paid;

        public LView(String titleSlug) {
            this.titleSlug = titleSlug;
            this.enUrl = "https://leetcode.com/problems/" + titleSlug;
            this.cnUrl = "https://leetcode-cn.com/problems/" + titleSlug;
        }

        public LView(long id, int level, String title, String titleSlug, boolean paid) {
            this(titleSlug);
            this.id = id;
            this.level = level;
            this.title = title;
            this.paid = paid;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy