Skip to content
This repository was archived by the owner on Oct 3, 2023. It is now read-only.

Commit 33d92ba

Browse files
author
Chen LangNing
authored
Merge pull request #583 from langningchen/langningchen/issue432
自制图床,讨论区 Ctrl+V 上传图片
2 parents ef4d828 + c45bc1f commit 33d92ba

4 files changed

Lines changed: 170 additions & 22 deletions

File tree

Server/Source/Process.ts

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { Result, ThrowErrorIfFailed } from "./Result";
22
import { Database } from "./Database";
33
import { Output } from "./Output";
4-
import { CaptchaSecretKey } from "./Secret";
4+
import { CaptchaSecretKey, GithubImagePAT } from "./Secret";
55
import { CheerioAPI, load } from "cheerio";
66
import CryptoJS from "crypto-js";
7+
import md5 from "crypto-js/md5";
78

89
export class Process {
910
private AdminUserList: Array<string> = ["chenlangning", "zhuchenrui2", "shanwenxiao"];
@@ -1017,21 +1018,92 @@ export class Process {
10171018
return new Result(true, "获得板块列表成功", {
10181019
"Boards": Boards
10191020
});
1021+
},
1022+
UploadImage: async (Data: object): Promise<Result> => {
1023+
const GithubImageRepo = "langningchen/XMOJ-Script-Pictures";
1024+
ThrowErrorIfFailed(this.CheckParams(Data, {
1025+
"Image": "string"
1026+
}));
1027+
let Image: String = Data["Image"];
1028+
let ImageID: String = "";
1029+
for (let i = 0; i < 32; i++) {
1030+
ImageID += String.fromCharCode(Math.floor(Math.random() * 26) + 97);
1031+
}
1032+
let ImageData = Image.replace(/^data:image\/\w+;base64,/, "");
1033+
await fetch(new URL("https://api.github.com/repos/" + GithubImageRepo + "/contents/" + ImageID), {
1034+
method: "PUT",
1035+
headers: {
1036+
"Authorization": "Bearer " + GithubImagePAT,
1037+
"Content-Type": "application/json",
1038+
"User-Agent": "XMOJ-Script-Server"
1039+
},
1040+
body: JSON.stringify({
1041+
message: `${this.Username} ${new Date().getFullYear()}/${new Date().getMonth() + 1}/${new Date().getDate()} ${new Date().getHours()}:${new Date().getMinutes()}:${new Date().getSeconds()}`,
1042+
content: ImageData
1043+
})
1044+
}).then((Response) => {
1045+
return Response.json();
1046+
}).then((Response) => {
1047+
if (Response["content"]["name"] !== ImageID) {
1048+
Output.Error("Upload image failed\n" +
1049+
"Username: \"" + this.Username + "\"\n" +
1050+
"ImageID : \"" + ImageID + "\"\n" +
1051+
"Response: \"" + JSON.stringify(Response) + "\"\n");
1052+
ThrowErrorIfFailed(new Result(false, "上传图片失败"));
1053+
}
1054+
}).catch((Error) => {
1055+
Output.Error("Upload image failed: " + Error + "\n" +
1056+
"Username: \"" + this.Username + "\"\n" +
1057+
"ImageID : \"" + ImageID + "\"\n");
1058+
ThrowErrorIfFailed(new Result(false, "上传图片失败"));
1059+
});
1060+
return new Result(true, "上传图片成功", {
1061+
ImageID: ImageID
1062+
});
1063+
},
1064+
GetImage: async (Data: object): Promise<Blob> => {
1065+
const GithubImageRepo = "langningchen/XMOJ-Script-Pictures";
1066+
ThrowErrorIfFailed(this.CheckParams(Data, {
1067+
"ImageID": "string"
1068+
}));
1069+
return await fetch(new URL("https://api.github.com/repos/" + GithubImageRepo + "/contents/" + Data["ImageID"] + "?1=1"), {
1070+
method: "GET",
1071+
headers: {
1072+
"Authorization": "Bearer " + GithubImagePAT,
1073+
"Accept": "application/vnd.github.v3.raw",
1074+
"User-Agent": "XMOJ-Script-Server"
1075+
}
1076+
}).then((Response) => {
1077+
return Response.blob();
1078+
}).catch((Error) => {
1079+
Output.Error("Get image failed: " + Error + "\n" +
1080+
"ImageID : \"" + Data["ImageID"] + "\"\n");
1081+
return new Blob();
1082+
});
10201083
}
10211084
};
10221085
constructor(RequestData: Request, Environment) {
10231086
this.XMOJDatabase = new Database(Environment.DB);
10241087
this.RequestData = RequestData;
10251088
this.RemoteIP = RequestData.headers.get("CF-Connecting-IP") || "";
10261089
}
1027-
public async Process(): Promise<Result> {
1090+
public async Process(): Promise<Response> {
10281091
try {
10291092
let PathName = new URL(this.RequestData.url).pathname;
10301093
PathName = PathName === "/" ? "/index" : PathName;
10311094
PathName = PathName.substring(1);
10321095
if (this.ProcessFunctions[PathName] === undefined) {
10331096
throw new Result(false, "访问的页面不存在");
10341097
}
1098+
if (this.RequestData.method === "GET" && PathName === "GetImage") {
1099+
return new Response(await this.ProcessFunctions[PathName]({
1100+
ImageID: new URL(this.RequestData.url).searchParams.get("ImageID")
1101+
}), {
1102+
headers: {
1103+
"content-type": "image/png"
1104+
}
1105+
});
1106+
}
10351107
if (this.RequestData.method !== "POST") {
10361108
throw new Result(false, "不允许此请求方式");
10371109
}
@@ -1067,7 +1139,11 @@ export class Process {
10671139
Output.Error(ResponseData);
10681140
ResponseData = new Result(false, "服务器运行错误:" + String(ResponseData).split("\n")[0]);
10691141
}
1070-
return ResponseData;
1142+
return new Response(JSON.stringify(ResponseData), {
1143+
headers: {
1144+
"content-type": "application/json;charset=UTF-8"
1145+
}
1146+
});
10711147
}
10721148
}
10731149
}

