59 lines
1.6 KiB
TypeScript
59 lines
1.6 KiB
TypeScript
import { type FileHandle, open } from "node:fs/promises";
|
|
import { orderBy } from "natural-orderby";
|
|
import { ZipReader, Reader, type Entry } from "@zip.js/zip.js";
|
|
|
|
class FileReader extends Reader<FileHandle> {
|
|
private fd: FileHandle;
|
|
private offset: number;
|
|
constructor(fd: FileHandle) {
|
|
super(fd);
|
|
this.fd = fd;
|
|
this.offset = 0;
|
|
}
|
|
|
|
async init(): Promise<void> {
|
|
this.offset = 0;
|
|
this.size = (await this.fd.stat()).size;
|
|
}
|
|
close(): void {
|
|
this.fd.close();
|
|
}
|
|
|
|
async readUint8Array(index: number, length: number): Promise<Uint8Array> {
|
|
const buffer = new Uint8Array(length);
|
|
const buf = await this.fd.read(buffer, 0, length, index);
|
|
if (buf.bytesRead !== length) {
|
|
console.error(`read error: ${buf.bytesRead} !== ${length}`);
|
|
throw new Error("read error");
|
|
}
|
|
return buffer;
|
|
}
|
|
}
|
|
|
|
export async function readZip(path: string): Promise<{
|
|
reader: ZipReader<FileHandle>
|
|
handle: FileHandle
|
|
}> {
|
|
const fd = await open(path);
|
|
const reader = new ZipReader(new FileReader(fd), {
|
|
useCompressionStream: true,
|
|
preventClose: false,
|
|
});
|
|
return { reader, handle: fd };
|
|
}
|
|
export async function entriesByNaturalOrder(zip: ZipReader<FileHandle>) {
|
|
// console.log(zip);
|
|
const entries = await zip.getEntries();
|
|
// console.log(entries.map((v) => v.filename));
|
|
const ret = orderBy(entries, (v) => v.filename);
|
|
return ret;
|
|
}
|
|
|
|
export async function createReadableStreamFromZip(_zip: ZipReader<FileHandle>, entry: Entry): Promise<ReadableStream> {
|
|
if (entry.getData === undefined) {
|
|
throw new Error("entry.getData is undefined");
|
|
}
|
|
const stream = new TransformStream<Uint8Array, Uint8Array>();
|
|
entry.getData(stream.writable);
|
|
return stream.readable;
|
|
}
|