diff options
| author | Fuwn <[email protected]> | 2024-03-17 00:19:05 -0700 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2024-03-17 00:19:05 -0700 |
| commit | bcbdafabb4b5eba069f7be5d6efd628f950433a6 (patch) | |
| tree | aa6d24da0145106b398bd354033ca883c447b3ac /src/lib/Tools | |
| parent | feat(tools): uma musume birthdays (diff) | |
| download | due.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.svelte | 75 | ||||
| -rw-r--r-- | src/lib/Tools/tools.ts | 5 |
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', |