From 863ca796b3aad97d19e2aa703769ac8ee23a563d Mon Sep 17 00:00:00 2001 From: Rintim Date: Sat, 11 May 2024 15:05:15 +0800 Subject: [PATCH 1/6] feat: add `Get#dataUrl` to turn blob to data url. --- noname/get/index.js | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/noname/get/index.js b/noname/get/index.js index cf0f2004c..2ca53aeff 100644 --- a/noname/get/index.js +++ b/noname/get/index.js @@ -4809,6 +4809,47 @@ export class Get { } return base; } + + /** + * 通过`FileReader`,将Blob转换成对应内容的[Data URL](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/Data_URLs) + * + * @param {Blob} blob - 需要转换的内容 + * @returns {Promise} 对应Blob内容的 + */ + dataUrl(blob) { + return new Promise((resolve, reject) => { + let fileReader = new FileReader(); + fileReader.onload = resolve; + fileReader.onerror = reject; + fileReader.readAsDataURL(blob); + }).then(event => event.target.result); + } + + /** + * 通过`fetch`读取data URL的内容,转换成Blob后返回生成的blob URL + * + * 该方法具有缓存,同一data URL仅会返回同一blob URL + * + * 该方法相比`get.objectURL`,会保留文件的类型 + * + * --- + * + * > 其实我不确定`get.objectURL`是否有实际意义上的需求,我也不确定`get.objectURL`不保留类型是否是刚需,但既然原先就存在,那么就不要动 + * + * @async + * @param {string | URL} dataUrl - 需要转换的data URL + * @returns {Promise} + */ + async objectURLAsync(dataUrl) { + let dataString = dataUrl instanceof URL ? dataUrl.href : dataUrl; + const objectURLMap = lib.objectURL; + if (objectURLMap.has(dataString)) return new URL(objectURLMap.get(dataString)); + + let blob = await (await fetch(dataUrl)).blob(); + const objectURL = URL.createObjectURL(blob); + objectURLMap.set(dataString, objectURL); + return new URL(objectURL); + } } export let get = new Get(); From 1f18dd6b7e235daad414b8943a57ee8bbe52f825 Mon Sep 17 00:00:00 2001 From: Rintim Date: Sat, 11 May 2024 15:24:24 +0800 Subject: [PATCH 2/6] feat: add `lib.init.parseResourceAddress`. --- noname/library/init/index.js | 320 ++++++++++++----------------------- 1 file changed, 106 insertions(+), 214 deletions(-) diff --git a/noname/library/init/index.js b/noname/library/init/index.js index 61f512b81..38295f735 100644 --- a/noname/library/init/index.js +++ b/noname/library/init/index.js @@ -9,6 +9,7 @@ import { gnc } from "../../gnc/index.js"; import { LibInitPromises } from "./promises.js"; import { GameEvent } from "../element/gameEvent.js"; import { GameEventPromise } from "../element/gameEventPromise.js"; +import { rootURL } from "../../../noname.js"; export class LibInit { /** @@ -23,11 +24,7 @@ export class LibInit { reset() { if (window.inSplash) return; if (window.resetExtension) { - if ( - confirm( - "游戏似乎未正常载入,有可能因为部分扩展未正常载入,或者因为部分扩展未载入完毕。\n是否禁用扩展并重新打开?" - ) - ) { + if (confirm("游戏似乎未正常载入,有可能因为部分扩展未正常载入,或者因为部分扩展未载入完毕。\n是否禁用扩展并重新打开?")) { window.resetExtension(); window.location.reload(); } @@ -91,7 +88,7 @@ export class LibInit { event._resultid = null; event._result = null; game.pause(); - "step 1"; + ("step 1"); if (result) { if (event._resultid) { result.id = event._resultid; @@ -176,10 +173,7 @@ export class LibInit { if (path) { if (path[path.length - 1] == "/") path = path.slice(0, path.length - 1); if (file) path = `${path}${/^db:extension-[^:]*$/.test(path) ? ":" : "/"}${file}.css`; - (path.startsWith("db:") - ? game.getDB("image", path.slice(3)).then(get.objectURL) - : new Promise((resolve) => resolve(path)) - ).then((resolvedPath) => { + (path.startsWith("db:") ? game.getDB("image", path.slice(3)).then(get.objectURL) : new Promise(resolve => resolve(path))).then(resolvedPath => { style.href = resolvedPath; if (typeof before == "function") { style.addEventListener("load", before); @@ -211,28 +205,19 @@ export class LibInit { return; } if (Array.isArray(file)) { - file.forEach((value) => lib.init.js(path, value, onLoad, onError)); + file.forEach(value => lib.init.js(path, value, onLoad, onError)); return; } let scriptSource = file ? `${path}${/^db:extension-[^:]*$/.test(path) ? ":" : "/"}${file}.js` : path; if (path.startsWith("http")) scriptSource += `?rand=${get.id()}`; - else if ( - lib.config.fuck_sojson && - scriptSource.includes("extension") != -1 && - scriptSource.startsWith(lib.assetURL) - ) { + else if (lib.config.fuck_sojson && scriptSource.includes("extension") != -1 && scriptSource.startsWith(lib.assetURL)) { const pathToRead = scriptSource.slice(lib.assetURL.length); const alertMessage = `检测到您安装了使用免费版sojson进行加密的扩展。请谨慎使用这些扩展,避免游戏数据遭到破坏。\n扩展文件:${pathToRead}`; if (typeof game.readFileAsText == "function") game.readFileAsText( pathToRead, - (result) => { - if ( - result.includes("sojson") || - result.includes("jsjiami") || - result.includes("var _0x") - ) - alert(alertMessage); + result => { + if (result.includes("sojson") || result.includes("jsjiami") || result.includes("var _0x")) alert(alertMessage); }, () => void 0 ); @@ -241,21 +226,13 @@ export class LibInit { pathToRead, function () { const result = this.responseText; - if ( - result.includes("sojson") || - result.includes("jsjiami") || - result.includes("var _0x") - ) - alert(alertMessage); + if (result.includes("sojson") || result.includes("jsjiami") || result.includes("var _0x")) alert(alertMessage); }, () => void 0 ); } const script = document.createElement("script"); - (scriptSource.startsWith("db:") - ? game.getDB("image", scriptSource.slice(3)).then(get.objectURL) - : new Promise((resolve) => resolve(scriptSource)) - ).then((resolvedScriptSource) => { + (scriptSource.startsWith("db:") ? game.getDB("image", scriptSource.slice(3)).then(get.objectURL) : new Promise(resolve => resolve(scriptSource))).then(resolvedScriptSource => { script.src = resolvedScriptSource; if (path.startsWith("http")) script.addEventListener("load", () => script.remove()); document.head.appendChild(script); @@ -282,7 +259,7 @@ export class LibInit { return; } if (Array.isArray(file)) { - return file.forEach((value) => lib.init.jsSync(path, value, onLoad, onError)); + return file.forEach(value => lib.init.jsSync(path, value, onLoad, onError)); } let scriptSource; if (!file) scriptSource = path; @@ -301,16 +278,9 @@ export class LibInit { if (typeof onError == "function") onError(new Error(`${scriptSource}加载失败!`)); return; } - if ( - lib.config.fuck_sojson && - scriptSource.includes("extension") != -1 && - scriptSource.startsWith(lib.assetURL) - ) { + if (lib.config.fuck_sojson && scriptSource.includes("extension") != -1 && scriptSource.startsWith(lib.assetURL)) { const pathToRead = scriptSource.slice(lib.assetURL.length); - if (data.includes("sojson") || data.includes("jsjiami") || data.includes("var _0x")) - alert( - `检测到您安装了使用免费版sojson进行加密的扩展。请谨慎使用这些扩展,避免游戏数据遭到破坏。\n扩展文件:${pathToRead}` - ); + if (data.includes("sojson") || data.includes("jsjiami") || data.includes("var _0x")) alert(`检测到您安装了使用免费版sojson进行加密的扩展。请谨慎使用这些扩展,避免游戏数据遭到破坏。\n扩展文件:${pathToRead}`); } try { window.eval(data); @@ -328,11 +298,7 @@ export class LibInit { let sScriptURL; if (str.startsWith("http")) sScriptURL = str; else if (str.startsWith("local:")) { - if ( - lib.assetURL.length == 0 && - location.origin == "file://" && - typeof game.readFile == "undefined" - ) { + if (lib.assetURL.length == 0 && location.origin == "file://" && typeof game.readFile == "undefined") { const e = new Error("浏览器file协议下无法使用此api,请在http/https协议下使用此api"); if (typeof onerror == "function") onerror(e); else throw e; @@ -346,7 +312,7 @@ export class LibInit { } const oReq = new XMLHttpRequest(); if (typeof onload == "function") - oReq.addEventListener("load", (result) => { + oReq.addEventListener("load", result => { if (![0, 200].includes(oReq.status)) { // @ts-ignore if (typeof onerror == "function") onerror(new Error(oReq.statusText || oReq.status)); @@ -366,11 +332,7 @@ export class LibInit { let sScriptURL; if (str.startsWith("http")) sScriptURL = str; else if (str.startsWith("local:")) { - if ( - lib.assetURL.length == 0 && - location.origin == "file://" && - typeof game.readFile == "undefined" - ) { + if (lib.assetURL.length == 0 && location.origin == "file://" && typeof game.readFile == "undefined") { const e = new Error("浏览器file协议下无法使用此api,请在http/https协议下使用此api"); if (typeof onerror == "function") onerror(e); else throw e; @@ -384,7 +346,7 @@ export class LibInit { } const oReq = new XMLHttpRequest(); if (typeof onload == "function") - oReq.addEventListener("load", (result) => { + oReq.addEventListener("load", result => { if (![0, 200].includes(oReq.status)) { // @ts-ignore if (typeof onerror == "function") onerror(new Error(oReq.statusText || oReq.status)); @@ -460,61 +422,26 @@ export class LibInit { ui.css.styles.remove(); } ui.css.styles = lib.init.sheet(); - ui.css.styles.sheet.insertRule( - "#arena .player>.name,#arena .button.character>.name {font-family: " + - (lib.config.name_font || "xinwei") + - ",xinwei}", - 0 - ); - ui.css.styles.sheet.insertRule( - "#arena .player>.name,.button.character>.name {font-family: " + - (lib.config.name_font || "xinwei") + - ",xinwei}", - 0 - ); - ui.css.styles.sheet.insertRule( - "#arena .player .identity>div {font-family: " + - (lib.config.identity_font || "huangcao") + - ",xinwei}", - 0 - ); - ui.css.styles.sheet.insertRule( - ".button.character.newstyle>.identity {font-family: " + - (lib.config.identity_font || "huangcao") + - ",xinwei}", - 0 - ); + ui.css.styles.sheet.insertRule("#arena .player>.name,#arena .button.character>.name {font-family: " + (lib.config.name_font || "xinwei") + ",xinwei}", 0); + ui.css.styles.sheet.insertRule("#arena .player>.name,.button.character>.name {font-family: " + (lib.config.name_font || "xinwei") + ",xinwei}", 0); + ui.css.styles.sheet.insertRule("#arena .player .identity>div {font-family: " + (lib.config.identity_font || "huangcao") + ",xinwei}", 0); + ui.css.styles.sheet.insertRule(".button.character.newstyle>.identity {font-family: " + (lib.config.identity_font || "huangcao") + ",xinwei}", 0); if (lib.config.cardtext_font && lib.config.cardtext_font != "default") { - ui.css.styles.sheet.insertRule( - ".card div:not(.info):not(.background) {font-family: " + lib.config.cardtext_font + ";}", - 0 - ); + ui.css.styles.sheet.insertRule(".card div:not(.info):not(.background) {font-family: " + lib.config.cardtext_font + ";}", 0); } if (lib.config.global_font && lib.config.global_font != "default") { ui.css.styles.sheet.insertRule("#window {font-family: " + lib.config.global_font + ",xinwei}", 0); - ui.css.styles.sheet.insertRule( - "#window #control{font-family: STHeiti,SimHei,Microsoft JhengHei,Microsoft YaHei,WenQuanYi Micro Hei,Suits,Helvetica,Arial,sans-serif}", - 0 - ); + ui.css.styles.sheet.insertRule("#window #control{font-family: STHeiti,SimHei,Microsoft JhengHei,Microsoft YaHei,WenQuanYi Micro Hei,Suits,Helvetica,Arial,sans-serif}", 0); } switch (lib.config.glow_phase) { case "yellow": - ui.css.styles.sheet.insertRule( - "#arena .player:not(.selectable):not(.selected).glow_phase {box-shadow: rgba(0, 0, 0, 0.3) 0 0 0 1px, rgb(217, 152, 62) 0 0 15px, rgb(217, 152, 62) 0 0 15px !important;}", - 0 - ); + ui.css.styles.sheet.insertRule("#arena .player:not(.selectable):not(.selected).glow_phase {box-shadow: rgba(0, 0, 0, 0.3) 0 0 0 1px, rgb(217, 152, 62) 0 0 15px, rgb(217, 152, 62) 0 0 15px !important;}", 0); break; case "green": - ui.css.styles.sheet.insertRule( - "#arena .player:not(.selectable):not(.selected).glow_phase {box-shadow: rgba(0, 0, 0, 0.3) 0 0 0 1px, rgba(10, 155, 67, 1) 0 0 15px, rgba(10, 155, 67, 1) 0 0 15px !important;}", - 0 - ); + ui.css.styles.sheet.insertRule("#arena .player:not(.selectable):not(.selected).glow_phase {box-shadow: rgba(0, 0, 0, 0.3) 0 0 0 1px, rgba(10, 155, 67, 1) 0 0 15px, rgba(10, 155, 67, 1) 0 0 15px !important;}", 0); break; case "purple": - ui.css.styles.sheet.insertRule( - "#arena .player:not(.selectable):not(.selected).glow_phase {box-shadow: rgba(0, 0, 0, 0.3) 0 0 0 1px, rgb(189, 62, 170) 0 0 15px, rgb(189, 62, 170) 0 0 15px !important;}", - 0 - ); + ui.css.styles.sheet.insertRule("#arena .player:not(.selectable):not(.selected).glow_phase {box-shadow: rgba(0, 0, 0, 0.3) 0 0 0 1px, rgb(189, 62, 170) 0 0 15px, rgb(189, 62, 170) 0 0 15px !important;}", 0); break; } } @@ -529,7 +456,7 @@ export class LibInit { if (!nosave) game.saveConfig("layout", layout); game.layout = layout; ui.arena.hide(); - new Promise((resolve) => setTimeout(resolve, 500)) + new Promise(resolve => setTimeout(resolve, 500)) .then(() => { if (game.layout == "default") { ui.css.layout.href = ""; @@ -541,12 +468,7 @@ export class LibInit { } else { ui.arena.classList.remove("mobile"); } - if ( - game.layout == "mobile" || - game.layout == "long" || - game.layout == "long2" || - game.layout == "nova" - ) { + if (game.layout == "mobile" || game.layout == "long" || game.layout == "long2" || game.layout == "nova") { if (game.me && game.me.node.handcards2.childNodes.length) { while (game.me.node.handcards2.childNodes.length) { game.me.node.handcards1.appendChild(game.me.node.handcards2.firstChild); @@ -558,13 +480,7 @@ export class LibInit { } else { ui.arena.classList.remove("oldlayout"); } - if ( - lib.config.cardshape == "oblong" && - (game.layout == "long" || - game.layout == "mobile" || - game.layout == "long2" || - game.layout == "nova") - ) { + if (lib.config.cardshape == "oblong" && (game.layout == "long" || game.layout == "mobile" || game.layout == "long2" || game.layout == "nova")) { ui.arena.classList.add("oblongcard"); ui.window.classList.add("oblongcard"); } else { @@ -607,11 +523,7 @@ export class LibInit { } else { ui.arena.classList.remove("slim_player"); } - if ( - lib.config.player_border == "normal" && - lib.config.mode != "brawl" && - (game.layout == "long" || game.layout == "long2") - ) { + if (lib.config.player_border == "normal" && lib.config.mode != "brawl" && (game.layout == "long" || game.layout == "long2")) { ui.arena.classList.add("lslim_player"); } else { ui.arena.classList.remove("lslim_player"); @@ -628,24 +540,22 @@ export class LibInit { } ui.updatej(); ui.updatem(); - return new Promise((resolve) => setTimeout(resolve, 100)); + return new Promise(resolve => setTimeout(resolve, 100)); }) .then(() => { ui.arena.show(); if (game.me) game.me.update(); - return new Promise((resolve) => setTimeout(resolve, 500)); + return new Promise(resolve => setTimeout(resolve, 500)); }) .then(() => { ui.updatex(); ui.updatePlayerPositions(); - return new Promise((resolve) => setTimeout(resolve, 500)); + return new Promise(resolve => setTimeout(resolve, 500)); }) .then(() => { ui.updatec(); loadingScreenStyle.animationName = "opacity-1-0"; - loadingScreen.addEventListener("animationend", (animationEvent) => - animationEvent.target.remove() - ); + loadingScreen.addEventListener("animationend", animationEvent => animationEvent.target.remove()); }); } @@ -658,11 +568,7 @@ export class LibInit { } list.remove(lib.config.image_background); localStorage.setItem(lib.configprefix + "background", JSON.stringify(list)); - } else if ( - lib.config.image_background && - lib.config.image_background != "default" && - !lib.config.image_background.startsWith("custom_") - ) { + } else if (lib.config.image_background && lib.config.image_background != "default" && !lib.config.image_background.startsWith("custom_")) { localStorage.setItem(lib.configprefix + "background", lib.config.image_background); } else if (lib.config.image_background == "default" && lib.config.theme == "simple") { localStorage.setItem(lib.configprefix + "background", "ol_bg"); @@ -687,10 +593,7 @@ export class LibInit { //移除所有注释 let str = func .toString() - .replace( - /((?:(?:^[ \t]*)?(?:\/\*[^*]*\*+(?:[^/*][^*]*\*+)*\/(?:[ \t]*\r?\n(?=[ \t]*(?:\r?\n|\/\*|\/\/)))?|\/\/(?:[^\\]|\\(?:\r?\n)?)*?(?:\r?\n(?=[ \t]*(?:\r?\n|\/\*|\/\/))|(?=\r?\n))))+)|("(?:\\[\s\S]|[^"\\])*"|'(?:\\[\s\S]|[^'\\])*'|(?:\r?\n|[\s\S])[^/"'\\\s]*)/gm, - "$2" - ) + .replace(/((?:(?:^[ \t]*)?(?:\/\*[^*]*\*+(?:[^/*][^*]*\*+)*\/(?:[ \t]*\r?\n(?=[ \t]*(?:\r?\n|\/\*|\/\/)))?|\/\/(?:[^\\]|\\(?:\r?\n)?)*?(?:\r?\n(?=[ \t]*(?:\r?\n|\/\*|\/\/))|(?=\r?\n))))+)|("(?:\\[\s\S]|[^"\\])*"|'(?:\\[\s\S]|[^'\\])*'|(?:\r?\n|[\s\S])[^/"'\\\s]*)/gm, "$2") .trim(); //获取第一个 { 后的所有字符 str = str.slice(str.indexOf("{") + 1); @@ -702,10 +605,7 @@ export class LibInit { let debuggerResult; while ((debuggerResult = str.slice(debuggerSkip).match(regex)) != null) { let debuggerCopy = str; - debuggerCopy = - debuggerCopy.slice(0, debuggerSkip + debuggerResult.index) + - insertDebugger + - debuggerCopy.slice(debuggerSkip + debuggerResult.index + debuggerResult[0].length, -1); + debuggerCopy = debuggerCopy.slice(0, debuggerSkip + debuggerResult.index) + insertDebugger + debuggerCopy.slice(debuggerSkip + debuggerResult.index + debuggerResult[0].length, -1); //测试是否有错误 try { new GeneratorFunction(debuggerCopy); @@ -732,10 +632,7 @@ export class LibInit { insertStr = `break;case ${k}:`; } let copy = str; - copy = - copy.slice(0, skip + result.index) + - insertStr + - copy.slice(skip + result.index + result[0].length); + copy = copy.slice(0, skip + result.index) + insertStr + copy.slice(skip + result.index + result[0].length); //测试是否有错误 try { new (hasDebugger ? GeneratorFunction : Function)(copy); @@ -750,32 +647,9 @@ export class LibInit { str = `if(event.step==${k}){event.finish();return;}` + str; } if (!scope) { - return new (hasDebugger ? GeneratorFunction : Function)( - "event", - "step", - "source", - "player", - "target", - "targets", - "card", - "cards", - "skill", - "forced", - "num", - "trigger", - "result", - "_status", - "lib", - "game", - "ui", - "get", - "ai", - str - ); + return new (hasDebugger ? GeneratorFunction : Function)("event", "step", "source", "player", "target", "targets", "card", "cards", "skill", "forced", "num", "trigger", "result", "_status", "lib", "game", "ui", "get", "ai", str); } else { - return scope(`function${ - hasDebugger ? "*" : "" - } anonymous(event,step,source,player,target,targets, + return scope(`function${hasDebugger ? "*" : ""} anonymous(event,step,source,player,target,targets, card,cards,skill,forced,num,trigger,result, _status,lib,game,ui,get,ai){${str}}; anonymous;`); } @@ -784,31 +658,10 @@ export class LibInit { case "object": if (Array.isArray(item)) { let lastEvent = null; - return function* ( - event, - step, - source, - player, - target, - targets, - card, - cards, - skill, - forced, - num, - trigger, - result, - _status, - lib, - game, - ui, - get, - ai - ) { + return function* (event, step, source, player, target, targets, card, cards, skill, forced, num, trigger, result, _status, lib, game, ui, get, ai) { if (step >= item.length) return event.finish(); var current = item[step]; - if (typeof current != "function") - throw new Error(`content ${step} of ${event.name} is not vaild: ${current}`); + if (typeof current != "function") throw new Error(`content ${step} of ${event.name} is not vaild: ${current}`); var currentResult = current( event, { @@ -845,27 +698,7 @@ export class LibInit { case "function": if (gnc.is.generatorFunc(item)) { // let gen, lastEvent; - let content = function* ( - event, - step, - source, - player, - target, - targets, - card, - cards, - skill, - forced, - num, - trigger, - result, - _status, - lib, - game, - ui, - get, - ai - ) { + let content = function* (event, step, source, player, target, targets, card, cards, skill, forced, num, trigger, result, _status, lib, game, ui, get, ai) { event.step = NaN; if (!this.gen) this.gen = item(event, { @@ -887,8 +720,7 @@ export class LibInit { let res; if (!this.last) res = this.gen.next(); else if (typeof this.last !== "object") res = this.gen.next(this.last); - else if (this.last instanceof GameEvent || this.last instanceof GameEventPromise) - res = this.gen.next(this.last.result); + else if (this.last instanceof GameEvent || this.last instanceof GameEventPromise) res = this.gen.next(this.last.result); else res = this.gen.next(this.last); if (res.done) { @@ -952,8 +784,7 @@ export class LibInit { decode(str) { var strUtf = atob(str); var strUni = strUtf.replace(/[\u00e0-\u00ef][\u0080-\u00bf][\u0080-\u00bf]/g, function (c) { - var cc = - ((c.charCodeAt(0) & 0x0f) << 12) | ((c.charCodeAt(1) & 0x3f) << 6) | (c.charCodeAt(2) & 0x3f); + var cc = ((c.charCodeAt(0) & 0x0f) << 12) | ((c.charCodeAt(1) & 0x3f) << 6) | (c.charCodeAt(2) & 0x3f); return String.fromCharCode(cc); }); strUni = strUni.replace(/[\u00c0-\u00df][\u0080-\u00bf]/g, function (c) { @@ -1005,4 +836,65 @@ export class LibInit { let ret = url.replace(head, ""); return decodeURIComponent(ret); } + + /** + * @async + * @param {string | URL} link - 需要解析的路径 + * @param {(item: string) => string} [defaultHandle] - 在给定路径不符合可用情况(或基于无名杀相关默认情况)时,处理路径的函数,返回的路径应是相对于根目录的相对路径,默认为恒等函数 + * @param {boolean} [forceLoadAsDataUrl] - 是否将资源加载为[Data URL](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/Data_URLs),默认为`false` + * @param {boolean} [dbNow] - 此刻是否在解析数据库中的内容,请勿直接使用 + * @returns {Promise} + */ + async parseResourceAddress(link, defaultHandle = item => item, forceLoadAsDataUrl = false, dbNow = false) { + let linkString = link instanceof URL ? link.href : link; + + // 如果传入值为Data URL,经过分析可知无需处理,故直接返回成品URL + if (linkString.startsWith("data:")) return new URL(linkString); + + /** + * @type {URL} + */ + let resultUrl; + if (linkString.startsWith("ext:")) { + let resultLink = `extension/${linkString.slice(4)}`; + resultUrl = new URL(resultLink, rootURL); + } else if (URL.canParse(linkString)) { + resultUrl = new URL(linkString); + } else if (dbNow) { + let content = new Blob([linkString], { type: "text/plain" }); + resultUrl = new URL(await get.dataUrl(content)); + } else { + let resultLink = defaultHandle(linkString); + resultUrl = new URL(resultLink, rootURL); + } + + if (forceLoadAsDataUrl && !resultUrl.href.startsWith("data:")) { + if (linkString.startsWith("db:")) { + /** + * @type {string} + */ + let storeResult = await game.getDB("image", linkString.slice(3)); + + // 我思索了一下,如果这玩意能造成无限递归 + // 那么我只能说,你赢了 + return this.parseResourceAddress(storeResult, defaultHandle, forceLoadAsDataUrl, true); + } + /** + * @type {Blob} + */ + let blob; + + if (linkString.startsWith("file:")) { + let buffer = await game.promises.readFile(get.relativePath(resultUrl)); + blob = new Blob([buffer]); + } else { + let response = await fetch(resultUrl.href); + blob = await response.blob(); + } + + resultUrl.href = await get.dataUrl(blob); + } + + return resultUrl; + } } From 26ef5daeca89a895eed8d85e79a67e41c8bd9db8 Mon Sep 17 00:00:00 2001 From: Rintim Date: Sat, 11 May 2024 15:24:34 +0800 Subject: [PATCH 3/6] docs: add example. --- noname/get/index.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/noname/get/index.js b/noname/get/index.js index 2ca53aeff..187957f37 100644 --- a/noname/get/index.js +++ b/noname/get/index.js @@ -4800,7 +4800,7 @@ export class Get { * @example * // 当前文件以"noname/get/index.js"举例 * let parsedPath = get.relativePath(import.meta.url, true); - * console.log(parsedPath == `${lib.assetURL}noname/get/index.js`) //=> true + * console.assert(parsedPath == `${lib.assetURL}noname/get/index.js`); */ relativePath(url, addAssetURL = false) { let base = lib.path.relative(decodeURI(rootURL.pathname), decodeURI(url.pathname)); @@ -4813,8 +4813,17 @@ export class Get { /** * 通过`FileReader`,将Blob转换成对应内容的[Data URL](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/Data_URLs) * + * @async * @param {Blob} blob - 需要转换的内容 * @returns {Promise} 对应Blob内容的 + * + * @example + * let text = "Hello, World!"; + * console.assert(btoa(text) === "SGVsbG8sIFdvcmxkIQ=="); + * + * let blob = new Blob([text], { type: "text/plain" }); + * let url = await get.dataUrl(blob); + * console.assert("data:text/plain;base64,SGVsbG8sIFdvcmxkIQ=="); */ dataUrl(blob) { return new Promise((resolve, reject) => { From 0e0cf646bcfe81a959e87f99af1a4a237bbb21ef Mon Sep 17 00:00:00 2001 From: Rintim Date: Sat, 11 May 2024 15:25:51 +0800 Subject: [PATCH 4/6] feat: add link of `parseResourceAddress` to `lib.init.promises`. --- noname/library/init/promises.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/noname/library/init/promises.js b/noname/library/init/promises.js index 844034828..e485ebbef 100644 --- a/noname/library/init/promises.js +++ b/noname/library/init/promises.js @@ -63,4 +63,15 @@ export class LibInitPromises { style.addEventListener("error", reject); }); } + + /** + * @async + * @param {string | URL} link - 需要解析的路径 + * @param {(item: string) => string} [defaultHandle] - 在给定路径不符合可用情况(或基于无名杀相关默认情况)时,处理路径的函数,返回的路径应是相对于根目录的相对路径,默认为恒等函数 + * @param {boolean} [forceLoadAsDataUrl] - 是否将资源加载为[Data URL](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/Data_URLs),默认为`false` + * @returns {Promise} + */ + parseResourceAddress(link, defaultHandle = item => item, forceLoadAsDataUrl = false) { + return lib.init.parseResourceAddress(link, defaultHandle, forceLoadAsDataUrl); + } } From 3910769de3676eed236252e4332b4540ada0fa35 Mon Sep 17 00:00:00 2001 From: Rintim Date: Sat, 11 May 2024 15:41:32 +0800 Subject: [PATCH 5/6] refactor: support null. --- noname/library/init/index.js | 6 +++--- noname/library/init/promises.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/noname/library/init/index.js b/noname/library/init/index.js index 38295f735..b7fbe69ac 100644 --- a/noname/library/init/index.js +++ b/noname/library/init/index.js @@ -840,12 +840,12 @@ export class LibInit { /** * @async * @param {string | URL} link - 需要解析的路径 - * @param {(item: string) => string} [defaultHandle] - 在给定路径不符合可用情况(或基于无名杀相关默认情况)时,处理路径的函数,返回的路径应是相对于根目录的相对路径,默认为恒等函数 + * @param {((item: string) => string) | null} [defaultHandle] - 在给定路径不符合可用情况(或基于无名杀相关默认情况)时,处理路径的函数,返回的路径应是相对于根目录的相对路径,默认为`null`,当且仅当无法解析成`URL`时会调用该回调 * @param {boolean} [forceLoadAsDataUrl] - 是否将资源加载为[Data URL](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/Data_URLs),默认为`false` * @param {boolean} [dbNow] - 此刻是否在解析数据库中的内容,请勿直接使用 * @returns {Promise} */ - async parseResourceAddress(link, defaultHandle = item => item, forceLoadAsDataUrl = false, dbNow = false) { + async parseResourceAddress(link, defaultHandle = null, forceLoadAsDataUrl = false, dbNow = false) { let linkString = link instanceof URL ? link.href : link; // 如果传入值为Data URL,经过分析可知无需处理,故直接返回成品URL @@ -864,7 +864,7 @@ export class LibInit { let content = new Blob([linkString], { type: "text/plain" }); resultUrl = new URL(await get.dataUrl(content)); } else { - let resultLink = defaultHandle(linkString); + let resultLink = defaultHandle == null ? linkString : defaultHandle(linkString); resultUrl = new URL(resultLink, rootURL); } diff --git a/noname/library/init/promises.js b/noname/library/init/promises.js index e485ebbef..0b50e1d3e 100644 --- a/noname/library/init/promises.js +++ b/noname/library/init/promises.js @@ -67,11 +67,11 @@ export class LibInitPromises { /** * @async * @param {string | URL} link - 需要解析的路径 - * @param {(item: string) => string} [defaultHandle] - 在给定路径不符合可用情况(或基于无名杀相关默认情况)时,处理路径的函数,返回的路径应是相对于根目录的相对路径,默认为恒等函数 + * @param {((item: string) => string) | null} [defaultHandle] - 在给定路径不符合可用情况(或基于无名杀相关默认情况)时,处理路径的函数,返回的路径应是相对于根目录的相对路径,默认为`null`,当且仅当无法解析成`URL`时会调用该回调 * @param {boolean} [forceLoadAsDataUrl] - 是否将资源加载为[Data URL](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/Data_URLs),默认为`false` * @returns {Promise} */ - parseResourceAddress(link, defaultHandle = item => item, forceLoadAsDataUrl = false) { + parseResourceAddress(link, defaultHandle = null, forceLoadAsDataUrl = false) { return lib.init.parseResourceAddress(link, defaultHandle, forceLoadAsDataUrl); } } From 616a67217141e0a2c6821a208c021b62153088ea Mon Sep 17 00:00:00 2001 From: Rintim Date: Sat, 11 May 2024 15:50:17 +0800 Subject: [PATCH 6/6] refactor: rename. --- noname/get/index.js | 4 ++-- noname/library/init/index.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/noname/get/index.js b/noname/get/index.js index 187957f37..026b75af1 100644 --- a/noname/get/index.js +++ b/noname/get/index.js @@ -4822,10 +4822,10 @@ export class Get { * console.assert(btoa(text) === "SGVsbG8sIFdvcmxkIQ=="); * * let blob = new Blob([text], { type: "text/plain" }); - * let url = await get.dataUrl(blob); + * let url = await get.dataUrlAsync(blob); * console.assert("data:text/plain;base64,SGVsbG8sIFdvcmxkIQ=="); */ - dataUrl(blob) { + dataUrlAsync(blob) { return new Promise((resolve, reject) => { let fileReader = new FileReader(); fileReader.onload = resolve; diff --git a/noname/library/init/index.js b/noname/library/init/index.js index b7fbe69ac..be1233119 100644 --- a/noname/library/init/index.js +++ b/noname/library/init/index.js @@ -862,7 +862,7 @@ export class LibInit { resultUrl = new URL(linkString); } else if (dbNow) { let content = new Blob([linkString], { type: "text/plain" }); - resultUrl = new URL(await get.dataUrl(content)); + resultUrl = new URL(await get.dataUrlAsync(content)); } else { let resultLink = defaultHandle == null ? linkString : defaultHandle(linkString); resultUrl = new URL(resultLink, rootURL); @@ -892,7 +892,7 @@ export class LibInit { blob = await response.blob(); } - resultUrl.href = await get.dataUrl(blob); + resultUrl.href = await get.dataUrlAsync(blob); } return resultUrl;