const path = require('path'), fs = require('fs'), minify = require('@node-minify/core'), uglifyJs = require("@node-minify/uglify-js"), htmlMinifier = require("minify-html"), cssMinifier = require("clean-css"), activityToHTML = require("./overcomplicatedStatuses.js"), randomThemer = require("./randomThemer.js"), himalaya = require("himalaya"), glob = require("glob"), api = require("./api.js"), child_process = require("child_process") var constants = JSON.parse(fs.readFileSync(path.join(__dirname, 'constants.json'))) var highlightedWords = constants.highlightedWords var quotes = constants.quotes var titles = constants.titles var commitCount = "600+" var uptime = Date.now() var lastPregen = 0 var pregenFiles = [] var javascriptCache = {} var testing = process.argv[2] == "test" var globResult = glob.globSync("**/static/**/*.html", { absolute: true }) for (var i = 0; i < globResult.length; i++) { var result = globResult[i] pregenFiles.push({ "absolutePath": result, "path": result.substring(result.indexOf("static") + 7), "html": undefined }) } (async function () { globResult = glob.globSync("**/static/**/*.js", { absolute: true }) for (var i = 0; i < globResult.length; i++) { javascriptCache[globResult[i]] = await minify({ compressor: uglifyJs, content: fs.readFileSync(globResult[i]).toString() }) } })() function firstToUpper(str) { return str.charAt(0).toUpperCase() + str.slice(1) } function onlyIfExists(string, check) { if (check) { return string } else { return "" } } function makeHtmlSafe(str="") { return String(str).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); } function timeFormatter(seconds) { seconds = Math.ceil(seconds) var minutes = Math.ceil(seconds / 60) var hours = Math.floor(minutes / 60) if (seconds <= 60) { return 'about ' + seconds + ' seconds' } else if (minutes < 60) { return `${minutes} Minutes` } return `${hours} hours and ${minutes % 60} minutes` } function pathReplacer(html) { while (html.includes("{PATH_")) { var pagePath = html.substring(html.indexOf("{PATH_")) pagePath = pagePath.substring(6, pagePath.indexOf('}')) var stringIndex = `{PATH_${pagePath}}` pagePath = pagePath.toLowerCase() var pageHTML = fs.readFileSync(path.join(__dirname, 'static', pagePath, 'index.html')).toString() pageHTML = pageHTML.substring(pageHTML.indexOf('
') + 6, pageHTML.indexOf('
')) html = html.replaceAll(stringIndex, pageHTML) } return html } function highlighter(json, full = true, linkParent = false) { for (var i = 0; i < json.length; i++) { var element = json[i] if (element.type == "element") { if (element.children.length > 0) { var valid = true if (element.attributes) { for (var x in element.attributes) { var attribute = element.attributes[x] if (attribute.key == "class" && attribute.value.includes("noHighlight")) { valid = false break } } } if (element.tagName == "code") { valid = false } if (valid) { element.children = highlighter(element.children, full, linkParent || element.tagName == "a") } } } else if (element.type == "text") { var index = 0 for (let i = 0; i < highlightedWords.length; i++) { var dict = highlightedWords[i] for (let x = 0; x < dict.words.length; x++) { index += 1 var term = dict.words[x]; var termProps = dict var reg = term if (termProps.caseInsensitive) { reg = new RegExp(`(${term})`, "gi") } element.content = element.content.replaceAll(`{${term}}`, "TEMPORARY_REPLACE") element.content = element.content.replaceAll(reg, "{TERM" + index + "}") element.content = element.content.replaceAll("TEMPORARY_REPLACE", `${term}`) } } if (full) { var index = 0 for (let i = 0; i < highlightedWords.length; i++) { var dict = highlightedWords[i] for (let x = 0; x < dict.words.length; x++) { index += 1 var termKey = "{TERM" + index + "}" var termProps = dict while (element.content.includes(termKey)) { var endRegex = " " var termIndex = element.content.indexOf(termKey) var spanEnd = element.content.indexOf(endRegex, termIndex) if (spanEnd == -1) { spanEnd = element.content.length } var spanStart = element.content.substring(0, termIndex).lastIndexOf(endRegex) + 1 // if (highTable[index] == "ULTRAKILL") { // console.log(startContent, " ---- ", endContent) // } var startContent = element.content.substring(spanStart - 1, termIndex) var endContent = element.content.substring(termIndex + termKey.length, spanEnd) if (startContent.includes("(") && !endContent.includes(")")) { var newSpanEnd = element.content.indexOf(")", spanStart) + 1 var newEndContent = element.content.substring(termIndex + termKey.length, newSpanEnd) if (newEndContent.includes("<") || newEndContent.includes("TERM")) { spanStart += 1 startContent = startContent.substring(2) } else { spanEnd = newSpanEnd endContent = newEndContent } } else if (endContent.includes(")") && !startContent.includes("(")) { var newSpanStart = element.content.substring(0, spanStart).lastIndexOf("(") var newStartContent = element.content.substring(newSpanStart - 1, termIndex) if (newStartContent.includes("<") || newStartContent.includes("TERM")) { spanEnd -= 1 endContent = endContent.substring(0, endContent.length - 1) } else { console.log(newStartContent) spanStart = newSpanStart startContent = newStartContent } } var style = termProps.style || "" var classes = termProps.classes || "" var link = termProps.link || "" if (termProps.color) { style += `color: ${termProps.color};` } if (termProps.italicized) { style += "font-style: italic;" } if (termProps.outline) { var width = 2 // style += `text-shadow: -1px -1px 0 ${termProps.outline}, 1px -1px 0 ${termProps.outline}, -1px 1px 0 ${termProps.outline}, 1px 1px 0 ${termProps.outline};` style += `-webkit-text-stroke: 1px ${termProps.outline};` // ^ Not in use because it looks bad :30 } if (termProps.bold) { classes += "bold" } if (style.length > 2) { style = `style="${style}"` } if (classes.length > 2) { classes = `class="${classes}"` } var stuff = (startContent + dict.words[x] + endContent).trim() if (!stuff.includes("span")) { var replacement = `${stuff}` if (link && !linkParent) { replacement = `${replacement}` // console.log(replacement) } element.content = element.content.substring(0, spanStart) + replacement + element.content.substring(spanEnd) } else { element.content = element.content.replace(termKey, dict.words[x]) } } } } // element.content = element.content.replaceAll(termKey, replacement) } } } return json } function converter(html, dynamic = true) { var startTime = Date.now() var config = JSON.parse(fs.readFileSync(path.join(__dirname, 'config/config.json'))) var staticReplacers = { "ALL_HIGHLIGHTS": () => { var addedHTML = "" for (var i = 0; i < highlightedWords.length; i++) { addedHTML += highlightedWords[i].words.join(", ") addedHTML += ", " } return addedHTML.substring(0, addedHTML.length - 2) }, "BRANCH_NAME": () => { if (process.env.BRANCH == "dev") { return "Stable" } return "Beta" }, "BRANCH_SUB": () => { if (process.env.BRANCH == "dev") { return "" } return "beta." }, "COMMIT_COUNT": commitCount, "QUOTE_COUNT": quotes.length, "DISCORD_STATUS": () => { if (api.lanyard) { return `${constants.discStatuses[api.lanyard.discord_status].text}` + ``; } return ""; }, "TOPBAR": `

Home Socials Stats Nerd FAQ Blog

`, "CUSTOM_STATUS": () => { if (api.lanyard && api.lanyard.custom_status) { var status = api.lanyard.custom_status var addedHTML = "

" if (status.emoji) { if (status.emoji.id) { addedHTML += `` } else { addedHTML += status.emoji.name + " " } } addedHTML += makeHtmlSafe(status.text) addedHTML += "

" return addedHTML } return "" }, "SELECTED_VIDEO": () => { if (api.lanyard && api.lanyard.video) { return `


Predetermined weekly video!

I would call it random but I actually select them manually.


` } return `` }, "WEATHER_MODIFIER": randomThemer.returnTheme(), "WEATHER_TEXT": "", "ANNOUNCEMENT": fs.readFileSync(path.join(__dirname, "config/announcement.html")), "SOCIALS": () => { if (api.lanyard && api.lanyard.socials) { var socials = api.lanyard.socials var html = `
` var socialsTable = Object.keys(socials) for (var i = 0; i < socialsTable.length; i++) { var category = socialsTable[i] var sites = socials[category] var sitesTable = Object.keys(sites) html += `

${category}

` for (var x = 0; x < sitesTable.length; x++) { var siteName = sitesTable[x] var siteData = sites[siteName] html += `${siteName}: ${siteData.name}` } html += "
" } html += "
" } else { html = "

Failed to load?!

Uh oh

" } return html }, "BLOG_POSTS": () => { var addedHTML = "" for (var i in api.blogPosts) { var post = api.blogPosts[i] if (!post.hidden) { addedHTML += `

${post.title}

${post.desc}

Path: /${post.folder}/

` } } if (!api.blogConnected) { addedHTML += "

Not connected to blog server :(

" } else if (addedHTML.length < 10) { addedHTML += "

No blog posts found...
wait
huh ???
what???????
how ???????????????
WHY ?!
Violet must've fucked up like. REALLY bad.
We're so cooked

" } return addedHTML }, "SUBPAGE_JS": () => { return ` ` } } var realtimeReplacers = { "API_CONNECTED": api.connected.toString(), "ACTIVITIES": activityToHTML.activitiesToHTML(api.lanyard), "SPINCOUNT": api.spins.toString(), "UPTIME": timeFormatter((Date.now() - uptime) / 1000), "LAST_LANYARD": timeFormatter((Date.now() - api.lastLanyardUpdate) / 1000), "RANDOM_TITLE": titles[Math.floor(Math.random() * titles.length)], "RANDOM_QUOTE": quotes[Math.floor(Math.random() * quotes.length)], "LAST_PREGEN": timeFormatter((Date.now() - lastPregen) / 1000) } if (dynamic) { var replacers = realtimeReplacers } else { var replacers = staticReplacers } html = pathReplacer(html) var rpTable = Object.keys(replacers) for (let index = 0; index < rpTable.length; index++) { const text = rpTable[index]; if (dynamic) { replacers[text] = himalaya.stringify(highlighter(himalaya.parse(replacers[text]))) } html = html.replaceAll(`{${text}}`, replacers[text]) } if (!dynamic) { if (html.includes("")) { var bodyHTML = htmlMinifier.minify(html.substring(html.indexOf("") + 6, html.lastIndexOf(""))) var parsedHTML = himalaya.parse(bodyHTML) } else { var parsedHTML = himalaya.parse(html) } parsedHTML = highlighter(parsedHTML) parsedHTML = himalaya.stringify(parsedHTML) if (html.includes("")) { parsedHTML = "" + parsedHTML + "" html = html.substring(0, html.indexOf("")) + parsedHTML + html.substring(html.indexOf("") + 7) } else { html = parsedHTML } } if (dynamic) { html = html.replaceAll("{LOAD_TIME}", (Date.now() - startTime).toString() + "ms") } return html } module.exports = { getActivities: function () { return htmlMinifier.minify(converter(activityToHTML.activitiesToHTML(api.lanyard))) }, middleWare: async function (req, res, next) { var filePath = (req.baseUrl + req.path).trim() if (!filePath.includes(".")) { if (filePath.charAt(filePath.length - 1) != '/') { res.redirect(filePath + '/') return } filePath = path.join(filePath, '/index.html') } filePath = path.join(__dirname, 'static', filePath || 'index.html') if (fs.existsSync(filePath)) { var data = fs.readFileSync(filePath).toString() res.contentType(path.basename(filePath)) if (filePath.includes(".html")) { for (var i = 0; i < pregenFiles.length; i++) { if (pregenFiles[i].html && pregenFiles[i].absolutePath == filePath) { data = pregenFiles[i].html } } data = converter(data, true) // console.log(data) } if (filePath.includes(".html")) { data = htmlMinifier.minify(data) } else if (filePath.includes(".css")) { data = new cssMinifier().minify(data).styles } else if (filePath.includes(".js")) { data = javascriptCache[filePath] } res.send(data) } else { next() } }, converter: converter } async function updateCommits() { // var commits = gitCommitCount() var commits = child_process.execSync("git rev-list --count HEAD") // var siteResponse = await (await fetch(`https://git.violets-purgatory.dev/bingus_violet/violets-purgatory/src/branch/${process.env.BRANCH || "origin"}`)).text() // var commits = siteResponse.substring(0, siteResponse.indexOf("Commits")) // commits = commits.substring(commits.lastIndexOf("") + 3, commits.lastIndexOf("")) // ^ this works for Forgejo (basically everything i use that isnt Github, E.G. Codeberg) // commits = commits.substring(commits.lastIndexOf(">") + 1) // ^ This works for Github (fuck you Github) commitCount = commits.toString().trim() if (process.env.BRANCH == "dev") { commitCount += " | Beta site" } } updateCommits() // Lanyard Stuffs function pregenerate() { lastPregen = Date.now() for (var i = 0; i < pregenFiles.length; i++) { var startTime = Date.now() pregenFiles[i].html = converter(fs.readFileSync(pregenFiles[i].absolutePath).toString(), false) pregenFiles[i].html = pregenFiles[i].html.replaceAll("{PREGEN_TIME}", Date.now() - startTime) } for (var i = 0; i < pregenFiles.length; i++) { pregenFiles[i].html = pregenFiles[i].html.replaceAll("{PREGEN_TOTAL}", Date.now() - lastPregen) } } pregenerate() api.events.on("lanyardConnect", pregenerate) api.events.on("blogUpdate", pregenerate) api.events.on("lanyardUpdate", async () => { if (!api.lanyard.activityChanged) { pregenerate() } for (var i = 0; i < api.lanyard.activities.length; i++) { var activity = api.lanyard.activities[i] if (activity.type == 4 && activity.emoji) { if (activity.emoji.id) { if (activity.emoji.animated) { var emoji = Buffer.from(await (await fetch(`https://cdn.discordapp.com/emojis/${activity.emoji.id}.gif?quality=lossless`)).arrayBuffer()) } else { var emoji = Buffer.from(await (await fetch(`https://cdn.discordapp.com/emojis/${activity.emoji.id}.png?quality=lossless`)).arrayBuffer()) } fs.writeFileSync(path.join(__dirname, "cached/emojis", activity.emoji.id), emoji) } } } })