Discord bot to open dong files
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}