HiddenPhox/src/modules/codePreviews.js

195 lines
5.4 KiB
JavaScript

const {MessageFlags} = require("@projectdysnomia/dysnomia").Constants;
const events = require("../lib/events.js");
const {hasFlag} = require("../lib/guildSettings.js");
const REGEX_GITHUB =
/(?:\s|^)(\|\|\s*)?https?:\/\/(www\.)?github\.com\/[a-z0-9-]+\/[a-z0-9-]+\/blob\/([a-z0-9-_.#/]*)(\s*\|\|)?/gi;
const REGEX_GITLAB =
/(?:\s|^)(\|\|\s*)?https?:\/\/.+?\/[a-z0-9-]+\/[a-z0-9-]+\/-\/blob\/([a-z0-9-_.#/]*)(\s*\|\|)?/gi;
const REGEX_GITEA =
/(?:\s|^)(\|\|\s*)?https?:\/\/.+?\/[a-z0-9-]+\/[a-z0-9-]+\/src\/branch\/([a-z0-9-_.#/]*)(\s*\|\|)?/gi;
const REGEX_SPOILER = /(?:\s|^)\|\|([\s\S]+?)\|\|/;
function unindent(str) {
str = str.replace(/\t/g, " ");
const minIndent =
str
.match(/^ *(?=\S)/gm)
?.reduce((prev, curr) => Math.min(prev, curr.length), Infinity) ?? 0;
if (!minIndent) return str;
return str.replace(new RegExp(`^ {${minIndent}}`, "gm"), "");
}
async function processFile(link, spoiler = false) {
link = link.replaceAll("||", "").trim();
const res = await fetch(link);
if (!res.ok) return "";
if (!res.headers.get("Content-Type").startsWith("text/plain")) return "";
const file = await res.text();
const lines = file.replace(/\r/g, "").split("\n");
const fileName = link.substring(
link.lastIndexOf("/") + 1,
link.indexOf("#") == -1 ? link.length : link.indexOf("#")
);
const fileType =
fileName.lastIndexOf(".") == -1
? ""
: fileName.substring(fileName.lastIndexOf(".") + 1);
if (fileType == "md") return "";
const lineStr = link.match(/#L\d+(-L?\d+)?/)?.[0];
let startLine, endLine;
let entireFile = false;
if (lineStr) {
const [start, end] = lineStr.match(/\d+/g);
if (!end) {
startLine = endLine = start;
} else {
startLine = start;
endLine = end;
}
} else {
entireFile = true;
startLine = 0;
endLine = lines.length;
}
const whichLines = entireFile
? ""
: startLine == endLine
? "Line " + startLine
: "Lines " + startLine + "-" + endLine;
if (entireFile && lines.length > 20) return "";
let targetLines = (
entireFile ? lines : lines.slice(startLine - 1, endLine)
).join("\n");
let warning = "";
if (spoiler && targetLines.includes("||")) {
targetLines = targetLines.replaceAll("||", "|\u200b|");
warning = " - :warning: Zero width spaces present";
}
if (targetLines.includes("``")) {
targetLines = targetLines.replaceAll("``", "`\u200b`");
warning = " - :warning: Zero width spaces present";
}
return `**${fileName}: **${whichLines}${warning}\n${
spoiler ? "||" : ""
}\`\`\`${fileType}\n${unindent(targetLines)}\n\`\`\`${spoiler ? "||" : ""}`;
}
events.add("messageCreate", "codePreviews", async function (msg) {
if (msg.author.id == hf.bot.user.id) return;
if (!msg.guildID) return;
if (!(await hasFlag(msg.guildID, "codePreviews"))) return;
const files = [];
const githubLinks = msg.content.match(REGEX_GITHUB);
const gitlabLinks = msg.content.match(REGEX_GITLAB);
const giteaLinks = msg.content.match(REGEX_GITEA);
if (githubLinks?.length) {
for (const link of githubLinks) {
const spoiler = REGEX_SPOILER.test(link);
files.push(await processFile(link.replace("/blob/", "/raw/"), spoiler));
}
}
if (gitlabLinks?.length) {
for (const link of gitlabLinks) {
const spoiler = REGEX_SPOILER.test(link);
files.push(await processFile(link.replace("/blob/", "/raw/"), spoiler));
}
}
if (giteaLinks?.length) {
for (const link of giteaLinks) {
const spoiler = REGEX_SPOILER.test(link);
files.push(await processFile(link.replace("/src/", "/raw/"), spoiler));
}
}
let out = "";
const allFiles = files.join("\n").trim();
if (allFiles !== "" && allFiles.length <= 2000) {
await msg.edit({flags: MessageFlags.SUPPRESS_EMBEDS}).catch(() => {});
}
for (let i = 0; i < files.length; i++) {
const file = files[i];
if (file === "") continue;
if (out.length + file.length > 2000) {
await msg.channel.createMessage({
content: out,
allowedMentions: {
repliedUser: false,
},
messageReference: {
messageID: msg.id,
},
});
out = file;
} else {
out += "\n" + file;
out = out.trim();
}
if (i == files.length - 1 && out.length <= 2000) {
await msg.channel.createMessage({
content: out,
allowedMentions: {
repliedUser: false,
},
messageReference: {
messageID: msg.id,
},
});
}
}
});
// TODO: maybe all command outputs should have this ability
events.add(
"messageReactionAdd",
"codePreviews",
async function (msg, reaction, reactor) {
if (!msg.guildID) return;
if (!(await hasFlag(msg.guildID, "codePreviews"))) return;
if (reaction.name != "\u274c") return;
let channel = msg.channel;
if (!channel.name) {
channel = hf.bot.getChannel(channel.id);
}
if (!msg.messageReference) {
msg = await channel.getMessage(msg.id);
}
if (!msg.messageReference) return;
const ref = await channel.getMessage(msg.messageReference.messageID);
if (!ref) return;
if (
ref.author.id != reactor.id &&
!channel.permissionsOf(reactor.id).has("manageMessages")
)
return;
if (
!REGEX_GITHUB.test(ref.content) &&
!REGEX_GITLAB.test(ref.content) &&
!REGEX_GITEA.test(ref.content)
)
return;
await msg.delete("Author requested code preview deletion");
}
);