|
| 1 | +export default async function ({ addon }) { |
| 2 | + while (true) { |
| 3 | + const spriteSelector = '[class*="sprite-selector_sprite-selector_"] [class*="action-menu_more-buttons_"] input'; |
| 4 | + const stageSelector = '[class*="stage-selector_stage-selector_"] [class*="action-menu_more-buttons_"] input'; |
| 5 | + const costumeSelector = '[data-tabs] > :nth-child(3) [class*="action-menu_more-buttons_"] input'; |
| 6 | + let menuInput = await addon.tab.waitForElement(`${spriteSelector}, ${stageSelector}, ${costumeSelector}`, { |
| 7 | + markAsSeen: true, |
| 8 | + reduxCondition: (state) => !state.scratchGui.mode.isPlayerOnly, |
| 9 | + reduxEvents: [ |
| 10 | + "scratch-gui/mode/SET_PLAYER", |
| 11 | + "fontsLoaded/SET_FONTS_LOADED", |
| 12 | + "scratch-gui/locales/SELECT_LOCALE", |
| 13 | + "scratch-gui/navigation/ACTIVATE_TAB", |
| 14 | + ], |
| 15 | + }); |
| 16 | + |
| 17 | + const acceptsStr = menuInput.accept.trim(); |
| 18 | + // Set to dedupe |
| 19 | + const accepts = new Set(acceptsStr.split(",").map((s) => s.trim())); |
| 20 | + accepts.add(".webp"); |
| 21 | + |
| 22 | + menuInput.accept = Array.from(accepts).join(", "); |
| 23 | + |
| 24 | + // Let HD uploads handle it |
| 25 | + if (menuInput.className.includes("sa-better-img-uploads-input")) continue; |
| 26 | + |
| 27 | + menuInput.addEventListener("change", async (e) => { |
| 28 | + if (e.detail === "converted") return; |
| 29 | + |
| 30 | + const input = e.target; |
| 31 | + const files = input.files; |
| 32 | + |
| 33 | + if (files.length === 0) return; |
| 34 | + |
| 35 | + for (const file of files) { |
| 36 | + console.log(file); |
| 37 | + |
| 38 | + const isWebP = file.name.endsWith(".webp") || file.type === "image/webp"; |
| 39 | + if (!isWebP) return; |
| 40 | + |
| 41 | + // Hide it from scratch hehe |
| 42 | + e.stopImmediatePropagation(); |
| 43 | + e.preventDefault(); |
| 44 | + |
| 45 | + try { |
| 46 | + const buffer = await file.arrayBuffer(); |
| 47 | + const blob = new Blob([buffer], { type: "image/webp" }); |
| 48 | + const imageURL = URL.createObjectURL(blob); |
| 49 | + |
| 50 | + const image = new Image(); |
| 51 | + |
| 52 | + await new Promise((resolve, reject) => { |
| 53 | + image.onload = () => resolve(); |
| 54 | + image.onerror = () => reject("Failed to load WebP image"); |
| 55 | + image.src = imageURL; |
| 56 | + }); |
| 57 | + |
| 58 | + const canvas = document.createElement("canvas"); |
| 59 | + canvas.width = image.width; |
| 60 | + canvas.height = image.height; |
| 61 | + const ctx = canvas.getContext("2d"); |
| 62 | + |
| 63 | + ctx.drawImage(image, 0, 0); |
| 64 | + URL.revokeObjectURL(imageURL); |
| 65 | + |
| 66 | + // Convert to chosen format |
| 67 | + let format = addon.settings.get("format"); |
| 68 | + |
| 69 | + console.log(addon.settings.get("format"), addon.settings.get("quality")); |
| 70 | + |
| 71 | + const newBlob = await new Promise((resolve, reject) => { |
| 72 | + canvas.toBlob( |
| 73 | + (b) => (b ? resolve(b) : reject(new Error("Encode failed"))), |
| 74 | + `image/${format}`, |
| 75 | + addon.settings.get("quality") / 100 |
| 76 | + ); |
| 77 | + }); |
| 78 | + |
| 79 | + // Create a new file |
| 80 | + const newName = file.name.replace(".webp", `.${format}`); |
| 81 | + const newFile = new File([newBlob], newName, { type: `image/${format}` }); |
| 82 | + |
| 83 | + console.log(newFile); |
| 84 | + |
| 85 | + const dt = new DataTransfer(); |
| 86 | + dt.items.add(newFile); |
| 87 | + input.files = dt.files; |
| 88 | + |
| 89 | + // Send it through back to scratch :D |
| 90 | + const evt = new CustomEvent("change", { bubbles: true, detail: "converted" }); |
| 91 | + input.dispatchEvent(evt); |
| 92 | + } catch (error) { |
| 93 | + console.error(error); |
| 94 | + |
| 95 | + // Default, just send it through for scratch to reject if smth messed up |
| 96 | + const evt = new Event("change", { bubbles: true }); |
| 97 | + input.dispatchEvent(evt); |
| 98 | + } |
| 99 | + } |
| 100 | + }); |
| 101 | + } |
| 102 | +} |
0 commit comments