Files
snort/packages/app/src/Upload/VoidCat.ts
2023-12-10 17:19:09 +00:00

100 lines
2.8 KiB
TypeScript

import { EventKind, EventPublisher } from "@snort/system";
import { UploadState, VoidApi } from "@void-cat/api";
import { FileExtensionRegex } from "@/Const";
import { UploadResult } from "@/Upload";
import { base64 } from "@scure/base";
import { throwIfOffline } from "@snort/shared";
/**
* Upload file to void.cat
* https://void.cat/swagger/index.html
*/
export default async function VoidCatUpload(
file: File | Blob,
filename: string,
publisher?: EventPublisher,
progress?: (n: number) => void,
stage?: (n: "starting" | "hashing" | "uploading" | "done" | undefined) => void,
): Promise<UploadResult> {
throwIfOffline();
const auth = publisher
? async (url: string, method: string) => {
const auth = await publisher.generic(eb => {
return eb.kind(EventKind.HttpAuthentication).tag(["u", url]).tag(["method", method]);
});
return `Nostr ${base64.encode(new TextEncoder().encode(JSON.stringify(auth)))}`;
}
: undefined;
const api = new VoidApi("https://void.cat", auth);
const uploader = api.getUploader(
file,
sx => {
stage?.(
(() => {
switch (sx) {
case UploadState.Starting:
return "starting";
case UploadState.Hashing:
return "hashing";
case UploadState.Uploading:
return "uploading";
case UploadState.Done:
return "done";
}
})(),
);
},
px => {
progress?.(px / file.size);
},
);
const rsp = await uploader.upload({
"V-Strip-Metadata": "true",
});
if (rsp.ok) {
let ext = filename.match(FileExtensionRegex);
if (rsp.file?.metadata?.mimeType === "image/webp") {
ext = ["", "webp"];
}
const resultUrl = rsp.file?.metadata?.url ?? `https://void.cat/d/${rsp.file?.id}${ext ? `.${ext[1]}` : ""}`;
const ret = {
url: resultUrl,
metadata: {
hash: rsp.file?.metadata?.digest,
},
} as UploadResult;
if (publisher) {
// NIP-94
/*const tags = [
["url", resultUrl],
["x", rsp.file?.metadata?.digest ?? ""],
["m", rsp.file?.metadata?.mimeType ?? "application/octet-stream"],
];
if (rsp.file?.metadata?.size) {
tags.push(["size", rsp.file.metadata.size.toString()]);
}
if (rsp.file?.metadata?.magnetLink) {
tags.push(["magnet", rsp.file.metadata.magnetLink]);
const parsedMagnet = magnetURIDecode(rsp.file.metadata.magnetLink);
if (parsedMagnet?.infoHash) {
tags.push(["i", parsedMagnet?.infoHash]);
}
}
ret.header = await publisher.generic(eb => {
eb.kind(EventKind.FileHeader).content(filename);
tags.forEach(t => eb.tag(t));
return eb;
});*/
}
return ret;
} else {
return {
error: rsp.errorMessage,
};
}
}