diff --git a/index.html b/index.html index c31321e..9ccea7d 100644 --- a/index.html +++ b/index.html @@ -226,7 +226,13 @@ along with this program. If not, see . O.onchange = updateConditionals; updateConditionals(); - + + const progressTarget = new EventTarget(); + progressTarget.addEventListener('data-progress', (e) => console.log(e.detail)); + // progressTarget.addEventListener('asset-fetch', (e) => console.log(e.detail)); + // progressTarget.addEventListener('asset-fetched', (e) => console.log(e.detail)); + progressTarget.addEventListener('nwjs-progress', (e) => console.log(e.detail)); + const loadProject = async () => { if (O.project.source === 'file') { if (!O.project.file) { @@ -239,7 +245,9 @@ along with this program. If not, see . if (!match) { throw new Error('Invalid project ID'); } - const project = await SBDownloader.download(match[0]); + const project = await SBDownloader.download(match[0], { + progressTarget + }); return new Packager.Project(await project.asBlob(), project.type); } throw new Error('unknown project source'); @@ -269,16 +277,13 @@ along with this program. If not, see . switch (O.environment.target) { case 'html': return new Packager.environments.HTML(); case 'zip': return new Packager.environments.Zip(); - case 'nwjs-win64': return new Packager.environments.NWjs({ - icon: O.nwjs.icon || getDefaultIcon(), - manifest: O.nwjs.manifest, - platform: 'windows', - }); - case 'nwjs-mac': return new Packager.environments.NWjs({ - icon: O.nwjs.icon || getDefaultIcon(), - manifest: O.nwjs.manifest, - platform: 'mac', - }) + case 'nwjs-win64': + case 'nwjs-mac': + return new Packager.environments.NWjs({ + icon: O.nwjs.icon || getDefaultIcon(), + manifest: O.nwjs.manifest, + platform: O.environment.target.substr('nwjs-'.length), + }); } throw new Error('unknown environment'); }; @@ -313,7 +318,7 @@ along with this program. If not, see . const runtime = getRuntime(); const environment = getEnvironment(); const projectData = await loadProject(); - const result = await environment.package(runtime, projectData); + const result = await environment.package(runtime, projectData, progressTarget); if (!(result.data instanceof Blob)) { result.data = new Blob([result.data]); } diff --git a/packager.js b/packager.js index 83de3c8..b5b2eb1 100644 --- a/packager.js +++ b/packager.js @@ -19,14 +19,14 @@ window.Packager = (function() { const readAsDataURL = (blob) => new Promise((resolve, reject) => { const fr = new FileReader(); fr.onload = () => resolve(fr.result); - fr.onerror = () => reject('could not read as data url'); + fr.onerror = () => reject(new Error('could not read as data url')); fr.readAsDataURL(blob); }); const readAsArrayBuffer = (blob) => new Promise((resolve, reject) => { const fr = new FileReader(); fr.onload = () => resolve(fr.result); - fr.onerror = () => reject('could not read as arraybuffer'); + fr.onerror = () => reject(new Error('could not read as arraybuffer')); fr.readAsArrayBuffer(blob); }); @@ -37,18 +37,53 @@ window.Packager = (function() { image.src = src; }); - const isObject = (obj) => typeof obj === 'object' && obj !== null; - const canvasToBlob = (canvas) => new Promise((resolve, reject) => { canvas.toBlob((blob) => { if (blob) { resolve(blob); } else { - reject('Could not read as blob'); + reject(new Error('Could not read as blob')); } }); // png is default type, quality is ignored }); + const isObject = (obj) => typeof obj === 'object' && obj !== null; + + // TODO: load dynamically + const assetManifest = { + 'nwjs-win64': { + src: 'https://packagerdata.turbowarp.org/nwjs-v0.49.0-win-x64.zip', + size: 97406745 + }, + 'nwjs-mac': { + src: 'https://packagerdata.turbowarp.org/nwjs-v0.49.0-osx-x64.zip', + size: 128684835 + } + }; + + const fetchManifestAsset = (assetName, progressCallback) => { + const manifestEntry = assetManifest[assetName]; + if (manifestEntry._data) { + return Promise.resolve(manifestEntry._data); + } + return new Promise((resolve, reject) => { + const {src, size} = manifestEntry; + const xhr = new XMLHttpRequest(); + xhr.responseType = 'blob'; + xhr.onload = () => { + manifestEntry._data = xhr.response; + resolve(xhr.response); + }; + xhr.onerror = () => reject(new Error('XHR failed')); + xhr.onprogress = (e) => { + progressCallback(e.loaded / size); + }; + xhr.onloadend = () => progressCallback(1); + xhr.open('GET', src); + xhr.send(); + }); + }; + class Project { constructor(blob, type) { this.blob = blob; @@ -588,11 +623,14 @@ ${scripts} this.platform = platform; this.icon = icon; } - async package(runtime, projectData) { + async package(runtime, projectData, progressTarget) { const packagerData = await runtime.package(await projectData.asFetchedFrom('project.zip')); - const response = await fetch(`https://packagerdata.turbowarp.org/nwjs-v0.49.0-${this.platform === 'windows' ? 'win' : 'osx'}-x64.zip`); - const nwjsData = await response.arrayBuffer(); + const nwjsData = await fetchManifestAsset(`nwjs-${this.platform}`, (progress) => { + progressTarget.dispatchEvent(new CustomEvent('nwjs-progress', { + detail: progress + })); + }) const nwjsZip = await JSZip.loadAsync(nwjsData); // Inside the nw.js zip is another folder called something like nwjs-v0.48.2-win-x64