aboutsummaryrefslogtreecommitdiff
path: root/src/lib/Tools
diff options
context:
space:
mode:
authorFuwn <[email protected]>2024-03-17 00:19:05 -0700
committerFuwn <[email protected]>2024-03-17 00:19:05 -0700
commitbcbdafabb4b5eba069f7be5d6efd628f950433a6 (patch)
treeaa6d24da0145106b398bd354033ca883c447b3ac /src/lib/Tools
parentfeat(tools): uma musume birthdays (diff)
downloaddue.moe-bcbdafabb4b5eba069f7be5d6efd628f950433a6.tar.xz
due.moe-bcbdafabb4b5eba069f7be5d6efd628f950433a6.zip
feat(tools): hayai v2
Diffstat (limited to 'src/lib/Tools')
-rw-r--r--src/lib/Tools/Hayai.svelte75
-rw-r--r--src/lib/Tools/tools.ts5
2 files changed, 80 insertions, 0 deletions
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>
diff --git a/src/lib/Tools/tools.ts b/src/lib/Tools/tools.ts
index 2b7d27f2..2ddbc337 100644
--- a/src/lib/Tools/tools.ts
+++ b/src/lib/Tools/tools.ts
@@ -43,6 +43,11 @@ export const tools: {
'Find and display the birthdays of all Uma Musume characters for today, or any other day of the year',
id: 'uma_musume_birthdays'
},
+ hayai: {
+ name: () => '早い',
+ description: () => 'Read light novels at 1.5x speed!',
+ id: 'hayai'
+ },
discussions: {
name: () => 'Episode Discussion Collector',
description: () => 'Find and display all episode discussions created by a given user',