Make Uploaders return NIP-94 tags
This commit is contained in:
parent
ff39dfc4ec
commit
6090c4a6d9
|
@ -9,46 +9,24 @@ interface FileMeta {
|
||||||
|
|
||||||
/** Upload a file, track it in the database, and return the resulting media object. */
|
/** Upload a file, track it in the database, and return the resulting media object. */
|
||||||
async function uploadFile(file: File, meta: FileMeta, signal?: AbortSignal): Promise<UnattachedMedia> {
|
async function uploadFile(file: File, meta: FileMeta, signal?: AbortSignal): Promise<UnattachedMedia> {
|
||||||
const { type, size } = file;
|
|
||||||
const { pubkey, description } = meta;
|
const { pubkey, description } = meta;
|
||||||
|
|
||||||
if (file.size > Conf.maxUploadSize) {
|
if (file.size > Conf.maxUploadSize) {
|
||||||
throw new Error('File size is too large.');
|
throw new Error('File size is too large.');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { url, sha256, cid, blurhash, width, height } = await uploader.upload(file, { signal });
|
const tags = await uploader.upload(file, { signal });
|
||||||
|
const url = tags[0][1];
|
||||||
const data: string[][] = [
|
|
||||||
['url', url],
|
|
||||||
['m', type],
|
|
||||||
['size', size.toString()],
|
|
||||||
];
|
|
||||||
|
|
||||||
if (typeof width === 'number' && typeof height === 'number') {
|
|
||||||
data.push(['dim', `${width}x${height}`]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sha256) {
|
|
||||||
data.push(['x', sha256]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cid) {
|
|
||||||
data.push(['cid', cid]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (blurhash) {
|
|
||||||
data.push(['blurhash', blurhash]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (description) {
|
if (description) {
|
||||||
data.push(['alt', description]);
|
tags.push(['alt', description]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return insertUnattachedMedia({
|
return insertUnattachedMedia({
|
||||||
id: crypto.randomUUID(),
|
id: crypto.randomUUID(),
|
||||||
pubkey,
|
pubkey,
|
||||||
url,
|
url,
|
||||||
data,
|
data: tags,
|
||||||
uploaded_at: Date.now(),
|
uploaded_at: Date.now(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,8 @@ const configUploader: Uploader = {
|
||||||
upload(file, opts) {
|
upload(file, opts) {
|
||||||
return uploader().upload(file, opts);
|
return uploader().upload(file, opts);
|
||||||
},
|
},
|
||||||
delete(id, opts) {
|
async delete(id, opts) {
|
||||||
return uploader().delete(id, opts);
|
return await uploader().delete?.(id, opts);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -32,11 +32,12 @@ const ipfsUploader: Uploader = {
|
||||||
|
|
||||||
const { Hash: cid } = ipfsAddResponseSchema.parse(await response.json());
|
const { Hash: cid } = ipfsAddResponseSchema.parse(await response.json());
|
||||||
|
|
||||||
return {
|
return [
|
||||||
id: cid,
|
['url', new URL(`/ipfs/${cid}`, Conf.mediaDomain).toString()],
|
||||||
cid,
|
['m', file.type],
|
||||||
url: new URL(`/ipfs/${cid}`, Conf.mediaDomain).toString(),
|
['cid', cid],
|
||||||
};
|
['size', file.size.toString()],
|
||||||
|
];
|
||||||
},
|
},
|
||||||
async delete(cid, opts) {
|
async delete(cid, opts) {
|
||||||
const url = new URL('/api/v0/pin/rm', Conf.ipfs.apiUrl);
|
const url = new URL('/api/v0/pin/rm', Conf.ipfs.apiUrl);
|
||||||
|
|
|
@ -22,11 +22,12 @@ const localUploader: Uploader = {
|
||||||
const url = new URL(mediaDomain);
|
const url = new URL(mediaDomain);
|
||||||
const path = url.pathname === '/' ? filename : join(url.pathname, filename);
|
const path = url.pathname === '/' ? filename : join(url.pathname, filename);
|
||||||
|
|
||||||
return {
|
return [
|
||||||
id: filename,
|
['url', new URL(path, url).toString()],
|
||||||
sha256,
|
['m', file.type],
|
||||||
url: new URL(path, url).toString(),
|
['x', sha256],
|
||||||
};
|
['size', file.size.toString()],
|
||||||
|
];
|
||||||
},
|
},
|
||||||
async delete(id) {
|
async delete(id) {
|
||||||
await Deno.remove(join(Conf.uploadsDir, id));
|
await Deno.remove(join(Conf.uploadsDir, id));
|
||||||
|
|
|
@ -17,17 +17,19 @@ export const nostrbuildUploader: Uploader = {
|
||||||
const json = await response.json();
|
const json = await response.json();
|
||||||
const [data] = nostrbuildSchema.parse(json).data;
|
const [data] = nostrbuildSchema.parse(json).data;
|
||||||
|
|
||||||
return {
|
const tags: [['url', string], ...string[][]] = [
|
||||||
id: data.url,
|
['url', data.url],
|
||||||
sha256: data.sha256,
|
['m', data.mime],
|
||||||
url: data.url,
|
['x', data.sha256],
|
||||||
blurhash: data.blurhash,
|
['ox', data.original_sha256],
|
||||||
width: data.dimensions?.width,
|
['size', file.size.toString()],
|
||||||
height: data.dimensions?.height,
|
['blurhash', data.blurhash],
|
||||||
};
|
];
|
||||||
},
|
|
||||||
// deno-lint-ignore require-await
|
if (data.dimensions) {
|
||||||
async delete(): Promise<void> {
|
tags.push(['dim', `${data.dimensions.width}x${data.dimensions.height}`]);
|
||||||
return;
|
}
|
||||||
|
|
||||||
|
return tags;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -25,12 +25,14 @@ const s3Uploader: Uploader = {
|
||||||
|
|
||||||
const { pathStyle, bucket } = Conf.s3;
|
const { pathStyle, bucket } = Conf.s3;
|
||||||
const path = (pathStyle && bucket) ? join(bucket, filename) : filename;
|
const path = (pathStyle && bucket) ? join(bucket, filename) : filename;
|
||||||
|
const url = new URL(path, Conf.mediaDomain).toString();
|
||||||
|
|
||||||
return {
|
return [
|
||||||
id: filename,
|
['url', url],
|
||||||
sha256,
|
['m', file.type],
|
||||||
url: new URL(path, Conf.mediaDomain).toString(),
|
['x', sha256],
|
||||||
};
|
['size', file.size.toString()],
|
||||||
|
];
|
||||||
},
|
},
|
||||||
async delete(id) {
|
async delete(id) {
|
||||||
await client().deleteObject(id);
|
await client().deleteObject(id);
|
||||||
|
|
|
@ -1,27 +1,9 @@
|
||||||
/** Modular uploader interface, to support uploading to different backends. */
|
/** Modular uploader interface, to support uploading to different backends. */
|
||||||
interface Uploader {
|
interface Uploader {
|
||||||
/** Upload the file to the backend. */
|
/** Upload the file to the backend. */
|
||||||
upload(file: File, opts?: { signal?: AbortSignal }): Promise<UploadResult>;
|
upload(file: File, opts?: { signal?: AbortSignal }): Promise<[['url', string], ...string[][]]>;
|
||||||
/** Delete the file from the backend. */
|
/** Delete the file from the backend. */
|
||||||
delete(cid: string, opts?: { signal?: AbortSignal }): Promise<void>;
|
delete?(cid: string, opts?: { signal?: AbortSignal }): Promise<void>;
|
||||||
}
|
|
||||||
|
|
||||||
/** Return value from the uploader after uploading a file. */
|
|
||||||
interface UploadResult {
|
|
||||||
/** File ID specific to the uploader, so it can later be referenced or deleted. */
|
|
||||||
id: string;
|
|
||||||
/** URL where the file can be accessed. */
|
|
||||||
url: string;
|
|
||||||
/** SHA-256 hash of the file. */
|
|
||||||
sha256?: string;
|
|
||||||
/** Blurhash of the file. */
|
|
||||||
blurhash?: string;
|
|
||||||
/** IPFS CID of the file. */
|
|
||||||
cid?: string;
|
|
||||||
/** Width of the file, if applicable. */
|
|
||||||
width?: number;
|
|
||||||
/** Height of the file, if applicable. */
|
|
||||||
height?: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type { Uploader };
|
export type { Uploader };
|
||||||
|
|
Loading…
Reference in New Issue