refactor(parser): import only the required asset when in a node environment (#745)
# PR Checklist - [X] Have you checked if it works normally in all models? *Ignore this if it doesn't use models.* - [X] Have you checked if it works normally in all web, local, and node hosted versions? If it doesn't, have you blocked it in those versions? - [ ] Have you added type definitions? # Description This PR contains modifications to import only the required assets when talking to Asset Bot. - refactor parseAdditionalAssets() - Modified the getClostMatch() to work well with Object<key, value> to which it is dynamically added.
This commit is contained in:
@@ -292,9 +292,38 @@ async function renderHighlightableMarkdown(data:string) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const assetRegex = /{{(raw|path|img|image|video|audio|bg|emotion|asset|video-img|source)::(.+?)}}/gms
|
export const assetRegex = /{{(raw|path|img|image|video|audio|bg|emotion|asset|video-img|source)::(.+?)}}/gms
|
||||||
|
|
||||||
|
async function replaceAsync(string, regexp, replacerFunction) {
|
||||||
|
const replacements = await Promise.all(
|
||||||
|
Array.from(string.matchAll(regexp),
|
||||||
|
match => replacerFunction(...match as any)))
|
||||||
|
let i = 0;
|
||||||
|
return string.replace(regexp, () => replacements[i++])
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getAssetSrc(assetArr: string[][], name: string, assetPaths: {[key: string]:{path: string, ext?: string}}) {
|
||||||
|
name = name.toLocaleLowerCase()
|
||||||
|
for (const asset of assetArr) {
|
||||||
|
if (trimmer(asset[0].toLocaleLowerCase()) !== trimmer(name)) continue
|
||||||
|
const assetPath = await getFileSrc(asset[1])
|
||||||
|
assetPaths[asset[0].toLocaleLowerCase()] = {
|
||||||
|
path: assetPath,
|
||||||
|
ext: asset[2]
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getEmoSrc(emoArr: string[][], emoPaths: {[key: string]:{path: string}}) {
|
||||||
|
for (const emo of emoArr) {
|
||||||
|
const emoPath = await getFileSrc(emo[1])
|
||||||
|
emoPaths[emo[0].toLocaleLowerCase()] = {
|
||||||
|
path: emoPath,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function parseAdditionalAssets(data:string, char:simpleCharacterArgument|character, mode:'normal'|'back', mode2:'unset'|'pre'|'post' = 'unset'){
|
async function parseAdditionalAssets(data:string, char:simpleCharacterArgument|character, mode:'normal'|'back', mode2:'unset'|'pre'|'post' = 'unset'){
|
||||||
const assetWidthString = (DBState.db.assetWidth && DBState.db.assetWidth !== -1 || DBState.db.assetWidth === 0) ? `max-width:${DBState.db.assetWidth}rem;` : ''
|
const assetWidthString = (DBState.db.assetWidth && DBState.db.assetWidth !== -1 || DBState.db.assetWidth === 0) ? `max-width:${DBState.db.assetWidth}rem;` : ''
|
||||||
|
|
||||||
@@ -306,37 +335,20 @@ async function parseAdditionalAssets(data:string, char:simpleCharacterArgument|c
|
|||||||
path:string
|
path:string
|
||||||
}} = {}
|
}} = {}
|
||||||
|
|
||||||
if(char.additionalAssets){
|
if (char.emotionImages) await getEmoSrc(char.emotionImages, emoPaths)
|
||||||
for(const asset of char.additionalAssets){
|
|
||||||
const assetPath = await getFileSrc(asset[1])
|
|
||||||
assetPaths[asset[0].toLocaleLowerCase()] = {
|
|
||||||
path: assetPath,
|
|
||||||
ext: asset[2]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(char.emotionImages){
|
|
||||||
for(const emo of char.emotionImages){
|
|
||||||
const emoPath = await getFileSrc(emo[1])
|
|
||||||
emoPaths[emo[0].toLocaleLowerCase()] = {
|
|
||||||
path: emoPath,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const moduleAssets = getModuleAssets()
|
|
||||||
if(moduleAssets.length > 0){
|
|
||||||
for(const asset of moduleAssets){
|
|
||||||
const assetPath = await getFileSrc(asset[1])
|
|
||||||
assetPaths[asset[0].toLocaleLowerCase()] = {
|
|
||||||
path: assetPath,
|
|
||||||
ext: asset[2]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const videoExtention = ['mp4', 'webm', 'avi', 'm4p', 'm4v']
|
const videoExtention = ['mp4', 'webm', 'avi', 'm4p', 'm4v']
|
||||||
let needsSourceAccess = false
|
let needsSourceAccess = false
|
||||||
data = data.replaceAll(assetRegex, (full:string, type:string, name:string) => {
|
|
||||||
name = name.toLocaleLowerCase()
|
data = await replaceAsync(data, assetRegex, async (full:string, type:string, name:string) => {
|
||||||
|
const moduleAssets = getModuleAssets()
|
||||||
|
if (char.additionalAssets) {
|
||||||
|
await getAssetSrc(char.additionalAssets, name, assetPaths)
|
||||||
|
}
|
||||||
|
if (moduleAssets.length > 0) {
|
||||||
|
await getAssetSrc(moduleAssets, name, assetPaths)
|
||||||
|
}
|
||||||
|
|
||||||
if(type === 'emotion'){
|
if(type === 'emotion'){
|
||||||
const path = emoPaths[name]?.path
|
const path = emoPaths[name]?.path
|
||||||
if(!path){
|
if(!path){
|
||||||
@@ -344,6 +356,7 @@ async function parseAdditionalAssets(data:string, char:simpleCharacterArgument|c
|
|||||||
}
|
}
|
||||||
return `<img src="${path}" alt="${path}" style="${assetWidthString} "/>`
|
return `<img src="${path}" alt="${path}" style="${assetWidthString} "/>`
|
||||||
}
|
}
|
||||||
|
|
||||||
if(type === 'source'){
|
if(type === 'source'){
|
||||||
needsSourceAccess = true
|
needsSourceAccess = true
|
||||||
switch(name){
|
switch(name){
|
||||||
@@ -355,13 +368,15 @@ async function parseAdditionalAssets(data:string, char:simpleCharacterArgument|c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = assetPaths[name]
|
let path = assetPaths[name]
|
||||||
|
|
||||||
if(!path){
|
if(!path){
|
||||||
if(DBState.db.legacyMediaFindings){
|
if(DBState.db.legacyMediaFindings){
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
path = getClosestMatch(name, assetPaths)
|
path = await getClosestMatch(char, name, assetPaths)
|
||||||
|
|
||||||
if(!path){
|
if(!path){
|
||||||
return ''
|
return ''
|
||||||
@@ -411,63 +426,72 @@ async function parseAdditionalAssets(data:string, char:simpleCharacterArgument|c
|
|||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
function getClosestMatch(name:string, assetPaths:{[key:string]:{path:string, ext?:string}}){
|
async function getClosestMatch(char: simpleCharacterArgument|character, name:string, assetPaths:{[key:string]:{path:string, ext?:string}}){
|
||||||
|
if(!char.additionalAssets) return null
|
||||||
if(Object.keys(assetPaths).length === 0){
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
//Levenshtein distance, new with 1d array
|
|
||||||
const dest = (a:string, b:string) => {
|
|
||||||
const h = a.length + 1
|
|
||||||
const w = b.length + 1
|
|
||||||
let d = new Int16Array(h * w)
|
|
||||||
for(let i=0;i<h;i++){
|
|
||||||
d[i * w] = i
|
|
||||||
}
|
|
||||||
for(let i=0;i<w;i++){
|
|
||||||
d[i] = i
|
|
||||||
}
|
|
||||||
for(let i=1; i<h; i++){
|
|
||||||
for(let j=1;j<w;j++){
|
|
||||||
d[i * w + j] = Math.min(
|
|
||||||
d[(i-1) * w + j-1] + (a.charAt(i-1)===b.charAt(j-1) ? 0 : 1),
|
|
||||||
d[(i-1) * w + j]+1, d[i * w + j-1]+1
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return d[h * w - 1]
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function trimmer(str:string){
|
|
||||||
const ext = ['webp', 'png', 'jpg', 'jpeg', 'gif', 'mp4', 'webm', 'avi', 'm4p', 'm4v', 'mp3', 'wav', 'ogg']
|
|
||||||
for(const e of ext){
|
|
||||||
if(str.endsWith('.' + e)){
|
|
||||||
str = str.substring(0, str.length - e.length - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return str.trim().replace(/[_ -.]/g, '')
|
|
||||||
}
|
|
||||||
|
|
||||||
let closest = ''
|
let closest = ''
|
||||||
let closestDist = 999999
|
let closestDist = 999999
|
||||||
|
let targetPath = ''
|
||||||
|
let targetExt = ''
|
||||||
|
|
||||||
const trimmedName = trimmer(name)
|
const trimmedName = trimmer(name)
|
||||||
for(const key in assetPaths){
|
for(const asset of char.additionalAssets) {
|
||||||
const dist = dest(trimmedName, trimmer(key))
|
const key = asset[0].toLocaleLowerCase()
|
||||||
|
const dist = getDistance(trimmedName, trimmer(key))
|
||||||
if(dist < closestDist){
|
if(dist < closestDist){
|
||||||
closest = key
|
closest = key
|
||||||
closestDist = dist
|
closestDist = dist
|
||||||
|
targetPath = asset[1]
|
||||||
|
targetExt = asset[2]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(closestDist > DBState.db.assetMaxDifference){
|
if(closestDist > DBState.db.assetMaxDifference){
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const assetPath = await getFileSrc(targetPath)
|
||||||
|
assetPaths[closest] = {
|
||||||
|
path: assetPath,
|
||||||
|
ext: targetExt
|
||||||
|
}
|
||||||
|
|
||||||
return assetPaths[closest]
|
return assetPaths[closest]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Levenshtein distance, new with 1d array
|
||||||
|
function getDistance(a:string, b:string) {
|
||||||
|
const h = a.length + 1
|
||||||
|
const w = b.length + 1
|
||||||
|
let d = new Int16Array(h * w)
|
||||||
|
for(let i=0;i<h;i++){
|
||||||
|
d[i * w] = i
|
||||||
|
}
|
||||||
|
for(let i=0;i<w;i++){
|
||||||
|
d[i] = i
|
||||||
|
}
|
||||||
|
for(let i=1; i<h; i++){
|
||||||
|
for(let j=1;j<w;j++){
|
||||||
|
d[i * w + j] = Math.min(
|
||||||
|
d[(i-1) * w + j-1] + (a.charAt(i-1)===b.charAt(j-1) ? 0 : 1),
|
||||||
|
d[(i-1) * w + j]+1, d[i * w + j-1]+1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return d[h * w - 1]
|
||||||
|
}
|
||||||
|
|
||||||
|
function trimmer(str:string){
|
||||||
|
const ext = ['webp', 'png', 'jpg', 'jpeg', 'gif', 'mp4', 'webm', 'avi', 'm4p', 'm4v', 'mp3', 'wav', 'ogg']
|
||||||
|
for(const e of ext){
|
||||||
|
if(str.endsWith('.' + e)){
|
||||||
|
str = str.substring(0, str.length - e.length - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return str.trim().replace(/[_ -.]/g, '')
|
||||||
|
}
|
||||||
|
|
||||||
async function parseInlayAssets(data:string){
|
async function parseInlayAssets(data:string){
|
||||||
const inlayMatch = data.match(/{{(inlay|inlayed)::(.+?)}}/g)
|
const inlayMatch = data.match(/{{(inlay|inlayed)::(.+?)}}/g)
|
||||||
if(inlayMatch){
|
if(inlayMatch){
|
||||||
@@ -605,7 +629,6 @@ function decodeStyleRule(rule:CssAtRuleAST){
|
|||||||
}
|
}
|
||||||
|
|
||||||
function decodeStyle(text:string){
|
function decodeStyle(text:string){
|
||||||
|
|
||||||
return text.replaceAll(styleDecodeRegex, (full, txt:string) => {
|
return text.replaceAll(styleDecodeRegex, (full, txt:string) => {
|
||||||
try {
|
try {
|
||||||
let text = Buffer.from(txt, 'hex').toString('utf-8')
|
let text = Buffer.from(txt, 'hex').toString('utf-8')
|
||||||
|
|||||||
Reference in New Issue
Block a user