api: move request functions to separate file
- request status id is no longer a cryptic number - descriptive function names
This commit is contained in:
parent
c10012130b
commit
cc6345ff63
6 changed files with 183 additions and 131 deletions
|
@ -6,14 +6,14 @@ const ipSalt = randomBytes(64).toString('hex');
|
||||||
|
|
||||||
import { env, version } from "../modules/config.js";
|
import { env, version } from "../modules/config.js";
|
||||||
import match from "../modules/processing/match.js";
|
import match from "../modules/processing/match.js";
|
||||||
import { apiJSON, checkJSONPost, getIP, languageCode } from "../modules/sub/utils.js";
|
import { languageCode } from "../modules/sub/utils.js";
|
||||||
|
import { createResponse, verifyRequest, getIP } from "../modules/processing/request.js";
|
||||||
import { Bright, Cyan } from "../modules/sub/consoleText.js";
|
import { Bright, Cyan } from "../modules/sub/consoleText.js";
|
||||||
import stream from "../modules/stream/stream.js";
|
import stream from "../modules/stream/stream.js";
|
||||||
import loc from "../localization/manager.js";
|
import loc from "../localization/manager.js";
|
||||||
import { generateHmac } from "../modules/sub/crypto.js";
|
import { generateHmac } from "../modules/sub/crypto.js";
|
||||||
import { verifyStream, getInternalStream } from "../modules/stream/manage.js";
|
import { verifyStream, getInternalStream } from "../modules/stream/manage.js";
|
||||||
import { extract } from "../modules/processing/url.js";
|
import { extract } from "../modules/processing/url.js";
|
||||||
import { errorUnsupported } from "../modules/sub/errors.js";
|
|
||||||
|
|
||||||
export function runAPI(express, app, gitCommit, gitBranch, __dirname) {
|
export function runAPI(express, app, gitCommit, gitBranch, __dirname) {
|
||||||
const corsConfig = !env.corsWildcard ? {
|
const corsConfig = !env.corsWildcard ? {
|
||||||
|
@ -100,7 +100,7 @@ export function runAPI(express, app, gitCommit, gitBranch, __dirname) {
|
||||||
const request = req.body;
|
const request = req.body;
|
||||||
const lang = languageCode(req);
|
const lang = languageCode(req);
|
||||||
const fail = (t) => {
|
const fail = (t) => {
|
||||||
const { status, body } = apiJSON(0, { t: loc(lang, t) });
|
const { status, body } = createResponse("error", { t: loc(lang, t) });
|
||||||
res.status(status).json(body);
|
res.status(status).json(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ export function runAPI(express, app, gitCommit, gitBranch, __dirname) {
|
||||||
}
|
}
|
||||||
|
|
||||||
request.dubLang = request.dubLang ? lang : false;
|
request.dubLang = request.dubLang ? lang : false;
|
||||||
const normalizedRequest = checkJSONPost(request);
|
const normalizedRequest = verifyRequest(request);
|
||||||
if (!normalizedRequest) {
|
if (!normalizedRequest) {
|
||||||
return fail('ErrorCantProcess');
|
return fail('ErrorCantProcess');
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { strict as assert } from "node:assert";
|
import { strict as assert } from "node:assert";
|
||||||
|
|
||||||
import { apiJSON } from "../sub/utils.js";
|
import { createResponse } from "../processing/request.js";
|
||||||
import { errorUnsupported, genericError, brokenLink } from "../sub/errors.js";
|
import { errorUnsupported, genericError, brokenLink } from "../sub/errors.js";
|
||||||
|
|
||||||
import loc from "../../localization/manager.js";
|
import loc from "../../localization/manager.js";
|
||||||
|
@ -45,8 +45,8 @@ export default async function(host, patternMatch, lang, obj) {
|
||||||
try {
|
try {
|
||||||
let r, isAudioOnly = !!obj.isAudioOnly, disableMetadata = !!obj.disableMetadata;
|
let r, isAudioOnly = !!obj.isAudioOnly, disableMetadata = !!obj.disableMetadata;
|
||||||
|
|
||||||
if (!testers[host]) return apiJSON(0, { t: errorUnsupported(lang) });
|
if (!testers[host]) return createResponse("error", { t: errorUnsupported(lang) });
|
||||||
if (!(testers[host](patternMatch))) return apiJSON(0, { t: brokenLink(lang, host) });
|
if (!(testers[host](patternMatch))) return createResponse("error", { t: brokenLink(lang, host) });
|
||||||
|
|
||||||
switch (host) {
|
switch (host) {
|
||||||
case "twitter":
|
case "twitter":
|
||||||
|
@ -177,17 +177,17 @@ export default async function(host, patternMatch, lang, obj) {
|
||||||
r = await dailymotion(patternMatch);
|
r = await dailymotion(patternMatch);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return apiJSON(0, { t: errorUnsupported(lang) });
|
return createResponse("error", { t: errorUnsupported(lang) });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r.isAudioOnly) isAudioOnly = true;
|
if (r.isAudioOnly) isAudioOnly = true;
|
||||||
let isAudioMuted = isAudioOnly ? false : obj.isAudioMuted;
|
let isAudioMuted = isAudioOnly ? false : obj.isAudioMuted;
|
||||||
|
|
||||||
if (r.error && r.critical)
|
if (r.error && r.critical)
|
||||||
return apiJSON(6, { t: loc(lang, r.error) })
|
return createResponse("critical", { t: loc(lang, r.error) })
|
||||||
|
|
||||||
if (r.error)
|
if (r.error)
|
||||||
return apiJSON(0, {
|
return createResponse("error", {
|
||||||
t: Array.isArray(r.error)
|
t: Array.isArray(r.error)
|
||||||
? loc(lang, r.error[0], r.error[1])
|
? loc(lang, r.error[0], r.error[1])
|
||||||
: loc(lang, r.error)
|
: loc(lang, r.error)
|
||||||
|
@ -199,7 +199,7 @@ export default async function(host, patternMatch, lang, obj) {
|
||||||
obj.filenamePattern, obj.twitterGif,
|
obj.filenamePattern, obj.twitterGif,
|
||||||
requestIP
|
requestIP
|
||||||
)
|
)
|
||||||
} catch (e) {
|
} catch {
|
||||||
return apiJSON(0, { t: genericError(lang, host) })
|
return createResponse("error", { t: genericError(lang, host) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import { audioIgnore, services, supportedAudio } from "../config.js";
|
import { audioIgnore, services, supportedAudio } from "../config.js";
|
||||||
import { apiJSON } from "../sub/utils.js";
|
import { createResponse } from "../processing/request.js";
|
||||||
import loc from "../../localization/manager.js";
|
import loc from "../../localization/manager.js";
|
||||||
import createFilename from "./createFilename.js";
|
import createFilename from "./createFilename.js";
|
||||||
|
|
||||||
export default function(r, host, userFormat, isAudioOnly, lang, isAudioMuted, disableMetadata, filenamePattern, toGif, requestIP) {
|
export default function(r, host, userFormat, isAudioOnly, lang, isAudioMuted, disableMetadata, filenamePattern, toGif, requestIP) {
|
||||||
let action,
|
let action,
|
||||||
responseType = 2,
|
responseType = "stream",
|
||||||
defaultParams = {
|
defaultParams = {
|
||||||
u: r.urls,
|
u: r.urls,
|
||||||
service: host,
|
service: host,
|
||||||
|
@ -36,10 +36,10 @@ export default function(r, host, userFormat, isAudioOnly, lang, isAudioMuted, di
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
default:
|
default:
|
||||||
return apiJSON(0, { t: loc(lang, 'ErrorEmptyDownload') });
|
return createResponse("error", { t: loc(lang, 'ErrorEmptyDownload') });
|
||||||
|
|
||||||
case "photo":
|
case "photo":
|
||||||
responseType = 1;
|
responseType = "redirect";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "gif":
|
case "gif":
|
||||||
|
@ -56,11 +56,12 @@ export default function(r, host, userFormat, isAudioOnly, lang, isAudioMuted, di
|
||||||
u: Array.isArray(r.urls) ? r.urls[0] : r.urls,
|
u: Array.isArray(r.urls) ? r.urls[0] : r.urls,
|
||||||
mute: true
|
mute: true
|
||||||
}
|
}
|
||||||
if (host === "reddit" && r.typeId === 1) responseType = 1;
|
if (host === "reddit" && r.typeId === "redirect")
|
||||||
|
responseType = "redirect";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "picker":
|
case "picker":
|
||||||
responseType = 5;
|
responseType = "picker";
|
||||||
switch (host) {
|
switch (host) {
|
||||||
case "instagram":
|
case "instagram":
|
||||||
case "twitter":
|
case "twitter":
|
||||||
|
@ -98,7 +99,7 @@ export default function(r, host, userFormat, isAudioOnly, lang, isAudioMuted, di
|
||||||
if (Array.isArray(r.urls)) {
|
if (Array.isArray(r.urls)) {
|
||||||
params = { type: "render" }
|
params = { type: "render" }
|
||||||
} else {
|
} else {
|
||||||
responseType = 1;
|
responseType = "redirect";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -106,7 +107,7 @@ export default function(r, host, userFormat, isAudioOnly, lang, isAudioMuted, di
|
||||||
if (r.type === "remux") {
|
if (r.type === "remux") {
|
||||||
params = { type: r.type };
|
params = { type: r.type };
|
||||||
} else {
|
} else {
|
||||||
responseType = 1;
|
responseType = "redirect";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -121,14 +122,15 @@ export default function(r, host, userFormat, isAudioOnly, lang, isAudioMuted, di
|
||||||
case "tumblr":
|
case "tumblr":
|
||||||
case "pinterest":
|
case "pinterest":
|
||||||
case "streamable":
|
case "streamable":
|
||||||
responseType = 1;
|
responseType = "redirect";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "audio":
|
case "audio":
|
||||||
if ((host === "reddit" && r.typeId === 1) || audioIgnore.includes(host)) {
|
if (audioIgnore.includes(host)
|
||||||
return apiJSON(0, { t: loc(lang, 'ErrorEmptyDownload') })
|
|| (host === "reddit" && r.typeId === "redirect")) {
|
||||||
|
return createResponse("error", { t: loc(lang, 'ErrorEmptyDownload') })
|
||||||
}
|
}
|
||||||
|
|
||||||
let processType = "render",
|
let processType = "render",
|
||||||
|
@ -178,5 +180,5 @@ export default function(r, host, userFormat, isAudioOnly, lang, isAudioMuted, di
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return apiJSON(responseType, {...defaultParams, ...params})
|
return createResponse(responseType, {...defaultParams, ...params})
|
||||||
}
|
}
|
||||||
|
|
154
src/modules/processing/request.js
Normal file
154
src/modules/processing/request.js
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
import ipaddr from "ipaddr.js";
|
||||||
|
|
||||||
|
import { normalizeURL } from "../processing/url.js";
|
||||||
|
import { createStream } from "../stream/manage.js";
|
||||||
|
|
||||||
|
const apiVar = {
|
||||||
|
allowed: {
|
||||||
|
vCodec: ["h264", "av1", "vp9"],
|
||||||
|
vQuality: ["max", "4320", "2160", "1440", "1080", "720", "480", "360", "240", "144"],
|
||||||
|
aFormat: ["best", "mp3", "ogg", "wav", "opus"],
|
||||||
|
filenamePattern: ["classic", "pretty", "basic", "nerdy"]
|
||||||
|
},
|
||||||
|
booleanOnly: [
|
||||||
|
"isAudioOnly",
|
||||||
|
"isTTFullAudio",
|
||||||
|
"isAudioMuted",
|
||||||
|
"dubLang",
|
||||||
|
"disableMetadata",
|
||||||
|
"twitterGif",
|
||||||
|
"tiktokH265"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createResponse(responseType, responseData) {
|
||||||
|
try {
|
||||||
|
let status = 200,
|
||||||
|
response = {};
|
||||||
|
|
||||||
|
switch(responseType) {
|
||||||
|
case "error":
|
||||||
|
status = 400;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "rate-limit":
|
||||||
|
status = 429;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (responseType) {
|
||||||
|
case "error":
|
||||||
|
case "success":
|
||||||
|
case "rate-limit":
|
||||||
|
response = {
|
||||||
|
text: responseData.t
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "redirect":
|
||||||
|
response = {
|
||||||
|
url: responseData.u
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "stream":
|
||||||
|
response = {
|
||||||
|
url: createStream(responseData)
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "picker":
|
||||||
|
let pickerType = "various",
|
||||||
|
audio = false;
|
||||||
|
|
||||||
|
if (responseData.service === "tiktok") {
|
||||||
|
audio = responseData.u
|
||||||
|
pickerType = "images"
|
||||||
|
}
|
||||||
|
|
||||||
|
response = {
|
||||||
|
pickerType: pickerType,
|
||||||
|
picker: responseData.picker,
|
||||||
|
audio: audio
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw "unreachable"
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
status,
|
||||||
|
body: {
|
||||||
|
status: responseType,
|
||||||
|
...response
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
return {
|
||||||
|
status: 500,
|
||||||
|
body: {
|
||||||
|
status: "error",
|
||||||
|
text: "Internal Server Error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function verifyRequest(request) {
|
||||||
|
try {
|
||||||
|
let template = {
|
||||||
|
url: normalizeURL(decodeURIComponent(request.url)),
|
||||||
|
vCodec: "h264",
|
||||||
|
vQuality: "720",
|
||||||
|
aFormat: "mp3",
|
||||||
|
filenamePattern: "classic",
|
||||||
|
isAudioOnly: false,
|
||||||
|
isTTFullAudio: false,
|
||||||
|
isAudioMuted: false,
|
||||||
|
disableMetadata: false,
|
||||||
|
dubLang: false,
|
||||||
|
twitterGif: false,
|
||||||
|
tiktokH265: false
|
||||||
|
}
|
||||||
|
|
||||||
|
const requestKeys = Object.keys(request);
|
||||||
|
const templateKeys = Object.keys(template);
|
||||||
|
|
||||||
|
if (requestKeys.length > templateKeys.length + 1 || !request.url) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const i in requestKeys) {
|
||||||
|
const key = requestKeys[i];
|
||||||
|
const item = request[key];
|
||||||
|
|
||||||
|
if (String(key) !== "url" && templateKeys.includes(key)) {
|
||||||
|
if (apiVar.booleanOnly.includes(key)) {
|
||||||
|
template[key] = !!item;
|
||||||
|
} else if (apiVar.allowed[key] && apiVar.allowed[key].includes(item)) {
|
||||||
|
template[key] = String(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (template.dubLang)
|
||||||
|
template.dubLang = verifyLanguageCode(request.dubLang);
|
||||||
|
|
||||||
|
return template
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getIP(req) {
|
||||||
|
const strippedIP = req.ip.replace(/^::ffff:/, '');
|
||||||
|
const ip = ipaddr.parse(strippedIP);
|
||||||
|
if (ip.kind() === 'ipv4') {
|
||||||
|
return strippedIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
const prefix = 56;
|
||||||
|
const v6Bytes = ip.toByteArray();
|
||||||
|
v6Bytes.fill(0, prefix / 8);
|
||||||
|
|
||||||
|
return ipaddr.fromByteArray(v6Bytes).toString();
|
||||||
|
}
|
|
@ -68,7 +68,7 @@ export default async function(obj) {
|
||||||
data = data[0]?.data?.children[0]?.data;
|
data = data[0]?.data?.children[0]?.data;
|
||||||
|
|
||||||
if (data?.url?.endsWith('.gif')) return {
|
if (data?.url?.endsWith('.gif')) return {
|
||||||
typeId: 1,
|
typeId: "redirect",
|
||||||
urls: data.url
|
urls: data.url
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,12 +106,12 @@ export default async function(obj) {
|
||||||
let id = video.split('/')[3];
|
let id = video.split('/')[3];
|
||||||
|
|
||||||
if (!audio) return {
|
if (!audio) return {
|
||||||
typeId: 1,
|
typeId: "redirect",
|
||||||
urls: video
|
urls: video
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
typeId: 2,
|
typeId: "stream",
|
||||||
type: "render",
|
type: "render",
|
||||||
urls: [video, audioFileLink],
|
urls: [video, audioFileLink],
|
||||||
audioFilename: `reddit_${id}_audio`,
|
audioFilename: `reddit_${id}_audio`,
|
||||||
|
|
|
@ -1,58 +1,5 @@
|
||||||
import { normalizeURL } from "../processing/url.js";
|
|
||||||
import { createStream } from "../stream/manage.js";
|
|
||||||
import ipaddr from "ipaddr.js";
|
|
||||||
|
|
||||||
const apiVar = {
|
|
||||||
allowed: {
|
|
||||||
vCodec: ["h264", "av1", "vp9"],
|
|
||||||
vQuality: ["max", "4320", "2160", "1440", "1080", "720", "480", "360", "240", "144"],
|
|
||||||
aFormat: ["best", "mp3", "ogg", "wav", "opus"],
|
|
||||||
filenamePattern: ["classic", "pretty", "basic", "nerdy"]
|
|
||||||
},
|
|
||||||
booleanOnly: [
|
|
||||||
"isAudioOnly",
|
|
||||||
"isTTFullAudio",
|
|
||||||
"isAudioMuted",
|
|
||||||
"dubLang",
|
|
||||||
"disableMetadata",
|
|
||||||
"twitterGif",
|
|
||||||
"tiktokH265"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
const forbiddenCharsString = ['}', '{', '%', '>', '<', '^', ';', '`', '$', '"', "@", '='];
|
const forbiddenCharsString = ['}', '{', '%', '>', '<', '^', ';', '`', '$', '"', "@", '='];
|
||||||
|
|
||||||
export function apiJSON(type, obj) {
|
|
||||||
try {
|
|
||||||
switch (type) {
|
|
||||||
case 0:
|
|
||||||
return { status: 400, body: { status: "error", text: obj.t } };
|
|
||||||
case 1:
|
|
||||||
return { status: 200, body: { status: "redirect", url: obj.u } };
|
|
||||||
case 2:
|
|
||||||
return { status: 200, body: { status: "stream", url: createStream(obj) } };
|
|
||||||
case 3:
|
|
||||||
return { status: 200, body: { status: "success", text: obj.t } };
|
|
||||||
case 4:
|
|
||||||
return { status: 429, body: { status: "rate-limit", text: obj.t } };
|
|
||||||
case 5:
|
|
||||||
let pickerType = "various", audio = false
|
|
||||||
switch (obj.service) {
|
|
||||||
case "douyin":
|
|
||||||
case "tiktok":
|
|
||||||
audio = obj.u
|
|
||||||
pickerType = "images"
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return { status: 200, body: { status: "picker", pickerType: pickerType, picker: obj.picker, audio: audio } };
|
|
||||||
case 6: // critical error, action should be taken by balancer/other server software
|
|
||||||
return { status: 500, body: { status: "error", text: obj.t, critical: true } };
|
|
||||||
default:
|
|
||||||
return { status: 400, body: { status: "error", text: "Bad Request" } };
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
return { status: 500, body: { status: "error", text: "Internal Server Error", critical: true } };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export function metadataManager(obj) {
|
export function metadataManager(obj) {
|
||||||
let keys = Object.keys(obj);
|
let keys = Object.keys(obj);
|
||||||
let tags = ["album", "composer", "genre", "copyright", "encoded_by", "title", "language", "artist", "album_artist", "performer", "disc", "publisher", "track", "encoder", "compilation", "date", "creation_time", "comment"]
|
let tags = ["album", "composer", "genre", "copyright", "encoded_by", "title", "language", "artist", "album_artist", "performer", "disc", "publisher", "track", "encoder", "compilation", "date", "creation_time", "comment"]
|
||||||
|
@ -79,57 +26,6 @@ export function unicodeDecode(str) {
|
||||||
return String.fromCharCode(parseInt(unicode.replace(/\\u/g, ""), 16));
|
return String.fromCharCode(parseInt(unicode.replace(/\\u/g, ""), 16));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
export function checkJSONPost(obj) {
|
|
||||||
let def = {
|
|
||||||
url: normalizeURL(decodeURIComponent(obj.url)),
|
|
||||||
vCodec: "h264",
|
|
||||||
vQuality: "720",
|
|
||||||
aFormat: "mp3",
|
|
||||||
filenamePattern: "classic",
|
|
||||||
isAudioOnly: false,
|
|
||||||
isTTFullAudio: false,
|
|
||||||
isAudioMuted: false,
|
|
||||||
disableMetadata: false,
|
|
||||||
dubLang: false,
|
|
||||||
twitterGif: false,
|
|
||||||
tiktokH265: false
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
let objKeys = Object.keys(obj);
|
|
||||||
let defKeys = Object.keys(def);
|
|
||||||
if (objKeys.length > defKeys.length + 1 || !obj.url) return false;
|
|
||||||
|
|
||||||
for (let i in objKeys) {
|
|
||||||
if (String(objKeys[i]) !== "url" && defKeys.includes(objKeys[i])) {
|
|
||||||
if (apiVar.booleanOnly.includes(objKeys[i])) {
|
|
||||||
def[objKeys[i]] = obj[objKeys[i]] ? true : false;
|
|
||||||
} else {
|
|
||||||
if (apiVar.allowed[objKeys[i]] && apiVar.allowed[objKeys[i]].includes(obj[objKeys[i]])) def[objKeys[i]] = String(obj[objKeys[i]])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (def.dubLang)
|
|
||||||
def.dubLang = verifyLanguageCode(obj.dubLang);
|
|
||||||
|
|
||||||
return def
|
|
||||||
} catch (e) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export function getIP(req) {
|
|
||||||
const strippedIP = req.ip.replace(/^::ffff:/, '');
|
|
||||||
const ip = ipaddr.parse(strippedIP);
|
|
||||||
if (ip.kind() === 'ipv4') {
|
|
||||||
return strippedIP;
|
|
||||||
}
|
|
||||||
|
|
||||||
const prefix = 56;
|
|
||||||
const v6Bytes = ip.toByteArray();
|
|
||||||
v6Bytes.fill(0, prefix / 8);
|
|
||||||
|
|
||||||
return ipaddr.fromByteArray(v6Bytes).toString();
|
|
||||||
}
|
|
||||||
export function cleanHTML(html) {
|
export function cleanHTML(html) {
|
||||||
let clean = html.replace(/ {4}/g, '');
|
let clean = html.replace(/ {4}/g, '');
|
||||||
clean = clean.replace(/\n/g, '');
|
clean = clean.replace(/\n/g, '');
|
||||||
|
|
Loading…
Reference in a new issue