scratch extension loader

none

当前为 2025-03-06 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name scratch extension loader
  3. // @version 3
  4. // @description none
  5. // @run-at document-start
  6. // @tag lib loader
  7. // @author rssaromeo
  8. // @license GPLv3
  9. // @match *://*/*
  10. // @sandbox dom
  11. // @icon data:image/png;base64,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
  12. // @require https://update.gf.qytechs.cn/scripts/491829/1356221/tampermonkey%20storage%20proxy.js
  13. // @grant GM_getValue
  14. // @grant GM_setValue
  15. // @grant GM_registerMenuCommand
  16. // @grant unsafeWindow
  17. // @namespace https://gf.qytechs.cn/users/1184528
  18. // ==/UserScript==
  19.  
  20. // add get turbomode state
  21. // add way to toggle on and off extensions
  22. // how to change the properties of a menu baised on the value of another menu
  23. //
  24. // add set var
  25. // add get var
  26. // add return project id
  27. ;(async () => {
  28. var menus = {}
  29. var extensionerrors = []
  30. unsafeWindow.ee = extensionerrors
  31. var projectid =
  32. location.href.match(/(?<=\/)[0-9]+(?=\/)/)?.[0] || "local"
  33. // debugger
  34. var sp = new storageproxy("extensionoptions")
  35. // debugger
  36. var bt = {
  37. cmd: "command",
  38. ret: "reporter",
  39. hat: "hat",
  40. bool: "Boolean",
  41. }
  42. var inp = {
  43. int: "number",
  44. num: "number",
  45. str: "string",
  46. }
  47. var menufuncs = class {
  48. menu_varnames(targetid) {
  49. try {
  50. var name = vm.runtime.targets.find((e) => e.id == targetid)
  51. .sprite.name
  52. if (!gettarget(name).runtime.ioDevices.cloud.stage)
  53. return [" "]
  54. var globalvars = Object.values(
  55. gettarget(name).runtime.ioDevices.cloud.stage.variables
  56. )
  57. var localvars = Object.values(gettarget(name).variables)
  58. globalvars = globalvars.filter((e) => e.type == "")
  59. localvars = localvars.filter((e) => e.type == "")
  60. // log(globalvars, localvars)
  61. var arr = [
  62. ...localvars.map((e) => ({
  63. text: "__local " + e.name,
  64. value: JSON.stringify([name, e.name]),
  65. })),
  66. ...globalvars.map((e) => ({
  67. text: "__global " + e.name,
  68. value: JSON.stringify([undefined, e.name]),
  69. })),
  70. ]
  71. return arr.length ? arr : [" "]
  72. } catch (e) {
  73. error("error from menu_varnames", e)
  74. return [" "]
  75. }
  76. }
  77. menu_listnames(targetid) {
  78. try {
  79. // if (!gettarget(name)) return [" "]
  80. var name = vm.runtime.targets.find((e) => e.id == targetid)
  81. .sprite.name
  82. if (!gettarget(name).runtime.ioDevices.cloud.stage)
  83. return [" "]
  84. var globalvars = Object.values(
  85. gettarget(name).runtime.ioDevices.cloud.stage.variables
  86. )
  87. var localvars = Object.values(gettarget(name).variables)
  88. globalvars = globalvars.filter((e) => e.type == "list")
  89. localvars = localvars.filter((e) => e.type == "list")
  90. // log(globalvars, localvars)
  91. var arr = [
  92. ...localvars.map((e) => ({
  93. text: "__local " + e.name,
  94. value: JSON.stringify([name, e.name]),
  95. })),
  96. ...globalvars.map((e) => ({
  97. text: "__global " + e.name,
  98. value: JSON.stringify([undefined, e.name]),
  99. })),
  100. ]
  101.  
  102. return arr.length ? arr : [" "]
  103. } catch (e) {
  104. error("error from menu_listnames", e)
  105. return [" "]
  106. }
  107. }
  108. menu_spritelistwithglobal(targetid) {
  109. try {
  110. var spritenames = Object.values(vm.runtime.targets).map(
  111. (e) => e.sprite.name
  112. )
  113. var name = Object.values(vm.runtime.targets).find(
  114. (e) => e.id == targetid
  115. ).sprite.name
  116. return [
  117. name,
  118. { text: "--- global list ---", value: "" },
  119. ...spritenames.filter((e) => e !== name && e !== "Stage"),
  120. ]
  121. } catch (e) {
  122. error("error from menu_spritelistwithglobal", e)
  123. return [" "]
  124. }
  125. }
  126. menu_spritelistwithoutglobal(targetid) {
  127. try {
  128. var spritenames = Object.values(vm.runtime.targets).map(
  129. (e) => e.sprite.name
  130. )
  131. var name = Object.values(vm.runtime.targets).find(
  132. (e) => e.id == targetid
  133. ).sprite.name
  134. return [
  135. name,
  136. ...spritenames.filter((e) => e !== name && e !== "Stage"),
  137. ]
  138. } catch (e) {
  139. error("error from menu_spritelistwithoutglobal", e)
  140. return [" "]
  141. }
  142. }
  143. menu_fullkeylist() {
  144. return [
  145. "escape",
  146. "enter",
  147. "up arrow",
  148. "down arrow",
  149. "left arrow",
  150. "right arrow",
  151. "tab",
  152. "control",
  153. "alt",
  154. "shift",
  155. "win",
  156. "delete",
  157. "insert",
  158. "home",
  159. "end",
  160. "page up",
  161. "page down",
  162. "caps lock",
  163. "scroll lock",
  164. ...Array.from({ length: 24 }, (_, i) => i + 1).map((e) => ({
  165. text: "F" + e,
  166. value: "f" + e,
  167. })),
  168. { text: "space", value: " " },
  169. ..."~`abcdefghijklmnopqrstuvwxyz1234567890!@#$%^&*()-_=+[]\\|;:'\",<.>/?{}",
  170. "contextmenu",
  171. "mediaplaypause",
  172. "audiovolumemute",
  173. "audiovolumedown",
  174. "audiovolumeup",
  175. "launchapplication2",
  176. "launchmediaplayer",
  177. "mediatracknext",
  178. "mediatrackprevious",
  179. "Meta",
  180. ]
  181. }
  182. menu_fullkeylistandany() {
  183. return ["any", ...this.menu_fullkeylist()]
  184. }
  185. }
  186. var a = loadlib("newallfuncs")
  187. var enabledextensions = sp.get() ?? {
  188. extensionmanagercreatedbyrssaromeo: true,
  189. }
  190. var extensionclasses = []
  191. // unsafeWindow.extensionclasses = extensionclasses
  192. newext(
  193. "extension manager",
  194. "rssaromeo",
  195. class {
  196. getlasterror() {
  197. return String(
  198. extensionerrors[extensionerrors.length - 1]?.message ??
  199. false
  200. )
  201. }
  202. getlasterrorextensionid() {
  203. return String(
  204. extensionerrors[extensionerrors.length - 1]?.extensionid ??
  205. false
  206. )
  207. }
  208. getlasterrorblockid() {
  209. return String(
  210. extensionerrors[extensionerrors.length - 1]?.blockid ??
  211. false
  212. )
  213. }
  214. puterrorsintolist({ listname }) {
  215. var [sprite, listname] = JSON.parse(listname)
  216. scratchlist(
  217. listname,
  218. extensionerrors.map((e) => JSON.stringify(e)),
  219. sprite
  220. )
  221. }
  222. },
  223. [
  224. newblock(
  225. bt.ret,
  226. "getlasterrorextensionid",
  227. "lasterror: extension id"
  228. ),
  229. newblock(bt.ret, "getlasterror", "lasterror: message"),
  230. newblock(bt.ret, "getlasterrorblockid", "lasterror: block id"),
  231. newblock(
  232. bt.cmd,
  233. "puterrorsintolist",
  234. "put errors into list [listname]",
  235. [newmenu("listnames", { defaultValue: "" })]
  236. ),
  237. ]
  238. )
  239. loadlib("libloader").savelib("scratchextesnsionmanager", {
  240. newmenu,
  241. newext,
  242. newblock,
  243. bt,
  244. inp,
  245. gettarget,
  246. totype,
  247. scratch_math,
  248. projectid,
  249. canvas,
  250. scratchvar,
  251. scratchlist,
  252. })
  253. // unsafeWindow.sp = sp
  254. await loadlib("libloader").waitforlib("scratch")
  255. await a.waituntil(canvas)
  256.  
  257. var vm = loadlib("scratch").vm
  258. loadallextensions()
  259. function loadallextensions() {
  260. // debugger
  261. for (var __class of extensionclasses) {
  262. var extensionInstance = new __class(
  263. vm.extensionManager.runtime,
  264. __class.thisExtensionIsEnabled
  265. )
  266. vm.extensionManager._loadedExtensions.set(
  267. extensionInstance.getInfo().id,
  268. vm.extensionManager._registerInternalExtension(
  269. extensionInstance
  270. )
  271. )
  272. }
  273. }
  274.  
  275. function newblock(blockType, opcode, text, args) {
  276. var arguments = Object.fromEntries(
  277. [...(text.match(/(?<=\[)\w+(?=\])/g) || [])].map((_, i) => [
  278. _,
  279. typeof args?.[i] == "object"
  280. ? {
  281. type: args?.[i]?.type || args?.[i] || inp.str,
  282. disableMonitor: false,
  283. // defaultValue: false,
  284. // filter: [Scratch.TargetType.SPRITE],
  285. // filter: [Scratch.TargetType.STAGE],
  286. // isTerminal: false,
  287. // shouldRestartExistingThreads: true,
  288. // isEdgeActivated: false,
  289. ...(0 in args[i] && 1 in args[i]
  290. ? {
  291. type: args[i][0] ?? inp.str,
  292. defaultValue: args[i][1],
  293. }
  294. : args[i]),
  295. }
  296. : {
  297. type: args?.[i]?.type || args?.[i] || inp.str,
  298. // defaultValue: false,
  299. disableMonitor: false,
  300. },
  301. ])
  302. )
  303. // log(arguments)
  304. return {
  305. hideFromPalette: false,
  306. blockType,
  307. opcode,
  308. text,
  309. arguments,
  310. }
  311. }
  312.  
  313. function newmenu(name, opts = {}) {
  314. var data = {
  315. acceptReporters: true,
  316. items: "menu_" + name,
  317. ...opts,
  318. }
  319. menus[name] = data
  320. return { menu: name, ...opts }
  321. }
  322.  
  323. function newext(
  324. name,
  325. username,
  326. _class,
  327. blockinfo,
  328. blockcolor = "#777777",
  329. menuicon = "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDY0IDY0IiB3aWR0aD0iNjQiIGhlaWdodD0iNjQiPgoJPHRpdGxlPk5ldyBQcm9qZWN0PC90aXRsZT4KCTxkZWZzPgoJCTxpbWFnZSAgd2lkdGg9IjY0IiBoZWlnaHQ9IjY0IiBpZD0iaW1nMSIgaHJlZj0iZGF0YTppbWFnZS9wbmc7YmFzZTY0LGlWQk9SdzBLR2dvQUFBQU5TVWhFVWdBQUFFQUFBQUJBQkFNQUFBQllSMnp0QUFBQUFYTlNSMElCMmNrc2Z3QUFBQ1JRVEZSRkFBQUFBT05sLy8vL0FPTmwvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL0I2Y0NhQUFBQUF4MFVrNVRBUDhBQUFJRUR4TUJBd1VIM0Q5UFB3QUFBRVZKUkVGVWVKeGpaRUFHakFKQTR2OEhGS0ZSQmFNS1JoWFFRb0VnQTM0d3FvQllCVXJJUEhBb2c4T2JCQVhHWU9yOXFJSkJyMEJaQ2ErQ3RMMmhCd2RGN2g0WkNnRFBCSCtKaSsyWXRnQUFBQUJKUlU1RXJrSmdnZz09Ii8+Cgk8L2RlZnM+Cgk8c3R5bGU+Cgk8L3N0eWxlPgoJPHVzZSBpZD0iQmFja2dyb3VuZCIgaHJlZj0iI2ltZzEiIHg9IjAiIHk9IjAiLz4KPC9zdmc+",
  330. blockimg = ""
  331. ) {
  332. var bg = "#282828"
  333. if (blockcolor[0] != "#") blockcolor = "#" + blockcolor
  334. blockinfo = {
  335. color1: /https?:\/\/turbowarp\.org/.test(location.href)
  336. ? blockcolor
  337. : bg,
  338. color2: bg,
  339. color3: blockcolor,
  340.  
  341. menuIconURI: menuicon,
  342. blockIconURI: blockimg,
  343.  
  344. blocks: blockinfo,
  345. }
  346. blockinfo.id =
  347. name.replaceAll(/[^a-z]+/gi, "") + "createdby" + username
  348. blockinfo.name = name.replaceAll(/ /gi, " ") //+ " - by " + username
  349. blockinfo.menus = menus
  350. // warn(enabledextensions)
  351. GM_registerMenuCommand(
  352. (enabledextensions[blockinfo.id] ? "enabled" : "dissabled") +
  353. (": " + blockinfo.name),
  354. () => {
  355. // warn(enabledextensions[blockinfo.id])
  356. enabledextensions[blockinfo.id] =
  357. !enabledextensions[blockinfo.id]
  358. // warn(enabledextensions[blockinfo.id])
  359. }
  360. )
  361. // log("menus", menus.spritelistwithoutglobal.items)
  362. blockinfo.blocks.unshift(
  363. newblock(
  364. bt.bool,
  365. "thisextensionexists",
  366. "the extension {" + blockinfo.name + "} is enabled"
  367. )
  368. )
  369. function Classes(bases) {
  370. class Bases {
  371. constructor() {
  372. bases.forEach((base) => Object.assign(this, new base()))
  373. }
  374. }
  375. bases.forEach((base) => {
  376. Object.getOwnPropertyNames(base.prototype)
  377. .filter((prop) => prop != "constructor")
  378. .forEach(
  379. (prop) => (Bases.prototype[prop] = base.prototype[prop])
  380. )
  381. })
  382. return Bases
  383. }
  384. var enabled = enabledextensions[blockinfo.id]
  385. if (!enabled) {
  386. const properties = Object.getOwnPropertyNames(_class.prototype)
  387. for (const property of properties) {
  388. if (typeof _class.prototype[property] === "function") {
  389. _class.prototype[property] = function () {
  390. return false
  391. }
  392. }
  393. }
  394. _class.prototype.thisextensionexists = () => {
  395. return false
  396. }
  397. } else {
  398. _class.prototype.thisextensionexists = () => {
  399. return true
  400. }
  401. }
  402. function tryCatchDecorator(constructor) {
  403. const prototype = constructor.prototype
  404. const originalPrototype = Object.getPrototypeOf(prototype)
  405.  
  406. for (let key of [
  407. ...Object.getOwnPropertyNames(prototype),
  408. ...Object.getOwnPropertyNames(originalPrototype),
  409. ]) {
  410. if (typeof prototype[key] === "function") {
  411. let originalMethod = prototype[key]
  412. prototype[key] = function (...args) {
  413. try {
  414. return originalMethod.apply(this, args)
  415. } catch (e) {
  416. extensionerrors.push({
  417. extensionid: blockinfo.id,
  418. blockid: key,
  419. message: e.message,
  420. })
  421. console.error("error from " + key, e)
  422. return false
  423. }
  424. }
  425. }
  426. }
  427.  
  428. return constructor
  429. }
  430. // log("blockinfo.blocks", blockinfo.blocks)
  431. var __class = tryCatchDecorator(
  432. class extends Classes([_class, menufuncs]) {
  433. constructor(runtime, enabled) {
  434. super(runtime)
  435. if (enabled !== undefined)
  436. this.thisExtensionIsEnabled = enabled
  437. this.runtime = runtime
  438. }
  439. getInfo() {
  440. // log("getInfo", blockinfo)
  441. return blockinfo
  442. }
  443. }
  444. )
  445. extensionclasses.push(__class)
  446. sp.enabledextensions = enabledextensions
  447. }
  448.  
  449. function scratchvar(varname, value, spritename) {
  450. if (value !== undefined) {
  451. if (gettarget(spritename)?.getvar(varname))
  452. gettarget(spritename).getvar(varname).value = String(value)
  453. else {
  454. console.warn(`var "${varname}" does not exist`)
  455. }
  456. }
  457. }
  458.  
  459. function totype(inp, type, forced) {
  460. //number, string, list, object, json, bool
  461. inp = String(inp)
  462. try {
  463. switch (type) {
  464. // case "regex":
  465. // try {
  466. // return new RegExp(inp)
  467. // } catch (e) {
  468. // return fail(inp, type, forced)
  469. // }
  470. case "string":
  471. return String(inp)
  472. case "number":
  473. if (inp == "true") inp = 1
  474. if (inp == "false") inp = 0
  475. if (/^-?[0-9]*\.?[0-9]+$/.test(inp)) return Number(inp)
  476. if (inp === "NaN" || inp == "nan") return NaN
  477. return fail(inp, type, forced)
  478. case "list":
  479. if (scratchlist(inp)) return scratchlist(inp)
  480. inp = JSON.parse(inp)
  481. if (inp.reverse) return inp
  482. return fail(inp, type, forced)
  483. case "object":
  484. inp = JSON.parse(inp)
  485. // if (/^[\-0-9]+$/.test(inp) || inp === true || inp === false)
  486. // return undefined
  487. if (
  488. Object.keys(inp).length !== undefined &&
  489. inp.length === undefined &&
  490. !Array.isArray(inp)
  491. )
  492. return inp
  493. return fail(inp, type, forced)
  494. case "bool":
  495. if (inp === "1" || inp === "true") return true
  496. if (inp === "0" || inp === "false") return false
  497. return fail(inp, type)
  498. // case "json":
  499. // if (
  500. // totype(inp, "object") !== undefined ||
  501. // totype(inp, "list") !== undefined
  502. // )
  503. // return totype(inp, "object") || totype(inp, "list")
  504. // else {
  505. // fail(inp, type, forced)
  506. // }
  507. }
  508. } catch (s) {
  509. return fail(inp, type, forced)
  510. }
  511.  
  512. function fail(inp, type, forced) {
  513. if (forced) {
  514. throw new Error(`"${inp}" must be of type "${type}"`)
  515. } else return undefined
  516. }
  517. }
  518.  
  519. // listen(window, "keydown", (e) => {
  520. // var index = vm.runtime.ioDevices.keyboard._keysPressed.indexOf(
  521. // e.key.toUpperCase(),
  522. // )
  523. // if (index !== -1) {
  524. // vm.runtime.ioDevices.keyboard._keysPressed.splice(index, 1)
  525. // }
  526. // vm.runtime.ioDevices.keyboard._keysPressed.push(e.key.toUpperCase())
  527. // })
  528. // listen(window, "keyup", (e) => {
  529. // var index = vm.runtime.ioDevices.keyboard._keysPressed.indexOf(
  530. // e.key.toUpperCase(),
  531. // )
  532. // if (index !== -1) {
  533. // vm.runtime.ioDevices.keyboard._keysPressed.splice(index, 1)
  534. // }
  535. // })
  536.  
  537. function gettarget(sprite) {
  538. if (sprite)
  539. var x =
  540. vm.runtime.getSpriteTargetByName(sprite) ||
  541. vm.runtime.getTargetForStage()
  542. else var x = vm.runtime.getTargetForStage()
  543. x.getvar = x?.lookupVariableByNameAndType
  544. return x
  545. }
  546.  
  547. function scratchlist(listname, value, spritename) {
  548. //fix regex?
  549. if (value === undefined && /^\[\]$/.test(listname))
  550. return JSON.parse(listname)
  551. if (value !== undefined) {
  552. if (gettarget(spritename)?.getvar(listname, "list"))
  553. gettarget(spritename).getvar(listname, "list").value = [
  554. ...value,
  555. ]
  556. else console.warn(`list "${listname}" does not exist`)
  557. } else {
  558. return gettarget(spritename)?.getvar(listname, "list")?.value
  559. }
  560. }
  561.  
  562. function scratch_math(operator, n) {
  563. switch (operator) {
  564. case "sin":
  565. return Math.round(Math.sin((Math.PI * n) / 180) * 1e10) / 1e10
  566. case "cos":
  567. return Math.round(Math.cos((Math.PI * n) / 180) * 1e10) / 1e10
  568. case "asin":
  569. return (Math.asin(n) * 180) / Math.PI
  570. case "acos":
  571. return (Math.acos(n) * 180) / Math.PI
  572. case "atan":
  573. return (Math.atan(n) * 180) / Math.PI
  574. case "log":
  575. return Math.log(n) / Math.LN10
  576. }
  577. return 0
  578. }
  579.  
  580. function canvas() {
  581. return (
  582. window?.vm?.runtime?.renderer?.canvas ||
  583. document.querySelector(
  584. "#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"
  585. ) ||
  586. document.querySelector(
  587. "#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"
  588. ) ||
  589. document.querySelector(
  590. "#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"
  591. ) ||
  592. document.querySelector(
  593. ".stage_stage_yEvd4 > div:nth-child(1) > canvas:nth-child(1)"
  594. )
  595. )
  596. }
  597. })()

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址