diff --git a/src/lib/libraries/extensions/SuperStorage/SuperStorage.svg b/src/lib/libraries/extensions/SuperStorage/SuperStorage.svg
new file mode 100644
index 00000000000..aa4c46d0901
--- /dev/null
+++ b/src/lib/libraries/extensions/SuperStorage/SuperStorage.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/lib/libraries/extensions/cloudstorage/CloudStorage.svg b/src/lib/libraries/extensions/cloudstorage/CloudStorage.svg
new file mode 100644
index 00000000000..615eb0fb0ab
--- /dev/null
+++ b/src/lib/libraries/extensions/cloudstorage/CloudStorage.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/lib/libraries/extensions/index.jsx b/src/lib/libraries/extensions/index.jsx
index d31b93f59ad..f93f23f47da 100644
--- a/src/lib/libraries/extensions/index.jsx
+++ b/src/lib/libraries/extensions/index.jsx
@@ -3,6 +3,7 @@ import React from 'react';
import { FormattedMessage } from 'react-intl';
import VideoSharing from './VidShare/VideoSharing.svg';
+import SuperStorage from './SuperStorage/SuperStorage.svg';
import NoahgptThumb from './noahgpt/costume1.svg';
import typescriptIcon from './snail-ide/typescript.svg';
import twGalleryIcon from './snail-ide/turbowarpgallery.svg';
@@ -10,7 +11,7 @@ import pmGalleryIcon from './snail-ide/penguinmodgallery.svg';
import musicIconURL from './music/music.png';
import roku from './roku/roku.png';
import share from './share/share.svg';
-import cloudstorageIconURL from './cloudstorage/costume1.svg';
+import cloudstorageIconURL from './cloudstorage/CloudStorage.svg';
import pythonIcon from './python/py.svg';
import extCreateIcon from './ext-create/logo.svg';
import extCreateInset from './ext-create/inset.svg';
@@ -229,15 +230,6 @@ const menuItems = [
description: 'Do many things via the Scratch API; you can even fetch cloud data from projects!',
featured: true
},
- {
- name: 'Screensharing',
- extensionId: 'https://editor.snail-ide.com/screen-sharing.js',
- iconURL: 'https://editor.snail-ide.com/Screensharing.png', // please forgive me the text is slightly offcenter
- collaborator: 'pooiod7',
- tags: ['penguinmod'],
- description: 'Share your screen and get the current frame as a image.',
- featured: true
- },
{
name: 'VideoSharing',
extensionId: 'https://editor.snail-ide.com/VideoSharing.js',
@@ -541,11 +533,20 @@ const menuItems = [
name: 'Cloud Storage',
extensionId: 'https://editor.snail-ide.com/cloudstorage.js',
collaborator: 'pooiod7',
- iconURL: cloudstorageIconURL, // this needs to be redone soon
+ iconURL: cloudstorageIconURL,
tags: ['penguinmod'],
description: 'Store data in a database, similar to Storage and Better Storage, but powered by a Snap! extension.',
featured: true
},
+ {
+ name: 'SuperStorage',
+ extensionId: 'https://editor.snail-ide.com/SuperStorage.js',
+ iconURL: SuperStorage,
+ tags: ['penguinmod'],
+ description: 'Store and retrieve data locally on device or remotely on a server.',
+ collaborator: 'pooiod7',
+ featured: true
+ },
{
name: 'Text to Speech 2.0',
extensionId: 'https://sharkpools-extensions.vercel.app/extension-code/Text-to-Speech.js',
diff --git a/static/SuperStorage.js b/static/SuperStorage.js
new file mode 100644
index 00000000000..0dbaf0a94ae
--- /dev/null
+++ b/static/SuperStorage.js
@@ -0,0 +1,178 @@
+ (function(Scratch) {
+ 'use strict';
+
+ if (!Scratch.extensions.unsandboxed) {
+ throw new Error('This extension must run unsandboxed');
+ }
+
+ class StorageV2 {
+ constructor() {
+ this.currentServer = "https://storage-ext.penguinmod.com/";
+ this.useGlobal = true;
+ this.waitingForResponse = false;
+ this.serverFailedResponse = false;
+ this.serverError = "";
+ }
+
+ getInfo() {
+ return {
+ id: 'P7SuperStorage',
+ name: 'Super Storage',
+ color1: '#31b3d4',
+ color2: '#179fc2',
+ docsURI: 'https://pooiod7.neocities.org/markdown/#/projects/scratch/extensions/other/markdown/SuperStorage',
+ blocks: [
+ { blockType: Scratch.BlockType.LABEL, text: "Local Storage" },
+ {
+ opcode: 'getValue',
+ text: 'get local [KEY]',
+ disableMonitor: true,
+ blockType: Scratch.BlockType.REPORTER,
+ arguments: {
+ KEY: { type: Scratch.ArgumentType.STRING, defaultValue: "key" }
+ }
+ },
+ {
+ opcode: 'setValue',
+ text: 'set local [KEY] to [VALUE]',
+ blockType: Scratch.BlockType.COMMAND,
+ arguments: {
+ KEY: { type: Scratch.ArgumentType.STRING, defaultValue: "key" },
+ VALUE: { type: Scratch.ArgumentType.STRING, defaultValue: "value" }
+ }
+ },
+ {
+ opcode: 'deleteValue',
+ text: 'delete local [KEY]',
+ blockType: Scratch.BlockType.COMMAND,
+ arguments: { KEY: { type: Scratch.ArgumentType.STRING, defaultValue: "key" } }
+ },
+ {
+ opcode: 'getKeys',
+ text: 'get all local stored names',
+ disableMonitor: true,
+ blockType: Scratch.BlockType.REPORTER
+ },
+ {
+ blockType: Scratch.BlockType.LABEL,
+ text: "Server Storage"
+ },
+ {
+ opcode: 'waitingForConnection',
+ text: 'waiting for server to respond?',
+ disableMonitor: true,
+ blockType: Scratch.BlockType.BOOLEAN
+ },
+ {
+ opcode: 'connectionFailed',
+ text: 'server failed to respond?',
+ disableMonitor: true,
+ blockType: Scratch.BlockType.BOOLEAN
+ },
+ {
+ opcode: 'serverErrorOutput',
+ text: 'server error',
+ disableMonitor: false,
+ blockType: Scratch.BlockType.REPORTER
+ },
+ "---",
+ {
+ opcode: 'getServerValue',
+ text: 'get server [KEY]',
+ disableMonitor: true,
+ blockType: Scratch.BlockType.REPORTER,
+ arguments: { KEY: { type: Scratch.ArgumentType.STRING, defaultValue: "key" } }
+ },
+ {
+ opcode: 'setServerValue',
+ text: 'set server [KEY] to [VALUE]',
+ blockType: Scratch.BlockType.COMMAND,
+ arguments: {
+ KEY: { type: Scratch.ArgumentType.STRING, defaultValue: "key" },
+ VALUE: { type: Scratch.ArgumentType.STRING, defaultValue: "value" }
+ }
+ },
+ {
+ opcode: 'deleteServerValue',
+ text: 'delete server [KEY]',
+ blockType: Scratch.BlockType.COMMAND,
+ arguments: { KEY: { type: Scratch.ArgumentType.STRING, defaultValue: "key" } }
+ }
+ ]
+ };
+ }
+
+ getPrefix() {
+ return `P7_PROJECTSTORAGE_`;
+ }
+
+ getAllKeys() {
+ return Object.keys(localStorage).filter(key => key.startsWith(this.getPrefix())).map(key => key.replace(this.getPrefix(), ""));
+ }
+
+ runPenguinWebRequest(url, options, ifFailReturn) {
+ this.waitingForResponse = true;
+ this.serverFailedResponse = false;
+ this.serverError = "";
+
+ return fetch(url, options)
+ .then(response => response.ok ? response.text() : Promise.reject(response.text()))
+ .then(text => {
+ this.waitingForResponse = false;
+ return text;
+ })
+ .catch(err => {
+ this.waitingForResponse = false;
+ this.serverFailedResponse = true;
+ this.serverError = err;
+ return ifFailReturn;
+ });
+ }
+
+ getKeys() {
+ return JSON.stringify(this.getAllKeys());
+ }
+
+ getValue(args) {
+ return localStorage.getItem(this.getPrefix() + args.KEY) || "";
+ }
+
+ setValue(args) {
+ localStorage.setItem(this.getPrefix() + args.KEY, args.VALUE);
+ }
+
+ deleteValue(args) {
+ localStorage.removeItem(this.getPrefix() + args.KEY);
+ }
+
+ waitingForConnection() {
+ return this.waitingForResponse;
+ }
+
+ connectionFailed() {
+ return this.serverFailedResponse;
+ }
+
+ serverErrorOutput() {
+ return this.serverError;
+ }
+
+ getServerValue(args) {
+ return this.runPenguinWebRequest(`${this.currentServer}get?key=${args.KEY}`, null, "");
+ }
+
+ setServerValue(args) {
+ return this.runPenguinWebRequest(`${this.currentServer}set?key=${args.KEY}`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ "value": args.VALUE })
+ });
+ }
+
+ deleteServerValue(args) {
+ return this.runPenguinWebRequest(`${this.currentServer}delete?key=${args.KEY}`, { method: "DELETE" });
+ }
+ }
+
+ Scratch.extensions.register(new StorageV2());
+})(Scratch);
diff --git a/static/VideoSharing.js b/static/VideoSharing.js
index f959f95c954..2c4d6fe5e2f 100644
--- a/static/VideoSharing.js
+++ b/static/VideoSharing.js
@@ -1,5 +1,5 @@
-// Video sharing (v2.4.1) by pooiod7
-// The successor to ScreenSharing
+// Video sharing (v2.4.2) by pooiod7
+// Was originally the "ScreenSharing" extension
(function(Scratch) {
'use strict';
@@ -21,7 +21,7 @@
let haswarned;
function shouldwarn(){
- return Scratch.vm.runtime.isPackaged;
+ return !Scratch.vm.runtime.isPackaged;
}
class VideoSharing {
@@ -245,18 +245,12 @@
}
startScreenSharing() {
- if (this.isSharing()) {
- this.stopSharing();
- }
+ if (this.isSharing()) this.stopSharing();
- if (!this.canScreen()) {
- return;
- }
+ if (!this.canScreen()) return;
if (shouldwarn()) {
- if (!this.warn("screen")) {
- return;
- }
+ if (!this.warn("screen")) return;
}
return new Promise((resolve) => {
@@ -283,14 +277,10 @@
}
startCameraSharing() {
- if (this.isSharing()) {
- this.stopSharing();
- }
+ if (this.isSharing()) this.stopSharing();
if (shouldwarn()) {
- if (!this.warn("camera")) {
- return;
- }
+ if (!this.warn("camera")) return;
}
return new Promise((resolve, reject) => {
@@ -326,14 +316,10 @@
}
getHEX(args) {
- if (!this.isSharing()) {
- return;
- }
+ if (!this.isSharing()) return;
var rez = args.REZ;
- if (rez > 1) {
- rez = 1;
- }
+ if (rez > 1) rez = 1;
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
const width = videoElement.videoWidth * rez;
@@ -357,14 +343,10 @@
}
getPNG(args) {
- if (!this.isSharing()) {
- return;
- }
+ if (!this.isSharing()) return;
var rez = args.REZ;
- if (rez > 1) {
- rez = 1;
- }
+ if (rez > 1) rez = 1;
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
const width = videoElement.videoWidth * rez;
@@ -380,14 +362,10 @@
}
getJPEG(args) {
- if (!this.isSharing()) {
- return;
- }
+ if (!this.isSharing()) return;
let rez = args.REZ;
- if (rez > 1) {
- rez = 1;
- }
+ if (rez > 1) rez = 1;
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
const width = videoElement.videoWidth * rez;
@@ -404,14 +382,10 @@
}
getWEBP(args) {
- if (!this.isSharing()) {
- return;
- }
+ if (!this.isSharing()) return;
let rez = args.REZ;
- if (rez > 1) {
- rez = 1;
- }
+ if (rez > 1) rez = 1;
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
diff --git a/static/cloudstorage.js b/static/cloudstorage.js
index 89a15f13a81..eec5c845928 100644
--- a/static/cloudstorage.js
+++ b/static/cloudstorage.js
@@ -1,5 +1,4 @@
-// Simple file storage made with tools from Snap!
-// Be careful, data can be replaced
+// Simple file storage made with tools from Snap! (v1.2) by pooiod7
class ServerExtension {
constructor(runtime) {
@@ -29,6 +28,17 @@ class ServerExtension {
},
},
},
+ {
+ opcode: 'deleteFromServer',
+ blockType: Scratch.BlockType.COMMAND,
+ text: 'Delete [variableName]',
+ arguments: {
+ variableName: {
+ type: Scratch.ArgumentType.STRING,
+ defaultValue: 'default.txt',
+ },
+ },
+ },
{
opcode: 'loadFromServer',
blockType: Scratch.BlockType.REPORTER,
@@ -36,7 +46,7 @@ class ServerExtension {
arguments: {
variableName: {
type: Scratch.ArgumentType.STRING,
- defaultValue: 'data.txt',
+ defaultValue: 'default.txt',
},
},
},
@@ -64,6 +74,24 @@ class ServerExtension {
return false;
});
}
+
+ deleteFromServer(args, util) {
+ const variableName = args.variableName;
+ const content = args.content;
+
+ const url =
+ this.serverURL +
+ '?type=delete&filename=./textfiles/' +
+ encodeURIComponent(variableName);
+
+ return fetch(url)
+ .then(response => response.text())
+ .then(result => (result === 'ok'))
+ .catch(error => {
+ console.error('Failed to delete data:', error);
+ return false;
+ });
+ }
loadFromServer(args, util) {
const variableName = args.variableName;