Continue refactoring

This commit is contained in:
Thomas Weber committed 2021-06-24 14:09:20 -05:00
1 parent 21b8bf85e6
commit 7ce98dc0dd
5 files changed
+130 -65

No files matched your search

+1 -1
View File
@@ -15,7 +15,7 @@
const packager = new Packager();
packager.project = projectData.project;
const cloudVariables = Object.values(projectData.stageVariables)
const cloudVariables = Object.values(projectData.project.analysis.stageVariables)
.filter(i => i.isCloud)
.map(i => i.name);
const canUseCloudVariableServer = !!projectData.projectId;
+12 -36
View File
@@ -3,11 +3,9 @@
import Button from './Button.svelte';
import writablePersistentStore from './persistent-store';
import {error, progress} from './stores';
import xhr from './lib/xhr';
import {UserError} from './errors';
import {readAsArrayBuffer} from './lib/readers';
import * as Comlink from 'comlink';
import DownloadWorker from 'worker-loader?name=downloader.worker.js!./downloader.worker.js';
import loadProject from './load-project';
import getProjectTitle from './lib/get-project-meta.js';
export let projectData = null;
const type = writablePersistentStore('SelectProject.type', 'id');
@@ -39,10 +37,15 @@
reset();
$progress.visible = true;
let data;
let uniqueId = '';
let id = null;
let projectTitle = '';
let project;
const progressCallback = (loadedAssets, totalAssets) => {
$progress.text = `Loading assets (${loadedAssets}/${totalAssets})`;
$progress.progress = loadedAssets / totalAssets;
};
if ($type === 'id') {
id = getId();
@@ -50,28 +53,10 @@
throw new UserError('Invalid project ID');
}
uniqueId = `#${id}`;
$progress.text = 'Loading project metadata';
try {
const meta = await xhr({
url: `https://trampoline.turbowarp.org/proxy/projects/${id}`,
timeout: 5000,
type: 'json'
});
projectTitle = meta.title;
} catch (e) {
// Happens commonly when loading unshared projects, not something to worry about
console.warn(e);
}
$progress.text = 'Loading project data';
data = await xhr({
url: `https://projects.scratch.mit.edu/${id}`,
type: 'arraybuffer',
progressCallback: (p) => {
$progress.progress = p;
}
});
projectTitle = await getProjectTitle(id);
$progress.text = 'Loading project';
project = await loadProject.fromID(id, progressCallback);
} else {
if (!files) {
throw new UserError('No file selected');
@@ -80,23 +65,14 @@
uniqueId = `@${file.name}`;
projectTitle = file.name;
$progress.text = 'Reading project';
data = await readAsArrayBuffer(file);
project = await loadProject.fromFile(file);
}
const progressCallback = (loadedAssets, totalAssets) => {
$progress.text = `Loading assets (${loadedAssets}/${totalAssets})`;
$progress.progress = loadedAssets / totalAssets;
};
const worker = Comlink.wrap(new DownloadWorker());
const project = await worker.downloadProject(data, Comlink.proxy(progressCallback));
projectData = {
projectId: id,
uniqueId,
title: projectTitle,
project,
stageVariables: project.stageVariables
};
} catch (e) {
$error = e;
+72 -28
View File
@@ -11,6 +11,19 @@ const identifyProjectType = (projectData) => {
return null;
};
const analyzeScratch2 = (projectData) => {
const stageVariables = {};
for (const {name, value, isPersistent} of projectData.variables) {
stageVariables[name] = {
name,
isCloud: isPersistent
};
}
return {
stageVariables
};
};
const loadScratch2 = (projectData, progressTarget) => {
const zip = new JSZip();
@@ -106,20 +119,28 @@ const loadScratch2 = (projectData, progressTarget) => {
.then(() => {
// We must add the project JSON at the end because it is changed during the loading due to updating asset IDs
zip.file('project.json', JSON.stringify(projectData));
const stageVariables = {};
for (const {name, value, isPersistent} of projectData.variables) {
stageVariables[name] = {
name,
isCloud: isPersistent
};
}
return {
zip,
stageVariables: {}
analysis: analyzeScratch2(projectData)
};
});
};
const analyzeScratch3 = (projectData) => {
const stage = projectData.targets[0];
const stageVariables = {};
for (const id of Object.keys(stage.variables)) {
const [name, value, cloud] = stage.variables[id];
stageVariables[id] = {
name,
isCloud: !!cloud
};
}
return {
stageVariables
};
};
const loadScratch3 = (projectData, progressTarget) => {
const zip = new JSZip();
@@ -164,18 +185,9 @@ const loadScratch3 = (projectData, progressTarget) => {
return Promise.all(assets.map((a) => addFile(a)))
.then(() => {
const stage = targets[0];
const stageVariables = {};
for (const id of Object.keys(stage.variables)) {
const [name, value, cloud] = stage.variables[id];
stageVariables[id] = {
name,
isCloud: !!cloud
};
}
return {
zip,
stageVariables
analysis: analyzeScratch3(projectData)
};
});
};
@@ -192,8 +204,13 @@ const downloadJSONProject = (json, progressTarget) => {
};
const downloadProject = async (data, progressCallback) => {
let type;
let blob;
let analysis;
const bufferView = new Uint8Array(data);
if (bufferView[0] === '{'.charCodeAt(0)) {
// JSON project, we have to download everything else
const progressTarget = new EventTarget();
let totalAssets = 0;
let loadedAssets = 0;
@@ -206,26 +223,53 @@ const downloadProject = async (data, progressCallback) => {
progressCallback(loadedAssets, totalAssets);
});
// Looks like it's JSON
const text = new TextDecoder().decode(data);
const json = JSON.parse(text);
const type = identifyProjectType(json);
const result = await downloadJSONProject(json, progressTarget);
const blob = await result.zip.generateAsync({
type = identifyProjectType(json);
const downloaded = await downloadJSONProject(json, progressTarget);
blob = await downloaded.zip.generateAsync({
type: 'blob',
compression: 'DEFLATE'
});
analysis = downloaded.analysis;
} else {
// It's a binary blob
blob = new Blob([data]);
let zip;
try {
zip = await JSZip.loadAsync(data);
} catch (e) {
console.warn(e);
}
if (zip) {
const projectDataFile = zip.file('project.json');
const projectDataText = await projectDataFile.async('text');
const projectData = JSON.parse(projectDataText);
type = identifyProjectType(projectData);
if (type === 'sb3') {
analysis = analyzeScratch3(projectData);
} else {
analysis = analyzeScratch2(projectData);
}
} else {
type = 'sb';
analysis = {
stageVariables: {}
};
}
}
if (type === 'sb3') {
return {
type: type === 'sb3' ? 'sb3' : 'blob',
type: 'sb3',
blob,
stageVariables: result.stageVariables
};
analysis
}
}
// It's a binary blob
return {
type: 'blob',
blob: new Blob([data]),
stageVariables: {}
blob,
analysis
};
};
+17
View File
@@ -0,0 +1,17 @@
import xhr from './xhr';
const getProjectTitle = async (id) => {
try {
const meta = await xhr({
url: `https://trampoline.turbowarp.org/proxy/projects/${id}`,
timeout: 5000,
type: 'json'
});
return meta.title;
} catch (e) {
// Happens commonly when loading unshared projects, not something to worry about
return '';
}
};
export default getProjectTitle;
+28
View File
@@ -0,0 +1,28 @@
import * as Comlink from 'comlink';
import DownloadWorker from 'worker-loader?name=downloader.worker.js!./downloader.worker.js';
import {readAsArrayBuffer} from './lib/readers';
import xhr from './lib/xhr';
const fromID = async (id, progressCallback) => {
const buffer = await xhr({
url: `https://projects.scratch.mit.edu/${id}`,
type: 'arraybuffer'
// TODO: bubble progress
});
const worker = Comlink.wrap(new DownloadWorker());
const project = await worker.downloadProject(Comlink.transfer(buffer, [buffer]), Comlink.proxy(progressCallback));
return project;
};
const fromFile = async (file) => {
const worker = Comlink.wrap(new DownloadWorker());
const buffer = await readAsArrayBuffer(file);
const progressCallback = () => {};
const project = await worker.downloadProject(Comlink.transfer(buffer, [buffer]), Comlink.proxy(progressCallback));
return project;
};
export default {
fromID,
fromFile
};