Server/Source/index.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,7 @@ import { Database } from "./Database";
44
export default {
55
async fetch(RequestData: Request, Environment, Context) {
66
let Processor = new Process(RequestData, Environment);
7-
return new Response(JSON.stringify(await Processor.Process()), {
8-
headers: {
9-
"content-type": "application/json;charset=UTF-8"
10-
}
11-
});
7+
return await Processor.Process();
128
},
139
async scheduled(Event, Environment, Context) {
1410
let XMOJDatabase = new Database(Environment.DB);

Update.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,16 @@
705705
"Description": "修复关闭时左上角仍显示为高老师的OJ"
706706
}
707707
]
708+
},
709+
"0.3.192": {
710+
"UpdateDate": 1696222135180,
711+
"Prerelease": true,
712+
"UpdateContents": [
713+
{
714+
"PR": 583,
715+
"Description": "自制图床,讨论区 Ctrl+V 上传图片"
716+
}
717+
]
708718
}
709719
}
710720
}

XMOJ.user.js

Lines changed: 80 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// ==UserScript==
22
// @name XMOJ
3-
// @version 0.3.191
3+
// @version 0.3.192
44
// @description XMOJ增强脚本
55
// @author @langningchen
66
// @namespace https://github/langningchen
@@ -47,17 +47,22 @@ let GetRelativeTime = (Input) => {
4747
else { RelativeName = Math.floor((Now - Input) / 1000 / 60 / 60 / 24 / 365) + "年前"; }
4848
return "<span title=\"" + Input.toLocaleString() + "\">" + RelativeName + "</span>";
4949
};
50-
let RenderMathJax = () => {
51-
var ScriptElement = document.createElement("script");
52-
ScriptElement.id = "MathJax-script";
53-
ScriptElement.type = "text/javascript";
54-
ScriptElement.src = "https://cdn.bootcdn.net/ajax/libs/mathjax/3.0.5/es5/tex-chtml.js";
55-
document.body.appendChild(ScriptElement);
56-
ScriptElement.onload = () => {
57-
MathJax.startup.input[0].findTeX.options.inlineMath.push(["$", "$"]);
58-
MathJax.startup.input[0].findTeX.getPatterns();
59-
MathJax.typeset();
60-
};
50+
let RenderMathJax = async () => {
51+
if (document.getElementById("MathJax-script") === null) {
52+
var ScriptElement = document.createElement("script");
53+
ScriptElement.id = "MathJax-script";
54+
ScriptElement.type = "text/javascript";
55+
ScriptElement.src = "https://cdn.bootcdn.net/ajax/libs/mathjax/3.0.5/es5/tex-chtml.js";
56+
document.body.appendChild(ScriptElement);
57+
await new Promise((Resolve) => {
58+
ScriptElement.onload = () => {
59+
Resolve();
60+
};
61+
});
62+
}
63+
MathJax.startup.input[0].findTeX.options.inlineMath.push(["$", "$"]);
64+
MathJax.startup.input[0].findTeX.getPatterns();
65+
MathJax.typeset();
6166
};
6267
let GetUserInfo = async (Username) => {
6368
if (localStorage.getItem("UserScript-User-" + Username + "-UserRating") != null &&
@@ -3697,14 +3702,33 @@ int main()
36973702
}
36983703
});
36993704
ContentElement.addEventListener("input", () => {
3705+
ContentElement.classList.remove("is-invalid");
37003706
PreviewTab.innerHTML = DOMPurify.sanitize(marked.parse(ContentElement.value));
37013707
RenderMathJax();
37023708
});
37033709
TitleElement.addEventListener("input", () => {
37043710
TitleElement.classList.remove("is-invalid");
37053711
});
3706-
ContentElement.addEventListener("input", () => {
3707-
ContentElement.classList.remove("is-invalid");
3712+
ContentElement.addEventListener("paste", (Event) => {
3713+
let Items = Event.clipboardData.items;
3714+
if (Items.length !== 0) {
3715+
for (let i = 0; i < Items.length; i++) {
3716+
if (Items[i].type.indexOf("image") != -1) {
3717+
let Reader = new FileReader();
3718+
Reader.readAsDataURL(Items[i].getAsFile());
3719+
Reader.onload = () => {
3720+
RequestAPI("UploadImage", {
3721+
"Image": Reader.result
3722+
}, (ResponseData) => {
3723+
if (ResponseData.Success) {
3724+
ContentElement.value += `![](https://api.xmoj-bbs.tech/GetImage?ImageID=${ResponseData.Data.ImageID})`;
3725+
ContentElement.dispatchEvent(new Event("input"));
3726+
}
3727+
});
3728+
};
3729+
}
3730+
}
3731+
}
37083732
});
37093733
SubmitElement.addEventListener("click", async () => {
37103734
ErrorElement.style.display = "none";
@@ -3853,6 +3877,27 @@ int main()
38533877
PreviewTab.innerHTML = DOMPurify.sanitize(marked.parse(ContentElement.value));
38543878
RenderMathJax();
38553879
});
3880+
ContentElement.addEventListener("paste", (Event) => {
3881+
let Items = Event.clipboardData.items;
3882+
if (Items.length !== 0) {
3883+
for (let i = 0; i < Items.length; i++) {
3884+
if (Items[i].type.indexOf("image") != -1) {
3885+
let Reader = new FileReader();
3886+
Reader.readAsDataURL(Items[i].getAsFile());
3887+
Reader.onload = () => {
3888+
RequestAPI("UploadImage", {
3889+
"Image": Reader.result
3890+
}, (ResponseData) => {
3891+
if (ResponseData.Success) {
3892+
ContentElement.value += `![](https://api.xmoj-bbs.tech/GetImage?ImageID=${ResponseData.Data.ImageID})`;
3893+
ContentElement.dispatchEvent(new Event("input"));
3894+
}
3895+
});
3896+
};
3897+
}
3898+
}
3899+
}
3900+
});
38563901
let RefreshReply = (Silent = true) => {
38573902
if (!Silent) {
38583903
PostTitle.innerHTML = `<span class="placeholder col-${Math.ceil(Math.random() * 6)}"></span>`;
@@ -4057,6 +4102,27 @@ int main()
40574102
PreviewTab.innerHTML = DOMPurify.sanitize(marked.parse(ContentEditor.value));
40584103
RenderMathJax();
40594104
});
4105+
ContentEditor.addEventListener("paste", (Event) => {
4106+
let Items = Event.clipboardData.items;
4107+
if (Items.length !== 0) {
4108+
for (let i = 0; i < Items.length; i++) {
4109+
if (Items[i].type.indexOf("image") != -1) {
4110+
let Reader = new FileReader();
4111+
Reader.readAsDataURL(Items[i].getAsFile());
4112+
Reader.onload = () => {
4113+
RequestAPI("UploadImage", {
4114+
"Image": Reader.result
4115+
}, (ResponseData) => {
4116+
if (ResponseData.Success) {
4117+
ContentEditor.value += `![](https://api.xmoj-bbs.tech/GetImage?ImageID=${ResponseData.Data.ImageID})`;
4118+
ContentEditor.dispatchEvent(new Event("input"));
4119+
}
4120+
});
4121+
};
4122+
}
4123+
}
4124+
}
4125+
});
40604126
}
40614127

40624128
let UsernameElements = document.getElementsByClassName("Usernames");

0 commit comments

Comments
 (0)