Continue refactoring
This commit is contained in:
5 files changed
+130
-65
No files matched your search
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -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
|
||||
};
|
||||
Reference in new issue
Block a user