您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
none
当前为
// ==UserScript== // @name scratch extension loader // @version 1 // @description none // @run-at document-start // @tag lib loader // @author rssaromeo // @license GPLv3 // @match *://*/* // @sandbox dom // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAMAAABiM0N1AAAAAXNSR0IB2cksfwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAHJQTFRFAAAAEIijAo2yAI60BYyuF4WaFIifAY6zBI2wB4usGIaZEYigIoiZCIyrE4igG4iYD4mjEomhFoedCoqpDIqnDomlBYyvE4efEYmiDYqlA42xBoytD4mkCYqqGYSUFYidC4qoC4upAo6yCoupDYqmCYur4zowOQAAACZ0Uk5TAO////9vr////1+/D/+/L+/Pf/////+f3///////H4////////+5G91rAAACgUlEQVR4nM2Y22KjIBCGidg1264liZqDadK03X3/V2wNKHMC7MpF/xthHD5mgERAqZhWhfYqH6K+Qf2qNNf625hCoFj9/gblMUi5q5jLkXLCKudgyiRm0FMK82cWJp1fLbV5VmvJbCIc0GCYaFqqlDJgADdBjncqAXYobm1xh72aFMflbysteFfdy2Yi1XGOm5HGBzQ1dq7TzEoxjeNTjQZb7VA3e1c7+ImgasAgQ9+xusNVNZIo5xmOMgihIS2PbCQIiHEUdTvhxCcS/kPomfFI2zHy2PkWmA6aNatIJpKFJyekyy02xh5Y3DI9T4aOT6VhIUrsNTFp1pf79Z4SIIVDegl6IJO6cHiL/GimIZDhgTu/BlYWCQzHMl0zBWT/T3KAhtxOuUB9FtBrpsz0RV4xsjHmW+UCaffcSy/5viMGer0/6HdFNMZBq/vjJL38H9Dqx4Fuy0Em12DbZy+9pGtiDijbglwAehyj11n0tRD3WUBm+lwulE/8h4BuA+iWAQQnteg2Xm63WQLTpnMnpjdge0Mgu/GRPsV4xdjQ94Lfi624fabhDkfUqIKNrM64Q837v8yL0prasepCgrtvw1sJpoqanGEX7b5mQboNW8eawXaWXTMfMGxub472hzWzHSn6Sg2G9+6TAyRruE71s+zAzjWaknoyJCQzwxrghH2k5FDT4eqWunuNxyN9QCGcxVod5oADbYnIUkDTGZEf1xDJnSFteQ3KdsT8zYDMQXcHxsevcLH1TrsABzkNPyA/L7b0jg704viMMlpQI96WsHknCt/3YH0kOEo9zcGkwrFK39ck72rmoehmKqo2RKlilzSy/nJKEV45CT38myJp456fezktHjN5aeMAAAAASUVORK5CYII= // @require https://update.gf.qytechs.cn/scripts/491829/1356221/tampermonkey%20storage%20proxy.js // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @grant unsafeWindow // @namespace https://gf.qytechs.cn/users/1184528 // ==/UserScript== // add get turbomode state // add way to toggle on and off extensions // how to change the properties of a menu baised on the value of another menu // // add set var // add get var // add return project id ;(async () => { var menus = {} var extensionerrors = [] unsafeWindow.ee = extensionerrors var projectid = location.href.match(/(?<=\/)[0-9]+(?=\/)/)?.[0] || "local" // debugger var sp = new storageproxy("extensionoptions") // debugger var bt = { cmd: "command", ret: "reporter", hat: "hat", bool: "Boolean", } var inp = { int: "number", num: "number", str: "string", } var menufuncs = class { menu_varnames(targetid) { try { var name = vm.runtime.targets.find((e) => e.id == targetid) .sprite.name if (!gettarget(name).runtime.ioDevices.cloud.stage) return [" "] var globalvars = Object.values( gettarget(name).runtime.ioDevices.cloud.stage.variables ) var localvars = Object.values(gettarget(name).variables) globalvars = globalvars.filter((e) => e.type == "") localvars = localvars.filter((e) => e.type == "") // log(globalvars, localvars) var arr = [ ...localvars.map((e) => ({ text: "__local " + e.name, value: JSON.stringify([name, e.name]), })), ...globalvars.map((e) => ({ text: "__global " + e.name, value: JSON.stringify([undefined, e.name]), })), ] return arr.length ? arr : [" "] } catch (e) { error("error from menu_varnames", e) return [" "] } } menu_listnames(targetid) { try { // if (!gettarget(name)) return [" "] var name = vm.runtime.targets.find((e) => e.id == targetid) .sprite.name if (!gettarget(name).runtime.ioDevices.cloud.stage) return [" "] var globalvars = Object.values( gettarget(name).runtime.ioDevices.cloud.stage.variables ) var localvars = Object.values(gettarget(name).variables) globalvars = globalvars.filter((e) => e.type == "list") localvars = localvars.filter((e) => e.type == "list") // log(globalvars, localvars) var arr = [ ...localvars.map((e) => ({ text: "__local " + e.name, value: JSON.stringify([name, e.name]), })), ...globalvars.map((e) => ({ text: "__global " + e.name, value: JSON.stringify([undefined, e.name]), })), ] return arr.length ? arr : [" "] } catch (e) { error("error from menu_listnames", e) return [" "] } } menu_spritelistwithglobal(targetid) { try { var spritenames = Object.values(vm.runtime.targets).map( (e) => e.sprite.name ) var name = Object.values(vm.runtime.targets).find( (e) => e.id == targetid ).sprite.name return [ name, { text: "--- global list ---", value: "" }, ...spritenames.filter((e) => e !== name && e !== "Stage"), ] } catch (e) { error("error from menu_spritelistwithglobal", e) return [" "] } } menu_spritelistwithoutglobal(targetid) { try { var spritenames = Object.values(vm.runtime.targets).map( (e) => e.sprite.name ) var name = Object.values(vm.runtime.targets).find( (e) => e.id == targetid ).sprite.name return [ name, ...spritenames.filter((e) => e !== name && e !== "Stage"), ] } catch (e) { error("error from menu_spritelistwithoutglobal", e) return [" "] } } menu_fullkeylist() { return [ "escape", "enter", "up arrow", "down arrow", "left arrow", "right arrow", "tab", "control", "alt", "shift", "win", "delete", "insert", "home", "end", "page up", "page down", "caps lock", "scroll lock", ...Array.from({ length: 24 }, (_, i) => i + 1).map((e) => ({ text: "F" + e, value: "f" + e, })), { text: "space", value: " " }, ..."~`abcdefghijklmnopqrstuvwxyz1234567890!@#$%^&*()-_=+[]\\|;:'\",<.>/?{}", "contextmenu", "mediaplaypause", "audiovolumemute", "audiovolumedown", "audiovolumeup", "launchapplication2", "launchmediaplayer", "mediatracknext", "mediatrackprevious", "Meta", ] } menu_fullkeylistandany() { return ["any", ...this.menu_fullkeylist()] } } var a = loadlib("allfuncs") var enabledextensions = sp.get() ?? { extensionmanagercreatedbyrssaromeo: true, } var extensionclasses = [] // unsafeWindow.extensionclasses = extensionclasses newext( "extension manager", "rssaromeo", class { getlasterror() { return String( extensionerrors[extensionerrors.length - 1]?.message ?? false ) } getlasterrorextensionid() { return String( extensionerrors[extensionerrors.length - 1]?.extensionid ?? false ) } getlasterrorblockid() { return String( extensionerrors[extensionerrors.length - 1]?.blockid ?? false ) } puterrorsintolist({ listname }) { var [sprite, listname] = JSON.parse(listname) scratchlist( listname, extensionerrors.map((e) => JSON.stringify(e)), sprite ) } }, [ newblock( bt.ret, "getlasterrorextensionid", "lasterror: extension id" ), newblock(bt.ret, "getlasterror", "lasterror: message"), newblock(bt.ret, "getlasterrorblockid", "lasterror: block id"), newblock( bt.cmd, "puterrorsintolist", "put errors into list [listname]", [newmenu("listnames", { defaultValue: "" })] ), ] ) loadlib("libloader").savelib("scratchextesnsionmanager", { newmenu, newext, newblock, bt, inp, gettarget, totype, scratch_math, projectid, canvas, scratchvar, scratchlist, }) // unsafeWindow.sp = sp await loadlib("libloader").waitforlib("scratch") await a(canvas).waituntil() var vm = loadlib("scratch").vm // await a(100).wait() loadallextensions() function loadallextensions() { // debugger for (var __class of extensionclasses) { var extensionInstance = new __class( vm.extensionManager.runtime, __class.thisExtensionIsEnabled ) vm.extensionManager._loadedExtensions.set( extensionInstance.getInfo().id, vm.extensionManager._registerInternalExtension( extensionInstance ) ) } } function newblock(blockType, opcode, text, args) { var arguments = Object.fromEntries( [...(text.match(/(?<=\[)\w+(?=\])/g) || [])].map((_, i) => [ _, typeof args?.[i] == "object" ? { type: args?.[i]?.type || args?.[i] || inp.str, disableMonitor: false, // defaultValue: false, // filter: [Scratch.TargetType.SPRITE], // filter: [Scratch.TargetType.STAGE], // isTerminal: false, // shouldRestartExistingThreads: true, // isEdgeActivated: false, ...(0 in args[i] && 1 in args[i] ? { type: args[i][0] ?? inp.str, defaultValue: args[i][1], } : args[i]), } : { type: args?.[i]?.type || args?.[i] || inp.str, // defaultValue: false, disableMonitor: false, }, ]) ) // log(arguments) return { hideFromPalette: false, blockType, opcode, text, arguments, } } function newmenu(name, opts = {}) { var data = { acceptReporters: true, items: "menu_" + name, ...opts, } menus[name] = data return { menu: name, ...opts } } function newext( name, username, _class, blockinfo, blockcolor = "#777777", menuicon = "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDY0IDY0IiB3aWR0aD0iNjQiIGhlaWdodD0iNjQiPgoJPHRpdGxlPk5ldyBQcm9qZWN0PC90aXRsZT4KCTxkZWZzPgoJCTxpbWFnZSAgd2lkdGg9IjY0IiBoZWlnaHQ9IjY0IiBpZD0iaW1nMSIgaHJlZj0iZGF0YTppbWFnZS9wbmc7YmFzZTY0LGlWQk9SdzBLR2dvQUFBQU5TVWhFVWdBQUFFQUFBQUJBQkFNQUFBQllSMnp0QUFBQUFYTlNSMElCMmNrc2Z3QUFBQ1JRVEZSRkFBQUFBT05sLy8vL0FPTmwvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL0I2Y0NhQUFBQUF4MFVrNVRBUDhBQUFJRUR4TUJBd1VIM0Q5UFB3QUFBRVZKUkVGVWVKeGpaRUFHakFKQTR2OEhGS0ZSQmFNS1JoWFFRb0VnQTM0d3FvQllCVXJJUEhBb2c4T2JCQVhHWU9yOXFJSkJyMEJaQ2ErQ3RMMmhCd2RGN2g0WkNnRFBCSCtKaSsyWXRnQUFBQUJKUlU1RXJrSmdnZz09Ii8+Cgk8L2RlZnM+Cgk8c3R5bGU+Cgk8L3N0eWxlPgoJPHVzZSBpZD0iQmFja2dyb3VuZCIgaHJlZj0iI2ltZzEiIHg9IjAiIHk9IjAiLz4KPC9zdmc+", blockimg = "" ) { var bg = "#282828" if (blockcolor[0] != "#") blockcolor = "#" + blockcolor blockinfo = { color1: /https?:\/\/turbowarp\.org/.test(location.href) ? blockcolor : bg, color2: bg, color3: blockcolor, menuIconURI: menuicon, blockIconURI: blockimg, blocks: blockinfo, } blockinfo.id = name.replaceAll(/[^a-z]+/gi, "") + "createdby" + username blockinfo.name = name.replaceAll(/ /gi, " ") //+ " - by " + username blockinfo.menus = menus // warn(enabledextensions) GM_registerMenuCommand( (enabledextensions[blockinfo.id] ? "enabled" : "dissabled") + (": " + blockinfo.name), () => { // warn(enabledextensions[blockinfo.id]) enabledextensions[blockinfo.id] = !enabledextensions[blockinfo.id] // warn(enabledextensions[blockinfo.id]) } ) // log("menus", menus.spritelistwithoutglobal.items) blockinfo.blocks.unshift( newblock( bt.bool, "thisextensionexists", "the extension {" + blockinfo.name + "} is enabled" ) ) function Classes(bases) { class Bases { constructor() { bases.forEach((base) => Object.assign(this, new base())) } } bases.forEach((base) => { Object.getOwnPropertyNames(base.prototype) .filter((prop) => prop != "constructor") .forEach( (prop) => (Bases.prototype[prop] = base.prototype[prop]) ) }) return Bases } var enabled = enabledextensions[blockinfo.id] if (!enabled) { const properties = Object.getOwnPropertyNames(_class.prototype) for (const property of properties) { if (typeof _class.prototype[property] === "function") { _class.prototype[property] = function () { return false } } } _class.prototype.thisextensionexists = () => { return false } } else { _class.prototype.thisextensionexists = () => { return true } } function tryCatchDecorator(constructor) { const prototype = constructor.prototype const originalPrototype = Object.getPrototypeOf(prototype) for (let key of [ ...Object.getOwnPropertyNames(prototype), ...Object.getOwnPropertyNames(originalPrototype), ]) { if (typeof prototype[key] === "function") { let originalMethod = prototype[key] prototype[key] = function (...args) { try { return originalMethod.apply(this, args) } catch (e) { extensionerrors.push({ extensionid: blockinfo.id, blockid: key, message: e.message, }) console.error("error from " + key, e) return false } } } } return constructor } // log("blockinfo.blocks", blockinfo.blocks) var __class = tryCatchDecorator( class extends Classes([_class, menufuncs]) { constructor(runtime, enabled) { super(runtime) if (enabled !== undefined) this.thisExtensionIsEnabled = enabled this.runtime = runtime } getInfo() { // log("getInfo", blockinfo) return blockinfo } } ) extensionclasses.push(__class) sp.enabledextensions = enabledextensions } function scratchvar(varname, value, spritename) { if (value !== undefined) { if (gettarget(spritename)?.getvar(varname)) gettarget(spritename).getvar(varname).value = String(value) else { console.warn(`var "${varname}" does not exist`) } } } function totype(inp, type, forced) { //number, string, list, object, json, bool inp = String(inp) try { switch (type) { // case "regex": // try { // return new RegExp(inp) // } catch (e) { // return fail(inp, type, forced) // } case "string": return String(inp) case "number": if (inp == "true") inp = 1 if (inp == "false") inp = 0 if (/^-?[0-9]*\.?[0-9]+$/.test(inp)) return Number(inp) if (inp === "NaN" || inp == "nan") return NaN return fail(inp, type, forced) case "list": if (scratchlist(inp)) return scratchlist(inp) inp = JSON.parse(inp) if (inp.reverse) return inp return fail(inp, type, forced) case "object": inp = JSON.parse(inp) // if (/^[\-0-9]+$/.test(inp) || inp === true || inp === false) // return undefined if ( Object.keys(inp).length !== undefined && inp.length === undefined && !Array.isArray(inp) ) return inp return fail(inp, type, forced) case "bool": if (inp === "1" || inp === "true") return true if (inp === "0" || inp === "false") return false return fail(inp, type) // case "json": // if ( // totype(inp, "object") !== undefined || // totype(inp, "list") !== undefined // ) // return totype(inp, "object") || totype(inp, "list") // else { // fail(inp, type, forced) // } } } catch (s) { return fail(inp, type, forced) } function fail(inp, type, forced) { if (forced) { throw new Error(`"${inp}" must be of type "${type}"`) } else return undefined } } // listen(window, "keydown", (e) => { // var index = vm.runtime.ioDevices.keyboard._keysPressed.indexOf( // e.key.toUpperCase(), // ) // if (index !== -1) { // vm.runtime.ioDevices.keyboard._keysPressed.splice(index, 1) // } // vm.runtime.ioDevices.keyboard._keysPressed.push(e.key.toUpperCase()) // }) // listen(window, "keyup", (e) => { // var index = vm.runtime.ioDevices.keyboard._keysPressed.indexOf( // e.key.toUpperCase(), // ) // if (index !== -1) { // vm.runtime.ioDevices.keyboard._keysPressed.splice(index, 1) // } // }) function gettarget(sprite) { if (sprite) var x = vm.runtime.getSpriteTargetByName(sprite) || vm.runtime.getTargetForStage() else var x = vm.runtime.getTargetForStage() x.getvar = x?.lookupVariableByNameAndType return x } function scratchlist(listname, value, spritename) { //fix regex? if (value === undefined && /^\[\]$/.test(listname)) return JSON.parse(listname) if (value !== undefined) { if (gettarget(spritename)?.getvar(listname, "list")) gettarget(spritename).getvar(listname, "list").value = [ ...value, ] else console.warn(`list "${listname}" does not exist`) } else { return gettarget(spritename)?.getvar(listname, "list")?.value } } function scratch_math(operator, n) { switch (operator) { case "sin": return Math.round(Math.sin((Math.PI * n) / 180) * 1e10) / 1e10 case "cos": return Math.round(Math.cos((Math.PI * n) / 180) * 1e10) / 1e10 case "asin": return (Math.asin(n) * 180) / Math.PI case "acos": return (Math.acos(n) * 180) / Math.PI case "atan": return (Math.atan(n) * 180) / Math.PI case "log": return Math.log(n) / Math.LN10 } return 0 } function canvas() { return ( window?.vm?.runtime?.renderer?.canvas || document.querySelector( "#app > div > div.gui_body-wrapper_-N0sA.box_box_2jjDp > div > div.gui_stage-and-target-wrapper_69KBf.box_box_2jjDp > div.stage-wrapper_stage-wrapper_2bejr.box_box_2jjDp > div.stage-wrapper_stage-canvas-wrapper_3ewmd.box_box_2jjDp > div > div.stage_stage_1fD7k.box_box_2jjDp > div:nth-child(1) > canvas" ) || document.querySelector( "#view > div > div.inner > div:nth-child(2) > div.guiPlayer > div.stage-wrapper_stage-wrapper_2bejr.box_box_2jjDp > div.stage-wrapper_stage-canvas-wrapper_3ewmd.box_box_2jjDp > div > div.stage_stage_1fD7k.box_box_2jjDp > div:nth-child(1) > canvas" ) || document.querySelector( "#app > div > div > div > div.gui_body-wrapper_-N0sA.box_box_2jjDp > div > div.gui_stage-and-target-wrapper_69KBf.box_box_2jjDp > div.stage-wrapper_stage-wrapper_2bejr.box_box_2jjDp > div.stage-wrapper_stage-canvas-wrapper_3ewmd.box_box_2jjDp > div > div.stage_stage_1fD7k.box_box_2jjDp > div:nth-child(1) > canvas" ) || document.querySelector( ".stage_stage_yEvd4 > div:nth-child(1) > canvas:nth-child(1)" ) ) } })()
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址