MastodonBot/src/Utils.ts

129 lines
No EOL
4.1 KiB
TypeScript

import https from "https";
import * as fs from "fs";
import {DOMParser} from '@xmldom/xmldom'
import * as fakedom from "fake-dom"
export default class Utils {
public static async DownloadJson(url, headers?: any): Promise<any> {
const data = await Utils.Download(url, headers)
try {
return JSON.parse(data.content)
} catch (e) {
console.log("Could not parse the result of ", url, ": not a valid json:\n ", data.content)
throw e
}
}
public static Sum(t: (number | undefined)[]) {
let sum = 0;
for (const n of t) {
if (n === undefined || n === null || Number.isNaN(n)) {
continue
}
sum += n
}
return sum
}
public static TwoDigits(i: number) {
if (i < 10) {
return "0" + i
}
return "" + i
}
public static async DownloadXml(url, headers?: any): Promise<Document> {
const content = await Utils.Download(url, {...headers, accept: "application/xml"})
const parser = new DOMParser();
return parser.parseFromString(content.content, "text/xml");
}
public static Download(url, headers?: any): Promise<{ content: string }> {
return new Promise((resolve, reject) => {
try {
headers = headers ?? {}
headers.accept ??= "application/json"
const urlObj = new URL(url)
https.get(
{
host: urlObj.host,
path: urlObj.pathname + urlObj.search,
port: urlObj.port,
headers: headers,
},
(res) => {
const parts: string[] = []
res.setEncoding("utf8")
res.on("data", function (chunk) {
// @ts-ignore
parts.push(chunk)
})
res.addListener("end", function () {
resolve({content: parts.join("")})
})
}
)
} catch (e) {
reject(e)
}
})
}
/**
* Adds commas and a single 'and' between the given items
*
* Utils.commasAnd(["A","B","C"]) // => "A, B and C"
* Utils.commasAnd(["A"]) // => "A"
* Utils.commasAnd([]) // => ""
*/
public static commasAnd(items: string[]) {
if (items.length === 1) {
return items[0]
}
if (items.length === 0) {
return ""
}
const last = items[items.length - 1]
return items.slice(0, items.length - 1).join(", ") + " and " + last
}
public static DownloadBlob(url: string, filepath: string): Promise<string> {
return new Promise((resolve, reject) => {
https.get(url, (res) => {
if (res.statusCode === 200) {
res.pipe(fs.createWriteStream(filepath))
.on('error', reject)
.once('close', () => resolve(filepath));
} else {
// Consume response data to free up memory
res.resume();
reject(new Error(`Request Failed With a Status Code: ${res.statusCode}`));
}
});
});
}
public static stripHtmlToInnerText(htmlText: string): string;
public static stripHtmlToInnerText(htmlText: string | undefined): string | undefined;
/**
*
* const input = "#<span>nobot</span>"
* Utils.stripHtmlToInnerText(input) // => "#nobot"
*/
public static stripHtmlToInnerText(htmlText: string | undefined): string | undefined {
if (fakedom === undefined || window === undefined) {
throw "FakeDom not initialized"
}
if (htmlText === undefined) {
return undefined
}
const el = document.createElement("div")
el.innerHTML = htmlText
return el.textContent
}
}