From bcbdafabb4b5eba069f7be5d6efd628f950433a6 Mon Sep 17 00:00:00 2001
From: Fuwn <contact@fuwn.me>
Date: Sun, 17 Mar 2024 00:19:05 -0700
Subject: feat(tools): hayai v2

---
 src/lib/Tools/Hayai.svelte | 75 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 75 insertions(+)
 create mode 100644 src/lib/Tools/Hayai.svelte

(limited to 'src/lib/Tools/Hayai.svelte')

diff --git a/src/lib/Tools/Hayai.svelte b/src/lib/Tools/Hayai.svelte
new file mode 100644
index 00000000..b782f579
--- /dev/null
+++ b/src/lib/Tools/Hayai.svelte
@@ -0,0 +1,75 @@
+<script lang="ts">
+	import { onMount } from 'svelte';
+	import JSZip from 'jszip';
+
+	let fileInput: HTMLInputElement | null = null;
+
+	const handleFileUpload = async () => {
+		if (!fileInput || !fileInput.files || fileInput.files.length === 0) return;
+
+		const file = fileInput.files[0];
+		const reader = new FileReader();
+
+		reader.onload = async (event) => {
+			const zip = await JSZip.loadAsync((event.target as FileReader).result as ArrayBuffer);
+			const newZip = new JSZip();
+
+			for (const relativePath in zip.files) {
+				const zipEntry = zip.files[relativePath];
+
+				if (zipEntry.dir) {
+					newZip.folder(relativePath);
+				} else if (relativePath.endsWith('.xhtml') || relativePath.endsWith('.html')) {
+					newZip.file(relativePath, applyBionicReading(await zipEntry.async('text')));
+				} else {
+					newZip.file(relativePath, await zipEntry.async('arraybuffer'));
+				}
+			}
+
+			downloadEpub(
+				await newZip.generateAsync({ type: 'blob' }),
+				`${file.name.split('.epub')[0]}_hayai.epub`
+			);
+		};
+
+		reader.readAsArrayBuffer(file);
+	};
+
+	const applyBionicReading = (content: string) => {
+		const contentParser = new DOMParser().parseFromString(content, 'text/html');
+
+		for (const paragraph of contentParser.getElementsByTagName('p'))
+			paragraph.innerHTML = (paragraph.textContent ?? '')
+				.split(/\s+/)
+				.map((word) => {
+					const strippedWord = word.replace(/[^\w]/g, '');
+					const halfLength = Math.ceil(strippedWord.length * 0.6);
+					const firstHalf = `<strong>${strippedWord.slice(0, halfLength)}</strong>`;
+					const secondHalf = strippedWord.slice(halfLength);
+					return `${firstHalf}${secondHalf}${word.slice(strippedWord.length)}`;
+				})
+				.join(' ');
+
+		return contentParser.documentElement.outerHTML;
+	};
+
+	const downloadEpub = (blob: Blob | MediaSource, fileName: string) => {
+		const link = document.createElement('a');
+
+		link.href = URL.createObjectURL(blob);
+		link.download = fileName;
+
+		link.click();
+		URL.revokeObjectURL(link.href);
+	};
+
+	onMount(() => (fileInput = document.getElementById('epub-file') as HTMLInputElement));
+</script>
+
+<div class="card">
+	Upload an EPUB, receive a "<b>bi</b>onic" <b>EP</b>UB.
+
+	<p />
+
+	<input type="file" id="epub-file" accept=".epub" on:change={handleFileUpload} />
+</div>
-- 
cgit v1.2.3

