Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.github.dennisit.vplus.data.utils.LeetUtils Maven / Gradle / Ivy
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;
}
}
}