Canonical repo for Dong Web (dong.vielle.dev)

add file handler support to PWA

Changed files
+54 -32
src
+4 -20
src/dong-io.ts
··· 12 12 }); 13 13 }; 14 14 15 - const uint8array64 = (arru8: Uint8Array) => { 16 - if ("toBase64" in arru8) return arru8.toBase64(); 17 - 18 - function _arrayBufferToBase64(bytes: Uint8Array) { 19 - var binary = ""; 20 - var len = bytes.byteLength; 21 - for (var i = 0; i < len; i++) { 22 - binary += String.fromCharCode(bytes[i]); 23 - } 24 - return btoa(binary); 25 - } 26 - return _arrayBufferToBase64(arru8); 27 - }; 28 - 29 15 export const createDong = async ( 30 16 image: File, 31 17 audio: File ··· 74 60 75 61 export async function readDong(dongFile: File): Promise< 76 62 | { 77 - image: { data: Uint8Array; b64?: string; mime: string }; 78 - audio: { data: Uint8Array; b64?: string; mime: string }; 63 + image: { data: Uint8Array; mime: string }; 64 + audio: { data: Uint8Array; mime: string }; 79 65 } 80 66 | string 81 67 > { ··· 113 99 return { 114 100 image: { 115 101 mime: imgMimeType, 116 - data: uint8array64(imageBytes), 117 - b64: uint8array64(imageBytes), 102 + data: imageBytes, 118 103 }, 119 104 audio: { 120 105 mime: audMimeType, 121 - data: uint8array64(audioBytes), 122 - b64: uint8array64(audioBytes), 106 + data: audioBytes, 123 107 }, 124 108 }; 125 109 }
+42 -12
src/pages/index.astro
··· 5 5 <Base title="Dong Web"> 6 6 <script> 7 7 import { createDong, download, readDong } from "../dong-io"; 8 - 8 + 9 9 class CreateDong extends HTMLElement { 10 10 connectedCallback() { 11 11 // create input ··· 120 120 } 121 121 122 122 class LoadDong extends HTMLElement { 123 + // do not append as this is only for playing audio 124 + // loaded here to prevent overlaying the sound 125 + image = document.createElement("img"); 126 + audio = new Audio(); 127 + 123 128 connectedCallback() { 124 129 // create input 125 130 const form = document.createElement("form"); ··· 127 132 const dongSelect = document.createElement("input"); 128 133 // image 129 134 const errormsg = document.createElement("div"); 130 - const image = document.createElement("img"); 131 - 132 - // do not append as this is only for playing audio 133 - // loaded here to prevent overlaying the sound 134 - const audio = new Audio(); 135 135 136 136 dongSelect.type = "file"; 137 137 dongSelect.accept = ".dong"; ··· 145 145 form.appendChild(dongLabel); 146 146 147 147 this.appendChild(form); 148 - this.appendChild(image); 148 + this.appendChild(this.image); 149 149 this.appendChild(errormsg); 150 150 151 151 // functionality ··· 167 167 return; 168 168 } 169 169 170 - image.src = `data:${res.image.mime};base64,${res.image.b64}`; 170 + this.image.src = URL.createObjectURL(new Blob([res.image.data])); 171 171 172 172 // audio play 173 - audio.src = `data:${res.audio.mime};base64,${res.audio.data}`; 174 - audio.play(); 173 + this.audio.src = URL.createObjectURL(new Blob([res.audio.data])); 174 + this.audio.play(); 175 175 }); 176 176 } 177 177 } 178 178 179 179 customElements.define("create-dong", CreateDong); 180 180 customElements.define("load-dong", LoadDong); 181 + 182 + async function handleFile(file: File) { 183 + const load_dong = document.getElementById("load") as LoadDong; 184 + const res = await readDong(file); 185 + if (typeof res === "string") return; 186 + load_dong.image.src = URL.createObjectURL(new Blob([res.image.data])); 187 + load_dong.audio.src = URL.createObjectURL(new Blob([res.audio.data])); 188 + load_dong.audio.play(); 189 + } 190 + 191 + // if ("LaunchParams" in window && 'launchQueue' in window && 'files' in window.LaunchParams.prototype) { 192 + // window.launchQueue.setConsumer((launchParams) => { 193 + // if (launchParams.files && launchParams.files.length) { 194 + // handleFile(launchParams.files[0]); 195 + // } 196 + // }); 197 + // } 198 + 199 + if ("launchQueue" in window && "LaunchParams" in window) { 200 + (window as any).launchQueue.setConsumer( 201 + async (launchParams: { files: any[] }) => { 202 + if (!launchParams.files.length) { 203 + return; 204 + } 205 + const fileHandle = launchParams.files[0]; 206 + const blob: Blob = await fileHandle.getFile(); 207 + handleFile(new File([blob], "", { type: blob.type })); 208 + } 209 + ); 210 + } 181 211 </script> 182 212 183 213 <style slot="head" is:inline> ··· 294 324 <hr /> 295 325 296 326 <!-- creation --> 297 - <create-dong></create-dong> 327 + <create-dong id="create"></create-dong> 298 328 299 329 <hr /> 300 330 301 331 <!-- loading --> 302 - <load-dong></load-dong> 332 + <load-dong id="load"></load-dong> 303 333 </Base>
+8
src/pages/manifest.json.ts
··· 470 470 start_url: "/", 471 471 display: "standalone", 472 472 prefer_related_applications: false, 473 + file_handlers: [ 474 + { 475 + action: "/", 476 + accept: { 477 + "application/prs.vielle.dong": [".dong"], 478 + } 479 + } 480 + ] 473 481 }), 474 482 { 475 483 headers: {