diff --git a/extensions/Clay/upload.js b/extensions/Clay/upload.js new file mode 100644 index 0000000000..a01c42e679 --- /dev/null +++ b/extensions/Clay/upload.js @@ -0,0 +1,218 @@ +// Name: Upload +// ID: clayuploadfile +// Description: Upload files to web servers. +// By: ClaytonTDM + +(function (Scratch) { + "use strict"; + + const getGofileServer = async () => { + try { + const response = await Scratch.fetch("https://api.gofile.io/getServer"); + if (!response.ok) { + throw new Error("HTTP error " + response.status); + } + const serverData = await response.json(); + return `https://${serverData.data.server}.gofile.io/uploadFile`; + } catch (error) { + console.error("Failed to fetch Gofile server: ", error); + throw error; + } + }; + + class Upload { + getInfo() { + return { + id: "clayuploadfile", + name: "Upload", + blocks: [ + { + opcode: "upload", + blockType: Scratch.BlockType.REPORTER, + text: "upload file to [url]", + arguments: { + url: { + type: Scratch.ArgumentType.STRING, + defaultValue: "https://store1.gofile.io/uploadFile", + }, + }, + }, + { + opcode: "uploadToWebsite", + blockType: Scratch.BlockType.REPORTER, + text: "upload file to [url]", + arguments: { + url: { + type: Scratch.ArgumentType.STRING, + defaultValue: "gofile.io", + menu: "websites", + }, + }, + }, + { + opcode: "uploadData", + blockType: Scratch.BlockType.REPORTER, + text: "upload [data] to [url]", + arguments: { + data: { + type: Scratch.ArgumentType.STRING, + defaultValue: "Hello TurboWarp!", + }, + url: { + type: Scratch.ArgumentType.STRING, + defaultValue: "https://store1.gofile.io/uploadFile", + }, + }, + }, + { + opcode: "uploadDataToMenu", + blockType: Scratch.BlockType.REPORTER, + text: "upload [data] to [menu]", + arguments: { + data: { + type: Scratch.ArgumentType.STRING, + defaultValue: "Hello TurboWarp!", + }, + menu: { + type: Scratch.ArgumentType.STRING, + menu: "websites", + }, + }, + }, + ], + menus: { + websites: { + acceptReporters: false, + items: ["gofile.io", "file.io"], + }, + }, + }; + } + + upload(args) { + return this.performUpload(args.url, true); + } + + async uploadToWebsite(args) { + let url; + switch (args.url.toLowerCase()) { + case "gofile.io": + url = await getGofileServer(); + break; + case "file.io": + url = "https://file.io/"; + break; + default: + return "invalid host"; + } + return this.performUpload(url, false); + } + + uploadData(args) { + return this.performUploadWithData(args.data, args.url, "data.txt", true); + } + + uploadDataToMenu(args) { + let urlPromise; + switch (args.menu.toLowerCase()) { + case "gofile.io": + urlPromise = getGofileServer(); + break; + case "file.io": + urlPromise = Promise.resolve("https://file.io/"); + break; + default: + return "invalid host"; + } + + return urlPromise.then((url) => { + return this.performUploadWithData(args.data, url, "data.txt", false); + }); + } + + performUpload(url, rawJson = false) { + return new Promise((resolve, reject) => { + const inputElement = document.createElement("input"); + inputElement.type = "file"; + inputElement.style.display = "none"; + document.body.appendChild(inputElement); + + inputElement.click(); + + inputElement.addEventListener("cancel", function () { + resolve("Upload cancelled"); + inputElement.remove(); + }); + + inputElement.addEventListener("change", function () { + if (this.files && this.files[0]) { + const formData = new FormData(); + formData.append("file", this.files[0], "data.txt"); + + const options = { + body: formData, + method: "POST", + mode: "cors", + }; + + Scratch.fetch(url, options) + .then((response) => { + if (response.ok) { + return response.json(); + } else { + throw new Error("Upload failed"); + } + }) + .then((data) => { + const result = rawJson + ? JSON.stringify(data) + : data.link || data.data.downloadPage; + resolve(result); + inputElement.remove(); + }) + .catch((error) => { + reject(error.message); + inputElement.remove(); + }); + } else { + resolve("No file chosen"); + inputElement.remove(); + } + }); + }); + } + + performUploadWithData(data, url, fileName, rawJson = false) { + const formData = new FormData(); + formData.append("file", new Blob([data]), fileName); + + const options = { + body: formData, + method: "POST", + mode: "cors", + }; + + return new Promise((resolve, reject) => { + Scratch.fetch(url, options) + .then((response) => { + if (response.ok) { + return response.json(); + } else { + throw new Error("Upload failed"); + } + }) + .then((data) => { + const result = rawJson + ? JSON.stringify(data) + : data.link || data.data.downloadPage; + resolve(result); + }) + .catch((error) => { + reject(error.message); + }); + }); + } + } + + Scratch.extensions.register(new Upload()); +})(Scratch); diff --git a/images/Clay/upload.png b/images/Clay/upload.png new file mode 100644 index 0000000000..22beec96f3 Binary files /dev/null and b/images/Clay/upload.png differ diff --git a/images/README.md b/images/README.md index 4a239c2aa1..b4fbc0f544 100644 --- a/images/README.md +++ b/images/README.md @@ -257,6 +257,11 @@ All images in this folder are licensed under the [GNU General Public License ver - Dango based on dango from [Twemoji](https://twemoji.twitter.com/) under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/). - Background "blobs" by Scratch. +## Clay/upload.png + - Created by [@ClaytonTDM](https://github.com/ClaytonTDM) + - Upload icon based on https://icons8.com/icon/367/upload + - Background based on https://app.haikei.app/ + ## XeroName/Deltatime.svg - Created by [@XeroName](https://scratch.mit.edu/users/plant2014/) in https://github.com/TurboWarp/extensions/pull/622