Discord bot to open dong files
at main 2.7 kB view raw
1declare global { 2 interface Uint8Array { 3 toBase64(): string; 4 } 5} 6 7const blobBytes = (blob: Blob) => { 8 if ("bytes" in blob) return blob.bytes(); 9 return new Response(blob).arrayBuffer().then((buffer) => { 10 const uint = new Uint8Array(buffer); 11 return uint; 12 }); 13}; 14 15export const createDong = async ( 16 image: File, 17 audio: File 18): Promise<Blob | string> => { 19 if ( 20 image.type === "" || 21 !image.type.startsWith("image/") || 22 audio.type === "" || 23 !audio.type.startsWith("audio/") 24 ) 25 return "Mime types invalid"; 26 return new Blob([ 27 // version 28 (() => { 29 const version = new Int8Array(new ArrayBuffer(2)); 30 version[0] = 0xd0; 31 version[1] = 2; 32 return version; 33 })(), 34 // image type 35 image.type, 36 // 00 padding 37 new ArrayBuffer(256 - image.type.length), 38 // image size 39 (() => { 40 const value = new Uint32Array(1); 41 value[0] = image.size; 42 return value; 43 })(), 44 // audio type 45 audio.type, 46 // 00 padding 47 new ArrayBuffer(256 - audio.type.length), 48 // audio size 49 (() => { 50 const value = new Uint32Array(1); 51 value[0] = audio.size; 52 return value; 53 })(), 54 // image data 55 await blobBytes(image), 56 // audio data 57 await blobBytes(audio), 58 ]); 59}; 60 61export async function readDong(dongFile: File): Promise< 62 | { 63 image: { data: Uint8Array; mime: string }; 64 audio: { data: Uint8Array; mime: string }; 65 } 66 | string 67> { 68 // get first 2 bytes and verify 69 const version = new Uint8Array(await blobBytes(dongFile.slice(0, 2))); 70 if (version[0] !== 0xd0 || version[1] !== 2) return "Invalid file"; 71 72 // get next 256 bytes and get mime type 73 const imgMimeType: string | undefined = ( 74 await dongFile.slice(2, 258).text() 75 ).match(/[a-zA-Z0-9.]+\/[a-zA-Z0-9.]+/gm)?.[0]; 76 if (!imgMimeType) return "Image mime type parse failed"; 77 78 // get next 4 bytes and get image size 79 const imgSize = new Uint32Array( 80 (await blobBytes(dongFile.slice(258, 262))).buffer 81 )[0]; 82 83 // get next 256 bytes and get mime type 84 const audMimeType: string | undefined = ( 85 await dongFile.slice(262, 518).text() 86 ).match(/[a-zA-Z0-9.]+\/[a-zA-Z0-9.]+/gm)?.[0]; 87 if (!audMimeType) return "Audio mime type parse failed"; 88 89 // get next 4 bytes and get image size 90 const audSize = new Uint32Array( 91 (await blobBytes(dongFile.slice(518, 522))).buffer 92 )[0]; 93 94 const imageBytes = await blobBytes(dongFile.slice(522, 522 + imgSize)); 95 const audioBytes = await blobBytes( 96 dongFile.slice(522 + imgSize, 522 + imgSize + audSize) 97 ); 98 99 return { 100 image: { 101 mime: imgMimeType, 102 data: imageBytes, 103 }, 104 audio: { 105 mime: audMimeType, 106 data: audioBytes, 107 }, 108 }; 109}