Add manga extracting
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { catalog } from '$lib/catalog';
|
import { catalog } from '$lib/catalog';
|
||||||
import { P } from 'flowbite-svelte';
|
|
||||||
|
|
||||||
export let id: string;
|
export let id: string;
|
||||||
|
|
||||||
|
|||||||
@@ -2,3 +2,4 @@ export * from './snackbar';
|
|||||||
export * from './upload';
|
export * from './upload';
|
||||||
export * from './misc';
|
export * from './misc';
|
||||||
export * from './modals';
|
export * from './modals';
|
||||||
|
export * from './zip'
|
||||||
56
src/lib/util/zip.ts
Normal file
56
src/lib/util/zip.ts
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import type { Volume } from "$lib/types";
|
||||||
|
import {
|
||||||
|
BlobReader,
|
||||||
|
BlobWriter,
|
||||||
|
TextReader,
|
||||||
|
ZipWriter,
|
||||||
|
} from "@zip.js/zip.js";
|
||||||
|
|
||||||
|
async function zipVolumes(manga: Volume[]) {
|
||||||
|
const volumeZips = []
|
||||||
|
|
||||||
|
for (const volume of manga) {
|
||||||
|
const files = Object.values(volume.files);
|
||||||
|
const zipWriter = new ZipWriter(new BlobWriter("application/zip"));
|
||||||
|
|
||||||
|
const promises = files.map((file) => {
|
||||||
|
return zipWriter.add(file.name, new BlobReader(file))
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
await Promise.all(promises);
|
||||||
|
|
||||||
|
|
||||||
|
volumeZips.push({
|
||||||
|
zipName: volume.volumeName,
|
||||||
|
zipBlob: await zipWriter.close(),
|
||||||
|
mokuroData: JSON.stringify(volume.mokuroData)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return volumeZips;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function zipManga(manga: Volume[]) {
|
||||||
|
const volumeZips = await zipVolumes(manga)
|
||||||
|
const zipWriter = new ZipWriter(new BlobWriter("application/zip"));
|
||||||
|
|
||||||
|
|
||||||
|
const promises = volumeZips.map((volumeZip) => {
|
||||||
|
return [
|
||||||
|
zipWriter.add(`${volumeZip.zipName}.mokuro`, new TextReader(volumeZip.mokuroData)),
|
||||||
|
zipWriter.add(`${volumeZip.zipName}.zip`, new BlobReader(volumeZip.zipBlob))
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
await Promise.all(promises);
|
||||||
|
|
||||||
|
const zipFileBlob = await zipWriter.close();
|
||||||
|
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = URL.createObjectURL(zipFileBlob);
|
||||||
|
link.download = `${manga[0].mokuroData.title}.zip`;
|
||||||
|
link.click();
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
@@ -2,9 +2,9 @@
|
|||||||
import { catalog } from '$lib/catalog';
|
import { catalog } from '$lib/catalog';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import VolumeItem from '$lib/components/VolumeItem.svelte';
|
import VolumeItem from '$lib/components/VolumeItem.svelte';
|
||||||
import { Button, Listgroup } from 'flowbite-svelte';
|
import { Button, Listgroup, Progressbar, Spinner } from 'flowbite-svelte';
|
||||||
import { db } from '$lib/catalog/db';
|
import { db } from '$lib/catalog/db';
|
||||||
import { promptConfirmation } from '$lib/util';
|
import { promptConfirmation, zipManga } from '$lib/util';
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import type { Volume } from '$lib/types';
|
import type { Volume } from '$lib/types';
|
||||||
import { deleteVolume, volumes } from '$lib/settings';
|
import { deleteVolume, volumes } from '$lib/settings';
|
||||||
@@ -38,6 +38,8 @@
|
|||||||
{ timeReadInMinutes: 0, chars: 0, completed: 0 }
|
{ timeReadInMinutes: 0, chars: 0, completed: 0 }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$: loading = false;
|
||||||
|
|
||||||
async function confirmDelete() {
|
async function confirmDelete() {
|
||||||
const title = manga?.[0].mokuroData.title_uuid;
|
const title = manga?.[0].mokuroData.title_uuid;
|
||||||
manga?.forEach((vol) => {
|
manga?.forEach((vol) => {
|
||||||
@@ -52,6 +54,13 @@
|
|||||||
function onDelete() {
|
function onDelete() {
|
||||||
promptConfirmation('Are you sure you want to delete this manga?', confirmDelete);
|
promptConfirmation('Are you sure you want to delete this manga?', confirmDelete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function onExtract() {
|
||||||
|
if (manga) {
|
||||||
|
loading = true;
|
||||||
|
loading = await zipManga(manga);
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
@@ -70,6 +79,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Button color="alternative" on:click={onDelete}>Remove manga</Button>
|
<Button color="alternative" on:click={onDelete}>Remove manga</Button>
|
||||||
|
<Button color="light" on:click={onExtract} disabled={loading}>
|
||||||
|
{loading ? 'Extracting...' : 'Extract manga'}
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Listgroup items={manga} let:item active class="flex-1 h-full w-full">
|
<Listgroup items={manga} let:item active class="flex-1 h-full w-full">
|
||||||
|
|||||||
Reference in New Issue
Block a user